VirtualBox

Changeset 30863 in vbox


Ignore:
Timestamp:
Jul 15, 2010 7:53:40 PM (15 years ago)
Author:
vboxsync
Message:

VD: Finish async I/O support for VMDK. Still disabled by default until images are tested which were not created by VirtualBox

Location:
trunk
Files:
6 edited

Legend:

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

    r30788 r30863  
    10291029     * @param   pszAddress      The address to connect to.
    10301030     * @param   uPort           The port to connect to.
    1031      * @param   pSock           Where to store the handle to the established connect
    1032 ion.
     1031     * @param   pSock           Where to store the handle to the established connection.
    10331032     */
    10341033    DECLR3CALLBACKMEMBER(int, pfnClientConnect, (const char *pszAddress, uint32_t uPort, PRTSOCKET pSock));
     
    10391038     * @return  iprt status code.
    10401039     * @param   Sock            Socket descriptor.
    1041 ion.
    10421040     */
    10431041    DECLR3CALLBACKMEMBER(int, pfnClientClose, (RTSOCKET Sock));
     
    15431541     *
    15441542     * @returns VBox status code.
    1545      * @param   pvUser        The opaque user data passed on container creation.
    1546      * @param   pStorage      The storage handle.
    1547      * @param   uOffset       Offset to start reading from.
    1548      * @param   pvBuf         Where to store the data.
    1549      * @param   cbRead        How many bytes to read.
    1550      * @param   pIoCtx        The I/O context which triggered the read.
    1551      * @param   ppMetaXfer    Where to store the metadata transfer handle on success.
     1543     * @param   pvUser         The opaque user data passed on container creation.
     1544     * @param   pStorage       The storage handle.
     1545     * @param   uOffset        Offset to start reading from.
     1546     * @param   pvBuf          Where to store the data.
     1547     * @param   cbRead         How many bytes to read.
     1548     * @param   pIoCtx         The I/O context which triggered the read.
     1549     * @param   ppMetaXfer     Where to store the metadata transfer handle on success.
     1550     * @param   pfnCompleted   Completion callback.
     1551     * @param   pvCompleteUser Opaque user data passed in the completion callback.
    15521552     */
    15531553    DECLR3CALLBACKMEMBER(int, pfnReadMetaAsync, (void *pvUser, PVDIOSTORAGE pStorage,
    15541554                                                 uint64_t uOffset, void *pvBuf,
    15551555                                                 size_t cbRead, PVDIOCTX pIoCtx,
    1556                                                  PPVDMETAXFER ppMetaXfer));
     1556                                                 PPVDMETAXFER ppMetaXfer,
     1557                                                 PFNVDXFERCOMPLETED pfnComplete,
     1558                                                 void *pvCompleteUser));
    15571559
    15581560    /**
  • trunk/src/VBox/Devices/Storage/ParallelsHDDCore.cpp

    r28800 r30863  
    567567    else
    568568    {
    569         /** Calculate offset in the real file. */
     569        /* Calculate offset in the real file. */
    570570        uSector = uOffset / 512;
    571         /** One chunk in the file is always one track big. */
     571        /* One chunk in the file is always one track big. */
    572572        iIndexInAllocationTable = (uint32_t)(uSector / pImage->PCHSGeometry.cSectors);
    573573        uSector = uSector % pImage->PCHSGeometry.cSectors;
  • trunk/src/VBox/Devices/Storage/VBoxHDD.cpp

    r30555 r30863  
    711711    }
    712712
     713    LogFlow(("Allocated root I/O context %#p\n", pIoCtx));
    713714    return pIoCtx;
    714715}
     
    736737    }
    737738
     739    LogFlow(("Allocated child I/O context %#p\n", pIoCtx));
    738740    return pIoCtx;
    739741}
     
    776778DECLINLINE(void) vdIoCtxFree(PVBOXHDD pDisk, PVDIOCTX pIoCtx)
    777779{
     780    LogFlow(("Freeing I/O context %#p\n", pIoCtx));
    778781    if (pIoCtx->pvAllocation)
    779782        RTMemFree(pIoCtx->pvAllocation);
     783#ifdef DEBUG
     784    memset(pIoCtx, 0xff, sizeof(VDIOCTX));
     785#endif
    780786    RTMemCacheFree(pDisk->hMemCacheIoCtx, pIoCtx);
    781787}
     
    845851    LogFlowFunc(("pIoCtx=%#p\n", pIoCtx));
    846852
     853    RTCritSectEnter(&pDisk->CritSect);
     854
    847855    if (   !pIoCtx->cbTransferLeft
    848856        && !pIoCtx->cMetaTransfersPending
    849857        && !pIoCtx->cDataTransfersPending
    850858        && !pIoCtx->pfnIoCtxTransfer)
    851         return VINF_VD_ASYNC_IO_FINISHED;
     859    {
     860        rc = VINF_VD_ASYNC_IO_FINISHED;
     861        goto out;
     862    }
    852863
    853864    /*
     
    858869        && !pIoCtx->cMetaTransfersPending
    859870        && !pIoCtx->cDataTransfersPending)
    860         return VINF_VD_ASYNC_IO_FINISHED;
    861 
    862     /* Don't change anything if there is a metadata transfer pending. */
    863     if (pIoCtx->cMetaTransfersPending)
    864         return VERR_VD_ASYNC_IO_IN_PROGRESS;
     871    {
     872        rc = VINF_VD_ASYNC_IO_FINISHED;
     873        goto out;
     874    }
     875
     876    /* Don't change anything if there is a metadata transfer pending or we are blocked. */
     877    if (   pIoCtx->cMetaTransfersPending
     878        || pIoCtx->fBlocked)
     879    {
     880        rc = VERR_VD_ASYNC_IO_IN_PROGRESS;
     881        goto out;
     882    }
    865883
    866884    if (pIoCtx->pfnIoCtxTransfer)
    867885    {
    868886        /* Call the transfer function advancing to the next while there is no error. */
    869         RTCritSectEnter(&pDisk->CritSect);
    870887        while (   pIoCtx->pfnIoCtxTransfer
    871888               && RT_SUCCESS(rc))
     
    881898            }
    882899        }
    883         RTCritSectLeave(&pDisk->CritSect);
    884900    }
    885901
     
    904920            rc = VERR_VD_ASYNC_IO_IN_PROGRESS;
    905921    }
     922
     923out:
     924    RTCritSectLeave(&pDisk->CritSect);
    906925
    907926    LogFlowFunc(("pIoCtx=%#p rc=%Rrc cbTransferLeft=%u cMetaTransfersPending=%u fComplete=%RTbool\n",
     
    15541573                LogFlowFunc(("Deferring write pIoCtx=%#p\n", pIoCtx));
    15551574
     1575                Assert(!pIoCtx->pIoCtxParent && !pIoCtx->fBlocked);
     1576
    15561577                RTListInit(&pDeferred->NodeDeferred);
    15571578                pDeferred->pIoCtx = pIoCtx;
     
    16181639                }
    16191640                else
     1641                {
    16201642                    LogFlow(("Child write pending\n"));
     1643                    pIoCtx->fBlocked = true;
     1644                    rc = VERR_VD_ASYNC_IO_IN_PROGRESS;
     1645                    cbWrite -= cbThisWrite;
     1646                    uOffset += cbThisWrite;
     1647                    break;
     1648                }
    16211649            }
    16221650        }
     
    19431971                Assert(!pIoCtxParent->pIoCtxParent);
    19441972                Assert(pIoCtx->enmTxDir == VDIOCTXTXDIR_WRITE);
     1973                Assert(pIoCtxParent->cbTransferLeft >= pIoCtx->Type.Child.cbTransferParent);
    19451974                ASMAtomicSubU32(&pIoCtxParent->cbTransferLeft, pIoCtx->Type.Child.cbTransferParent);
    19461975
     
    19491978
    19501979                /*
    1951                  * A completed child write means that we finsihed growing the image.
     1980                 * A completed child write means that we finished growing the image.
    19521981                 * We have to process any pending writes now.
    19531982                 */
    19541983                Assert(pDisk->fGrowing);
    19551984                ASMAtomicWriteBool(&pDisk->fGrowing, false);
     1985
     1986                /* Unblock the parent */
     1987                pIoCtxParent->fBlocked = false;
    19561988
    19571989                rc = vdIoCtxProcess(pIoCtxParent);
     
    19682000                }
    19692001
    1970                 /* Process any pending writes. */
     2002                /* Process any pending writes if the current request didn't caused another growing. */
    19712003                RTCritSectEnter(&pDisk->CritSect);
    19722004
    1973                 if (!RTListIsEmpty(&pDisk->ListWriteGrowing))
     2005                if (!RTListIsEmpty(&pDisk->ListWriteGrowing) && !pDisk->fGrowing)
    19742006                {
    19752007                    RTLISTNODE ListTmp;
     
    19962028                        RTMemFree(pDeferred);
    19972029
     2030                        Assert(!pIoCtxWait->pIoCtxParent);
     2031
    19982032                        pIoCtxWait->fBlocked = false;
    1999 
    2000                         Assert(!pIoCtxWait->pIoCtxParent);
    2001 
    20022033                        LogFlowFunc(("Processing waiting I/O context pIoCtxWait=%#p\n", pIoCtxWait));
    20032034
     
    20522083                 pIoStorage, pIoCtx, pfnComplete, pvUser, cbTransfer, rcReq));
    20532084
     2085    Assert(pIoCtx->cbTransferLeft >= cbTransfer);
    20542086    ASMAtomicSubU32(&pIoCtx->cbTransferLeft, cbTransfer);
    20552087    ASMAtomicDecU32(&pIoCtx->cDataTransfersPending);
    20562088
    20572089    if (pfnComplete)
     2090    {
     2091        RTCritSectEnter(&pDisk->CritSect);
    20582092        rc = pfnComplete(pIoStorage->pImage->pvBackendData, pIoCtx, pvUser, rcReq);
     2093        RTCritSectLeave(&pDisk->CritSect);
     2094    }
    20592095
    20602096    if (RT_SUCCESS(rc))
     
    20742110    PVBOXHDD pDisk = pIoStorage->pImage->pDisk;
    20752111    RTLISTNODE ListIoCtxWaiting;
    2076     bool fFlush = VDMETAXFER_TXDIR_GET(pMetaXfer->fFlags) == VDMETAXFER_TXDIR_FLUSH;
     2112    bool fFlush;
    20772113
    20782114    LogFlowFunc(("pIoStorage=%#p pfnComplete=%#p pvUser=%#p pMetaXfer=%#p rcReq=%Rrc\n",
    20792115                 pIoStorage, pfnComplete, pvUser, pMetaXfer, rcReq));
    20802116
     2117    RTCritSectEnter(&pDisk->CritSect);
     2118    fFlush = VDMETAXFER_TXDIR_GET(pMetaXfer->fFlags) == VDMETAXFER_TXDIR_FLUSH;
    20812119    VDMETAXFER_TXDIR_SET(pMetaXfer->fFlags, VDMETAXFER_TXDIR_NONE);
    20822120
    20832121    if (!fFlush)
    20842122    {
    2085         RTCritSectEnter(&pDisk->CritSect);
    2086 
    20872123        RTListMove(&ListIoCtxWaiting, &pMetaXfer->ListIoCtxWaiting);
    20882124
     
    20902126        {
    20912127            /* Remove from the AVL tree. */
     2128            LogFlow(("Removing meta xfer=%#p\n", pMetaXfer));
    20922129            bool fRemoved = RTAvlrFileOffsetRemove(pIoStorage->pTreeMetaXfers, pMetaXfer->Core.Key);
    20932130            Assert(fRemoved);
     
    20992136            pMetaXfer->cRefs++;
    21002137        }
    2101 
    2102         RTCritSectLeave(&pDisk->CritSect);
    21032138    }
    21042139    else
    2105     {
    2106         /*
    2107          *  Flushes don't need the critical section because they are never accessed concurrently
    2108          * (they also have only one context attached).
    2109          */
    21102140        RTListMove(&ListIoCtxWaiting, &pMetaXfer->ListIoCtxWaiting);
    2111     }
     2141    RTCritSectLeave(&pDisk->CritSect);
    21122142
    21132143    /* Go through the waiting list and continue the I/O contexts. */
     
    21242154
    21252155        if (pfnComplete)
     2156        {
     2157            RTCritSectEnter(&pDisk->CritSect);
    21262158            rc = pfnComplete(pIoStorage->pImage->pvBackendData, pIoCtx, pvUser, rcReq);
     2159            RTCritSectLeave(&pDisk->CritSect);
     2160        }
    21272161
    21282162        LogFlow(("Completion callback for I/O context %#p returned %Rrc\n", pIoCtx, rc));
     
    21422176        RTCritSectEnter(&pDisk->CritSect);
    21432177        pMetaXfer->cRefs--;
    2144         if (!pMetaXfer->cRefs)
     2178        if (!pMetaXfer->cRefs && RTListIsEmpty(&pMetaXfer->ListIoCtxWaiting))
    21452179        {
    21462180            /* Remove from the AVL tree. */
     2181            LogFlow(("Removing meta xfer=%#p\n", pMetaXfer));
    21472182            bool fRemoved = RTAvlrFileOffsetRemove(pIoStorage->pTreeMetaXfers, pMetaXfer->Core.Key);
    21482183            Assert(fRemoved);
     
    24302465                             uint64_t uOffset, void *pvBuf,
    24312466                             size_t cbRead, PVDIOCTX pIoCtx,
    2432                              PPVDMETAXFER ppMetaXfer)
     2467                             PPVDMETAXFER ppMetaXfer,
     2468                             PFNVDXFERCOMPLETED pfnComplete,
     2469                             void *pvCompleteUser)
    24332470{
    24342471    PVDIMAGE pImage = (PVDIMAGE)pvUser;
     
    24482485    if (!pMetaXfer)
    24492486    {
     2487#ifdef RT_STRICT
     2488        pMetaXfer = (PVDMETAXFER)RTAvlrFileOffsetGetBestFit(pIoStorage->pTreeMetaXfers, uOffset, false /* fAbove */);
     2489        AssertMsg(!pMetaXfer || (pMetaXfer->Core.Key + pMetaXfer->cbMeta <= uOffset),
     2490                  ("Overlapping meta transfers!\n"));
     2491#endif
     2492
    24502493        /* Allocate a new meta transfer. */
    24512494        pMetaXfer = vdMetaXferAlloc(pImage, pIoStorage, uOffset, cbRead);
     
    24532496            return VERR_NO_MEMORY;
    24542497
    2455         pIoTask = vdIoTaskMetaAlloc(pIoStorage, NULL, NULL, pMetaXfer);
     2498        pIoTask = vdIoTaskMetaAlloc(pIoStorage, pfnComplete, pvCompleteUser, pMetaXfer);
    24562499        if (!pIoTask)
    24572500        {
     
    24692512                                                             cbRead, pIoTask,
    24702513                                                             &pvTask);
     2514
     2515        if (RT_SUCCESS(rc) || rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
     2516        {
     2517            bool fInserted = RTAvlrFileOffsetInsert(pIoStorage->pTreeMetaXfers, &pMetaXfer->Core);
     2518            Assert(fInserted);
     2519        }
     2520        else
     2521            RTMemFree(pMetaXfer);
     2522
    24712523        if (RT_SUCCESS(rc))
    24722524        {
     
    24742526            vdIoTaskFree(pDisk, pIoTask);
    24752527        }
    2476         else if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
     2528        else if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS && !pfnComplete)
    24772529            rc = VERR_VD_NOT_ENOUGH_METADATA;
    2478 
    2479         if (RT_SUCCESS(rc) || rc == VERR_VD_NOT_ENOUGH_METADATA)
    2480         {
    2481             bool fInserted = RTAvlrFileOffsetInsert(pIoStorage->pTreeMetaXfers, &pMetaXfer->Core);
    2482             Assert(fInserted);
    2483         }
    2484         else
    2485             RTMemFree(pMetaXfer);
    24862530    }
    24872531
    24882532    Assert(VALID_PTR(pMetaXfer) || RT_FAILURE(rc));
    24892533
    2490     if (RT_SUCCESS(rc) || rc == VERR_VD_NOT_ENOUGH_METADATA)
     2534    if (RT_SUCCESS(rc) || rc == VERR_VD_NOT_ENOUGH_METADATA || rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
    24912535    {
    24922536        /* If it is pending add the request to the list. */
     
    25082552            pMetaXfer->cRefs++;
    25092553            Assert(pMetaXfer->cbMeta >= cbRead);
     2554            Assert(pMetaXfer->Core.Key == (RTFOFF)uOffset);
    25102555            memcpy(pvBuf, pMetaXfer->abData, cbRead);
    25112556            *ppMetaXfer = pMetaXfer;
     
    25282573    PVDIOTASK pIoTask;
    25292574    PVDMETAXFER pMetaXfer = NULL;
     2575    bool fInTree = false;
    25302576    void *pvTask = NULL;
    25312577
     
    25422588        if (!pMetaXfer)
    25432589            return VERR_NO_MEMORY;
    2544 
    2545         pIoTask = vdIoTaskMetaAlloc(pIoStorage, pfnComplete, pvCompleteUser, pMetaXfer);
    2546         if (!pIoTask)
    2547         {
    2548             RTMemFree(pMetaXfer);
    2549             return VERR_NO_MEMORY;
    2550         }
    2551 
    2552         memcpy(pMetaXfer->abData, pvBuf, cbWrite);
    2553         Seg.cbSeg = cbWrite;
    2554         Seg.pvSeg = pMetaXfer->abData;
    2555 
    2556         ASMAtomicIncU32(&pIoCtx->cMetaTransfersPending);
    2557 
    2558         VDMETAXFER_TXDIR_SET(pMetaXfer->fFlags, VDMETAXFER_TXDIR_WRITE);
    2559         rc = pDisk->pInterfaceAsyncIOCallbacks->pfnWriteAsync(pDisk->pInterfaceAsyncIO->pvUser,
    2560                                                               pIoStorage->u.pStorage,
    2561                                                               uOffset, &Seg, 1,
    2562                                                               cbWrite, pIoTask,
    2563                                                               &pvTask);
    2564         if (RT_SUCCESS(rc))
    2565         {
    2566             VDMETAXFER_TXDIR_SET(pMetaXfer->fFlags, VDMETAXFER_TXDIR_NONE);
    2567             ASMAtomicDecU32(&pIoCtx->cMetaTransfersPending);
    2568             vdIoTaskFree(pDisk, pIoTask);
     2590    }
     2591    else
     2592    {
     2593        Assert(pMetaXfer->cbMeta >= cbWrite);
     2594        Assert(pMetaXfer->Core.Key == (RTFOFF)uOffset);
     2595        fInTree = true;
     2596    }
     2597
     2598    Assert(VDMETAXFER_TXDIR_GET(pMetaXfer->fFlags) == VDMETAXFER_TXDIR_NONE);
     2599
     2600    pIoTask = vdIoTaskMetaAlloc(pIoStorage, pfnComplete, pvCompleteUser, pMetaXfer);
     2601    if (!pIoTask)
     2602    {
     2603        RTMemFree(pMetaXfer);
     2604        return VERR_NO_MEMORY;
     2605    }
     2606
     2607    memcpy(pMetaXfer->abData, pvBuf, cbWrite);
     2608    Seg.cbSeg = cbWrite;
     2609    Seg.pvSeg = pMetaXfer->abData;
     2610
     2611    ASMAtomicIncU32(&pIoCtx->cMetaTransfersPending);
     2612
     2613    VDMETAXFER_TXDIR_SET(pMetaXfer->fFlags, VDMETAXFER_TXDIR_WRITE);
     2614    rc = pDisk->pInterfaceAsyncIOCallbacks->pfnWriteAsync(pDisk->pInterfaceAsyncIO->pvUser,
     2615                                                          pIoStorage->u.pStorage,
     2616                                                          uOffset, &Seg, 1,
     2617                                                          cbWrite, pIoTask,
     2618                                                          &pvTask);
     2619    if (RT_SUCCESS(rc))
     2620    {
     2621        VDMETAXFER_TXDIR_SET(pMetaXfer->fFlags, VDMETAXFER_TXDIR_NONE);
     2622        ASMAtomicDecU32(&pIoCtx->cMetaTransfersPending);
     2623        vdIoTaskFree(pDisk, pIoTask);
     2624        if (fInTree && !pMetaXfer->cRefs)
     2625        {
     2626            LogFlow(("Removing meta xfer=%#p\n", pMetaXfer));
     2627            bool fRemoved = RTAvlrFileOffsetRemove(pIoStorage->pTreeMetaXfers, pMetaXfer->Core.Key);
     2628            AssertMsg(fRemoved, ("Metadata transfer wasn't removed\n"));
    25692629            RTMemFree(pMetaXfer);
    25702630            pMetaXfer = NULL;
    25712631        }
    2572         else if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
    2573         {
    2574             PVDIOCTXDEFERRED pDeferred = (PVDIOCTXDEFERRED)RTMemAllocZ(sizeof(VDIOCTXDEFERRED));
    2575             AssertPtr(pDeferred);
    2576 
    2577             RTListInit(&pDeferred->NodeDeferred);
    2578             pDeferred->pIoCtx = pIoCtx;
    2579 
     2632    }
     2633    else if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
     2634    {
     2635        PVDIOCTXDEFERRED pDeferred = (PVDIOCTXDEFERRED)RTMemAllocZ(sizeof(VDIOCTXDEFERRED));
     2636        AssertPtr(pDeferred);
     2637
     2638        RTListInit(&pDeferred->NodeDeferred);
     2639        pDeferred->pIoCtx = pIoCtx;
     2640
     2641        if (!fInTree)
     2642        {
    25802643            bool fInserted = RTAvlrFileOffsetInsert(pIoStorage->pTreeMetaXfers, &pMetaXfer->Core);
    25812644            Assert(fInserted);
    2582 
    2583             RTListAppend(&pMetaXfer->ListIoCtxWaiting, &pDeferred->NodeDeferred);
    2584         }
    2585         else
    2586         {
    2587             RTMemFree(pMetaXfer);
    2588             pMetaXfer = NULL;
    2589         }
    2590     }
    2591 
    2592     Assert(VALID_PTR(pMetaXfer) || RT_SUCCESS(rc) || rc != VERR_VD_ASYNC_IO_IN_PROGRESS);
     2645        }
     2646
     2647        RTListAppend(&pMetaXfer->ListIoCtxWaiting, &pDeferred->NodeDeferred);
     2648    }
     2649    else
     2650    {
     2651        RTMemFree(pMetaXfer);
     2652        pMetaXfer = NULL;
     2653    }
    25932654
    25942655    return rc;
     
    26122673    {
    26132674        /* Free the meta data entry. */
     2675        LogFlow(("Removing meta xfer=%#p\n", pMetaXfer));
    26142676        bool fRemoved = RTAvlrFileOffsetRemove(pIoStorage->pTreeMetaXfers, pMetaXfer->Core.Key);
    26152677        AssertMsg(fRemoved, ("Metadata transfer wasn't removed\n"));
  • trunk/src/VBox/Devices/Storage/VDIHDDCore.cpp

    r30555 r30863  
    220220                                                           pImage->pStorage,
    221221                                                           off, pvBuf, cbRead, pIoCtx,
    222                                                            NULL);
     222                                                           NULL, NULL, NULL);
    223223}
    224224
  • trunk/src/VBox/Devices/Storage/VHDHDDCore.cpp

    r30555 r30863  
    23282328                                                             pImage->pStorage,
    23292329                                                             ((uint64_t)pImage->pBlockAllocationTable[cBlockAllocationTableEntry]) * VHD_SECTOR_SIZE,
    2330                                                              pImage->pu8Bitmap, pImage->cbDataBlockBitmap, pIoCtx, &pMetaXfer);
     2330                                                             pImage->pu8Bitmap, pImage->cbDataBlockBitmap, pIoCtx, &pMetaXfer,
     2331                                                             NULL, NULL);
    23312332
    23322333        if (RT_SUCCESS(rc))
     
    25752576                                                                 pImage->pStorage,
    25762577                                                                 ((uint64_t)pImage->pBlockAllocationTable[cBlockAllocationTableEntry]) * VHD_SECTOR_SIZE,
    2577                                                                  pImage->pu8Bitmap, pImage->cbDataBlockBitmap, pIoCtx, &pMetaXfer);
     2578                                                                 pImage->pu8Bitmap, pImage->cbDataBlockBitmap, pIoCtx, &pMetaXfer,
     2579                                                                 NULL, NULL);
    25782580            if (RT_SUCCESS(rc))
    25792581            {
  • trunk/src/VBox/Devices/Storage/VmdkHDDCore.cpp

    r30555 r30863  
    495495} VMDKDEFLATESTATE;
    496496
     497/** Tracks async grain allocation. */
     498typedef struct VMDKGRAINALLOCASYNC
     499{
     500    /** Old size of the extent. Used for rollback after an error. */
     501    uint64_t    cbExtentOld;
     502    /** Flag whether the allocation failed. */
     503    bool        fIoErr;
     504    /** Current number of transfers pending.
     505     * If reached 0 and there is an error the old state is restored. */
     506    unsigned    cIoXfersPending;
     507    /** Sector number */
     508    uint64_t    uSector;
     509    /** Flag whether the grain table needs to be updated. */
     510    bool        fGTUpdateNeeded;
     511    /** Extent the allocation happens. */
     512    PVMDKEXTENT pExtent;
     513    /** New size of the extent, required for the grain table update. */
     514    uint64_t    cbExtentSize;
     515    /** Grain table sector. */
     516    uint64_t    uGTSector;
     517    /** Backup grain table sector. */
     518    uint64_t    uRGTSector;
     519} VMDKGRAINALLOCASYNC, *PVMDKGRAINALLOCASYNC;
     520
    497521/*******************************************************************************
    498522 *   Static Variables                                                           *
     
    520544static void vmdkFreeImage(PVMDKIMAGE pImage, bool fDelete);
    521545
     546static int vmdkAllocGrainAsyncComplete(void *pvBackendData, PVDIOCTX pIoCtx, void *pvUser, int rcReq);
    522547
    523548/**
     
    28962921}
    28972922
     2923/**
     2924 * Internal: write/update the metadata for a sparse extent - async version.
     2925 */
     2926static int vmdkWriteMetaSparseExtentAsync(PVMDKIMAGE pImage, PVMDKEXTENT pExtent,
     2927                                          uint64_t uOffset, PVDIOCTX pIoCtx)
     2928{
     2929    SparseExtentHeader Header;
     2930
     2931    memset(&Header, '\0', sizeof(Header));
     2932    Header.magicNumber = RT_H2LE_U32(VMDK_SPARSE_MAGICNUMBER);
     2933    Header.version = RT_H2LE_U32(pExtent->uVersion);
     2934    Header.flags = RT_H2LE_U32(RT_BIT(0));
     2935    if (pExtent->pRGD)
     2936        Header.flags |= RT_H2LE_U32(RT_BIT(1));
     2937    if (pExtent->pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)
     2938        Header.flags |= RT_H2LE_U32(RT_BIT(16) | RT_BIT(17));
     2939    Header.capacity = RT_H2LE_U64(pExtent->cSectors);
     2940    Header.grainSize = RT_H2LE_U64(pExtent->cSectorsPerGrain);
     2941    Header.descriptorOffset = RT_H2LE_U64(pExtent->uDescriptorSector);
     2942    Header.descriptorSize = RT_H2LE_U64(pExtent->cDescriptorSectors);
     2943    Header.numGTEsPerGT = RT_H2LE_U32(pExtent->cGTEntries);
     2944    if (pExtent->fFooter && uOffset == 0)
     2945    {
     2946        if (pExtent->pRGD)
     2947        {
     2948            Assert(pExtent->uSectorRGD);
     2949            Header.rgdOffset = RT_H2LE_U64(VMDK_GD_AT_END);
     2950            Header.gdOffset = RT_H2LE_U64(VMDK_GD_AT_END);
     2951        }
     2952        else
     2953        {
     2954            Header.gdOffset = RT_H2LE_U64(VMDK_GD_AT_END);
     2955        }
     2956    }
     2957    else
     2958    {
     2959        if (pExtent->pRGD)
     2960        {
     2961            Assert(pExtent->uSectorRGD);
     2962            Header.rgdOffset = RT_H2LE_U64(pExtent->uSectorRGD);
     2963            Header.gdOffset = RT_H2LE_U64(pExtent->uSectorGD);
     2964        }
     2965        else
     2966        {
     2967            Header.gdOffset = RT_H2LE_U64(pExtent->uSectorGD);
     2968        }
     2969    }
     2970    Header.overHead = RT_H2LE_U64(pExtent->cOverheadSectors);
     2971    Header.uncleanShutdown = pExtent->fUncleanShutdown;
     2972    Header.singleEndLineChar = '\n';
     2973    Header.nonEndLineChar = ' ';
     2974    Header.doubleEndLineChar1 = '\r';
     2975    Header.doubleEndLineChar2 = '\n';
     2976    Header.compressAlgorithm = RT_H2LE_U16(pExtent->uCompression);
     2977
     2978    int rc = pImage->pInterfaceIOCallbacks->pfnWriteMetaAsync(pImage->pInterfaceIO->pvUser,
     2979                                                              pExtent->pFile->pStorage,
     2980                                                              uOffset, &Header, sizeof(Header),
     2981                                                              pIoCtx, NULL, NULL);
     2982    if (RT_FAILURE(rc) && (rc != VERR_VD_ASYNC_IO_IN_PROGRESS))
     2983        rc = vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: error writing extent header in '%s'"), pExtent->pszFullname);
     2984    return rc;
     2985}
     2986
    28982987#ifdef VBOX_WITH_VMDK_ESX
    28992988/**
     
    43974486    }
    43984487
     4488    LogFlowFunc(("uGTSector=%llu\n", uGTSector));
     4489
    43994490    uGTBlock = uSector / (pExtent->cSectorsPerGrain * VMDK_GT_CACHELINE_SIZE);
    44004491    uGTHash = vmdkGTCacheHash(pCache, uGTBlock, pExtent->uExtent);
     
    44084499                                                             pExtent->pFile->pStorage,
    44094500                                                             VMDK_SECTOR2BYTE(uGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp),
    4410                                                              aGTDataTmp, sizeof(aGTDataTmp), pIoCtx, &pMetaXfer);
     4501                                                             aGTDataTmp, sizeof(aGTDataTmp), pIoCtx, &pMetaXfer, NULL, NULL);
    44114502        if (RT_FAILURE(rc))
    44124503            return rc;
     
    46964787    }
    46974788#endif /* VBOX_WITH_VMDK_ESX */
     4789    return rc;
     4790}
     4791
     4792/**
     4793 * Internal: Updates the grain table during a async grain allocation.
     4794 */
     4795static int vmdkAllocGrainAsyncGTUpdate(PVMDKIMAGE pImage, PVMDKEXTENT pExtent,
     4796                                       PVMDKGTCACHE pCache, PVDIOCTX pIoCtx,
     4797                                       PVMDKGRAINALLOCASYNC pGrainAlloc)
     4798{
     4799    int rc = VINF_SUCCESS;
     4800    uint32_t aGTDataTmp[VMDK_GT_CACHELINE_SIZE];
     4801    uint32_t uGTHash, uGTBlockIndex;
     4802    uint64_t uGDIndex, uGTSector, uRGTSector, uGTBlock;
     4803    uint64_t uSector = pGrainAlloc->uSector;
     4804    PVMDKGTCACHEENTRY pGTCacheEntry;
     4805
     4806    LogFlowFunc(("pImage=%#p pExtent=%#p pCache=%#p pIoCtx=%#p pGrainAlloc=%#p\n",
     4807                 pImage, pExtent, pCache, pIoCtx, pGrainAlloc));
     4808
     4809    uGTSector = pGrainAlloc->uGTSector;
     4810    uRGTSector = pGrainAlloc->uRGTSector;
     4811    LogFlow(("uGTSector=%llu uRGTSector=%llu\n", uGTSector, uRGTSector));
     4812
     4813    /* Update the grain table (and the cache). */
     4814    uGTBlock = uSector / (pExtent->cSectorsPerGrain * VMDK_GT_CACHELINE_SIZE);
     4815    uGTHash = vmdkGTCacheHash(pCache, uGTBlock, pExtent->uExtent);
     4816    pGTCacheEntry = &pCache->aGTCache[uGTHash];
     4817    if (    pGTCacheEntry->uExtent != pExtent->uExtent
     4818        ||  pGTCacheEntry->uGTBlock != uGTBlock)
     4819    {
     4820        /* Cache miss, fetch data from disk. */
     4821        LogFlow(("Cache miss, fetch data from disk\n"));
     4822        PVDMETAXFER pMetaXfer = NULL;
     4823        rc = pImage->pInterfaceIOCallbacks->pfnReadMetaAsync(pExtent->pImage->pInterfaceIO->pvUser,
     4824                                                             pExtent->pFile->pStorage,
     4825                                                             VMDK_SECTOR2BYTE(uGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp),
     4826                                                             aGTDataTmp, sizeof(aGTDataTmp), pIoCtx,
     4827                                                             &pMetaXfer,
     4828                                                             vmdkAllocGrainAsyncComplete, pGrainAlloc);
     4829        if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
     4830        {
     4831            pGrainAlloc->cIoXfersPending++;
     4832            pGrainAlloc->fGTUpdateNeeded = true;
     4833            /* Leave early, we will be called  again after the read completed. */
     4834            LogFlowFunc(("Metadata read in progress, leaving\n"));
     4835            return rc;
     4836        }
     4837        else if (RT_FAILURE(rc))
     4838            return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot read allocated grain table entry in '%s'"), pExtent->pszFullname);
     4839        pImage->pInterfaceIOCallbacks->pfnMetaXferRelease(pExtent->pImage->pInterfaceIO->pvUser, pMetaXfer);
     4840        pGTCacheEntry->uExtent = pExtent->uExtent;
     4841        pGTCacheEntry->uGTBlock = uGTBlock;
     4842        for (unsigned i = 0; i < VMDK_GT_CACHELINE_SIZE; i++)
     4843            pGTCacheEntry->aGTData[i] = RT_LE2H_U32(aGTDataTmp[i]);
     4844    }
     4845    else
     4846    {
     4847        /* Cache hit. Convert grain table block back to disk format, otherwise
     4848         * the code below will write garbage for all but the updated entry. */
     4849        for (unsigned i = 0; i < VMDK_GT_CACHELINE_SIZE; i++)
     4850            aGTDataTmp[i] = RT_H2LE_U32(pGTCacheEntry->aGTData[i]);
     4851    }
     4852    pGrainAlloc->fGTUpdateNeeded = false;
     4853    uGTBlockIndex = (uSector / pExtent->cSectorsPerGrain) % VMDK_GT_CACHELINE_SIZE;
     4854    aGTDataTmp[uGTBlockIndex] = RT_H2LE_U32(VMDK_BYTE2SECTOR(pGrainAlloc->cbExtentSize));
     4855    pGTCacheEntry->aGTData[uGTBlockIndex] = VMDK_BYTE2SECTOR(pGrainAlloc->cbExtentSize);
     4856    /* Update grain table on disk. */
     4857    rc = pImage->pInterfaceIOCallbacks->pfnWriteMetaAsync(pExtent->pImage->pInterfaceIO->pvUser,
     4858                                                          pExtent->pFile->pStorage,
     4859                                                          VMDK_SECTOR2BYTE(uGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp),
     4860                                                          aGTDataTmp, sizeof(aGTDataTmp), pIoCtx,
     4861                                                          vmdkAllocGrainAsyncComplete, pGrainAlloc);
     4862    if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
     4863        pGrainAlloc->cIoXfersPending++;
     4864    else if (RT_FAILURE(rc))
     4865        return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write updated grain table in '%s'"), pExtent->pszFullname);
     4866    if (pExtent->pRGD)
     4867    {
     4868        /* Update backup grain table on disk. */
     4869        rc = pImage->pInterfaceIOCallbacks->pfnWriteMetaAsync(pExtent->pImage->pInterfaceIO->pvUser,
     4870                                                              pExtent->pFile->pStorage,
     4871                                                              VMDK_SECTOR2BYTE(uRGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp),
     4872                                                              aGTDataTmp, sizeof(aGTDataTmp), pIoCtx,
     4873                                                              vmdkAllocGrainAsyncComplete, pGrainAlloc);
     4874        if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
     4875            pGrainAlloc->cIoXfersPending++;
     4876        else if (RT_FAILURE(rc))
     4877            return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write updated backup grain table in '%s'"), pExtent->pszFullname);
     4878    }
     4879#ifdef VBOX_WITH_VMDK_ESX
     4880    if (RT_SUCCESS(rc) && pExtent->enmType == VMDKETYPE_ESX_SPARSE)
     4881    {
     4882        pExtent->uFreeSector = uGTSector + VMDK_BYTE2SECTOR(cbWrite);
     4883        pExtent->fMetaDirty = true;
     4884    }
     4885#endif /* VBOX_WITH_VMDK_ESX */
     4886
     4887    LogFlowFunc(("leaving rc=%Rrc\n", rc));
     4888
     4889    return rc;
     4890}
     4891
     4892/**
     4893 * Internal - complete the grain allocation by updating disk grain table if required.
     4894 */
     4895static int vmdkAllocGrainAsyncComplete(void *pvBackendData, PVDIOCTX pIoCtx, void *pvUser, int rcReq)
     4896{
     4897    int rc = VINF_SUCCESS;
     4898    PVMDKIMAGE pImage = (PVMDKIMAGE)pvBackendData;
     4899    PVMDKGRAINALLOCASYNC pGrainAlloc = (PVMDKGRAINALLOCASYNC)pvUser;
     4900    PVMDKEXTENT pExtent = pGrainAlloc->pExtent;
     4901
     4902    LogFlowFunc(("pvBackendData=%#p pIoCtx=%#p pvUser=%#p rcReq=%Rrc\n",
     4903                 pvBackendData, pIoCtx, pvUser, rcReq));
     4904
     4905    pGrainAlloc->cIoXfersPending--;
     4906    if (!pGrainAlloc->cIoXfersPending && pGrainAlloc->fGTUpdateNeeded)
     4907        rc = vmdkAllocGrainAsyncGTUpdate(pImage, pGrainAlloc->pExtent, pImage->pGTCache,
     4908                                         pIoCtx, pGrainAlloc);
     4909
     4910    if (!pGrainAlloc->cIoXfersPending)
     4911    {
     4912        /* Grain allocation completed. */
     4913        RTMemFree(pGrainAlloc);
     4914    }
     4915
     4916    LogFlowFunc(("Leaving rc=%Rrc\n", rc));
     4917    return rc;
     4918}
     4919
     4920/**
     4921 * Internal. Allocates a new grain table (if necessary) - async version.
     4922 */
     4923static int vmdkAllocGrainAsync(PVMDKGTCACHE pCache, PVMDKEXTENT pExtent,
     4924                               PVDIOCTX pIoCtx, uint64_t uSector,
     4925                               uint64_t cbWrite)
     4926{
     4927    uint64_t uGDIndex, uGTSector, uRGTSector, uGTBlock;
     4928    uint64_t cbExtentSize;
     4929    uint32_t aGTDataTmp[VMDK_GT_CACHELINE_SIZE];
     4930    PVMDKGRAINALLOCASYNC pGrainAlloc = NULL;
     4931    PVMDKIMAGE pImage = pExtent->pImage;
     4932    int rc;
     4933
     4934    LogFlowFunc(("pCache=%#p pExtent=%#p pIoCtx=%#p uSector=%llu cbWrite=%llu\n",
     4935                 pCache, pExtent, pIoCtx, uSector, cbWrite));
     4936
     4937    AssertReturn(!(pExtent->pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED), VERR_NOT_SUPPORTED);
     4938
     4939    pGrainAlloc = (PVMDKGRAINALLOCASYNC)RTMemAllocZ(sizeof(VMDKGRAINALLOCASYNC));
     4940    if (!pGrainAlloc)
     4941        return VERR_NO_MEMORY;
     4942
     4943    pGrainAlloc->pExtent = pExtent;
     4944    pGrainAlloc->uSector = uSector;
     4945
     4946    uGDIndex = uSector / pExtent->cSectorsPerGDE;
     4947    if (uGDIndex >= pExtent->cGDEntries)
     4948        return VERR_OUT_OF_RANGE;
     4949    uGTSector = pExtent->pGD[uGDIndex];
     4950    if (pExtent->pRGD)
     4951        uRGTSector = pExtent->pRGD[uGDIndex];
     4952    else
     4953        uRGTSector = 0; /**< avoid compiler warning */
     4954    if (!uGTSector)
     4955    {
     4956        LogFlow(("Allocating new grain table\n"));
     4957
     4958        /* There is no grain table referenced by this grain directory
     4959         * entry. So there is absolutely no data in this area. Allocate
     4960         * a new grain table and put the reference to it in the GDs. */
     4961        rc = vmdkFileGetSize(pExtent->pFile, &cbExtentSize);
     4962        if (RT_FAILURE(rc))
     4963            return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: error getting size in '%s'"), pExtent->pszFullname);
     4964        Assert(!(cbExtentSize % 512));
     4965
     4966        pGrainAlloc->cbExtentOld = cbExtentSize;
     4967
     4968        cbExtentSize = RT_ALIGN_64(cbExtentSize, 512);
     4969        uGTSector = VMDK_BYTE2SECTOR(cbExtentSize);
     4970
     4971        /* Normally the grain table is preallocated for hosted sparse extents
     4972         * that support more than 32 bit sector numbers. So this shouldn't
     4973         * ever happen on a valid extent. */
     4974        if (uGTSector > UINT32_MAX)
     4975            return VERR_VD_VMDK_INVALID_HEADER;
     4976
     4977        /* Write grain table by writing the required number of grain table
     4978         * cache chunks. Allocate memory dynamically here or we flood the
     4979         * metadata cache with very small entries.
     4980         */
     4981        size_t cbGTDataTmp = (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE) * VMDK_GT_CACHELINE_SIZE * sizeof(uint32_t);
     4982        uint32_t *paGTDataTmp = (uint32_t *)RTMemTmpAllocZ(cbGTDataTmp);
     4983
     4984        if (!paGTDataTmp)
     4985            return VERR_NO_MEMORY;
     4986
     4987        memset(paGTDataTmp, '\0', cbGTDataTmp);
     4988        rc = pImage->pInterfaceIOCallbacks->pfnWriteMetaAsync(pExtent->pImage->pInterfaceIO->pvUser,
     4989                                                              pExtent->pFile->pStorage,
     4990                                                              VMDK_SECTOR2BYTE(uGTSector),
     4991                                                              paGTDataTmp, cbGTDataTmp, pIoCtx,
     4992                                                              vmdkAllocGrainAsyncComplete, pGrainAlloc);
     4993        if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
     4994            pGrainAlloc->cIoXfersPending++;
     4995        else if (RT_FAILURE(rc))
     4996        {
     4997            RTMemTmpFree(paGTDataTmp);
     4998            return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write grain table allocation in '%s'"), pExtent->pszFullname);
     4999        }
     5000
     5001        if (pExtent->pRGD)
     5002        {
     5003            AssertReturn(!uRGTSector, VERR_VD_VMDK_INVALID_HEADER);
     5004            rc = vmdkFileGetSize(pExtent->pFile, &cbExtentSize);
     5005            if (RT_FAILURE(rc))
     5006                return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: error getting size in '%s'"), pExtent->pszFullname);
     5007            Assert(!(cbExtentSize % 512));
     5008            uRGTSector = VMDK_BYTE2SECTOR(cbExtentSize);
     5009
     5010            /* Normally the redundant grain table is preallocated for hosted
     5011             * sparse extents that support more than 32 bit sector numbers. So
     5012             * this shouldn't ever happen on a valid extent. */
     5013            if (uRGTSector > UINT32_MAX)
     5014            {
     5015                RTMemTmpFree(paGTDataTmp);
     5016                return VERR_VD_VMDK_INVALID_HEADER;
     5017            }
     5018            /* Write backup grain table by writing the required number of grain
     5019             * table cache chunks. */
     5020            rc = pImage->pInterfaceIOCallbacks->pfnWriteMetaAsync(pExtent->pImage->pInterfaceIO->pvUser,
     5021                                                                  pExtent->pFile->pStorage,
     5022                                                                  VMDK_SECTOR2BYTE(uRGTSector),
     5023                                                                  paGTDataTmp, cbGTDataTmp, pIoCtx,
     5024                                                                  vmdkAllocGrainAsyncComplete, pGrainAlloc);
     5025            if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
     5026                pGrainAlloc->cIoXfersPending++;
     5027            else if (RT_FAILURE(rc))
     5028            {
     5029                RTMemTmpFree(paGTDataTmp);
     5030                return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write backup grain table allocation in '%s'"), pExtent->pszFullname);
     5031            }
     5032        }
     5033
     5034        RTMemTmpFree(paGTDataTmp);
     5035
     5036        /* Update the grain directory on disk (doing it before writing the
     5037         * grain table will result in a garbled extent if the operation is
     5038         * aborted for some reason. Otherwise the worst that can happen is
     5039         * some unused sectors in the extent. */
     5040        uint32_t uGTSectorLE = RT_H2LE_U64(uGTSector);
     5041        rc = pImage->pInterfaceIOCallbacks->pfnWriteMetaAsync(pExtent->pImage->pInterfaceIO->pvUser,
     5042                                                              pExtent->pFile->pStorage,
     5043                                                              VMDK_SECTOR2BYTE(pExtent->uSectorGD) + uGDIndex * sizeof(uGTSectorLE),
     5044                                                              &uGTSectorLE, sizeof(uGTSectorLE), pIoCtx,
     5045                                                              vmdkAllocGrainAsyncComplete, pGrainAlloc);
     5046        if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
     5047            pGrainAlloc->cIoXfersPending++;
     5048        else if (RT_FAILURE(rc))
     5049            return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write grain directory entry in '%s'"), pExtent->pszFullname);
     5050        if (pExtent->pRGD)
     5051        {
     5052            uint32_t uRGTSectorLE = RT_H2LE_U64(uRGTSector);
     5053            rc = pImage->pInterfaceIOCallbacks->pfnWriteMetaAsync(pExtent->pImage->pInterfaceIO->pvUser,
     5054                                                                  pExtent->pFile->pStorage,
     5055                                                                  VMDK_SECTOR2BYTE(pExtent->uSectorRGD) + uGDIndex * sizeof(uGTSectorLE),
     5056                                                                  &uRGTSectorLE, sizeof(uRGTSectorLE), pIoCtx,
     5057                                                                  vmdkAllocGrainAsyncComplete, pGrainAlloc);
     5058            if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
     5059                pGrainAlloc->cIoXfersPending++;
     5060            else if (RT_FAILURE(rc))
     5061                return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write backup grain directory entry in '%s'"), pExtent->pszFullname);
     5062        }
     5063
     5064        /* As the final step update the in-memory copy of the GDs. */
     5065        pExtent->pGD[uGDIndex] = uGTSector;
     5066        if (pExtent->pRGD)
     5067            pExtent->pRGD[uGDIndex] = uRGTSector;
     5068    }
     5069
     5070    LogFlow(("uGTSector=%llu uRGTSector=%llu\n", uGTSector, uRGTSector));
     5071    pGrainAlloc->uGTSector = uGTSector;
     5072    pGrainAlloc->uRGTSector = uRGTSector;
     5073
     5074    rc = vmdkFileGetSize(pExtent->pFile, &cbExtentSize);
     5075    if (RT_FAILURE(rc))
     5076        return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: error getting size in '%s'"), pExtent->pszFullname);
     5077    Assert(!(cbExtentSize % 512));
     5078
     5079    if (!pGrainAlloc->cbExtentOld)
     5080        pGrainAlloc->cbExtentOld = cbExtentSize;
     5081
     5082    pGrainAlloc->cbExtentSize = cbExtentSize;
     5083
     5084    /* Write the data. Always a full grain, or we're in big trouble. */
     5085    rc = pImage->pInterfaceIOCallbacks->pfnWriteUserAsync(pImage->pInterfaceIO->pvUser,
     5086                                                          pExtent->pFile->pStorage,
     5087                                                          cbExtentSize,
     5088                                                          pIoCtx, cbWrite,
     5089                                                          vmdkAllocGrainAsyncComplete, pGrainAlloc);
     5090    if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
     5091        pGrainAlloc->cIoXfersPending++;
     5092    else if (RT_FAILURE(rc))
     5093        return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write allocated data block in '%s'"), pExtent->pszFullname);
     5094
     5095    rc = vmdkAllocGrainAsyncGTUpdate(pImage, pExtent, pCache, pIoCtx, pGrainAlloc);
     5096
     5097    if (!pGrainAlloc->cIoXfersPending)
     5098    {
     5099        /* Grain allocation completed. */
     5100        RTMemFree(pGrainAlloc);
     5101    }
     5102
     5103    LogFlowFunc(("leaving rc=%Rrc\n", rc));
     5104
    46985105    return rc;
    46995106}
     
    60676474    PVMDKIMAGE pImage = (PVMDKIMAGE)pvBackendData;
    60686475
    6069 #if 1
     6476#if 1 /** @todo: Remove once the async support is tested throughly */
    60706477    bool fAsyncIOSupported = false;
    60716478
     
    62536660                    if (!(fWrite & VD_WRITE_NO_ALLOC))
    62546661                    {
    6255                         AssertMsgFailed(("Implement\n"));
    6256 #if 0
    62576662                        /* Allocate GT and find out where to store the grain. */
    6258                         rc = vmdkAllocGrain(pImage->pGTCache, pExtent,
    6259                                             uSectorExtentRel, pvBuf, cbWrite);
    6260 #endif
     6663                        rc = vmdkAllocGrainAsync(pImage->pGTCache, pExtent, pIoCtx,
     6664                                                 uSectorExtentRel, cbWrite);
    62616665                    }
    62626666                    else
     
    63236727                case VMDKETYPE_ESX_SPARSE:
    63246728#endif /* VBOX_WITH_VMDK_ESX */
    6325                     /** @todo: Fake success for now */
    6326                     rc = VINF_SUCCESS;
     6729                    rc = vmdkWriteMetaSparseExtentAsync(pImage, pExtent, 0, pIoCtx);
     6730                    if (RT_FAILURE(rc) && (rc != VERR_VD_ASYNC_IO_IN_PROGRESS))
     6731                        goto out;
     6732                    if (pExtent->fFooter)
     6733                    {
     6734                        uint64_t cbSize;
     6735                        rc = vmdkFileGetSize(pExtent->pFile, &cbSize);
     6736                        if (RT_FAILURE(rc))
     6737                            goto out;
     6738                        cbSize = RT_ALIGN_64(cbSize, 512);
     6739                        rc = vmdkWriteMetaSparseExtent(pExtent, cbSize - 2*512);
     6740                        if (RT_FAILURE(rc) && (rc != VERR_VD_ASYNC_IO_IN_PROGRESS))
     6741                            goto out;
     6742                    }
    63276743                    break;
    63286744                case VMDKETYPE_VMFS:
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