VirtualBox

Changeset 51623 in vbox for trunk/src


Ignore:
Timestamp:
Jun 16, 2014 7:09:13 PM (11 years ago)
Author:
vboxsync
Message:

Storage: Fix possible data corruption or read errors if a request accesses the same region while another write is active and allocating a new data block in the image

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Storage/VD.cpp

    r51102 r51623  
    278278     * the current one completes. - NIL_VDIOCTX if unlocked. */
    279279    volatile PVDIOCTX      pIoCtxLockOwner;
     280    /** If the disk was locked by a growing write, flush or discard request this
     281     * contains the start offset to check for interfering I/O while it is in progress. */
     282    uint64_t               uOffsetStartLocked;
     283    /** If the disk was locked by a growing write, flush or discard request this contains
     284     * the first non affected offset to check for interfering I/O while it is in progress. */
     285    uint64_t               uOffsetEndLocked;
    280286
    281287    /** Pointer to the L2 disk cache if any. */
     
    15501556DECLINLINE(void) vdIoCtxDefer(PVBOXHDD pDisk, PVDIOCTX pIoCtx)
    15511557{
    1552     LogFlowFunc(("Deferring write pIoCtx=%#p\n", pIoCtx));
     1558    LogFlowFunc(("Deferring I/O context pIoCtx=%#p\n", pIoCtx));
    15531559
    15541560    Assert(!pIoCtx->pIoCtxParent && !(pIoCtx->fFlags & VDIOCTX_FLAGS_BLOCKED));
     
    16461652    if (   RT_SUCCESS(rc)
    16471653        && !pIoCtx->cMetaTransfersPending
    1648         && !pIoCtx->cDataTransfersPending)
     1654        && !pIoCtx->cDataTransfersPending
     1655        && !(pIoCtx->fFlags & VDIOCTX_FLAGS_BLOCKED))
    16491656        rc = VINF_VD_ASYNC_IO_FINISHED;
    16501657    else if (   RT_SUCCESS(rc)
     
    19731980    size_t cbThisRead;
    19741981
     1982    /*
     1983     * Check whether there is a full block write in progress which was not allocated.
     1984     * Defer I/O if the range interferes but only if it does not belong to the
     1985     * write doing the allocation.
     1986     */
     1987    if (   pDisk->pIoCtxLockOwner != NIL_VDIOCTX
     1988        && uOffset >= pDisk->uOffsetStartLocked
     1989        && uOffset < pDisk->uOffsetEndLocked
     1990        && (   !pIoCtx->pIoCtxParent
     1991            || pIoCtx->pIoCtxParent != pDisk->pIoCtxLockOwner))
     1992    {
     1993        Log(("Interferring read while allocating a new block => deferring read\n"));
     1994        vdIoCtxDefer(pDisk, pIoCtx);
     1995        return VINF_SUCCESS;
     1996    }
     1997
    19751998    /* Loop until all reads started or we have a backend which needs to read metadata. */
    19761999    do
     
    20022025        else
    20032026        {
    2004 
    20052027            /*
    20062028             * Try to read from the given image.
     
    29212943         * unwanted expanding of images. VMDK is an example. */
    29222944        cbThisWrite = cbWrite;
     2945
     2946        /*
     2947         * Check whether there is a full block write in progress which was not allocated.
     2948         * Defer I/O if the range interferes.
     2949         */
     2950        if (   pDisk->pIoCtxLockOwner != NIL_VDIOCTX
     2951            && uOffset >= pDisk->uOffsetStartLocked
     2952            && uOffset < pDisk->uOffsetEndLocked)
     2953        {
     2954            Log(("Interferring write while allocating a new block => deferring write\n"));
     2955            vdIoCtxDefer(pDisk, pIoCtx);
     2956            rc = VERR_VD_ASYNC_IO_IN_PROGRESS;
     2957            break;
     2958        }
     2959
    29232960        fWrite =   (pImage->uOpenFlags & VD_OPEN_FLAGS_HONOR_SAME)
    29242961                 ? 0 : VD_WRITE_NO_ALLOC;
    2925         rc = pImage->Backend->pfnWrite(pImage->pBackendData, uOffset,
    2926                                             cbThisWrite, pIoCtx,
    2927                                             &cbThisWrite, &cbPreRead,
    2928                                             &cbPostRead, fWrite);
     2962        rc = pImage->Backend->pfnWrite(pImage->pBackendData, uOffset, cbThisWrite,
     2963                                       pIoCtx, &cbThisWrite, &cbPreRead, &cbPostRead,
     2964                                       fWrite);
    29292965        if (rc == VERR_VD_BLOCK_FREE)
    29302966        {
     
    29632999                LogFlowFunc(("Disk is growing because of pIoCtx=%#p pIoCtxWrite=%#p\n",
    29643000                             pIoCtx, pIoCtxWrite));
     3001
     3002                /* Save the current range for the growing operation to check for intersecting requests later. */
     3003                pDisk->uOffsetStartLocked = uOffset - cbPreRead;
     3004                pDisk->uOffsetEndLocked = uOffset + cbThisWrite + cbPostRead;
    29653005
    29663006                pIoCtxWrite->Type.Child.cbPreRead  = cbPreRead;
     
    30503090    if (RT_SUCCESS(rc))
    30513091    {
     3092        /* Mark the whole disk as locked. */
     3093        pDisk->uOffsetStartLocked = 0;
     3094        pDisk->uOffsetEndLocked = UINT64_C(0xffffffffffffffff);
     3095
    30523096        vdResetModifiedFlag(pDisk);
    30533097        rc = pImage->Backend->pfnFlush(pImage->pBackendData, pIoCtx);
     
    33193363        size_t   cbDiscardLeft = pIoCtx->Req.Discard.cbDiscardLeft;
    33203364        size_t   cbThisDiscard;
     3365
     3366        pDisk->uOffsetStartLocked = offStart;
     3367        pDisk->uOffsetEndLocked = offStart + cbDiscardLeft;
    33213368
    33223369        if (RT_UNLIKELY(!pDiscard))
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