VirtualBox

Changeset 35162 in vbox


Ignore:
Timestamp:
Dec 15, 2010 7:39:54 PM (14 years ago)
Author:
vboxsync
Message:

BlkCache: Fix possible crash during suspend of the VM. The cache must be suspended before making the disk readonly to make sure all I/O completed

Location:
trunk
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/pdmblkcache.h

    r34219 r35162  
    310310 */
    311311VMMR3DECL(void) PDMR3BlkCacheIoXferComplete(PPDMBLKCACHE pBlkCache, PPDMBLKCACHEIOXFER hIoXfer, int rcIoXfer);
     312
     313/**
     314 * Suspends the block cache. The cache waits until all I/O transfers completed
     315 * and stops to enqueue new requests after the call returned but will not accept
     316 * reads, write or flushes either.
     317 *
     318 * @returns VBox status code.
     319 * @param   pBlkCache       The cache instance.
     320 */
     321VMMR3DECL(int) PDMR3BlkCacheSuspend(PPDMBLKCACHE pBlkCache);
     322
     323/**
     324 * Resumes operation of the block cache.
     325 *
     326 * @returns VBox status code.
     327 * @param   pBlkCache       The cache instance.
     328 */
     329VMMR3DECL(int) PDMR3BlkCacheResume(PPDMBLKCACHE pBlkCache);
     330
    312331/** @} */
    313332
  • trunk/src/VBox/Devices/Storage/DrvVD.cpp

    r35072 r35162  
    18971897    LogFlowFunc(("\n"));
    18981898    PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
     1899
    18991900    drvvdSetWritable(pThis);
    19001901    pThis->fErrorUseRuntime = true;
     1902
     1903    if (pThis->pBlkCache)
     1904    {
     1905        int rc = PDMR3BlkCacheResume(pThis->pBlkCache);
     1906        AssertRC(rc);
     1907    }
    19011908}
    19021909
     
    19201927    LogFlowFunc(("\n"));
    19211928    PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
     1929
     1930    if (pThis->pBlkCache)
     1931    {
     1932        int rc = PDMR3BlkCacheSuspend(pThis->pBlkCache);
     1933        AssertRC(rc);
     1934    }
     1935
    19221936    drvvdSetReadonly(pThis);
    19231937}
  • trunk/src/VBox/VMM/PDMBlkCache.cpp

    r34658 r35162  
    647647{
    648648    uint32_t cbCommitted = 0;
     649
     650    /* Return if the cache was suspended. */
     651    if (pBlkCache->fSuspended)
     652        return;
     653
    649654    RTSemRWRequestWrite(pBlkCache->SemRWEntries, RT_INDEFINITE_WAIT);
    650655
     
    683688    AssertMsg(pBlkCache->pCache->cbDirty >= cbCommitted,
    684689              ("Number of committed bytes exceeds number of dirty bytes\n"));
    685     ASMAtomicSubU32(&pBlkCache->pCache->cbDirty, cbCommitted);
     690    uint32_t cbDirtyOld = ASMAtomicSubU32(&pBlkCache->pCache->cbDirty, cbCommitted);
     691
     692    /* Reset the commit timer if we don't have any dirty bits. */
     693    if (   !(cbDirtyOld - cbCommitted)
     694        && pBlkCache->pCache->u32CommitTimeoutMs != 0)
     695        TMTimerStop(pBlkCache->pCache->pTimerCommit);
    686696}
    687697
     
    752762        /* Prevent committing if the VM was suspended. */
    753763        if (RT_LIKELY(!ASMAtomicReadBool(&pCache->fIoErrorVmSuspended)))
    754             fDirtyBytesExceeded = (cbDirty >= pCache->cbCommitDirtyThreshold);
     764            fDirtyBytesExceeded = (cbDirty + pEntry->cbData >= pCache->cbCommitDirtyThreshold);
     765        else if (!cbDirty && pCache->u32CommitTimeoutMs > 0)
     766        {
     767            /* Arm the commit timer. */
     768            TMTimerSetMillies(pCache->pTimerCommit, pCache->u32CommitTimeoutMs);
     769        }
    755770    }
    756771
     
    788803        pdmBlkCacheCommitDirtyEntries(pCache);
    789804
    790     TMTimerSetMillies(pTimer, pCache->u32CommitTimeoutMs);
    791805    LogFlowFunc(("Entries committed, going to sleep\n"));
    792806}
     
    11911205            && pBlkCache->pszId)
    11921206        {
     1207            pBlkCache->fSuspended = false;
    11931208            pBlkCache->pCache = pBlkCacheGlobal;
    11941209            RTListInit(&pBlkCache->ListDirtyNotCommitted);
     
    12031218                    if (pBlkCache->pTree)
    12041219                    {
    1205                         /* Arm the timer if this is the first endpoint. */
    1206                         if (   !pBlkCacheGlobal->cRefs
    1207                             && pBlkCacheGlobal->u32CommitTimeoutMs > 0)
    1208                             rc = TMTimerSetMillies(pBlkCacheGlobal->pTimerCommit, pBlkCacheGlobal->u32CommitTimeoutMs);
    1209 
    1210                         if (RT_SUCCESS(rc))
    1211                         {
    12121220#ifdef VBOX_WITH_STATISTICS
    1213                             STAMR3RegisterF(pBlkCacheGlobal->pVM, &pBlkCache->StatWriteDeferred,
    1214                                            STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS,
    1215                                            STAMUNIT_COUNT, "Number of deferred writes",
    1216                                            "/PDM/BlkCache/%s/Cache/DeferredWrites", pBlkCache->pszId);
     1221                        STAMR3RegisterF(pBlkCacheGlobal->pVM, &pBlkCache->StatWriteDeferred,
     1222                                        STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS,
     1223                                        STAMUNIT_COUNT, "Number of deferred writes",
     1224                                        "/PDM/BlkCache/%s/Cache/DeferredWrites", pBlkCache->pszId);
    12171225#endif
    12181226
    1219                             /* Add to the list of users. */
    1220                             pBlkCacheGlobal->cRefs++;
    1221                             RTListAppend(&pBlkCacheGlobal->ListUsers, &pBlkCache->NodeCacheUser);
    1222                             pdmBlkCacheLockLeave(pBlkCacheGlobal);
    1223 
    1224                             *ppBlkCache = pBlkCache;
    1225                             LogFlowFunc(("returns success\n"));
    1226                             return VINF_SUCCESS;
    1227                         }
     1227                        /* Add to the list of users. */
     1228                        pBlkCacheGlobal->cRefs++;
     1229                        RTListAppend(&pBlkCacheGlobal->ListUsers, &pBlkCache->NodeCacheUser);
     1230                        pdmBlkCacheLockLeave(pBlkCacheGlobal);
     1231
     1232                        *ppBlkCache = pBlkCache;
     1233                        LogFlowFunc(("returns success\n"));
     1234                        return VINF_SUCCESS;
    12281235                    }
    12291236                    else
     
    14171424    pCache->cRefs--;
    14181425    RTListNodeRemove(&pBlkCache->NodeCacheUser);
    1419 
    1420     if (   !pCache->cRefs
    1421         && pCache->u32CommitTimeoutMs > 0)
    1422         TMTimerStop(pCache->pTimerCommit);
    14231426
    14241427    pdmBlkCacheLockLeave(pCache);
     
    19341937    LogFlowFunc((": pBlkCache=%#p{%s} off=%llu pcSgBuf=%#p cbRead=%u pvUser=%#p\n",
    19351938                 pBlkCache, pBlkCache->pszId, off, pcSgBuf, cbRead, pvUser));
     1939
     1940    AssertPtrReturn(pBlkCache, VERR_INVALID_POINTER);
     1941    AssertReturn(!pBlkCache->fSuspended, VERR_INVALID_STATE);
    19361942
    19371943    RTSGBUF SgBuf;
     
    21492155    LogFlowFunc((": pBlkCache=%#p{%s} off=%llu pcSgBuf=%#p cbWrite=%u pvUser=%#p\n",
    21502156                 pBlkCache, pBlkCache->pszId, off, pcSgBuf, cbWrite, pvUser));
     2157
     2158    AssertPtrReturn(pBlkCache, VERR_INVALID_POINTER);
     2159    AssertReturn(!pBlkCache->fSuspended, VERR_INVALID_STATE);
    21512160
    21522161    RTSGBUF SgBuf;
     
    23782387    LogFlowFunc((": pBlkCache=%#p{%s}\n", pBlkCache, pBlkCache->pszId));
    23792388
     2389    AssertPtrReturn(pBlkCache, VERR_INVALID_POINTER);
     2390    AssertReturn(!pBlkCache->fSuspended, VERR_INVALID_STATE);
     2391
    23802392    /* Commit dirty entries in the cache. */
    23812393    pdmBlkCacheCommit(pBlkCache);
     
    25392551}
    25402552
     2553/**
     2554 * Callback for the AVL do with all routine. Waits for a cachen entry to finish any pending I/O.
     2555 *
     2556 * @returns IPRT status code.
     2557 * @param    pNode     The node to destroy.
     2558 * @param    pvUser    Opaque user data.
     2559 */
     2560static int pdmBlkCacheEntryQuiesce(PAVLRU64NODECORE pNode, void *pvUser)
     2561{
     2562    PPDMBLKCACHEENTRY  pEntry = (PPDMBLKCACHEENTRY)pNode;
     2563    PPDMBLKCACHE pBlkCache = pEntry->pBlkCache;
     2564
     2565    while (ASMAtomicReadU32(&pEntry->fFlags) & PDMBLKCACHE_ENTRY_IO_IN_PROGRESS)
     2566    {
     2567        /* Leave the locks to let the I/O thread make progress but reference the entry to prevent eviction. */
     2568        pdmBlkCacheEntryRef(pEntry);
     2569        RTSemRWReleaseWrite(pBlkCache->SemRWEntries);
     2570
     2571        RTThreadSleep(1);
     2572
     2573        /* Re-enter all locks and drop the reference. */
     2574        RTSemRWRequestWrite(pBlkCache->SemRWEntries, RT_INDEFINITE_WAIT);
     2575        pdmBlkCacheEntryRelease(pEntry);
     2576    }
     2577
     2578    AssertMsg(!(pEntry->fFlags & PDMBLKCACHE_ENTRY_IO_IN_PROGRESS),
     2579                ("Entry is dirty and/or still in progress fFlags=%#x\n", pEntry->fFlags));
     2580
     2581    return VINF_SUCCESS;
     2582}
     2583
     2584VMMR3DECL(int) PDMR3BlkCacheSuspend(PPDMBLKCACHE pBlkCache)
     2585{
     2586    int rc = VINF_SUCCESS;
     2587    LogFlowFunc(("pBlkCache=%#p\n", pBlkCache));
     2588
     2589    AssertPtrReturn(pBlkCache, VERR_INVALID_POINTER);
     2590
     2591    ASMAtomicXchgBool(&pBlkCache->fSuspended, true);
     2592
     2593    /* Wait for all I/O to complete. */
     2594    RTSemRWRequestWrite(pBlkCache->SemRWEntries, RT_INDEFINITE_WAIT);
     2595    rc = RTAvlrU64DoWithAll(pBlkCache->pTree, true, pdmBlkCacheEntryQuiesce, NULL);
     2596    AssertRC(rc);
     2597    RTSemRWReleaseWrite(pBlkCache->SemRWEntries);
     2598
     2599    return rc;
     2600}
     2601
     2602VMMR3DECL(int) PDMR3BlkCacheResume(PPDMBLKCACHE pBlkCache)
     2603{
     2604    LogFlowFunc(("pBlkCache=%#p\n", pBlkCache));
     2605
     2606    AssertPtrReturn(pBlkCache, VERR_INVALID_POINTER);
     2607
     2608    ASMAtomicXchgBool(&pBlkCache->fSuspended, false);
     2609
     2610    return VINF_SUCCESS;
     2611}
     2612
  • trunk/src/VBox/VMM/PDMBlkCacheInternal.h

    r34347 r35162  
    247247    STAMCOUNTER StatWriteDeferred;
    248248#endif
     249
     250    /** Flag whether the cache was suspended. */
     251    volatile bool                 fSuspended;
     252
    249253} PDMBLKCACHE, *PPDMBLKCACHE;
    250254#ifdef VBOX_WITH_STATISTICS
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