VirtualBox

Changeset 34428 in vbox for trunk/src/VBox/VMM


Ignore:
Timestamp:
Nov 26, 2010 11:08:55 PM (14 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
68200
Message:

PDMBlkCache: Save dirty entries so they get written again on restart if the VM was saved after an I/O error (image size exceeded for FAT32 filesystems for example)

File:
1 edited

Legend:

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

    r34406 r34428  
    6464#endif
    6565
     66#define PDM_BLK_CACHE_SAVED_STATE_VERSION 1
     67
    6668/*******************************************************************************
    6769*   Internal Functions                                                         *
    6870*******************************************************************************/
     71
     72static PPDMBLKCACHEENTRY pdmBlkCacheEntryAlloc(PPDMBLKCACHE pBlkCache,
     73                                               uint64_t off, size_t cbData, uint8_t *pbBuffer);
     74static bool pdmBlkCacheAddDirtyEntry(PPDMBLKCACHE pBlkCache, PPDMBLKCACHEENTRY pEntry);
    6975
    7076/**
     
    752758}
    753759
     760static PPDMBLKCACHE pdmR3BlkCacheFindById(PPDMBLKCACHEGLOBAL pBlkCacheGlobal, const char *pcszId)
     761{
     762    bool fFound = false;
     763    PPDMBLKCACHE pBlkCache = NULL;
     764
     765    RTListForEach(&pBlkCacheGlobal->ListUsers, pBlkCache, PDMBLKCACHE, NodeCacheUser)
     766    {
     767        if (!RTStrCmp(pBlkCache->pszId, pcszId))
     768        {
     769            fFound = true;
     770            break;
     771        }
     772    }
     773
     774    return fFound ?  pBlkCache : NULL;
     775}
     776
    754777/**
    755778 * Commit timer callback.
     
    767790    TMTimerSetMillies(pTimer, pCache->u32CommitTimeoutMs);
    768791    LogFlowFunc(("Entries committed, going to sleep\n"));
     792}
     793
     794static DECLCALLBACK(int) pdmR3BlkCacheSaveExec(PVM pVM, PSSMHANDLE pSSM)
     795{
     796    PPDMBLKCACHEGLOBAL pBlkCacheGlobal = pVM->pUVM->pdm.s.pBlkCacheGlobal;
     797
     798    AssertPtr(pBlkCacheGlobal);
     799
     800    pdmBlkCacheLockEnter(pBlkCacheGlobal);
     801
     802    SSMR3PutU32(pSSM, pBlkCacheGlobal->cRefs);
     803
     804    /* Go through the list and save all dirty entries. */
     805    PPDMBLKCACHE pBlkCache;
     806    RTListForEach(&pBlkCacheGlobal->ListUsers, pBlkCache, PDMBLKCACHE, NodeCacheUser)
     807    {
     808        uint32_t cEntries = 0;
     809        PPDMBLKCACHEENTRY pEntry;
     810
     811        RTSemRWRequestRead(pBlkCache->SemRWEntries, RT_INDEFINITE_WAIT);
     812        SSMR3PutU32(pSSM, strlen(pBlkCache->pszId));
     813        SSMR3PutStrZ(pSSM, pBlkCache->pszId);
     814
     815        /* Count the number of entries to safe. */
     816        RTListForEach(&pBlkCache->ListDirtyNotCommitted, pEntry, PDMBLKCACHEENTRY, NodeNotCommitted)
     817        {
     818            cEntries++;
     819        }
     820
     821        SSMR3PutU32(pSSM, cEntries);
     822
     823        /* Walk the list of all dirty entries and save them. */
     824        RTListForEach(&pBlkCache->ListDirtyNotCommitted, pEntry, PDMBLKCACHEENTRY, NodeNotCommitted)
     825        {
     826            /* A few sanity checks. */
     827            AssertMsg(!pEntry->cRefs, ("The entry is still referenced\n"));
     828            AssertMsg(pEntry->fFlags & PDMBLKCACHE_ENTRY_IS_DIRTY, ("Entry is not dirty\n"));
     829            AssertMsg(!(pEntry->fFlags & ~PDMBLKCACHE_ENTRY_IS_DIRTY), ("Invalid flags set\n"));
     830            AssertMsg(!pEntry->pWaitingHead && !pEntry->pWaitingTail, ("There are waiting requests\n"));
     831            AssertMsg(   pEntry->pList == &pBlkCacheGlobal->LruRecentlyUsedIn
     832                      || pEntry->pList == &pBlkCacheGlobal->LruFrequentlyUsed,
     833                      ("Invalid list\n"));
     834            AssertMsg(pEntry->cbData == pEntry->Core.KeyLast - pEntry->Core.Key + 1,
     835                      ("Size and range do not match\n"));
     836
     837            /* Save */
     838            SSMR3PutU64(pSSM, pEntry->Core.Key);
     839            SSMR3PutU32(pSSM, pEntry->cbData);
     840            SSMR3PutMem(pSSM, pEntry->pbData, pEntry->cbData);
     841        }
     842
     843        RTSemRWReleaseRead(pBlkCache->SemRWEntries);
     844    }
     845
     846    pdmBlkCacheLockLeave(pBlkCacheGlobal);
     847
     848    /* Terminator */
     849    return SSMR3PutU32(pSSM, UINT32_MAX);
     850}
     851
     852static DECLCALLBACK(int) pdmR3BlkCacheLoadExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
     853{
     854    int rc = VINF_SUCCESS;
     855    uint32_t cRefs;
     856    PPDMBLKCACHEGLOBAL pBlkCacheGlobal = pVM->pUVM->pdm.s.pBlkCacheGlobal;
     857
     858    AssertPtr(pBlkCacheGlobal);
     859
     860    pdmBlkCacheLockEnter(pBlkCacheGlobal);
     861
     862    if (uVersion != PDM_BLK_CACHE_SAVED_STATE_VERSION)
     863        return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
     864
     865    SSMR3GetU32(pSSM, &cRefs);
     866
     867    if (cRefs == pBlkCacheGlobal->cRefs)
     868    {
     869        char *pszId = NULL;
     870
     871        while (   cRefs > 0
     872               && RT_SUCCESS(rc))
     873        {
     874            PPDMBLKCACHE pBlkCache = NULL;
     875            uint32_t cbId = 0;
     876
     877            SSMR3GetU32(pSSM, &cbId);
     878            Assert(cbId > 0);
     879
     880            cbId++; /* Include terminator */
     881            pszId = (char *)RTMemAllocZ(cbId * sizeof(char));
     882            if (!pszId)
     883            {
     884                rc = VERR_NO_MEMORY;
     885                break;
     886            }
     887
     888            rc = SSMR3GetStrZ(pSSM, pszId, cbId);
     889            AssertRC(rc);
     890
     891            /* Search for the block cache with the provided id. */
     892            pBlkCache = pdmR3BlkCacheFindById(pBlkCacheGlobal, pszId);
     893            if (!pBlkCache)
     894            {
     895                rc = SSMR3SetCfgError(pSSM, RT_SRC_POS,
     896                                      N_("The VM is missing a block device. Please make sure the source and target VMs have compatible storage configurations"));
     897                break;
     898            }
     899
     900            RTStrFree(pszId);
     901            pszId = NULL;
     902
     903            /* Get the entries */
     904            uint32_t cEntries;
     905            SSMR3GetU32(pSSM, &cEntries);
     906
     907            while (cEntries > 0)
     908            {
     909                PPDMBLKCACHEENTRY pEntry;
     910                uint64_t off;
     911                uint32_t cbEntry;
     912
     913                SSMR3GetU64(pSSM, &off);
     914                SSMR3GetU32(pSSM, &cbEntry);
     915
     916                pEntry = pdmBlkCacheEntryAlloc(pBlkCache, off, cbEntry, NULL);
     917                if (!pEntry)
     918                {
     919                    rc = VERR_NO_MEMORY;
     920                    break;
     921                }
     922
     923                rc = SSMR3GetMem(pSSM, pEntry->pbData, cbEntry);
     924                if (RT_FAILURE(rc))
     925                {
     926                    RTMemFree(pEntry->pbData);
     927                    RTMemFree(pEntry);
     928                    break;
     929                }
     930
     931                /* Insert into the tree. */
     932                bool fInserted = RTAvlrU64Insert(pBlkCache->pTree, &pEntry->Core);
     933                Assert(fInserted);
     934
     935                /* Add to the dirty list. */
     936                pdmBlkCacheAddDirtyEntry(pBlkCache, pEntry);
     937                pdmBlkCacheEntryAddToList(&pBlkCacheGlobal->LruRecentlyUsedIn, pEntry);
     938                pdmBlkCacheAdd(pBlkCacheGlobal, cbEntry);
     939                pdmBlkCacheEntryRelease(pEntry);
     940                cEntries--;
     941            }
     942
     943            cRefs--;
     944        }
     945
     946        if (pszId)
     947            RTStrFree(pszId);
     948    }
     949    else
     950        rc = SSMR3SetCfgError(pSSM, RT_SRC_POS,
     951                              N_("The VM is missing a block device. Please make sure the source and target VMs have compatible storage configurations"));
     952
     953    pdmBlkCacheLockLeave(pBlkCacheGlobal);
     954
     955    if (RT_SUCCESS(rc))
     956    {
     957        uint32_t u32 = 0;
     958        rc = SSMR3GetU32(pSSM, &u32);
     959        if (RT_SUCCESS(rc))
     960            AssertMsgReturn(u32 == UINT32_MAX, ("%#x\n", u32), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
     961    }
     962
     963    return rc;
    769964}
    770965
     
    9061101        if (RT_SUCCESS(rc))
    9071102        {
    908             LogRel(("BlkCache: Cache successfully initialised. Cache size is %u bytes\n", pBlkCacheGlobal->cbMax));
    909             LogRel(("BlkCache: Cache commit interval is %u ms\n", pBlkCacheGlobal->u32CommitTimeoutMs));
    910             LogRel(("BlkCache: Cache commit threshold is %u bytes\n", pBlkCacheGlobal->cbCommitDirtyThreshold));
    911             pUVM->pdm.s.pBlkCacheGlobal = pBlkCacheGlobal;
    912             return VINF_SUCCESS;
     1103            /* Register saved state handler. */
     1104            rc = SSMR3RegisterInternal(pVM, "pdmblkcache", 0, PDM_BLK_CACHE_SAVED_STATE_VERSION, pBlkCacheGlobal->cbMax,
     1105                                       NULL, NULL, NULL,
     1106                                       NULL, pdmR3BlkCacheSaveExec, NULL,
     1107                                       NULL, pdmR3BlkCacheLoadExec, NULL);
     1108            if (RT_SUCCESS(rc))
     1109            {
     1110                LogRel(("BlkCache: Cache successfully initialised. Cache size is %u bytes\n", pBlkCacheGlobal->cbMax));
     1111                LogRel(("BlkCache: Cache commit interval is %u ms\n", pBlkCacheGlobal->u32CommitTimeoutMs));
     1112                LogRel(("BlkCache: Cache commit threshold is %u bytes\n", pBlkCacheGlobal->cbCommitDirtyThreshold));
     1113                pUVM->pdm.s.pBlkCacheGlobal = pBlkCacheGlobal;
     1114                return VINF_SUCCESS;
     1115            }
    9131116        }
    9141117
     
    9651168    int rc = VINF_SUCCESS;
    9661169    PPDMBLKCACHE pBlkCache = NULL;
    967     bool fAlreadyExists = false;
    9681170    PPDMBLKCACHEGLOBAL pBlkCacheGlobal = pVM->pUVM->pdm.s.pBlkCacheGlobal;
    9691171
     
    9771179    pdmBlkCacheLockEnter(pBlkCacheGlobal);
    9781180
    979     RTListForEach(&pBlkCacheGlobal->ListUsers, pBlkCache, PDMBLKCACHE, NodeCacheUser)
    980     {
    981         if (!RTStrCmp(pBlkCache->pszId, pcszId))
    982         {
    983             fAlreadyExists = true;
    984             break;
    985         }
    986     }
    987 
    988     if (!fAlreadyExists)
     1181    pBlkCache = pdmR3BlkCacheFindById(pBlkCacheGlobal, pcszId);
     1182
     1183    if (!pBlkCache)
    9891184    {
    9901185        pBlkCache = (PPDMBLKCACHE)RTMemAllocZ(sizeof(PDMBLKCACHE));
     
    11621357    PPDMBLKCACHE pBlkCache = pEntry->pBlkCache;
    11631358
    1164     while (ASMAtomicReadU32(&pEntry->fFlags) & (PDMBLKCACHE_ENTRY_IO_IN_PROGRESS | PDMBLKCACHE_ENTRY_IS_DIRTY))
     1359    while (ASMAtomicReadU32(&pEntry->fFlags) & PDMBLKCACHE_ENTRY_IO_IN_PROGRESS)
    11651360    {
    11661361        /* Leave the locks to let the I/O thread make progress but reference the entry to prevent eviction. */
     
    11771372    }
    11781373
    1179     AssertMsg(!(pEntry->fFlags & (PDMBLKCACHE_ENTRY_IO_IN_PROGRESS | PDMBLKCACHE_ENTRY_IS_DIRTY)),
     1374    AssertMsg(!(pEntry->fFlags & PDMBLKCACHE_ENTRY_IO_IN_PROGRESS),
    11801375                ("Entry is dirty and/or still in progress fFlags=%#x\n", pEntry->fFlags));
    11811376
     
    22702465             * Add the waiters to the list again.
    22712466             */
     2467            pEntry->fFlags &= ~PDMBLKCACHE_ENTRY_IS_DIRTY; /* Clear so it gets added to the list again. */
    22722468            fDirty = true;
    22732469
Note: See TracChangeset for help on using the changeset viewer.

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