VirtualBox

Changeset 28620 in vbox


Ignore:
Timestamp:
Apr 22, 2010 10:43:37 PM (15 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
60469
Message:

VBoxHDD: async I/O updates. Mostly complete except for bug fixes

Location:
trunk
Files:
10 edited

Legend:

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

    r28383 r28620  
    13381338} VDBACKENDINFO, *PVDBACKENDINFO;
    13391339
    1340 /**
    1341  * Completion callback for metadata reads or writes.
    1342  *
    1343  * @return  nothing.
    1344  * @param   pvBackendData   The opaque backend data.
    1345  * @param   pvMetaUser      Opaque user data passed during a metadata read/write request.
    1346  */
    1347 typedef DECLCALLBACK(void) FNVDMETACOMPLETED(void *pvBackendData, void *pvMetaUser);
    1348 /** Pointer to FNVDCOMPLETED() */
    1349 typedef FNVDMETACOMPLETED *PFNVDMETACOMPLETED;
    13501340
    13511341/** Forward declaration. Only visible in the VBoxHDD module. */
     
    13561346/** Pointer to a storage backend handle. */
    13571347typedef PVDIOSTORAGE *PPVDIOSTORAGE;
     1348
     1349/**
     1350 * Completion callback for metadata reads or writes.
     1351 *
     1352 * @return  nothing.
     1353 * @param   pvBackendData   The opaque backend data.
     1354 * @param   pIoCtx          I/O context associated with this request.
     1355 * @param   pvMetaUser      Opaque user data passed during a metadata read/write request.
     1356 */
     1357typedef DECLCALLBACK(void) FNVDMETACOMPLETED(void *pvBackendData, PVDIOCTX pIoCtx, void *pvMetaUser);
     1358/** Pointer to FNVDCOMPLETED() */
     1359typedef FNVDMETACOMPLETED *PFNVDMETACOMPLETED;
    13581360
    13591361/**
  • trunk/src/VBox/Devices/Storage/DevAHCI.cpp

    r28524 r28620  
    48554855{
    48564856    /* Free system resources occupied by the scatter gather list. */
    4857     ahciScatterGatherListDestroy(pAhciPort, pAhciPortTaskState);
     4857    if (pAhciPortTaskState->enmTxDir != AHCITXDIR_FLUSH)
     4858        ahciScatterGatherListDestroy(pAhciPort, pAhciPortTaskState);
    48584859
    48594860    pAhciPortTaskState->cmdHdr.u32PRDBC = pAhciPortTaskState->cbTransfer;
     
    52905291        if (enmTxDir != AHCITXDIR_NONE)
    52915292        {
     5293            pAhciPortTaskState->enmTxDir = enmTxDir;
     5294
    52925295            if (pAhciPortTaskState->fQueued)
    52935296            {
  • trunk/src/VBox/Devices/Storage/DrvVD.cpp

    r28383 r28620  
    13521352                break;
    13531353            }
    1354             rc = CFGMR3QueryBoolDef(pCurNode, "UseNewIo", &fUseNewIo, false);
     1354            rc = CFGMR3QueryBoolDef(pCurNode, "UseNewIo", &fUseNewIo, true);
    13551355            if (RT_FAILURE(rc))
    13561356            {
  • trunk/src/VBox/Devices/Storage/ParallelsHDDCore.cpp

    r27808 r28620  
    6565{
    6666    /** Pointer to the per-disk VD interface list. */
    67     PVDINTERFACE         pVDIfsDisk;
     67    PVDINTERFACE        pVDIfsDisk;
     68    /** Pointer to the per-image VD interface list. */
     69    PVDINTERFACE        pVDIfsImage;
    6870    /** Error interface. */
    6971    PVDINTERFACE        pInterfaceError;
     
    284286#ifdef VBOX_WITH_NEW_IO_CODE
    285287    /* Try to get async I/O interface. */
    286     pImage->pInterfaceIO = VDInterfaceGet(pImage->pVDIfsDisk, VDINTERFACETYPE_IO);
     288    pImage->pInterfaceIO = VDInterfaceGet(pImage->pVDIfsImage, VDINTERFACETYPE_IO);
    287289    AssertPtr(pImage->pInterfaceIO);
    288290    pImage->pInterfaceIOCallbacks = VDGetInterfaceIO(pImage->pInterfaceIO);
     
    499501    pImage->pszFilename = pszFilename;
    500502    pImage->pVDIfsDisk = pVDIfsDisk;
     503    pImage->pVDIfsImage = pVDIfsImage;
    501504
    502505    rc = parallelsOpenImage(pImage, uOpenFlags);
  • trunk/src/VBox/Devices/Storage/RawHDDCore.cpp

    r28154 r28620  
    5858    /** Pointer to the per-disk VD interface list. */
    5959    PVDINTERFACE      pVDIfsDisk;
     60    /** Pointer to the per-image VD interface list. */
     61    PVDINTERFACE      pVDIfsImage;
    6062
    6163    /** Error callback. */
     
    269271#ifdef VBOX_WITH_NEW_IO_CODE
    270272    /* Try to get I/O interface. */
    271     pImage->pInterfaceIO = VDInterfaceGet(pImage->pVDIfsDisk, VDINTERFACETYPE_IO);
     273    pImage->pInterfaceIO = VDInterfaceGet(pImage->pVDIfsImage, VDINTERFACETYPE_IO);
    272274    AssertPtr(pImage->pInterfaceIO);
    273275    pImage->pInterfaceIOCallbacks = VDGetInterfaceIO(pImage->pInterfaceIO);
     
    335337#ifdef VBOX_WITH_NEW_IO_CODE
    336338    /* Try to get async I/O interface. */
    337     pImage->pInterfaceIO = VDInterfaceGet(pImage->pVDIfsDisk, VDINTERFACETYPE_IO);
     339    pImage->pInterfaceIO = VDInterfaceGet(pImage->pVDIfsImage, VDINTERFACETYPE_IO);
    338340    AssertPtr(pImage->pInterfaceIO);
    339341    pImage->pInterfaceIOCallbacks = VDGetInterfaceIO(pImage->pInterfaceIO);
     
    511513#endif
    512514    pImage->pVDIfsDisk = pVDIfsDisk;
     515    pImage->pVDIfsImage = pVDIfsImage;
    513516
    514517    rc = rawOpenImage(pImage, uOpenFlags);
     
    580583#endif
    581584    pImage->pVDIfsDisk = pVDIfsDisk;
     585    pImage->pVDIfsImage = pVDIfsImage;
    582586
    583587    rc = rawCreateImage(pImage, cbSize, uImageFlags, pszComment,
  • trunk/src/VBox/Devices/Storage/VBoxHDD.cpp

    r28383 r28620  
    4141#include <iprt/memcache.h>
    4242#include <iprt/sg.h>
     43#include <iprt/critsect.h>
     44#include <iprt/list.h>
    4345
    4446#include <VBox/VBoxHDD-Plugin.h>
     
    8789    /** Function pointers for the various backend methods. */
    8890    PCVBOXHDDBACKEND    Backend;
     91    /** Per image I/O interface. */
     92    VDINTERFACE         VDIIO;
    8993    /** Pointer to list of VD interfaces, per-image. */
    9094    PVDINTERFACE        pVDIfsImage;
     95    /** Disk this image is part of */
     96    PVBOXHDD            pDisk;
    9197} VDIMAGE, *PVDIMAGE;
    9298
     
    158164    /** Memory cache for I/O tasks. */
    159165    RTMEMCACHE          hMemCacheIoTask;
     166    /** Critical section protecting the disk against concurrent access. */
     167    RTCRITSECT          CritSect;
     168    /** Flag whether the last image is currently written to and needs to grow.
     169     * Other write requests which will grow the image too need to be deferred to
     170     * prevent data corruption. - Protected by the critical section.
     171     */
     172    bool                fGrowing;
     173    /** List of waiting requests. - Protected by the critical section. */
     174    RTLISTNODE          ListWriteGrowing;
    160175};
    161176
     
    187202} VDIOCTXTXDIR, *PVDIOCTXTXDIR;
    188203
     204/** Transfer function */
     205typedef DECLCALLBACK(int) FNVDIOCTXTRANSFER (PVDIOCTX pIoCtx);
     206/** Pointer to a transfer function. */
     207typedef FNVDIOCTXTRANSFER *PFNVDIOCTXTRANSFER;
     208
    189209/**
    190210 * I/O context
     
    192212typedef struct VDIOCTX
    193213{
     214    /** Node in the list of deferred requests. */
     215    RTLISTNODE                   NodeWriteGrowing;
    194216    /** Disk this is request is for. */
    195217    PVBOXHDD                     pDisk;
     
    202224    /** Current offset */
    203225    volatile uint64_t            uOffset;
     226    /** Number of bytes to transfer */
     227    volatile size_t              cbTransfer;
     228    /** Current image in the chain. */
     229    PVDIMAGE                     pImage;
    204230    /** S/G buffer */
    205231    RTSGBUF                      SgBuf;
     
    211237     * when the context completes. */
    212238    void                        *pvAllocation;
     239    /** Transfer function. */
     240    PFNVDIOCTXTRANSFER           pfnIoCtxTransfer;
     241    /** Next transfer part after the current one completed. */
     242    PFNVDIOCTXTRANSFER           pfnIoCtxTransferNext;
    213243    /** Parent I/O context if any. Sets the type of the context (root/child) */
    214244    PVDIOCTX                     pIoCtxParent;
     
    235265            /** Number of bytes transfered from the parent if this context completes. */
    236266            size_t                       cbTransferParent;
     267            /** Number of bytes to pre read */
     268            size_t                       cbPreRead;
     269            /** Number of bytes to post read. */
     270            size_t                       cbPostRead;
     271            /** Write type dependent data. */
     272            union
     273            {
     274                /** Optimized */
     275                struct
     276                {
     277                    /** Bytes to fill to satisfy the block size. Not part of the virtual disk. */
     278                    size_t               cbFill;
     279                    /** Bytes to copy instead of reading from the parent */
     280                    size_t               cbWriteCopy;
     281                    /** Bytes to read from the image. */
     282                    size_t               cbReadImage;
     283                    /** Number of bytes to wite left. */
     284                    size_t               cbWrite;
     285                } Optimized;
     286            } Write;
    237287        } Child;
    238288    } Type;
     
    266316            /** User data */
    267317            void                *pvMetaUser;
     318            /** Image the task was created for. */
     319            PVDIMAGE             pImage;
    268320        } Meta;
    269321    } Type;
     
    275327typedef struct VDIOSTORAGE
    276328{
     329    /** Image this storage handle belongs to. */
     330    PVDIMAGE                     pImage;
    277331    union
    278332    {
    279333        /** Storage handle */
    280         void                        *pStorage;
     334        void                    *pStorage;
    281335        /** File handle for the limited I/O version. */
    282         RTFILE                       hFile;
     336        RTFILE                   hFile;
    283337    } u;
    284338} VDIOSTORAGE;
     
    531585                                  uint64_t uOffset, size_t cbTransfer,
    532586                                  PCRTSGSEG pcaSeg, unsigned cSeg,
    533                                   void *pvAllocation)
     587                                  void *pvAllocation,
     588                                  PFNVDIOCTXTRANSFER pfnIoCtxTransfer)
    534589{
    535590    PVDIOCTX pIoCtx = NULL;
     
    542597        pIoCtx->cbTransferLeft        = cbTransfer;
    543598        pIoCtx->uOffset               = uOffset;
     599        pIoCtx->cbTransfer            = cbTransfer;
    544600        pIoCtx->cMetaTransfersPending = 0;
    545601        pIoCtx->fComplete             = false;
    546602        pIoCtx->pvAllocation          = pvAllocation;
     603        pIoCtx->pfnIoCtxTransfer      = pfnIoCtxTransfer;
     604        pIoCtx->pfnIoCtxTransferNext  = NULL;
    547605
    548606        RTSgBufInit(&pIoCtx->SgBuf, pcaSeg, cSeg);
     
    552610}
    553611
    554 static PVDIOCTX vdIoCtxRootAlloc(PVBOXHDD pDisk, VDIOCTXTXDIR enmTxDir,
    555                                  uint64_t uOffset, size_t cbTransfer,
    556                                  PCRTSGSEG paSeg, unsigned cSeg,
    557                                  PFNVDASYNCTRANSFERCOMPLETE pfnComplete,
    558                                  void *pvUser1, void *pvUser2,
    559                                  void *pvAllocation)
     612DECLINLINE(PVDIOCTX) vdIoCtxRootAlloc(PVBOXHDD pDisk, VDIOCTXTXDIR enmTxDir,
     613                                      uint64_t uOffset, size_t cbTransfer,
     614                                      PCRTSGSEG paSeg, unsigned cSeg,
     615                                      PFNVDASYNCTRANSFERCOMPLETE pfnComplete,
     616                                      void *pvUser1, void *pvUser2,
     617                                      void *pvAllocation,
     618                                      PFNVDIOCTXTRANSFER pfnIoCtxTransfer)
    560619{
    561620    PVDIOCTX pIoCtx = vdIoCtxAlloc(pDisk, enmTxDir, uOffset, cbTransfer,
    562                                    paSeg, cSeg, pvAllocation);
     621                                   paSeg, cSeg, pvAllocation, pfnIoCtxTransfer);
    563622
    564623    if (RT_LIKELY(pIoCtx))
     
    573632}
    574633
    575 static PVDIOCTX vdIoCtxChildAlloc(PVBOXHDD pDisk, VDIOCTXTXDIR enmTxDir,
    576                                   uint64_t uOffset, size_t cbTransfer,
    577                                   PCRTSGSEG paSeg, unsigned cSeg,
    578                                   PVDIOCTX pIoCtxParent, size_t cbTransferParent,
    579                                   void *pvAllocation)
     634DECLINLINE(PVDIOCTX) vdIoCtxChildAlloc(PVBOXHDD pDisk, VDIOCTXTXDIR enmTxDir,
     635                                       uint64_t uOffset, size_t cbTransfer,
     636                                       PCRTSGSEG paSeg, unsigned cSeg,
     637                                       PVDIOCTX pIoCtxParent, size_t cbTransferParent,
     638                                       void *pvAllocation,
     639                                       PFNVDIOCTXTRANSFER pfnIoCtxTransfer)
    580640{
    581641    PVDIOCTX pIoCtx = vdIoCtxAlloc(pDisk, enmTxDir, uOffset, cbTransfer,
    582                                    paSeg, cSeg, pvAllocation);
     642                                   paSeg, cSeg, pvAllocation, pfnIoCtxTransfer);
    583643
    584644    if (RT_LIKELY(pIoCtx))
     
    593653}
    594654
    595 static PVDIOTASK vdIoTaskUserAlloc(PVBOXHDD pDisk, PVDIOCTX pIoCtx, uint32_t cbTransfer)
     655DECLINLINE(PVDIOTASK) vdIoTaskUserAlloc(PVBOXHDD pDisk, PVDIOCTX pIoCtx, uint32_t cbTransfer)
    596656{
    597657    PVDIOTASK pIoTask = NULL;
     
    608668}
    609669
    610 static PVDIOTASK vdIoTaskMetaAlloc(PVBOXHDD pDisk, PVDIOCTX pIoCtx, VDIOCTXTXDIR enmTxDir,
    611                                    PFNVDMETACOMPLETED pfnMetaComplete, void *pvMetaUser)
     670DECLINLINE(PVDIOTASK) vdIoTaskMetaAlloc(PVBOXHDD pDisk, PVDIOCTX pIoCtx, VDIOCTXTXDIR enmTxDir,
     671                                        PVDIMAGE pImage,
     672                                        PFNVDMETACOMPLETED pfnMetaComplete, void *pvMetaUser)
    612673{
    613674    PVDIOTASK pIoTask = NULL;
     
    621682        pIoTask->Type.Meta.pfnMetaComplete   = pfnMetaComplete;
    622683        pIoTask->Type.Meta.pvMetaUser        = pvMetaUser;
     684        pIoTask->Type.Meta.pImage            = pImage;
    623685    }
    624686
     
    626688}
    627689
    628 static void vdIoCtxFree(PVBOXHDD pDisk, PVDIOCTX pIoCtx)
     690DECLINLINE(void) vdIoCtxFree(PVBOXHDD pDisk, PVDIOCTX pIoCtx)
    629691{
    630692    if (pIoCtx->pvAllocation)
     
    633695}
    634696
    635 static void vdIoTaskFree(PVBOXHDD pDisk, PVDIOTASK pIoTask)
     697DECLINLINE(void) vdIoTaskFree(PVBOXHDD pDisk, PVDIOTASK pIoTask)
    636698{
    637699    pIoTask->pIoCtx = NULL;
     
    639701}
    640702
    641 static void vdIoCtxChildReset(PVDIOCTX pIoCtx)
     703DECLINLINE(void) vdIoCtxChildReset(PVDIOCTX pIoCtx)
    642704{
    643705    AssertPtr(pIoCtx->pIoCtxParent);
     
    674736}
    675737
     738static int vdIoCtxProcess(PVDIOCTX pIoCtx)
     739{
     740    int rc = VINF_SUCCESS;
     741    PVBOXHDD pDisk = pIoCtx->pDisk;
     742
     743    if (   !pIoCtx->cbTransferLeft
     744        && !pIoCtx->cMetaTransfersPending)
     745        return VINF_VD_ASYNC_IO_FINISHED;
     746
     747    if (pIoCtx->pfnIoCtxTransfer)
     748    {
     749        /* Call the transfer function advancing to the next while there is no error. */
     750        RTCritSectEnter(&pDisk->CritSect);
     751        while (   pIoCtx->pfnIoCtxTransfer
     752               && RT_SUCCESS(rc))
     753        {
     754            rc = pIoCtx->pfnIoCtxTransfer(pIoCtx);
     755
     756            /* Advance to the next part of the transfer if the current one succeeded. */
     757            if (RT_SUCCESS(rc))
     758            {
     759                pIoCtx->pfnIoCtxTransfer = pIoCtx->pfnIoCtxTransferNext;
     760                pIoCtx->pfnIoCtxTransferNext = NULL;
     761            }
     762        }
     763        RTCritSectLeave(&pDisk->CritSect);
     764    }
     765
     766    if (   RT_SUCCESS(rc)
     767        && !pIoCtx->cbTransferLeft
     768        && !pIoCtx->cMetaTransfersPending)
     769        rc = VINF_VD_ASYNC_IO_FINISHED;
     770    else if (RT_SUCCESS(rc))
     771        rc = VERR_VD_ASYNC_IO_IN_PROGRESS;
     772
     773    LogFlowFunc(("pIoCtx=%#p rc=%Rrc cbTransferLeft=%u cMetaTransfersPending=%u fComplete=%RTbool\n",
     774                 pIoCtx, rc, pIoCtx->cbTransferLeft, pIoCtx->cMetaTransfersPending,
     775                 pIoCtx->fComplete));
     776
     777    return rc;
     778}
     779
    676780/**
    677781 * internal: read the specified amount of data in whatever blocks the backend
    678782 * will give us - async version.
    679783 */
    680 static int vdReadHelperAsync(PVBOXHDD pDisk, PVDIMAGE pImage, PVDIMAGE pImageParentOverride,
    681                              PVDIOCTX pIoCtx, uint64_t uOffset, size_t cbRead)
     784static int vdReadHelperAsync(PVDIOCTX pIoCtx)
    682785{
    683786    int rc;
     787    size_t cbToRead     = pIoCtx->cbTransfer;
     788    uint64_t uOffset    = pIoCtx->uOffset;
     789    PVDIMAGE pCurrImage = NULL;
    684790    size_t cbThisRead;
    685791
     
    687793    do
    688794    {
     795        pCurrImage = pIoCtx->pImage;
     796
    689797        /* Search for image with allocated block. Do not attempt to read more
    690798         * than the previous reads marked as valid. Otherwise this would return
    691799         * stale data when different block sizes are used for the images. */
    692         cbThisRead = cbRead;
     800        cbThisRead = cbToRead;
    693801
    694802        /*
     
    696804         * If the block is not allocated read from override chain if present.
    697805         */
    698         rc = pImage->Backend->pfnAsyncRead(pImage->pvBackendData,
    699                                            uOffset, cbThisRead,
    700                                            pIoCtx, &cbThisRead);
     806        rc = pCurrImage->Backend->pfnAsyncRead(pCurrImage->pvBackendData,
     807                                               uOffset, cbThisRead,
     808                                               pIoCtx, &cbThisRead);
    701809
    702810        if (rc == VERR_VD_BLOCK_FREE)
    703811        {
    704             for (PVDIMAGE pCurrImage = pImageParentOverride ? pImageParentOverride : pImage->pPrev;
     812            for (pCurrImage =  pCurrImage->pPrev;
    705813                 pCurrImage != NULL && rc == VERR_VD_BLOCK_FREE;
    706814                 pCurrImage = pCurrImage->pPrev)
     
    723831            break;
    724832
    725         cbRead -= cbThisRead;
    726         uOffset += cbThisRead;
    727     } while (cbRead != 0 && RT_SUCCESS(rc));
     833        cbToRead -= cbThisRead;
     834        uOffset  += cbThisRead;
     835    } while (cbToRead != 0 && RT_SUCCESS(rc));
    728836
    729837    if (rc == VERR_VD_NOT_ENOUGH_METADATA)
    730838    {
    731         pIoCtx->uOffset = uOffset;
     839        /* Save the current state. */
     840        pIoCtx->uOffset    = uOffset;
     841        pIoCtx->cbTransfer = cbToRead;
     842        pIoCtx->pImage     = pCurrImage;
     843        rc = VERR_VD_ASYNC_IO_IN_PROGRESS;
    732844    }
    733845
     
    10141126 * images that are really needed) - async version.
    10151127 */
    1016 static int vdWriteHelperStandardAsync(PVBOXHDD pDisk, PVDIMAGE pImage,
    1017                                       PVDIMAGE pImageParentOverride,
    1018                                       uint64_t uOffset, size_t cbWrite,
    1019                                       size_t cbThisWrite, size_t cbPreRead,
    1020                                       size_t cbPostRead, PVDIOCTX pIoCtxSrc,
    1021                                       PVDIOCTX pIoCtxDst)
     1128static int vdWriteHelperStandardAsync(PVDIOCTX pIoCtx)
    10221129{
    10231130    int rc = VINF_SUCCESS;
     1131
     1132#if 0
    10241133
    10251134    /* Read the data that goes before the write to fill the block. */
    10261135    if (cbPreRead)
    10271136    {
    1028         rc = vdReadHelperAsync(pDisk, pImage, pImageParentOverride, pIoCtxDst,
    1029                                uOffset - cbPreRead, cbPreRead);
     1137        rc = vdReadHelperAsync(pIoCtxDst);
    10301138        if (RT_FAILURE(rc))
    10311139            return rc;
     
    11021210
    11031211    return rc;
     1212#endif
     1213    return VERR_NOT_IMPLEMENTED;
     1214}
     1215
     1216static int vdWriteHelperOptimizedCmpAndWriteAsync(PVDIOCTX pIoCtx)
     1217{
     1218    int rc = VINF_SUCCESS;
     1219    PVDIMAGE pImage = pIoCtx->pImage;
     1220    size_t cbThisWrite    = 0;
     1221    size_t cbPreRead      = pIoCtx->Type.Child.cbPreRead;
     1222    size_t cbPostRead     = pIoCtx->Type.Child.cbPostRead;
     1223    size_t cbWriteCopy    = pIoCtx->Type.Child.Write.Optimized.cbWriteCopy;
     1224    size_t cbFill         = pIoCtx->Type.Child.Write.Optimized.cbFill;
     1225    size_t cbReadImage    = pIoCtx->Type.Child.Write.Optimized.cbReadImage;
     1226    PVDIOCTX pIoCtxParent = pIoCtx->pIoCtxParent;
     1227
     1228    AssertPtr(pIoCtxParent);
     1229    Assert(!pIoCtx->cbTransferLeft && !pIoCtx->cMetaTransfersPending);
     1230
     1231    vdIoCtxChildReset(pIoCtx);
     1232    cbThisWrite = pIoCtx->Type.Child.cbTransferParent;
     1233    RTSgBufAdvance(&pIoCtx->SgBuf, cbPreRead);
     1234
     1235    /* Check if the write would modify anything in this block. */
     1236    if (!RTSgBufCmp(&pIoCtx->SgBuf, &pIoCtxParent->SgBuf, cbThisWrite))
     1237    {
     1238        RTSGBUF SgBufSrcTmp;
     1239
     1240        RTSgBufClone(&SgBufSrcTmp, &pIoCtxParent->SgBuf);
     1241        RTSgBufAdvance(&SgBufSrcTmp, cbThisWrite);
     1242        RTSgBufAdvance(&pIoCtx->SgBuf, cbThisWrite);
     1243
     1244        if (!cbWriteCopy || !RTSgBufCmp(&pIoCtx->SgBuf, &SgBufSrcTmp, cbWriteCopy))
     1245        {
     1246            /* Block is completely unchanged, so no need to write anything. */
     1247            LogFlowFunc(("Block didn't changed\n"));
     1248            ASMAtomicWriteU32(&pIoCtx->cbTransferLeft, 0);
     1249            return VINF_VD_ASYNC_IO_FINISHED;
     1250        }
     1251    }
     1252
     1253    /* Copy the data to the right place in the buffer. */
     1254    RTSgBufReset(&pIoCtx->SgBuf);
     1255    RTSgBufAdvance(&pIoCtx->SgBuf, cbPreRead);
     1256    vdIoCtxCopy(pIoCtx, pIoCtxParent, cbThisWrite);
     1257
     1258    /* Handle the data that goes after the write to fill the block. */
     1259    if (cbPostRead)
     1260    {
     1261        /* Now assemble the remaining data. */
     1262        if (cbWriteCopy)
     1263            vdIoCtxCopy(pIoCtx, pIoCtxParent, cbWriteCopy);
     1264        /* Zero out the remainder of this block. Will never be visible, as this
     1265         * is beyond the limit of the image. */
     1266        if (cbFill)
     1267        {
     1268            RTSgBufAdvance(&pIoCtx->SgBuf, cbReadImage);
     1269            vdIoCtxSet(pIoCtx, '\0', cbFill);
     1270        }
     1271    }
     1272
     1273    /* Write the full block to the virtual disk. */
     1274    RTSgBufReset(&pIoCtx->SgBuf);
     1275    rc = pImage->Backend->pfnAsyncWrite(pImage->pvBackendData,
     1276                                        pIoCtx->uOffset - cbPreRead,
     1277                                        cbPreRead + pIoCtx->cbTransferLeft + cbPostRead,
     1278                                        pIoCtx, NULL, &cbPreRead, &cbPostRead, 0);
     1279    Assert(rc != VERR_VD_BLOCK_FREE);
     1280    Assert(cbPreRead == 0);
     1281    Assert(cbPostRead == 0);
     1282
     1283    return rc;
     1284}
     1285
     1286static int vdWriteHelperOptimizedPreReadAsync(PVDIOCTX pIoCtx)
     1287{
     1288    pIoCtx->pfnIoCtxTransferNext = vdWriteHelperOptimizedCmpAndWriteAsync;
     1289    return vdReadHelperAsync(pIoCtx);
    11041290}
    11051291
     
    11101296 * All backends which support differential/growing images support this - async version.
    11111297 */
    1112 static int vdWriteHelperOptimizedAsync(PVBOXHDD pDisk, PVDIMAGE pImage,
    1113                                        PVDIMAGE pImageParentOverride,
    1114                                        uint64_t uOffset, size_t cbWrite,
    1115                                        size_t cbThisWrite, size_t cbPreRead,
    1116                                        size_t cbPostRead, PVDIOCTX pIoCtxSrc,
    1117                                        PVDIOCTX pIoCtxDst)
    1118 {
     1298static int vdWriteHelperOptimizedAsync(PVDIOCTX pIoCtx)
     1299{
     1300    PVBOXHDD pDisk = pIoCtx->pDisk;
     1301    uint64_t uOffset   = pIoCtx->Type.Child.uOffsetSaved;
     1302    size_t cbThisWrite = pIoCtx->Type.Child.cbTransferParent;
     1303    size_t cbPreRead   = pIoCtx->Type.Child.cbPreRead;
     1304    size_t cbPostRead  = pIoCtx->Type.Child.cbPostRead;
     1305    size_t cbWrite     = pIoCtx->Type.Child.Write.Optimized.cbWrite;
    11191306    size_t cbFill = 0;
    11201307    size_t cbWriteCopy = 0;
    11211308    size_t cbReadImage = 0;
    11221309    int rc;
     1310
     1311    AssertPtr(pIoCtx->pIoCtxParent);
    11231312
    11241313    if (cbPostRead)
     
    11391328    }
    11401329
     1330    pIoCtx->Type.Child.Write.Optimized.cbFill      = cbFill;
     1331    pIoCtx->Type.Child.Write.Optimized.cbWriteCopy = cbWriteCopy;
     1332    pIoCtx->Type.Child.Write.Optimized.cbReadImage = cbReadImage;
     1333
    11411334    /* Read the entire data of the block so that we can compare whether it will
    11421335     * be modified by the write or not. */
    1143     rc = vdReadHelperAsync(pDisk, pImage, pImageParentOverride, pIoCtxDst,
    1144                            uOffset - cbPreRead,
    1145                            cbPreRead + cbThisWrite + cbPostRead - cbFill);
    1146     if (RT_FAILURE(rc))
    1147         return rc;
    1148 
    1149     /** @todo Snapshots */
    1150     Assert(!pIoCtxDst->cbTransferLeft && !pIoCtxDst->cMetaTransfersPending);
    1151 
    1152     vdIoCtxChildReset(pIoCtxDst);
    1153     RTSgBufAdvance(&pIoCtxDst->SgBuf, cbPreRead);
    1154 
    1155     /* Check if the write would modify anything in this block. */
    1156     if (!RTSgBufCmp(&pIoCtxDst->SgBuf, &pIoCtxSrc->SgBuf, cbThisWrite))
    1157     {
    1158         RTSGBUF SgBufSrcTmp;
    1159 
    1160         RTSgBufClone(&SgBufSrcTmp, &pIoCtxSrc->SgBuf);
    1161         RTSgBufAdvance(&SgBufSrcTmp, cbThisWrite);
    1162         RTSgBufAdvance(&pIoCtxDst->SgBuf, cbThisWrite);
    1163 
    1164         if (!cbWriteCopy || !RTSgBufCmp(&pIoCtxDst->SgBuf, &SgBufSrcTmp, cbWriteCopy))
    1165         {
    1166             /* Block is completely unchanged, so no need to write anything. */
    1167             LogFlowFunc(("Block didn't changed\n"));
    1168             ASMAtomicWriteU32(&pIoCtxDst->cbTransferLeft, 0);
    1169             return VINF_SUCCESS;
    1170         }
    1171     }
    1172 
    1173     /* Copy the data to the right place in the buffer. */
    1174     RTSgBufReset(&pIoCtxDst->SgBuf);
    1175     RTSgBufAdvance(&pIoCtxDst->SgBuf, cbPreRead);
    1176     vdIoCtxCopy(pIoCtxDst, pIoCtxSrc, cbThisWrite);
    1177 
    1178     /* Handle the data that goes after the write to fill the block. */
    1179     if (cbPostRead)
    1180     {
    1181         /* Now assemble the remaining data. */
    1182         if (cbWriteCopy)
    1183             vdIoCtxCopy(pIoCtxDst, pIoCtxSrc, cbWriteCopy);
    1184         /* Zero out the remainder of this block. Will never be visible, as this
    1185          * is beyond the limit of the image. */
    1186         if (cbFill)
    1187         {
    1188             RTSgBufAdvance(&pIoCtxDst->SgBuf, cbReadImage);
    1189             vdIoCtxSet(pIoCtxDst, '\0', cbFill);
    1190         }
    1191     }
    1192 
    1193     /* Write the full block to the virtual disk. */
    1194     RTSgBufReset(&pIoCtxDst->SgBuf);
    1195     rc = pImage->Backend->pfnAsyncWrite(pImage->pvBackendData,
    1196                                         uOffset - cbPreRead,
    1197                                         cbPreRead + cbThisWrite + cbPostRead,
    1198                                         pIoCtxDst, NULL, &cbPreRead, &cbPostRead, 0);
    1199     Assert(rc != VERR_VD_BLOCK_FREE);
    1200     Assert(cbPreRead == 0);
    1201     Assert(cbPostRead == 0);
    1202 
    1203     return rc;
     1336    pIoCtx->cbTransferLeft = cbPreRead + cbThisWrite + cbPostRead - cbFill;
     1337    pIoCtx->cbTransfer     = pIoCtx->cbTransferLeft;
     1338    pIoCtx->uOffset -= cbPreRead;
     1339
     1340    /* Next step */
     1341    pIoCtx->pfnIoCtxTransferNext = vdWriteHelperOptimizedPreReadAsync;
     1342    return VINF_SUCCESS;
    12041343}
    12051344
     
    12081347 * write optimizations - async version.
    12091348 */
    1210 static int vdWriteHelperAsync(PVBOXHDD pDisk, PVDIMAGE pImage, PVDIMAGE pImageParentOverride,
    1211                               PVDIOCTX pIoCtx, uint64_t uOffset, size_t cbWrite)
     1349static int vdWriteHelperAsync(PVDIOCTX pIoCtx)
    12121350{
    12131351    int rc;
     1352    size_t cbWrite   = pIoCtx->cbTransfer;
     1353    uint64_t uOffset = pIoCtx->uOffset;
     1354    PVDIMAGE pImage  = pIoCtx->pImage;
     1355    PVBOXHDD pDisk   = pIoCtx->pDisk;
    12141356    unsigned fWrite;
    12151357    size_t cbThisWrite;
     
    12351377        {
    12361378            /*
    1237              * Allocate segment and buffer in one go.
    1238              * A bit hackish but avoids the need to allocate memory twice.
     1379             * If there is a growing request already put this one onto the waiting list.
     1380             * It will be restarted if the current request completes.
    12391381             */
    1240             PRTSGSEG pTmp = (PRTSGSEG)RTMemAlloc(cbPreRead + cbThisWrite + cbPostRead + sizeof(RTSGSEG));
    1241             AssertBreakStmt(VALID_PTR(pTmp), rc = VERR_NO_MEMORY);
    1242 
    1243             pTmp->pvSeg = pTmp + 1;
    1244             pTmp->cbSeg = cbPreRead + cbThisWrite + cbPostRead;
    1245 
    1246             PVDIOCTX pIoCtxWrite = vdIoCtxChildAlloc(pDisk, VDIOCTXTXDIR_WRITE,
    1247                                                      uOffset - cbPreRead, pTmp->cbSeg,
    1248                                                      pTmp, 1,
    1249                                                      pIoCtx, cbThisWrite,
    1250                                                      pTmp);
    1251             if (!VALID_PTR(pIoCtxWrite))
     1382            if (pDisk->fGrowing)
    12521383            {
    1253                 RTMemTmpFree(pTmp);
    1254                 rc = VERR_NO_MEMORY;
     1384                LogFlowFunc(("Deferring write pIoCtx=%#p\n", pIoCtx));
     1385                RTListAppend(&pDisk->ListWriteGrowing, &pIoCtx->NodeWriteGrowing);
     1386                Assert(pIoCtx->NodeWriteGrowing.pNext == &pDisk->ListWriteGrowing);
     1387                rc = VERR_VD_ASYNC_IO_IN_PROGRESS;
    12551388                break;
    1256             }
    1257 
    1258             if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_HONOR_SAME))
    1259             {
    1260                 /* Optimized write, suppress writing to a so far unallocated
    1261                  * block if the data is in fact not changed. */
    1262                 rc = vdWriteHelperOptimizedAsync(pDisk, pImage, pImageParentOverride,
    1263                                                  uOffset, cbWrite,
    1264                                                  cbThisWrite, cbPreRead, cbPostRead,
    1265                                                  pIoCtx, pIoCtxWrite);
    12661389            }
    12671390            else
    12681391            {
    1269                 /* Normal write, not optimized in any way. The block will
    1270                  * be written no matter what. This will usually (unless the
    1271                  * backend has some further optimization enabled) cause the
    1272                  * block to be allocated. */
    1273                 rc = vdWriteHelperStandardAsync(pDisk, pImage, pImageParentOverride,
    1274                                                 uOffset, cbWrite,
    1275                                                 cbThisWrite, cbPreRead, cbPostRead,
    1276                                                 pIoCtx, pIoCtxWrite);
     1392                /*
     1393                 * Allocate segment and buffer in one go.
     1394                 * A bit hackish but avoids the need to allocate memory twice.
     1395                 */
     1396                PRTSGSEG pTmp = (PRTSGSEG)RTMemAlloc(cbPreRead + cbThisWrite + cbPostRead + sizeof(RTSGSEG));
     1397                AssertBreakStmt(VALID_PTR(pTmp), rc = VERR_NO_MEMORY);
     1398
     1399                pTmp->pvSeg = pTmp + 1;
     1400                pTmp->cbSeg = cbPreRead + cbThisWrite + cbPostRead;
     1401
     1402                PVDIOCTX pIoCtxWrite = vdIoCtxChildAlloc(pDisk, VDIOCTXTXDIR_WRITE,
     1403                                                         uOffset, pTmp->cbSeg,
     1404                                                         pTmp, 1,
     1405                                                         pIoCtx, cbThisWrite,
     1406                                                         pTmp,
     1407                                                           (pImage->uOpenFlags & VD_OPEN_FLAGS_HONOR_SAME)
     1408                                                         ? vdWriteHelperStandardAsync
     1409                                                         : vdWriteHelperOptimizedAsync);
     1410                if (!VALID_PTR(pIoCtxWrite))
     1411                {
     1412                    RTMemTmpFree(pTmp);
     1413                    rc = VERR_NO_MEMORY;
     1414                    break;
     1415                }
     1416
     1417                /* Set the state to growing. */
     1418                LogFlowFunc(("Disk is growing because of pIoCtx=%#p pIoCtxWrite=%#p\n",
     1419                             pIoCtx, pIoCtxWrite));
     1420                pDisk->fGrowing = true;
     1421
     1422                pIoCtxWrite->pImage                = pImage;
     1423                pIoCtxWrite->Type.Child.cbPreRead  = cbPreRead;
     1424                pIoCtxWrite->Type.Child.cbPostRead = cbPostRead;
     1425
     1426                /* Process the write request */
     1427                rc = vdIoCtxProcess(pIoCtxWrite);
     1428
     1429                if (RT_FAILURE(rc) && (rc != VERR_VD_ASYNC_IO_IN_PROGRESS))
     1430                {
     1431                    vdIoCtxFree(pDisk, pIoCtxWrite);
     1432                    break;
     1433                }
     1434                else if (   rc == VINF_VD_ASYNC_IO_FINISHED
     1435                         && ASMAtomicCmpXchgBool(&pIoCtxWrite->fComplete, true, false))
     1436                {
     1437                    LogFlow(("Child write request completed\n"));
     1438                    Assert(pIoCtx->cbTransferLeft >= cbThisWrite);
     1439                    ASMAtomicSubU32(&pIoCtx->cbTransferLeft, cbThisWrite);
     1440                    pDisk->fGrowing = false;
     1441                    vdIoCtxFree(pDisk, pIoCtxWrite);
     1442
     1443                    Assert(RTListIsEmpty(&pDisk->ListWriteGrowing));
     1444                    rc = VINF_SUCCESS;
     1445                }
     1446                else
     1447                    LogFlow(("Child write pending\n"));
    12771448            }
    1278 
    1279             if (RT_FAILURE(rc))
    1280             {
    1281                 vdIoCtxFree(pDisk, pIoCtxWrite);
    1282                 break;
    1283             }
    1284 
    1285             if (   !(pIoCtxWrite->cbTransferLeft || pIoCtxWrite->cMetaTransfersPending)
    1286                 && ASMAtomicCmpXchgBool(&pIoCtxWrite->fComplete, true, false))
    1287             {
    1288                 LogFlow(("Child write request completed\n"));
    1289                 ASMAtomicSubU32(&pIoCtx->cbTransferLeft, cbThisWrite);
    1290                 vdIoCtxFree(pDisk, pIoCtxWrite);
    1291             }
    1292             else
    1293                 LogFlow(("Child write pending\n"));
    1294         }
    1295 
    1296         if (RT_FAILURE(rc))
    1297             break;
     1449        }
    12981450
    12991451        cbWrite -= cbThisWrite;
    13001452        uOffset += cbThisWrite;
    13011453    } while (cbWrite != 0 && RT_SUCCESS(rc));
     1454
     1455    if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
     1456    {
     1457        /*
     1458         * Tell the caller that we don't need to go back here because all
     1459         * writes are initiated.
     1460         */
     1461        if (!cbWrite)
     1462            rc = VINF_SUCCESS;
     1463
     1464        pIoCtx->uOffset    = uOffset;
     1465        pIoCtx->cbTransfer = cbWrite;
     1466    }
     1467
     1468    return rc;
     1469}
     1470
     1471/**
     1472 * Flush helper async version.
     1473 */
     1474static int vdFlushHelperAsync(PVDIOCTX pIoCtx)
     1475{
     1476    int rc = VINF_SUCCESS;
     1477    PVBOXHDD pDisk = pIoCtx->pDisk;
     1478    PVDIMAGE pImage = pIoCtx->pImage;
     1479
     1480    vdResetModifiedFlag(pDisk);
     1481    rc = pImage->Backend->pfnAsyncFlush(pImage->pvBackendData, pIoCtx);
    13021482
    13031483    return rc;
     
    15561736static int vdIOReqCompleted(void *pvUser)
    15571737{
     1738    int rc = VINF_SUCCESS;
    15581739    PVDIOTASK pIoTask = (PVDIOTASK)pvUser;
    15591740    PVDIOCTX  pIoCtx  = pIoTask->pIoCtx;
     
    15671748    else
    15681749    {
    1569         Assert(pIoTask->Type.Meta.enmTxDir == VDIOCTXTXDIR_WRITE);
    15701750        if (pIoTask->Type.Meta.pfnMetaComplete)
    1571             pIoTask->Type.Meta.pfnMetaComplete(NULL, pIoTask->Type.Meta.pvMetaUser);
     1751            pIoTask->Type.Meta.pfnMetaComplete(pIoTask->Type.Meta.pImage->pvBackendData,
     1752                                               pIoCtx,
     1753                                               pIoTask->Type.Meta.pvMetaUser);
    15721754        ASMAtomicDecU32(&pIoCtx->cMetaTransfersPending);
    15731755    }
     
    15751757    vdIoTaskFree(pDisk, pIoTask);
    15761758
    1577     if (   !pIoCtx->cbTransferLeft
    1578         && !pIoCtx->cMetaTransfersPending
     1759    /* Continue the transfer */
     1760    rc = vdIoCtxProcess(pIoCtx);
     1761
     1762    if (   rc == VINF_VD_ASYNC_IO_FINISHED
    15791763        && ASMAtomicCmpXchgBool(&pIoCtx->fComplete, true, false))
    15801764    {
    1581         LogFlowFunc(("I/O context completed\n"));
     1765        LogFlowFunc(("I/O context completed pIoCtx=%#p\n", pIoCtx));
    15821766        if (pIoCtx->pIoCtxParent)
    15831767        {
    15841768            PVDIOCTX pIoCtxParent = pIoCtx->pIoCtxParent;
     1769
     1770            LogFlowFunc(("I/O context transfered %u bytes for the parent pIoCtxParent=%p\n",
     1771                         pIoCtx->Type.Child.cbTransferParent, pIoCtxParent));
    15851772
    15861773            /* Update the parent state. */
     
    15891776            ASMAtomicSubU32(&pIoCtxParent->cbTransferLeft, pIoCtx->Type.Child.cbTransferParent);
    15901777
    1591             if (   !pIoCtxParent->cbTransferLeft
    1592                 && !pIoCtxParent->cMetaTransfersPending
     1778            rc = vdIoCtxProcess(pIoCtxParent);
     1779
     1780            if (   rc == VINF_VD_ASYNC_IO_FINISHED
    15931781                && ASMAtomicCmpXchgBool(&pIoCtxParent->fComplete, true, false))
    15941782            {
     1783                LogFlowFunc(("Parent I/O context completed pIoCtxParent=%#p\n", pIoCtx));
    15951784                pIoCtxParent->Type.Root.pfnComplete(pIoCtxParent->Type.Root.pvUser1, pIoCtxParent->Type.Root.pvUser2);
    15961785                vdIoCtxFree(pDisk, pIoCtxParent);
     1786
     1787                /*
     1788                 * A completed parent means that we finsihed growing the image.
     1789                 * We have to process any pending writes now.
     1790                 */
     1791                Assert(pDisk->fGrowing);
     1792
     1793                RTCritSectEnter(&pDisk->CritSect);
     1794
     1795                pDisk->fGrowing = false;
     1796
     1797                if (!RTListIsEmpty(&pDisk->ListWriteGrowing))
     1798                {
     1799                    RTLISTNODE ListTmp;
     1800                    PVDIOCTX pIoCtxWait;
     1801
     1802                    RTListMove(&ListTmp, &pDisk->ListWriteGrowing);
     1803
     1804                    RTCritSectLeave(&pDisk->CritSect);
     1805
     1806                    /* Process the list. */
     1807                    RTListForEach(&ListTmp, pIoCtxWait, VDIOCTX, NodeWriteGrowing)
     1808                    {
     1809                        Assert(!pIoCtxWait->pIoCtxParent);
     1810
     1811                        LogFlowFunc(("Processing waiting I/O context pIoCtxWait=%#p\n", pIoCtxWait));
     1812
     1813                        rc = vdIoCtxProcess(pIoCtxWait);
     1814                        if (   rc == VINF_VD_ASYNC_IO_FINISHED
     1815                            && ASMAtomicCmpXchgBool(&pIoCtxWait->fComplete, true, false))
     1816                        {
     1817                            LogFlowFunc(("Waiting I/O context completed pIoCtxWait=%#p\n", pIoCtxWait));
     1818                            pIoCtxWait->Type.Root.pfnComplete(pIoCtxWait->Type.Root.pvUser1,
     1819                                                              pIoCtxWait->Type.Root.pvUser2);
     1820                            vdIoCtxFree(pDisk, pIoCtxWait);
     1821                        }
     1822                    }
     1823                }
     1824                else
     1825                    RTCritSectLeave(&pDisk->CritSect);
    15971826            }
    15981827        }
     
    16131842{
    16141843    int rc = VINF_SUCCESS;
    1615     PVBOXHDD pDisk          = (PVBOXHDD)pvUser;
     1844    PVDIMAGE pImage         = (PVDIMAGE)pvUser;
     1845    PVBOXHDD pDisk          = pImage->pDisk;
    16161846    PVDIOSTORAGE pIoStorage = (PVDIOSTORAGE)RTMemAllocZ(sizeof(VDIOSTORAGE));
    16171847
     
    16341864static int vdIOClose(void *pvUser, PVDIOSTORAGE pIoStorage)
    16351865{
    1636     PVBOXHDD pDisk = (PVBOXHDD)pvUser;
     1866    PVDIMAGE pImage = (PVDIMAGE)pvUser;
     1867    PVBOXHDD pDisk  = pImage->pDisk;
    16371868
    16381869    int rc = pDisk->pInterfaceAsyncIOCallbacks->pfnClose(pDisk->pInterfaceAsyncIO->pvUser,
     
    16471878                       uint64_t *pcbSize)
    16481879{
    1649     PVBOXHDD pDisk = (PVBOXHDD)pvUser;
     1880    PVDIMAGE pImage = (PVDIMAGE)pvUser;
     1881    PVBOXHDD pDisk  = pImage->pDisk;
    16501882
    16511883    return pDisk->pInterfaceAsyncIOCallbacks->pfnGetSize(pDisk->pInterfaceAsyncIO->pvUser,
     
    16571889                       uint64_t cbSize)
    16581890{
    1659     PVBOXHDD pDisk = (PVBOXHDD)pvUser;
     1891    PVDIMAGE pImage = (PVDIMAGE)pvUser;
     1892    PVBOXHDD pDisk  = pImage->pDisk;
    16601893
    16611894    return pDisk->pInterfaceAsyncIOCallbacks->pfnSetSize(pDisk->pInterfaceAsyncIO->pvUser,
     
    16671900                         size_t cbWrite, const void *pvBuf, size_t *pcbWritten)
    16681901{
    1669     PVBOXHDD pDisk = (PVBOXHDD)pvUser;
     1902    PVDIMAGE pImage = (PVDIMAGE)pvUser;
     1903    PVBOXHDD pDisk  = pImage->pDisk;
    16701904
    16711905    return pDisk->pInterfaceAsyncIOCallbacks->pfnWriteSync(pDisk->pInterfaceAsyncIO->pvUser,
     
    16781912                        size_t cbRead, void *pvBuf, size_t *pcbRead)
    16791913{
    1680     PVBOXHDD pDisk = (PVBOXHDD)pvUser;
     1914    PVDIMAGE pImage = (PVDIMAGE)pvUser;
     1915    PVBOXHDD pDisk  = pImage->pDisk;
    16811916
    16821917    return pDisk->pInterfaceAsyncIOCallbacks->pfnReadSync(pDisk->pInterfaceAsyncIO->pvUser,
     
    16881923static int vdIOFlushSync(void *pvUser, PVDIOSTORAGE pIoStorage)
    16891924{
    1690     PVBOXHDD pDisk = (PVBOXHDD)pvUser;
     1925    PVDIMAGE pImage = (PVDIMAGE)pvUser;
     1926    PVBOXHDD pDisk  = pImage->pDisk;
    16911927
    16921928    return pDisk->pInterfaceAsyncIOCallbacks->pfnFlushSync(pDisk->pInterfaceAsyncIO->pvUser,
     
    16991935{
    17001936    int rc = VINF_SUCCESS;
    1701     PVBOXHDD pDisk = (PVBOXHDD)pvUser;
     1937    PVDIMAGE pImage = (PVDIMAGE)pvUser;
     1938    PVBOXHDD pDisk  = pImage->pDisk;
     1939
     1940    LogFlowFunc(("pvUser=%#p pIoStorage=%#p uOffset=%llu pIoCtx=%#p cbRead=%u\n",
     1941                 pvUser, pIoStorage, uOffset, pIoCtx, cbRead));
    17021942
    17031943    /* Build the S/G array and spawn a new I/O task */
     
    17091949
    17101950        cbTaskRead = RTSgBufSegArrayCreate(&pIoCtx->SgBuf, aSeg, &cSegments, cbRead);
     1951
     1952        AssertMsg(cbTaskRead <= cbRead, ("Invalid number of bytes to read\n"));
     1953
     1954        LogFlow(("Reading %u bytes into %u segments\n", cbTaskRead, cSegments));
     1955
     1956#ifdef DEBUG
     1957        for (unsigned i = 0; i < cSegments; i++)
     1958                AssertMsg(aSeg[i].pvSeg && !(aSeg[i].cbSeg % 512),
     1959                          ("Segment %u is invalid\n", i));
     1960#endif
    17111961
    17121962        PVDIOTASK pIoTask = vdIoTaskUserAlloc(pDisk, pIoCtx, cbTaskRead);
     
    17471997{
    17481998    int rc = VINF_SUCCESS;
    1749     PVBOXHDD pDisk = (PVBOXHDD)pvUser;
     1999    PVDIMAGE pImage = (PVDIMAGE)pvUser;
     2000    PVBOXHDD pDisk  = pImage->pDisk;
     2001
     2002    LogFlowFunc(("pvUser=%#p pIoStorage=%#p uOffset=%llu pIoCtx=%#p cbWrite=%u\n",
     2003                 pvUser, pIoStorage, uOffset, pIoCtx, cbWrite));
    17502004
    17512005    /* Build the S/G array and spawn a new I/O task */
     
    17572011
    17582012        cbTaskWrite = RTSgBufSegArrayCreate(&pIoCtx->SgBuf, aSeg, &cSegments, cbWrite);
     2013
     2014        AssertMsg(cbTaskWrite <= cbWrite, ("Invalid number of bytes to write\n"));
     2015
     2016        LogFlow(("Writing %u bytes from %u segments\n", cbTaskWrite, cSegments));
     2017
     2018#ifdef DEBUG
     2019        for (unsigned i = 0; i < cSegments; i++)
     2020                AssertMsg(aSeg[i].pvSeg && !(aSeg[i].cbSeg % 512),
     2021                          ("Segment %u is invalid\n", i));
     2022#endif
    17592023
    17602024        PVDIOTASK pIoTask = vdIoTaskUserAlloc(pDisk, pIoCtx, cbTaskWrite);
     
    17962060                             void *pvMetaUser)
    17972061{
    1798     PVBOXHDD pDisk = (PVBOXHDD)pvUser;
     2062    PVDIMAGE pImage = (PVDIMAGE)pvUser;
     2063    PVBOXHDD pDisk  = pImage->pDisk;
    17992064    int rc = VINF_SUCCESS;
    18002065    RTSGSEG Seg;
     
    18022067    void *pvTask = NULL;
    18032068
    1804     pIoTask = vdIoTaskMetaAlloc(pDisk, pIoCtx, VDIOCTXTXDIR_READ,
     2069    pIoTask = vdIoTaskMetaAlloc(pDisk, pIoCtx, VDIOCTXTXDIR_READ, pImage,
    18052070                                pfnMetaComplete, pvMetaUser);
    18062071    if (!pIoTask)
     
    18362101                              void *pvMetaUser)
    18372102{
    1838     PVBOXHDD pDisk = (PVBOXHDD)pvUser;
     2103    PVDIMAGE pImage = (PVDIMAGE)pvUser;
     2104    PVBOXHDD pDisk  = pImage->pDisk;
    18392105    int rc = VINF_SUCCESS;
    18402106    RTSGSEG Seg;
     
    18422108    void *pvTask = NULL;
    18432109
    1844     pIoTask = vdIoTaskMetaAlloc(pDisk, pIoCtx, VDIOCTXTXDIR_WRITE,
     2110    pIoTask = vdIoTaskMetaAlloc(pDisk, pIoCtx, VDIOCTXTXDIR_WRITE, pImage,
    18452111                                pfnMetaComplete, pvMetaUser);
    18462112    if (!pIoTask)
     
    18732139                          PVDIOCTX pIoCtx)
    18742140{
    1875     PVBOXHDD pDisk = (PVBOXHDD)pvUser;
     2141    PVDIMAGE pImage = (PVDIMAGE)pvUser;
     2142    PVBOXHDD pDisk  = pImage->pDisk;
    18762143    int rc = VINF_SUCCESS;
    18772144    PVDIOTASK pIoTask;
    18782145    void *pvTask = NULL;
    18792146
    1880     pIoTask = vdIoTaskMetaAlloc(pDisk, pIoCtx, VDIOCTXTXDIR_FLUSH,
     2147    pIoTask = vdIoTaskMetaAlloc(pDisk, pIoCtx, VDIOCTXTXDIR_FLUSH, pImage,
    18812148                                NULL, NULL);
    18822149    if (!pIoTask)
     
    21722439            pDisk->pInterfaceThreadSync = NULL;
    21732440            pDisk->pInterfaceThreadSyncCallbacks = NULL;
     2441            pDisk->fGrowing = false;
     2442            RTListInit(&pDisk->ListWriteGrowing);
    21742443
    21752444            /* Create the I/O ctx cache */
     
    21922461            }
    21932462
     2463            /* Create critical section. */
     2464            rc = RTCritSectInit(&pDisk->CritSect);
     2465            if (RT_FAILURE(rc))
     2466            {
     2467                RTMemCacheDestroy(pDisk->hMemCacheIoCtx);
     2468                RTMemCacheDestroy(pDisk->hMemCacheIoTask);
     2469                RTMemFree(pDisk);
     2470                break;
     2471            }
    21942472
    21952473            pDisk->pInterfaceError = VDInterfaceGet(pVDIfsDisk, VDINTERFACETYPE_ERROR);
     
    22472525            pDisk->VDIIOCallbacks.pfnIoCtxCopyTo    = vdIOIoCtxCopyTo;
    22482526            pDisk->VDIIOCallbacks.pfnIoCtxSet       = vdIOIoCtxSet;
    2249 
    2250             /* Set up the I/O interface. */
    2251             rc = VDInterfaceAdd(&pDisk->VDIIO, "VD_IO", VDINTERFACETYPE_IO,
    2252                                 &pDisk->VDIIOCallbacks, pDisk, &pDisk->pVDIfsDisk);
    2253             AssertRC(rc);
    22542527
    22552528            *ppDisk = pDisk;
     
    24362709        }
    24372710
     2711        pImage->pDisk       = pDisk;
    24382712        pImage->pVDIfsImage = pVDIfsImage;
    24392713
     
    24472721            break;
    24482722        }
     2723
     2724        /* Set up the I/O interface. */
     2725        rc = VDInterfaceAdd(&pImage->VDIIO, "VD_IO", VDINTERFACETYPE_IO,
     2726                            &pDisk->VDIIOCallbacks, pImage, &pImage->pVDIfsImage);
     2727        AssertRC(rc);
    24492728
    24502729        pImage->uOpenFlags = uOpenFlags & VD_OPEN_FLAGS_HONOR_SAME;
     
    27182997            break;
    27192998        }
     2999        pImage->pDisk       = pDisk;
    27203000        pImage->pVDIfsImage = pVDIfsImage;
     3001
     3002        /* Set up the I/O interface. */
     3003        rc = VDInterfaceAdd(&pImage->VDIIO, "VD_IO", VDINTERFACETYPE_IO,
     3004                            &pDisk->VDIIOCallbacks, pImage, &pImage->pVDIfsImage);
     3005        AssertRC(rc);
    27213006
    27223007        rc = vdFindBackend(pszBackend, &pImage->Backend);
     
    29613246            break;
    29623247        }
     3248
     3249        pImage->pDisk       = pDisk;
     3250        pImage->pVDIfsImage = pVDIfsImage;
     3251
     3252        /* Set up the I/O interface. */
     3253        rc = VDInterfaceAdd(&pImage->VDIIO, "VD_IO", VDINTERFACETYPE_IO,
     3254                            &pDisk->VDIIOCallbacks, pImage, &pImage->pVDIfsImage);
     3255        AssertRC(rc);
    29633256
    29643257        /* Create UUID if the caller didn't specify one. */
     
    56085901                                  cbRead, paSeg, cSeg,
    56095902                                  pfnComplete, pvUser1, pvUser2,
    5610                                   NULL);
     5903                                  NULL, vdReadHelperAsync);
    56115904        if (!pIoCtx)
    56125905        {
     
    56155908        }
    56165909
    5617         PVDIMAGE pImage = pDisk->pLast;
    5618         AssertPtrBreakStmt(pImage, rc = VERR_VD_NOT_OPENED);
    5619 
    5620         rc = vdReadHelperAsync(pDisk, pImage, NULL, pIoCtx, uOffset, cbRead);
     5910        pIoCtx->pImage = pDisk->pLast;
     5911        AssertPtrBreakStmt(pIoCtx->pImage, rc = VERR_VD_NOT_OPENED);
     5912
     5913        rc = vdIoCtxProcess(pIoCtx);
     5914        if (rc == VINF_VD_ASYNC_IO_FINISHED)
     5915        {
     5916            if (ASMAtomicCmpXchgBool(&pIoCtx->fComplete, true, false))
     5917                vdIoCtxFree(pDisk, pIoCtx);
     5918            else
     5919                rc = VERR_VD_ASYNC_IO_IN_PROGRESS; /* Let the other handler complete the request. */
     5920        }
     5921        else if (rc != VERR_VD_ASYNC_IO_IN_PROGRESS) /* Another error */
     5922            vdIoCtxFree(pDisk, pIoCtx);
     5923
    56215924    } while (0);
    56225925
    5623     if (RT_UNLIKELY(fLockRead))
     5926    if (RT_UNLIKELY(fLockRead) && (rc != VINF_VD_ASYNC_IO_FINISHED))
    56245927    {
    56255928        rc2 = vdThreadFinishRead(pDisk);
    56265929        AssertRC(rc2);
    5627     }
    5628 
    5629     if (RT_SUCCESS(rc))
    5630     {
    5631         if (   !pIoCtx->cbTransferLeft
    5632             && !pIoCtx->cMetaTransfersPending
    5633             && ASMAtomicCmpXchgBool(&pIoCtx->fComplete, true, false))
    5634         {
    5635             vdIoCtxFree(pDisk, pIoCtx);
    5636             rc = VINF_VD_ASYNC_IO_FINISHED;
    5637         }
    5638         else
    5639         {
    5640             LogFlow(("cbTransferLeft=%u cMetaTransfersPending=%u fComplete=%RTbool\n",
    5641                      pIoCtx->cbTransferLeft, pIoCtx->cMetaTransfersPending,
    5642                      pIoCtx->fComplete));
    5643             rc = VERR_VD_ASYNC_IO_IN_PROGRESS;
    5644         }
    56455930    }
    56465931
     
    56915976                                  cbWrite, paSeg, cSeg,
    56925977                                  pfnComplete, pvUser1, pvUser2,
    5693                                   NULL);
     5978                                  NULL, vdWriteHelperAsync);
    56945979        if (!pIoCtx)
    56955980        {
     
    57005985        PVDIMAGE pImage = pDisk->pLast;
    57015986        AssertPtrBreakStmt(pImage, rc = VERR_VD_NOT_OPENED);
    5702 
    5703         rc = vdWriteHelperAsync(pDisk, pImage, NULL, pIoCtx, uOffset, cbWrite);
    5704 
     5987        pIoCtx->pImage = pImage;
     5988
     5989        rc = vdIoCtxProcess(pIoCtx);
     5990        if (rc == VINF_VD_ASYNC_IO_FINISHED)
     5991        {
     5992            if (ASMAtomicCmpXchgBool(&pIoCtx->fComplete, true, false))
     5993                vdIoCtxFree(pDisk, pIoCtx);
     5994            else
     5995                rc = VERR_VD_ASYNC_IO_IN_PROGRESS; /* Let the other handler complete the request. */
     5996        }
     5997        else if (rc != VERR_VD_ASYNC_IO_IN_PROGRESS) /* Another error */
     5998            vdIoCtxFree(pDisk, pIoCtx);
     5999    } while (0);
     6000
     6001    if (RT_UNLIKELY(fLockWrite) && RT_FAILURE(rc))
     6002    {
     6003        rc2 = vdThreadFinishWrite(pDisk);
     6004        AssertRC(rc2);
     6005    }
     6006
     6007    LogFlowFunc(("returns %Rrc\n", rc));
     6008    return rc;
     6009}
     6010
     6011
     6012VBOXDDU_DECL(int) VDAsyncFlush(PVBOXHDD pDisk, PFNVDASYNCTRANSFERCOMPLETE pfnComplete,
     6013                               void *pvUser1, void *pvUser2)
     6014{
     6015    int rc;
     6016    int rc2;
     6017    bool fLockWrite = false;
     6018    PVDIOCTX pIoCtx = NULL;
     6019
     6020    LogFlowFunc(("pDisk=%#p\n", pDisk));
     6021
     6022    do
     6023    {
     6024        /* sanity check */
     6025        AssertPtrBreakStmt(pDisk, rc = VERR_INVALID_PARAMETER);
     6026        AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
     6027
     6028        rc2 = vdThreadStartWrite(pDisk);
     6029        AssertRC(rc2);
     6030        fLockWrite = true;
     6031
     6032        pIoCtx = vdIoCtxRootAlloc(pDisk, VDIOCTXTXDIR_FLUSH, 0,
     6033                                  0, NULL, 0,
     6034                                  pfnComplete, pvUser1, pvUser2,
     6035                                  NULL, vdFlushHelperAsync);
     6036        if (!pIoCtx)
     6037        {
     6038            rc = VERR_NO_MEMORY;
     6039            break;
     6040        }
     6041
     6042        PVDIMAGE pImage = pDisk->pLast;
     6043        AssertPtrBreakStmt(pImage, rc = VERR_VD_NOT_OPENED);
     6044        pIoCtx->pImage = pImage;
     6045
     6046        rc = vdIoCtxProcess(pIoCtx);
    57056047    } while (0);
    57066048
     
    57336075}
    57346076
    5735 
    5736 VBOXDDU_DECL(int) VDAsyncFlush(PVBOXHDD pDisk, PFNVDASYNCTRANSFERCOMPLETE pfnComplete,
    5737                                void *pvUser1, void *pvUser2)
    5738 {
    5739     int rc;
    5740     int rc2;
    5741     bool fLockWrite = false;
    5742     PVDIOCTX pIoCtx = NULL;
    5743 
    5744     LogFlowFunc(("pDisk=%#p\n", pDisk));
    5745 
    5746     do
    5747     {
    5748         /* sanity check */
    5749         AssertPtrBreakStmt(pDisk, rc = VERR_INVALID_PARAMETER);
    5750         AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
    5751 
    5752         rc2 = vdThreadStartWrite(pDisk);
    5753         AssertRC(rc2);
    5754         fLockWrite = true;
    5755 
    5756         pIoCtx = vdIoCtxRootAlloc(pDisk, VDIOCTXTXDIR_FLUSH, 0,
    5757                                   0, NULL, 0,
    5758                                   pfnComplete, pvUser1, pvUser2,
    5759                                   NULL);
    5760         if (!pIoCtx)
    5761         {
    5762             rc = VERR_NO_MEMORY;
    5763             break;
    5764         }
    5765 
    5766         PVDIMAGE pImage = pDisk->pLast;
    5767         AssertPtrBreakStmt(pImage, rc = VERR_VD_NOT_OPENED);
    5768 
    5769         vdResetModifiedFlag(pDisk);
    5770         rc = pImage->Backend->pfnAsyncFlush(pImage->pvBackendData, pIoCtx);
    5771     } while (0);
    5772 
    5773     if (RT_UNLIKELY(fLockWrite) && RT_FAILURE(rc))
    5774     {
    5775         rc2 = vdThreadFinishWrite(pDisk);
    5776         AssertRC(rc2);
    5777     }
    5778 
    5779     if (RT_SUCCESS(rc))
    5780     {
    5781         if (   !pIoCtx->cbTransferLeft
    5782             && !pIoCtx->cMetaTransfersPending
    5783             && ASMAtomicCmpXchgBool(&pIoCtx->fComplete, true, false))
    5784         {
    5785             vdIoCtxFree(pDisk, pIoCtx);
    5786             rc = VINF_VD_ASYNC_IO_FINISHED;
    5787         }
    5788         else
    5789         {
    5790             LogFlow(("cbTransferLeft=%u cMetaTransfersPending=%u fComplete=%RTbool\n",
    5791                      pIoCtx->cbTransferLeft, pIoCtx->cMetaTransfersPending,
    5792                      pIoCtx->fComplete));
    5793             rc = VERR_VD_ASYNC_IO_IN_PROGRESS;
    5794         }
    5795     }
    5796 
    5797     LogFlowFunc(("returns %Rrc\n", rc));
    5798     return rc;
    5799 }
    5800 
    58016077#if 0
    58026078/** @copydoc VBOXHDDBACKEND::pfnComposeLocation */
  • trunk/src/VBox/Devices/Storage/VDICore.h

    r27808 r28620  
    586586    /** Pointer to the per-disk VD interface list. */
    587587    PVDINTERFACE            pVDIfsDisk;
     588    /** Pointer to the per-image VD interface list. */
     589    PVDINTERFACE            pVDIfsImage;
    588590    /** Error interface. */
    589591    PVDINTERFACE            pInterfaceError;
  • trunk/src/VBox/Devices/Storage/VDIHDDCore.cpp

    r28383 r28620  
    541541#ifdef VBOX_WITH_NEW_IO_CODE
    542542    /* Try to get I/O interface. */
    543     pImage->pInterfaceIO = VDInterfaceGet(pImage->pVDIfsDisk, VDINTERFACETYPE_IO);
     543    pImage->pInterfaceIO = VDInterfaceGet(pImage->pVDIfsImage, VDINTERFACETYPE_IO);
    544544    AssertPtr(pImage->pInterfaceIO);
    545545    pImage->pInterfaceIOCallbacks = VDGetInterfaceIO(pImage->pInterfaceIO);
     
    727727#ifdef VBOX_WITH_NEW_IO_CODE
    728728    /* Try to get I/O interface. */
    729     pImage->pInterfaceIO = VDInterfaceGet(pImage->pVDIfsDisk, VDINTERFACETYPE_IO);
     729    pImage->pInterfaceIO = VDInterfaceGet(pImage->pVDIfsImage, VDINTERFACETYPE_IO);
    730730    AssertPtr(pImage->pInterfaceIO);
    731731    pImage->pInterfaceIOCallbacks = VDGetInterfaceIO(pImage->pInterfaceIO);
     
    10711071    pImage->paBlocks = NULL;
    10721072    pImage->pVDIfsDisk = pVDIfsDisk;
     1073    pImage->pVDIfsImage = pVDIfsImage;
    10731074
    10741075    rc = vdiOpenImage(pImage, uOpenFlags);
     
    11491150    pImage->paBlocks = NULL;
    11501151    pImage->pVDIfsDisk = pVDIfsDisk;
     1152    pImage->pVDIfsImage = pVDIfsImage;
    11511153
    11521154    rc = vdiCreateImage(pImage, cbSize, uImageFlags, pszComment,
  • trunk/src/VBox/Devices/Storage/VHDHDDCore.cpp

    r27808 r28620  
    144144    /** Pointer to the per-disk VD interface list. */
    145145    PVDINTERFACE      pVDIfsDisk;
     146    /** Pointer to the per-image VD interface list. */
     147    PVDINTERFACE      pVDIfsImage;
    146148    /** Error interface. */
    147149    PVDINTERFACE      pInterfaceError;
     
    581583#ifdef VBOX_WITH_NEW_IO_CODE
    582584    /* Try to get async I/O interface. */
    583     pImage->pInterfaceIO = VDInterfaceGet(pImage->pVDIfsDisk, VDINTERFACETYPE_IO);
     585    pImage->pInterfaceIO = VDInterfaceGet(pImage->pVDIfsImage, VDINTERFACETYPE_IO);
    584586    AssertPtr(pImage->pInterfaceIO);
    585587    pImage->pInterfaceIOCallbacks = VDGetInterfaceIO(pImage->pInterfaceIO);
     
    684686#endif
    685687    pImage->pVDIfsDisk = pVDIfsDisk;
     688    pImage->pVDIfsImage = pVDIfsImage;
    686689
    687690    rc = vhdOpenImage(pImage, uOpenFlags);
     
    19721975#endif
    19731976    pImage->pVDIfsDisk = pVDIfsDisk;
     1977    pImage->pVDIfsImage = pVDIfsImage;
    19741978
    19751979#ifdef VBOX_WITH_NEW_IO_CODE
  • trunk/src/VBox/Devices/Storage/VmdkHDDCore.cpp

    r27977 r28620  
    423423    /** Pointer to the per-disk VD interface list. */
    424424    PVDINTERFACE    pVDIfsDisk;
     425    /** Pointer to the per-image VD interface list. */
     426    PVDINTERFACE    pVDIfsImage;
    425427
    426428    /** Error interface. */
     
    786788    if (pVmdkFile->fAsyncIO)
    787789        return pImage->pInterfaceIOCallbacks->pfnFlushSync(pImage->pInterfaceIO->pvUser,
    788                                                                 pVmdkFile->pStorage);
     790                                                           pVmdkFile->pStorage);
    789791    else
    790792        return RTFileFlush(pVmdkFile->File);
    791793#else
    792794    return pImage->pInterfaceIOCallbacks->pfnFlushSync(pImage->pInterfaceIO->pvUser,
    793                                                             pVmdkFile->pStorage);
     795                                                       pVmdkFile->pStorage);
    794796#endif
     797}
     798
     799
     800DECLINLINE(int) vmdkFileFlushAsync(PVMDKFILE pVmdkFile, PVDIOCTX pIoCtx)
     801{
     802    PVMDKIMAGE pImage = pVmdkFile->pImage;
     803
     804    return pImage->pInterfaceIOCallbacks->pfnFlushAsync(pImage->pInterfaceIO->pvUser,
     805                                                        pVmdkFile->pStorage, pIoCtx);
    795806}
    796807
     
    25362547
    25372548/**
     2549 * Internal: write/update the descriptor part of the image - async version.
     2550 */
     2551static int vmdkWriteDescriptorAsync(PVMDKIMAGE pImage, PVDIOCTX pIoCtx)
     2552{
     2553    int rc = VINF_SUCCESS;
     2554    uint64_t cbLimit;
     2555    uint64_t uOffset;
     2556    PVMDKFILE pDescFile;
     2557
     2558    if (pImage->pDescData)
     2559    {
     2560        /* Separate descriptor file. */
     2561        uOffset = 0;
     2562        cbLimit = 0;
     2563        pDescFile = pImage->pFile;
     2564    }
     2565    else
     2566    {
     2567        /* Embedded descriptor file. */
     2568        uOffset = VMDK_SECTOR2BYTE(pImage->pExtents[0].uDescriptorSector);
     2569        cbLimit = VMDK_SECTOR2BYTE(pImage->pExtents[0].cDescriptorSectors);
     2570        pDescFile = pImage->pExtents[0].pFile;
     2571    }
     2572    /* Bail out if there is no file to write to. */
     2573    if (pDescFile == NULL)
     2574        return VERR_INVALID_PARAMETER;
     2575
     2576    /*
     2577     * Allocate temporary descriptor buffer.
     2578     * In case there is no limit allocate a default
     2579     * and increase if required.
     2580     */
     2581    size_t cbDescriptor = cbLimit ? cbLimit : 4 * _1K;
     2582    char *pszDescriptor = (char *)RTMemAllocZ(cbDescriptor);
     2583    unsigned offDescriptor = 0;
     2584
     2585    if (!pszDescriptor)
     2586        return VERR_NO_MEMORY;
     2587
     2588    for (unsigned i = 0; i < pImage->Descriptor.cLines; i++)
     2589    {
     2590        const char *psz = pImage->Descriptor.aLines[i];
     2591        size_t cb = strlen(psz);
     2592
     2593        /*
     2594         * Increase the descriptor if there is no limit and
     2595         * there is not enough room left for this line.
     2596         */
     2597        if (offDescriptor + cb + 1 > cbDescriptor)
     2598        {
     2599            if (cbLimit)
     2600            {
     2601                rc = vmdkError(pImage, VERR_BUFFER_OVERFLOW, RT_SRC_POS, N_("VMDK: descriptor too long in '%s'"), pImage->pszFilename);
     2602                break;
     2603            }
     2604            else
     2605            {
     2606                char *pszDescriptorNew = NULL;
     2607                LogFlow(("Increasing descriptor cache\n"));
     2608
     2609                pszDescriptorNew = (char *)RTMemRealloc(pszDescriptor, cbDescriptor + cb + 4 * _1K);
     2610                if (!pszDescriptorNew)
     2611                {
     2612                    rc = VERR_NO_MEMORY;
     2613                    break;
     2614                }
     2615                pszDescriptorNew = pszDescriptor;
     2616                cbDescriptor += cb + 4 * _1K;
     2617            }
     2618        }
     2619
     2620        if (cb > 0)
     2621        {
     2622            memcpy(pszDescriptor + offDescriptor, psz, cb);
     2623            offDescriptor += cb;
     2624        }
     2625
     2626        memcpy(pszDescriptor + offDescriptor, "\n", 1);
     2627        offDescriptor++;
     2628    }
     2629
     2630    if (RT_SUCCESS(rc))
     2631    {
     2632        rc = vmdkFileWriteAt(pDescFile, uOffset, pszDescriptor, cbLimit ? cbLimit : offDescriptor, NULL);
     2633        if (RT_FAILURE(rc))
     2634            rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error writing descriptor in '%s'"), pImage->pszFilename);
     2635    }
     2636
     2637    if (RT_SUCCESS(rc) && !cbLimit)
     2638    {
     2639        rc = vmdkFileSetSize(pDescFile, offDescriptor);
     2640        if (RT_FAILURE(rc))
     2641            rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error truncating descriptor in '%s'"), pImage->pszFilename);
     2642    }
     2643
     2644    if (RT_SUCCESS(rc))
     2645        pImage->Descriptor.fDirty = false;
     2646
     2647    RTMemFree(pszDescriptor);
     2648    return rc;
     2649}
     2650
     2651/**
    25382652 * Internal: validate the consistency check values in a binary header.
    25392653 */
     
    29743088
    29753089    /* Try to get async I/O interface. */
    2976     pImage->pInterfaceIO = VDInterfaceGet(pImage->pVDIfsDisk, VDINTERFACETYPE_IO);
     3090    pImage->pInterfaceIO = VDInterfaceGet(pImage->pVDIfsImage, VDINTERFACETYPE_IO);
    29773091    if (pImage->pInterfaceIO)
    29783092        pImage->pInterfaceIOCallbacks = VDGetInterfaceIO(pImage->pInterfaceIO);
     
    38433957
    38443958    /* Try to get async I/O interface. */
    3845     pImage->pInterfaceIO = VDInterfaceGet(pImage->pVDIfsDisk, VDINTERFACETYPE_IO);
     3959    pImage->pInterfaceIO = VDInterfaceGet(pImage->pVDIfsImage, VDINTERFACETYPE_IO);
    38463960    if (pImage->pInterfaceIO)
    38473961        pImage->pInterfaceIOCallbacks = VDGetInterfaceIO(pImage->pInterfaceIO);
     
    41174231                    && !(pExtent->pszBasename[0] == RTPATH_SLASH))
    41184232                    rc = vmdkFileFlush(pExtent->pFile);
     4233                break;
     4234            case VMDKETYPE_ZERO:
     4235                /* No need to do anything for this extent. */
     4236                break;
     4237            default:
     4238                AssertMsgFailed(("unknown extent type %d\n", pExtent->enmType));
     4239                break;
     4240        }
     4241    }
     4242
     4243out:
     4244    return rc;
     4245}
     4246
     4247/**
     4248 * Internal. Flush image data (and metadata) to disk - async version.
     4249 */
     4250static int vmdkFlushImageAsync(PVMDKIMAGE pImage, PVDIOCTX pIoCtx)
     4251{
     4252    PVMDKEXTENT pExtent;
     4253    int rc = VINF_SUCCESS;
     4254
     4255    /* Update descriptor if changed. */
     4256    if (pImage->Descriptor.fDirty)
     4257    {
     4258        rc = vmdkWriteDescriptor(pImage);
     4259        if (RT_FAILURE(rc))
     4260            goto out;
     4261    }
     4262
     4263    for (unsigned i = 0; i < pImage->cExtents; i++)
     4264    {
     4265        pExtent = &pImage->pExtents[i];
     4266        if (pExtent->pFile != NULL && pExtent->fMetaDirty)
     4267        {
     4268            switch (pExtent->enmType)
     4269            {
     4270                case VMDKETYPE_HOSTED_SPARSE:
     4271                    AssertMsgFailed(("Async I/O not supported for sparse images\n"));
     4272                    break;
     4273#ifdef VBOX_WITH_VMDK_ESX
     4274                case VMDKETYPE_ESX_SPARSE:
     4275                    /** @todo update the header. */
     4276                    break;
     4277#endif /* VBOX_WITH_VMDK_ESX */
     4278                case VMDKETYPE_VMFS:
     4279                case VMDKETYPE_FLAT:
     4280                    /* Nothing to do. */
     4281                    break;
     4282                case VMDKETYPE_ZERO:
     4283                default:
     4284                    AssertMsgFailed(("extent with type %d marked as dirty\n",
     4285                                     pExtent->enmType));
     4286                    break;
     4287            }
     4288        }
     4289        switch (pExtent->enmType)
     4290        {
     4291            case VMDKETYPE_HOSTED_SPARSE:
     4292#ifdef VBOX_WITH_VMDK_ESX
     4293            case VMDKETYPE_ESX_SPARSE:
     4294#endif /* VBOX_WITH_VMDK_ESX */
     4295            case VMDKETYPE_VMFS:
     4296            case VMDKETYPE_FLAT:
     4297                /** @todo implement proper path absolute check. */
     4298                if (   pExtent->pFile != NULL
     4299                    && !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
     4300                    && !(pExtent->pszBasename[0] == RTPATH_SLASH))
     4301                    rc = vmdkFileFlushAsync(pExtent->pFile, pIoCtx);
    41194302                break;
    41204303            case VMDKETYPE_ZERO:
     
    45224705    pImage->pDescData = NULL;
    45234706    pImage->pVDIfsDisk = pVDIfsDisk;
     4707    pImage->pVDIfsImage = pVDIfsDisk;
    45244708    /** @todo speed up this test open (VD_OPEN_FLAGS_INFO) by skipping as
    45254709     * much as possible in vmdkOpenImage. */
     
    45724756    pImage->pDescData = NULL;
    45734757    pImage->pVDIfsDisk = pVDIfsDisk;
     4758    pImage->pVDIfsImage = pVDIfsImage;
    45744759
    45754760    rc = vmdkOpenImage(pImage, uOpenFlags);
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