VirtualBox

Changeset 26334 in vbox


Ignore:
Timestamp:
Feb 8, 2010 6:58:55 PM (15 years ago)
Author:
vboxsync
Message:

AsyncCompletion: Fix a few bugs which could result in cache exceeding the maximum size

Location:
trunk/src/VBox/VMM
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/PDMAsyncCompletionFileCache.cpp

    r26246 r26334  
    2222
    2323/** @page pg_pdm_async_completion_cache     PDM Async Completion Cache - The file I/O cache
    24  * This component implements an I/O cache for file endpoints based on the ARC algorithm.
    25  * http://en.wikipedia.org/wiki/Adaptive_Replacement_Cache
    26  *
    27  * The algorithm uses four LRU (Least frequently used) lists to store data in the cache.
    28  * Two of them contain data where one stores entries which were accessed recently and one
    29  * which is used for frequently accessed data.
    30  * The other two lists are called ghost lists and store information about the accessed range
    31  * but do not contain data. They are used to track data access. If these entries are accessed
    32  * they will push the data to a higher position in the cache preventing it from getting removed
    33  * quickly again.
    34  *
    35  * The algorithm needs to be modified to meet our requirements. Like the implementation
    36  * for the ZFS filesystem we need to handle pages with a variable size. It would
    37  * be possible to use a fixed size but would increase the computational
    38  * and memory overhead.
    39  * Because we do I/O asynchronously we also need to mark entries which are currently accessed
    40  * as non evictable to prevent removal of the entry while the data is being accessed.
     24 * This component implements an I/O cache for file endpoints based on the 2Q cache algorithm.
    4125 */
    4226
     
    7458    do \
    7559    { \
    76      AssertMsg(RTCritSectIsOwner(&pCache->CritSect), \
     60     AssertMsg(RTCritSectIsOwner(&Cache->CritSect), \
    7761               ("Thread does not own critical section\n"));\
    7862    } while(0);
     
    168152}
    169153
     154#ifdef DEBUG
     155static void pdmacFileCacheValidate(PPDMACFILECACHEGLOBAL pCache)
     156{
     157    /* Amount of cached data should never exceed the maximum amount. */
     158    AssertMsg(pCache->cbCached <= pCache->cbMax,
     159              ("Current amount of cached data exceeds maximum\n"));
     160
     161    /* The amount of cached data in the LRU and FRU list should match cbCached */
     162    AssertMsg(pCache->LruRecentlyUsedIn.cbCached + pCache->LruFrequentlyUsed.cbCached == pCache->cbCached,
     163              ("Amount of cached data doesn't match\n"));
     164
     165    AssertMsg(pCache->LruRecentlyUsedOut.cbCached <= pCache->cbRecentlyUsedOutMax,
     166              ("Paged out list exceeds maximum\n"));
     167}
     168#endif
     169
     170DECLINLINE(void) pdmacFileCacheLockEnter(PPDMACFILECACHEGLOBAL pCache)
     171{
     172    RTCritSectEnter(&pCache->CritSect);
     173#ifdef DEBUG
     174    pdmacFileCacheValidate(pCache);
     175#endif
     176}
     177
     178DECLINLINE(void) pdmacFileCacheLockLeave(PPDMACFILECACHEGLOBAL pCache)
     179{
     180#ifdef DEBUG
     181    pdmacFileCacheValidate(pCache);
     182#endif
     183    RTCritSectLeave(&pCache->CritSect);
     184}
     185
     186DECLINLINE(void) pdmacFileCacheSub(PPDMACFILECACHEGLOBAL pCache, uint32_t cbAmount)
     187{
     188    PDMACFILECACHE_IS_CRITSECT_OWNER(pCache);
     189    pCache->cbCached -= cbAmount;
     190}
     191
     192DECLINLINE(void) pdmacFileCacheAdd(PPDMACFILECACHEGLOBAL pCache, uint32_t cbAmount)
     193{
     194    PDMACFILECACHE_IS_CRITSECT_OWNER(pCache);
     195    pCache->cbCached += cbAmount;
     196}
     197
     198DECLINLINE(void) pdmacFileCacheListAdd(PPDMACFILELRULIST pList, uint32_t cbAmount)
     199{
     200    pList->cbCached += cbAmount;
     201}
     202
     203DECLINLINE(void) pdmacFileCacheListSub(PPDMACFILELRULIST pList, uint32_t cbAmount)
     204{
     205    pList->cbCached -= cbAmount;
     206}
     207
    170208#ifdef PDMACFILECACHE_WITH_LRULIST_CHECKS
    171209/**
     
    251289    pEntry->pPrev    = NULL;
    252290    pEntry->pNext    = NULL;
    253     pList->cbCached -= pEntry->cbData;
     291    pdmacFileCacheListSub(pList, pEntry->cbData);
    254292#ifdef PDMACFILECACHE_WITH_LRULIST_CHECKS
    255293    pdmacFileCacheCheckList(pList, pEntry);
     
    287325    pEntry->pPrev    = NULL;
    288326    pList->pHead     = pEntry;
    289     pList->cbCached += pEntry->cbData;
     327    pdmacFileCacheListAdd(pList, pEntry->cbData);
    290328    pEntry->pList    = pList;
    291329#ifdef PDMACFILECACHE_WITH_LRULIST_CHECKS
     
    345383
    346384    AssertMsg(cbData > 0, ("Evicting 0 bytes not possible\n"));
    347 #ifdef VBOX_WITH_2Q_CACHE
    348385    AssertMsg(   !pGhostListDst
    349386              || (pGhostListDst == &pCache->LruRecentlyUsedOut),
    350387              ("Destination list must be NULL or the recently used but paged out list\n"));
    351 #else
    352     AssertMsg(   !pGhostListDst
    353               || (pGhostListDst == &pCache->LruRecentlyGhost)
    354               || (pGhostListDst == &pCache->LruFrequentlyGhost),
    355               ("Destination list must be NULL or one of the ghost lists\n"));
    356 #endif
    357388
    358389    if (fReuseBuffer)
     
    400431                cbEvicted += pCurr->cbData;
    401432
    402                 pCache->cbCached -= pCurr->cbData;
    403 
    404433                pdmacFileCacheEntryRemoveFromList(pCurr);
     434                pdmacFileCacheSub(pCache, pCurr->cbData);
    405435
    406436                if (pGhostListDst)
    407437                {
    408438                    RTSemRWReleaseWrite(pEndpointCache->SemRWEntries);
    409 #ifdef VBOX_WITH_2Q_CACHE
     439
     440                    PPDMACFILECACHEENTRY pGhostEntFree = pGhostListDst->pTail;
     441
    410442                    /* We have to remove the last entries from the paged out list. */
    411                     while (pGhostListDst->cbCached > pCache->cbRecentlyUsedOutMax)
     443                    while (   ((pGhostListDst->cbCached + pCurr->cbData) > pCache->cbRecentlyUsedOutMax)
     444                           && pGhostEntFree)
    412445                    {
    413                         PPDMACFILECACHEENTRY pFree = pGhostListDst->pTail;
     446                        PPDMACFILECACHEENTRY pFree = pGhostEntFree;
    414447                        PPDMACFILEENDPOINTCACHE pEndpointCacheFree = &pFree->pEndpoint->DataCache;
    415448
     449                        pGhostEntFree = pGhostEntFree->pPrev;
     450
    416451                        RTSemRWRequestWrite(pEndpointCacheFree->SemRWEntries, RT_INDEFINITE_WAIT);
    417452
    418                         pdmacFileCacheEntryRemoveFromList(pFree);
    419 
     453                        if (ASMAtomicReadU32(&pFree->cRefs) == 0)
     454                        {
     455                            pdmacFileCacheEntryRemoveFromList(pFree);
     456
     457                            STAM_PROFILE_ADV_START(&pCache->StatTreeRemove, Cache);
     458                            RTAvlrFileOffsetRemove(pEndpointCacheFree->pTree, pFree->Core.Key);
     459                            STAM_PROFILE_ADV_STOP(&pCache->StatTreeRemove, Cache);
     460
     461                            RTMemFree(pFree);
     462                        }
     463
     464                        RTSemRWReleaseWrite(pEndpointCacheFree->SemRWEntries);
     465                    }
     466
     467                    if (pGhostListDst->cbCached + pCurr->cbData > pCache->cbRecentlyUsedOutMax)
     468                    {
     469                        /* Couldn't remove enough entries. Delete */
    420470                        STAM_PROFILE_ADV_START(&pCache->StatTreeRemove, Cache);
    421                         RTAvlrFileOffsetRemove(pEndpointCacheFree->pTree, pFree->Core.Key);
     471                        RTAvlrFileOffsetRemove(pCurr->pEndpoint->DataCache.pTree, pCurr->Core.Key);
    422472                        STAM_PROFILE_ADV_STOP(&pCache->StatTreeRemove, Cache);
    423473
    424                         RTSemRWReleaseWrite(pEndpointCacheFree->SemRWEntries);
    425                         RTMemFree(pFree);
     474                        RTMemFree(pCurr);
    426475                    }
    427 #endif
    428 
    429                     pdmacFileCacheEntryAddToList(pGhostListDst, pCurr);
     476                    else
     477                        pdmacFileCacheEntryAddToList(pGhostListDst, pCurr);
    430478                }
    431479                else
     
    449497}
    450498
    451 #ifdef VBOX_WITH_2Q_CACHE
    452499static bool pdmacFileCacheReclaim(PPDMACFILECACHEGLOBAL pCache, size_t cbData, bool fReuseBuffer, uint8_t **ppbBuffer)
    453500{
     
    484531    return (cbRemoved >= cbData);
    485532}
    486 
    487 #else
    488 
    489 static size_t pdmacFileCacheReplace(PPDMACFILECACHEGLOBAL pCache, size_t cbData, PPDMACFILELRULIST pEntryList,
    490                                     bool fReuseBuffer, uint8_t **ppbBuffer)
    491 {
    492     PDMACFILECACHE_IS_CRITSECT_OWNER(pCache);
    493 
    494     if (   (pCache->LruRecentlyUsed.cbCached)
    495         && (   (pCache->LruRecentlyUsed.cbCached > pCache->uAdaptVal)
    496             || (   (pEntryList == &pCache->LruFrequentlyGhost)
    497                 && (pCache->LruRecentlyUsed.cbCached == pCache->uAdaptVal))))
    498     {
    499         /* We need to remove entry size pages from T1 and move the entries to B1 */
    500         return pdmacFileCacheEvictPagesFrom(pCache, cbData,
    501                                             &pCache->LruRecentlyUsed,
    502                                             &pCache->LruRecentlyGhost,
    503                                             fReuseBuffer, ppbBuffer);
    504     }
    505     else
    506     {
    507         /* We need to remove entry size pages from T2 and move the entries to B2 */
    508         return pdmacFileCacheEvictPagesFrom(pCache, cbData,
    509                                             &pCache->LruFrequentlyUsed,
    510                                             &pCache->LruFrequentlyGhost,
    511                                             fReuseBuffer, ppbBuffer);
    512     }
    513 }
    514 
    515 /**
    516  * Tries to evict the given amount of the data from the cache.
    517  *
    518  * @returns Bytes removed.
    519  * @param    pCache    The global cache data.
    520  * @param    cbData    Number of bytes to evict.
    521  */
    522 static size_t pdmacFileCacheEvict(PPDMACFILECACHEGLOBAL pCache, size_t cbData, bool fReuseBuffer, uint8_t **ppbBuffer)
    523 {
    524     size_t cbRemoved = ~0;
    525 
    526     PDMACFILECACHE_IS_CRITSECT_OWNER(pCache);
    527 
    528     if ((pCache->LruRecentlyUsed.cbCached + pCache->LruRecentlyGhost.cbCached) >= pCache->cbMax)
    529     {
    530         /* Delete desired pages from the cache. */
    531         if (pCache->LruRecentlyUsed.cbCached < pCache->cbMax)
    532         {
    533             cbRemoved = pdmacFileCacheEvictPagesFrom(pCache, cbData,
    534                                                      &pCache->LruRecentlyGhost,
    535                                                      NULL,
    536                                                      fReuseBuffer, ppbBuffer);
    537         }
    538         else
    539         {
    540             cbRemoved = pdmacFileCacheEvictPagesFrom(pCache, cbData,
    541                                                      &pCache->LruRecentlyUsed,
    542                                                      NULL,
    543                                                      fReuseBuffer, ppbBuffer);
    544         }
    545     }
    546     else
    547     {
    548         uint32_t cbUsed = pCache->LruRecentlyUsed.cbCached + pCache->LruRecentlyGhost.cbCached +
    549                           pCache->LruFrequentlyUsed.cbCached + pCache->LruFrequentlyGhost.cbCached;
    550 
    551         if (cbUsed >= pCache->cbMax)
    552         {
    553             if (cbUsed == 2*pCache->cbMax)
    554                 cbRemoved = pdmacFileCacheEvictPagesFrom(pCache, cbData,
    555                                                          &pCache->LruFrequentlyGhost,
    556                                                          NULL,
    557                                                          fReuseBuffer, ppbBuffer);
    558 
    559             if (cbRemoved >= cbData)
    560                 cbRemoved = pdmacFileCacheReplace(pCache, cbData, NULL, fReuseBuffer, ppbBuffer);
    561         }
    562     }
    563 
    564     return cbRemoved;
    565 }
    566 
    567 /**
    568  * Updates the cache parameters
    569  *
    570  * @returns nothing.
    571  * @param    pCache    The global cache data.
    572  * @param    pEntry    The entry usign for the update.
    573  */
    574 static void pdmacFileCacheUpdate(PPDMACFILECACHEGLOBAL pCache, PPDMACFILECACHEENTRY pEntry)
    575 {
    576     int32_t uUpdateVal = 0;
    577 
    578     PDMACFILECACHE_IS_CRITSECT_OWNER(pCache);
    579 
    580     /* Update parameters */
    581     if (pEntry->pList == &pCache->LruRecentlyGhost)
    582     {
    583         if (pCache->LruRecentlyGhost.cbCached >= pCache->LruFrequentlyGhost.cbCached)
    584             uUpdateVal = 1;
    585         else
    586             uUpdateVal = pCache->LruFrequentlyGhost.cbCached / pCache->LruRecentlyGhost.cbCached;
    587 
    588         pCache->uAdaptVal = RT_MIN(pCache->uAdaptVal + uUpdateVal, pCache->cbMax);
    589     }
    590     else if (pEntry->pList == &pCache->LruFrequentlyGhost)
    591     {
    592         if (pCache->LruFrequentlyGhost.cbCached >= pCache->LruRecentlyGhost.cbCached)
    593             uUpdateVal = 1;
    594         else
    595             uUpdateVal = pCache->LruRecentlyGhost.cbCached / pCache->LruFrequentlyGhost.cbCached;
    596 
    597         pCache->uAdaptVal = RT_MIN(pCache->uAdaptVal - uUpdateVal, 0);
    598     }
    599     else
    600         AssertMsgFailed(("Invalid list type\n"));
    601 }
    602 #endif
    603533
    604534/**
     
    799729
    800730    /* Initialize members */
    801 #ifdef VBOX_WITH_2Q_CACHE
    802731    pCache->LruRecentlyUsedIn.pHead    = NULL;
    803732    pCache->LruRecentlyUsedIn.pTail    = NULL;
     
    815744    pCache->cbRecentlyUsedOutMax = (pCache->cbMax / 100) * 50; /* 50% of the buffer size */
    816745    LogFlowFunc((": cbRecentlyUsedInMax=%u cbRecentlyUsedOutMax=%u\n", pCache->cbRecentlyUsedInMax, pCache->cbRecentlyUsedOutMax));
    817 #else
    818     pCache->LruRecentlyUsed.pHead  = NULL;
    819     pCache->LruRecentlyUsed.pTail  = NULL;
    820     pCache->LruRecentlyUsed.cbCached = 0;
    821 
    822     pCache->LruFrequentlyUsed.pHead  = NULL;
    823     pCache->LruFrequentlyUsed.pTail  = NULL;
    824     pCache->LruFrequentlyUsed.cbCached = 0;
    825 
    826     pCache->LruRecentlyGhost.pHead  = NULL;
    827     pCache->LruRecentlyGhost.pTail  = NULL;
    828     pCache->LruRecentlyGhost.cbCached = 0;
    829 
    830     pCache->LruFrequentlyGhost.pHead  = NULL;
    831     pCache->LruFrequentlyGhost.pTail  = NULL;
    832     pCache->LruFrequentlyGhost.cbCached = 0;
    833 
    834     pCache->uAdaptVal = 0;
    835 #endif
    836746
    837747    STAMR3Register(pClassFile->Core.pVM, &pCache->cbMax,
     
    845755                   STAMUNIT_BYTES,
    846756                   "Currently used cache");
    847 #ifdef VBOX_WITH_2Q_CACHE
    848757    STAMR3Register(pClassFile->Core.pVM, &pCache->LruRecentlyUsedIn.cbCached,
    849758                   STAMTYPE_U32, STAMVISIBILITY_ALWAYS,
     
    861770                   STAMUNIT_BYTES,
    862771                   "Number of bytes cached in FRU ghost list");
    863 #else
    864     STAMR3Register(pClassFile->Core.pVM, &pCache->LruRecentlyUsed.cbCached,
    865                    STAMTYPE_U32, STAMVISIBILITY_ALWAYS,
    866                    "/PDM/AsyncCompletion/File/cbCachedMru",
    867                    STAMUNIT_BYTES,
    868                    "Number of bytes cached in Mru list");
    869     STAMR3Register(pClassFile->Core.pVM, &pCache->LruFrequentlyUsed.cbCached,
    870                    STAMTYPE_U32, STAMVISIBILITY_ALWAYS,
    871                    "/PDM/AsyncCompletion/File/cbCachedFru",
    872                    STAMUNIT_BYTES,
    873                    "Number of bytes cached in Fru list");
    874     STAMR3Register(pClassFile->Core.pVM, &pCache->LruRecentlyGhost.cbCached,
    875                    STAMTYPE_U32, STAMVISIBILITY_ALWAYS,
    876                    "/PDM/AsyncCompletion/File/cbCachedMruGhost",
    877                    STAMUNIT_BYTES,
    878                    "Number of bytes cached in Mru ghost list");
    879     STAMR3Register(pClassFile->Core.pVM, &pCache->LruFrequentlyGhost.cbCached,
    880                    STAMTYPE_U32, STAMVISIBILITY_ALWAYS,
    881                    "/PDM/AsyncCompletion/File/cbCachedFruGhost",
    882                    STAMUNIT_BYTES, "Number of bytes cached in Fru ghost list");
    883 #endif
    884772
    885773#ifdef VBOX_WITH_STATISTICS
     
    920808                   "/PDM/AsyncCompletion/File/CacheBuffersReused",
    921809                   STAMUNIT_COUNT, "Number of times a buffer could be reused");
    922 #ifndef VBOX_WITH_2Q_CACHE
    923     STAMR3Register(pClassFile->Core.pVM, &pCache->uAdaptVal,
    924                    STAMTYPE_U32, STAMVISIBILITY_ALWAYS,
    925                    "/PDM/AsyncCompletion/File/CacheAdaptValue",
    926                    STAMUNIT_COUNT,
    927                    "Adaption value of the cache");
    928 #endif
    929810#endif
    930811
     
    949830
    950831    /* Make sure no one else uses the cache now */
    951     RTCritSectEnter(&pCache->CritSect);
    952 
    953 #ifdef VBOX_WITH_2Q_CACHE
     832    pdmacFileCacheLockEnter(pCache);
     833
    954834    /* Cleanup deleting all cache entries waiting for in progress entries to finish. */
    955835    pdmacFileCacheDestroyList(&pCache->LruRecentlyUsedIn);
    956836    pdmacFileCacheDestroyList(&pCache->LruRecentlyUsedOut);
    957837    pdmacFileCacheDestroyList(&pCache->LruFrequentlyUsed);
    958 #else
    959     /* Cleanup deleting all cache entries waiting for in progress entries to finish. */
    960     pdmacFileCacheDestroyList(&pCache->LruRecentlyUsed);
    961     pdmacFileCacheDestroyList(&pCache->LruFrequentlyUsed);
    962     pdmacFileCacheDestroyList(&pCache->LruRecentlyGhost);
    963     pdmacFileCacheDestroyList(&pCache->LruFrequentlyGhost);
    964 #endif
    965 
    966     RTCritSectLeave(&pCache->CritSect);
     838
     839    pdmacFileCacheLockLeave(pCache);
    967840
    968841    RTCritSectDelete(&pCache->CritSect);
     
    1020893    PPDMACFILEENDPOINTCACHE pEndpointCache = &pEntry->pEndpoint->DataCache;
    1021894
    1022     while (pEntry->fFlags & (PDMACFILECACHE_ENTRY_IO_IN_PROGRESS | PDMACFILECACHE_ENTRY_IS_DIRTY))
     895    while (ASMAtomicReadU32(&pEntry->fFlags) & (PDMACFILECACHE_ENTRY_IO_IN_PROGRESS | PDMACFILECACHE_ENTRY_IS_DIRTY))
    1023896    {
    1024897        RTSemRWReleaseWrite(pEndpointCache->SemRWEntries);
     
    1030903                ("Entry is dirty and/or still in progress fFlags=%#x\n", pEntry->fFlags));
    1031904
     905    bool fUpdateCache =    pEntry->pList == &pCache->LruFrequentlyUsed
     906                        || pEntry->pList == &pCache->LruRecentlyUsedIn;
     907
    1032908    pdmacFileCacheEntryRemoveFromList(pEntry);
    1033     pCache->cbCached -= pEntry->cbData;
     909
     910    if (fUpdateCache)
     911        pdmacFileCacheSub(pCache, pEntry->cbData);
    1034912
    1035913    RTMemPageFree(pEntry->pbData);
     
    1051929
    1052930    /* Make sure nobody is accessing the cache while we delete the tree. */
    1053     RTCritSectEnter(&pCache->CritSect);
     931    pdmacFileCacheLockEnter(pCache);
    1054932    RTSemRWRequestWrite(pEndpointCache->SemRWEntries, RT_INDEFINITE_WAIT);
    1055933    RTAvlrFileOffsetDestroy(pEndpointCache->pTree, pdmacFileEpCacheEntryDestroy, pCache);
    1056934    RTSemRWReleaseWrite(pEndpointCache->SemRWEntries);
    1057     RTCritSectLeave(&pCache->CritSect);
     935    pdmacFileCacheLockLeave(pCache);
    1058936
    1059937    RTSemRWDestroy(pEndpointCache->SemRWEntries);
     
    12061084                                                                uint32_t fSet, uint32_t fClear)
    12071085{
    1208     bool fPassed = ((pEntry->fFlags & fSet) && !(pEntry->fFlags & fClear));
     1086    uint32_t fFlags = ASMAtomicReadU32(&pEntry->fFlags);
     1087    bool fPassed = ((fFlags & fSet) && !(fFlags & fClear));
    12091088
    12101089    if (fPassed)
     
    12131092        RTSemRWRequestWrite(pEndpointCache->SemRWEntries, RT_INDEFINITE_WAIT);
    12141093
    1215         fPassed = ((pEntry->fFlags & fSet) && !(pEntry->fFlags & fClear));
     1094        fFlags = ASMAtomicReadU32(&pEntry->fFlags);
     1095        fPassed = ((fFlags & fSet) && !(fFlags & fClear));
    12161096
    12171097        /* Drop the lock if we didn't passed the test. */
     
    14211301
    14221302            cbRead  -= cbToRead;
    1423             off     += cbToRead;
    14241303
    14251304            if (!cbRead)
     
    14311310
    14321311            /* Ghost lists contain no data. */
    1433 #ifdef VBOX_WITH_2Q_CACHE
    14341312            if (   (pEntry->pList == &pCache->LruRecentlyUsedIn)
    14351313                || (pEntry->pList == &pCache->LruFrequentlyUsed))
    14361314            {
    1437 #else
    1438             if (   (pEntry->pList == &pCache->LruRecentlyUsed)
    1439                 || (pEntry->pList == &pCache->LruFrequentlyUsed))
    1440             {
    1441 #endif
    14421315                if (pdmacFileEpCacheEntryFlagIsSetClearAcquireLock(pEndpointCache, pEntry,
    14431316                                                                   PDMACFILECACHE_ENTRY_IS_DEPRECATED,
     
    14711344
    14721345                /* Move this entry to the top position */
    1473 #ifdef VBOX_WITH_2Q_CACHE
    14741346                if (pEntry->pList == &pCache->LruFrequentlyUsed)
    14751347                {
    1476                     RTCritSectEnter(&pCache->CritSect);
     1348                    pdmacFileCacheLockEnter(pCache);
    14771349                    pdmacFileCacheEntryAddToList(&pCache->LruFrequentlyUsed, pEntry);
    1478                     RTCritSectLeave(&pCache->CritSect);
     1350                    pdmacFileCacheLockLeave(pCache);
    14791351                }
    1480 #else
    1481                 RTCritSectEnter(&pCache->CritSect);
    1482                 pdmacFileCacheEntryAddToList(&pCache->LruFrequentlyUsed, pEntry);
    1483                 RTCritSectLeave(&pCache->CritSect);
    1484 #endif
     1352                /* Release the entry */
     1353                pdmacFileEpCacheEntryRelease(pEntry);
    14851354            }
    14861355            else
     
    14901359                LogFlow(("Fetching data for ghost entry %#p from file\n", pEntry));
    14911360
    1492 #ifdef VBOX_WITH_2Q_CACHE
    1493                 RTCritSectEnter(&pCache->CritSect);
     1361                pdmacFileCacheLockEnter(pCache);
    14941362                pdmacFileCacheEntryRemoveFromList(pEntry); /* Remove it before we remove data, otherwise it may get freed when evicting data. */
    1495                 pdmacFileCacheReclaim(pCache, pEntry->cbData, true, &pbBuffer);
     1363                bool fEnough = pdmacFileCacheReclaim(pCache, pEntry->cbData, true, &pbBuffer);
    14961364
    14971365                /* Move the entry to Am and fetch it to the cache. */
    1498                 pdmacFileCacheEntryAddToList(&pCache->LruFrequentlyUsed, pEntry);
    1499                 RTCritSectLeave(&pCache->CritSect);
    1500 #else
    1501                 RTCritSectEnter(&pCache->CritSect);
    1502                 pdmacFileCacheUpdate(pCache, pEntry);
    1503                 pdmacFileCacheReplace(pCache, pEntry->cbData, pEntry->pList, true, &pbBuffer);
    1504 
    1505                 /* Move the entry to T2 and fetch it to the cache. */
    1506                 pdmacFileCacheEntryAddToList(&pCache->LruFrequentlyUsed, pEntry);
    1507                 RTCritSectLeave(&pCache->CritSect);
    1508 #endif
    1509 
    1510                 if (pbBuffer)
    1511                     pEntry->pbData = pbBuffer;
     1366                if (fEnough)
     1367                {
     1368                    pdmacFileCacheEntryAddToList(&pCache->LruFrequentlyUsed, pEntry);
     1369                    pdmacFileCacheAdd(pCache, pEntry->cbData);
     1370                    pdmacFileCacheLockLeave(pCache);
     1371
     1372                    if (pbBuffer)
     1373                        pEntry->pbData = pbBuffer;
     1374                    else
     1375                        pEntry->pbData = (uint8_t *)RTMemPageAlloc(pEntry->cbData);
     1376                    AssertPtr(pEntry->pbData);
     1377
     1378                    pdmacFileEpCacheEntryWaitersAdd(pEntry, pTask,
     1379                                                    &IoMemCtx,
     1380                                                    OffDiff, cbToRead,
     1381                                                    false /* fWrite */);
     1382                    pdmacFileCacheReadFromEndpoint(pEntry);
     1383                    /* Release the entry */
     1384                    pdmacFileEpCacheEntryRelease(pEntry);
     1385                }
    15121386                else
    1513                     pEntry->pbData = (uint8_t *)RTMemPageAlloc(pEntry->cbData);
    1514                 AssertPtr(pEntry->pbData);
    1515 
    1516                 pdmacFileEpCacheEntryWaitersAdd(pEntry, pTask,
    1517                                                 &IoMemCtx,
    1518                                                 OffDiff, cbToRead,
    1519                                                 false /* fWrite */);
    1520                 pdmacFileCacheReadFromEndpoint(pEntry);
     1387                {
     1388                    RTSemRWRequestWrite(pEndpointCache->SemRWEntries, RT_INDEFINITE_WAIT);
     1389                    STAM_PROFILE_ADV_START(&pCache->StatTreeRemove, Cache);
     1390                    RTAvlrFileOffsetRemove(pEndpointCache->pTree, pEntry->Core.Key);
     1391                    STAM_PROFILE_ADV_STOP(&pCache->StatTreeRemove, Cache);
     1392                    RTSemRWReleaseWrite(pEndpointCache->SemRWEntries);
     1393
     1394                    pdmacFileCacheLockLeave(pCache);
     1395
     1396                    RTMemFree(pEntry);
     1397
     1398                    pdmacFileEpCacheRequestPassthrough(pEndpoint, pTask,
     1399                                                       &IoMemCtx, off, cbToRead,
     1400                                                       PDMACTASKFILETRANSFER_READ);
     1401                }
    15211402            }
    1522 
    1523             /* Release the entry finally. */
    1524             pdmacFileEpCacheEntryRelease(pEntry);
    15251403        }
    15261404        else
     
    15741452            uint8_t *pbBuffer = NULL;
    15751453
    1576 #ifdef VBOX_WITH_2Q_CACHE
    1577             RTCritSectEnter(&pCache->CritSect);
     1454            pdmacFileCacheLockEnter(pCache);
    15781455            bool fEnough = pdmacFileCacheReclaim(pCache, cbToReadAligned, true, &pbBuffer);
    1579             RTCritSectLeave(&pCache->CritSect);
    15801456
    15811457            if (fEnough)
    15821458            {
    15831459                LogFlow(("Evicted enough bytes (%u requested). Creating new cache entry\n", cbToReadAligned));
    1584 #else
    1585             RTCritSectEnter(&pCache->CritSect);
    1586             size_t cbRemoved = pdmacFileCacheEvict(pCache, cbToReadAligned, true, &pbBuffer);
    1587             RTCritSectLeave(&pCache->CritSect);
    1588 
    1589             if (cbRemoved >= cbToReadAligned)
    1590             {
    1591                 LogFlow(("Evicted %u bytes (%u requested). Creating new cache entry\n", cbRemoved, cbToReadAligned));
    1592 #endif
     1460
    15931461                PPDMACFILECACHEENTRY pEntryNew = pdmacFileCacheEntryAlloc(pCache, pEndpoint, off, cbToReadAligned, pbBuffer);
    15941462                AssertPtr(pEntryNew);
    15951463
    1596                 RTCritSectEnter(&pCache->CritSect);
    1597 #ifdef VBOX_WITH_2Q_CACHE
    15981464                pdmacFileCacheEntryAddToList(&pCache->LruRecentlyUsedIn, pEntryNew);
    1599 #else
    1600                 pdmacFileCacheEntryAddToList(&pCache->LruRecentlyUsed, pEntryNew);
    1601 #endif
    1602                 pCache->cbCached += cbToReadAligned;
    1603                 RTCritSectLeave(&pCache->CritSect);
     1465                pdmacFileCacheAdd(pCache, cbToReadAligned);
     1466                pdmacFileCacheLockLeave(pCache);
    16041467
    16051468                pdmacFileEpCacheInsertEntry(pEndpointCache, pEntryNew);
    16061469
    16071470                AssertMsg(   (off >= pEntryNew->Core.Key)
    1608                           && (off + (RTFOFF)cbToRead <= pEntryNew->Core.Key + pEntryNew->Core.KeyLast),
     1471                          && (off + (RTFOFF)cbToRead <= pEntryNew->Core.Key + pEntryNew->Core.KeyLast + 1),
    16091472                          ("Overflow in calculation off=%RTfoff OffsetAligned=%RTfoff\n",
    1610                            off, pEntry->Core.Key));
     1473                           off, pEntryNew->Core.Key));
    16111474
    16121475                pdmacFileEpCacheEntryWaitersAdd(pEntryNew, pTask,
    16131476                                                &IoMemCtx, 0, cbToRead,
    16141477                                                false /* fWrite */);
    1615                 off += cbToRead;
    1616 
    16171478                pdmacFileCacheReadFromEndpoint(pEntryNew);
    16181479                pdmacFileEpCacheEntryRelease(pEntryNew); /* it is protected by the I/O in progress flag now. */
     
    16201481            else
    16211482            {
     1483                pdmacFileCacheLockLeave(pCache);
     1484
    16221485                /*
    16231486                 * There is not enough free space in the cache.
     
    16291492                                                   &IoMemCtx, off, cbToRead,
    16301493                                                   PDMACTASKFILETRANSFER_READ);
    1631                 off += cbToRead;
    16321494            }
    16331495        }
     1496        off += cbToRead;
    16341497    }
    16351498
     
    16971560            cbToWrite = RT_MIN(pEntry->cbData - OffDiff, cbWrite);
    16981561            cbWrite  -= cbToWrite;
    1699             off      += cbToWrite;
    17001562
    17011563            if (!cbWrite)
     
    17071569
    17081570            /* Ghost lists contain no data. */
    1709 #ifdef VBOX_WITH_2Q_CACHE
    17101571            if (   (pEntry->pList == &pCache->LruRecentlyUsedIn)
    17111572                || (pEntry->pList == &pCache->LruFrequentlyUsed))
    1712 #else
    1713             if (   (pEntry->pList == &pCache->LruRecentlyUsed)
    1714                 || (pEntry->pList == &pCache->LruFrequentlyUsed))
    1715 #endif
    17161573            {
    17171574                /* Check if the buffer is deprecated. */
     
    17211578                {
    17221579                    AssertMsg(pEntry->fFlags & PDMACFILECACHE_ENTRY_IO_IN_PROGRESS,
    1723                                 ("Entry is deprecated but not in progress\n"));
     1580                              ("Entry is deprecated but not in progress\n"));
    17241581                    AssertPtr(pEntry->pbDataReplace);
    17251582
     
    18161673
    18171674                    /* Move this entry to the top position */
    1818 #ifdef VBOX_WITH_2Q_CACHE
    1819                 if (pEntry->pList == &pCache->LruFrequentlyUsed)
    1820                 {
    1821                     RTCritSectEnter(&pCache->CritSect);
    1822                     pdmacFileCacheEntryAddToList(&pCache->LruFrequentlyUsed, pEntry);
    1823                     RTCritSectLeave(&pCache->CritSect);
    1824                 } /* Deprecated flag not set. */
    1825 #else
    1826                     RTCritSectEnter(&pCache->CritSect);
    1827                     pdmacFileCacheEntryAddToList(&pCache->LruFrequentlyUsed, pEntry);
    1828                     RTCritSectLeave(&pCache->CritSect);
    1829 #endif
     1675                    if (pEntry->pList == &pCache->LruFrequentlyUsed)
     1676                    {
     1677                        pdmacFileCacheLockEnter(pCache);
     1678                        pdmacFileCacheEntryAddToList(&pCache->LruFrequentlyUsed, pEntry);
     1679                        pdmacFileCacheLockLeave(pCache);
     1680                    } /* Deprecated flag not set. */
    18301681                }
     1682                pdmacFileEpCacheEntryRelease(pEntry);
    18311683            }
    18321684            else /* Entry is on the ghost list */
     
    18341686                uint8_t *pbBuffer = NULL;
    18351687
    1836 #ifdef VBOX_WITH_2Q_CACHE
    1837                 RTCritSectEnter(&pCache->CritSect);
     1688                pdmacFileCacheLockEnter(pCache);
    18381689                pdmacFileCacheEntryRemoveFromList(pEntry); /* Remove it before we remove data, otherwise it may get freed when evicting data. */
    1839                 pdmacFileCacheReclaim(pCache, pEntry->cbData, true, &pbBuffer);
    1840 
    1841                 /* Move the entry to Am and fetch it to the cache. */
    1842                 pdmacFileCacheEntryAddToList(&pCache->LruFrequentlyUsed, pEntry);
    1843                 RTCritSectLeave(&pCache->CritSect);
    1844 #else
    1845                 RTCritSectEnter(&pCache->CritSect);
    1846                 pdmacFileCacheUpdate(pCache, pEntry);
    1847                 pdmacFileCacheReplace(pCache, pEntry->cbData, pEntry->pList, true, &pbBuffer);
    1848 
    1849                 /* Move the entry to T2 and fetch it to the cache. */
    1850                 pdmacFileCacheEntryAddToList(&pCache->LruFrequentlyUsed, pEntry);
    1851                 RTCritSectLeave(&pCache->CritSect);
    1852 #endif
    1853 
    1854                 if (pbBuffer)
    1855                     pEntry->pbData = pbBuffer;
     1690                bool fEnough = pdmacFileCacheReclaim(pCache, pEntry->cbData, true, &pbBuffer);
     1691
     1692                if (fEnough)
     1693                {
     1694                    /* Move the entry to Am and fetch it to the cache. */
     1695                    pdmacFileCacheEntryAddToList(&pCache->LruFrequentlyUsed, pEntry);
     1696                    pdmacFileCacheAdd(pCache, pEntry->cbData);
     1697                    pdmacFileCacheLockLeave(pCache);
     1698
     1699                    if (pbBuffer)
     1700                        pEntry->pbData = pbBuffer;
     1701                    else
     1702                        pEntry->pbData = (uint8_t *)RTMemPageAlloc(pEntry->cbData);
     1703                    AssertPtr(pEntry->pbData);
     1704
     1705                    pdmacFileEpCacheEntryWaitersAdd(pEntry, pTask,
     1706                                                    &IoMemCtx,
     1707                                                    OffDiff, cbToWrite,
     1708                                                    true /* fWrite */);
     1709                    STAM_COUNTER_INC(&pEndpointCache->StatWriteDeferred);
     1710                    pdmacFileCacheReadFromEndpoint(pEntry);
     1711
     1712                    /* Release the reference. If it is still needed the I/O in progress flag should protect it now. */
     1713                    pdmacFileEpCacheEntryRelease(pEntry);
     1714                }
    18561715                else
    1857                     pEntry->pbData = (uint8_t *)RTMemPageAlloc(pEntry->cbData);
    1858                 AssertPtr(pEntry->pbData);
    1859 
    1860                 pdmacFileEpCacheEntryWaitersAdd(pEntry, pTask,
    1861                                                 &IoMemCtx,
    1862                                                 OffDiff, cbToWrite,
    1863                                                 true /* fWrite */);
    1864                 STAM_COUNTER_INC(&pEndpointCache->StatWriteDeferred);
    1865                 pdmacFileCacheReadFromEndpoint(pEntry);
     1716                {
     1717                    RTSemRWRequestWrite(pEndpointCache->SemRWEntries, RT_INDEFINITE_WAIT);
     1718                    STAM_PROFILE_ADV_START(&pCache->StatTreeRemove, Cache);
     1719                    RTAvlrFileOffsetRemove(pEndpointCache->pTree, pEntry->Core.Key);
     1720                    STAM_PROFILE_ADV_STOP(&pCache->StatTreeRemove, Cache);
     1721                    RTSemRWReleaseWrite(pEndpointCache->SemRWEntries);
     1722
     1723                    pdmacFileCacheLockLeave(pCache);
     1724
     1725                    RTMemFree(pEntry);
     1726                    pdmacFileEpCacheRequestPassthrough(pEndpoint, pTask,
     1727                                                       &IoMemCtx, off, cbToWrite,
     1728                                                       PDMACTASKFILETRANSFER_WRITE);
     1729                }
    18661730            }
    1867 
    1868             /* Release the reference. If it is still needed the I/O in progress flag should protect it now. */
    1869             pdmacFileEpCacheEntryRelease(pEntry);
    18701731        }
    18711732        else /* No entry found */
     
    19001761
    19011762            STAM_COUNTER_INC(&pCache->cMisses);
    1902             STAM_COUNTER_ADD(&pCache->StatWritten, cbToWrite);
    19031763
    19041764            uint8_t *pbBuffer = NULL;
    19051765
    1906 #ifdef VBOX_WITH_2Q_CACHE
    1907             RTCritSectEnter(&pCache->CritSect);
     1766            pdmacFileCacheLockEnter(pCache);
    19081767            bool fEnough = pdmacFileCacheReclaim(pCache, cbToWrite, true, &pbBuffer);
    1909             RTCritSectLeave(&pCache->CritSect);
    19101768
    19111769            if (fEnough)
    19121770            {
    19131771                LogFlow(("Evicted enough bytes (%u requested). Creating new cache entry\n", cbToWrite));
    1914 #else
    1915             RTCritSectEnter(&pCache->CritSect);
    1916             size_t cbRemoved = pdmacFileCacheEvict(pCache, cbToWrite, true, &pbBuffer);
    1917             RTCritSectLeave(&pCache->CritSect);
    1918 
    1919             if (cbRemoved >= cbToWrite)
    1920             {
    1921                 LogFlow(("Evicted %u bytes (%u requested). Creating new cache entry\n", cbRemoved, cbToWrite));
    1922 
    1923 #endif
     1772
    19241773                uint8_t *pbBuf;
    19251774                PPDMACFILECACHEENTRY pEntryNew;
     
    19281777                AssertPtr(pEntryNew);
    19291778
    1930                 RTCritSectEnter(&pCache->CritSect);
    1931 #ifdef VBOX_WITH_2Q_CACHE
    19321779                pdmacFileCacheEntryAddToList(&pCache->LruRecentlyUsedIn, pEntryNew);
    1933 #else
    1934                 pdmacFileCacheEntryAddToList(&pCache->LruRecentlyUsed, pEntryNew);
    1935 #endif
    1936                 pCache->cbCached += cbToWrite;
    1937                 RTCritSectLeave(&pCache->CritSect);
     1780                pdmacFileCacheAdd(pCache, cbToWrite);
     1781                pdmacFileCacheLockLeave(pCache);
    19381782
    19391783                pdmacFileEpCacheInsertEntry(pEndpointCache, pEntryNew);
     
    19421786                                                 pEntryNew->pbData,
    19431787                                                 cbToWrite);
    1944                 off += cbToWrite;
    19451788                ASMAtomicSubS32(&pTask->cbTransferLeft, cbToWrite);
    19461789
     
    19481791                pdmacFileCacheWriteToEndpoint(pEntryNew);
    19491792                pdmacFileEpCacheEntryRelease(pEntryNew); /* it is protected by the I/O in progress flag now. */
     1793                STAM_COUNTER_ADD(&pCache->StatWritten, cbToWrite);
    19501794            }
    19511795            else
    19521796            {
     1797                pdmacFileCacheLockLeave(pCache);
     1798
    19531799                /*
    19541800                 * There is not enough free space in the cache.
     
    19601806                                                   &IoMemCtx, off, cbToWrite,
    19611807                                                   PDMACTASKFILETRANSFER_WRITE);
    1962                 off += cbToWrite;
    19631808            }
    19641809        }
     1810
     1811        off += cbToWrite;
    19651812    }
    19661813
  • trunk/src/VBox/VMM/PDMAsyncCompletionFileInternal.h

    r25147 r26334  
    225225    PPDMASYNCCOMPLETIONENDPOINTFILE pEndpoint;
    226226    /** Flags for this entry. Combinations of PDMACFILECACHE_* #defines */
    227     uint32_t                        fFlags;
     227    volatile uint32_t               fFlags;
    228228    /** Reference counter. Prevents eviction of the entry if > 0. */
    229229    volatile uint32_t               cRefs;
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette