VirtualBox

Changeset 30555 in vbox


Ignore:
Timestamp:
Jul 1, 2010 1:43:04 PM (15 years ago)
Author:
vboxsync
Message:

VD/Async: Full support for VHD images. VMDK is still in progress

Location:
trunk
Files:
7 edited

Legend:

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

    r30309 r30555  
    13651365
    13661366/**
    1367  * Completion callback for metadata reads or writes.
    1368  *
    1369  * @return  nothing.
     1367 * Completion callback for meta/userdata reads or writes.
     1368 *
     1369 * @return  VBox status code.
     1370 *          VINF_SUCCESS if everything was successful and the transfer can continue.
     1371 *          VERR_VD_ASYNC_IO_IN_PROGRESS if there is another data transfer pending.
    13701372 * @param   pvBackendData   The opaque backend data.
    13711373 * @param   pIoCtx          I/O context associated with this request.
    1372  * @param   pvMetaUser      Opaque user data passed during a metadata read/write request.
    1373  */
    1374 typedef DECLCALLBACK(void) FNVDMETACOMPLETED(void *pvBackendData, PVDIOCTX pIoCtx, void *pvMetaUser);
    1375 /** Pointer to FNVDCOMPLETED() */
    1376 typedef FNVDMETACOMPLETED *PFNVDMETACOMPLETED;
     1374 * @param   pvUser          Opaque user data passed during a read/write request.
     1375 * @param   rcReq           Status code for the completed request.
     1376 */
     1377typedef DECLCALLBACK(int) FNVDXFERCOMPLETED(void *pvBackendData, PVDIOCTX pIoCtx, void *pvUser, int rcReq);
     1378/** Pointer to FNVDXFERCOMPLETED() */
     1379typedef FNVDXFERCOMPLETED *PFNVDXFERCOMPLETED;
     1380
     1381/** Metadata transfer handle. */
     1382typedef struct VDMETAXFER *PVDMETAXFER;
     1383/** Pointer to a metadata transfer handle. */
     1384typedef PVDMETAXFER *PPVDMETAXFER;
     1385
    13771386
    13781387/**
     
    14751484     * Flush data to the storage backend.
    14761485     *
    1477      * @return  VBox statis code.
     1486     * @return  VBox status code.
    14781487     * @param   pvUser          The opaque data passed on container creation.
    14791488     * @param   pStorage        The storage handle to flush.
     
    14871496     *
    14881497     * @return  VBox status code.
    1489      * @param   pvUser         The opqaue user data passed on container creation.
     1498     * @param   pvUser         The opaque user data passed on container creation.
    14901499     * @param   pStorage       The storage handle.
    14911500     * @param   uOffset        The offset to start reading from.
     
    15061515     * @param   pIoCtx         I/O context passed in VDAsyncRead/Write
    15071516     * @param   cbWrite        How many bytes to write.
     1517     * @param   pfnCompleted   Completion callback.
     1518     * @param   pvCompleteUser Opaque user data passed in the completion callback.
    15081519     */
    15091520    DECLR3CALLBACKMEMBER(int, pfnWriteUserAsync, (void *pvUser, PVDIOSTORAGE pStorage,
    15101521                                                  uint64_t uOffset, PVDIOCTX pIoCtx,
    1511                                                   size_t cbWrite));
     1522                                                  size_t cbWrite,
     1523                                                  PFNVDXFERCOMPLETED pfnComplete,
     1524                                                  void *pvCompleteUser));
    15121525
    15131526    /**
     
    15161529     *
    15171530     * @returns VBox status code.
    1518      * @param   pvUser              The opaque user data passed on container creation.
    1519      * @param   pStorage            The storage handle.
    1520      * @param   uOffset             Offsete to start reading from.
    1521      * @param   pvBuf               Where to store the data.
    1522      * @param   cbRead              How many bytes to read.
    1523      * @param   pIoCtx              The I/O context which triggered the read.
    1524      * @param   pfnMetaCompleted    Callback to call when the read completes.
    1525      * @param   pvMetaUser          Opaque user data which is passed in the callback.
     1531     * @param   pvUser        The opaque user data passed on container creation.
     1532     * @param   pStorage      The storage handle.
     1533     * @param   uOffset       Offset to start reading from.
     1534     * @param   pvBuf         Where to store the data.
     1535     * @param   cbRead        How many bytes to read.
     1536     * @param   pIoCtx        The I/O context which triggered the read.
     1537     * @param   ppMetaXfer    Where to store the metadata transfer handle on success.
    15261538     */
    15271539    DECLR3CALLBACKMEMBER(int, pfnReadMetaAsync, (void *pvUser, PVDIOSTORAGE pStorage,
    15281540                                                 uint64_t uOffset, void *pvBuf,
    15291541                                                 size_t cbRead, PVDIOCTX pIoCtx,
    1530                                                  PFNVDMETACOMPLETED pfnMetaCompleted,
    1531                                                  void *pvMetaUser));
     1542                                                 PPVDMETAXFER ppMetaXfer));
    15321543
    15331544    /**
     
    15351546     *
    15361547     * @returns VBox status code.
    1537      * @param   pvUser              The opaque user data passed on container creation.
    1538      * @param   pStorage            The storage handle.
    1539      * @param   uOffset             Offsete to start writing to.
    1540      * @param   pvBuf               Written data.
    1541      * @param   cbWrite             How many bytes to write.
    1542      * @param   pIoCtx              The I/O context which triggered the write.
    1543      * @param   pfnMetaCompleted    Callback to call when the write completes.
    1544      * @param   pvMetaUser          Opaque user data which is passed in the callback.
     1548     * @param   pvUser         The opaque user data passed on container creation.
     1549     * @param   pStorage       The storage handle.
     1550     * @param   uOffset        Offset to start writing to.
     1551     * @param   pvBuf          Written data.
     1552     * @param   cbWrite        How many bytes to write.
     1553     * @param   pIoCtx         The I/O context which triggered the write.
     1554     * @param   pfnCompleted   Completion callback.
     1555     * @param   pvCompleteUser Opaque user data passed in the completion callback.
    15451556     */
    15461557    DECLR3CALLBACKMEMBER(int, pfnWriteMetaAsync, (void *pvUser, PVDIOSTORAGE pStorage,
    15471558                                                  uint64_t uOffset, void *pvBuf,
    15481559                                                  size_t cbWrite, PVDIOCTX pIoCtx,
    1549                                                   PFNVDMETACOMPLETED pfnMetaCompleted,
    1550                                                   void *pvMetaUser));
     1560                                                  PFNVDXFERCOMPLETED pfnComplete,
     1561                                                  void *pvCompleteUser));
     1562
     1563    /**
     1564     * Releases a metadata transfer handle.
     1565     * The free space can be used for another transfer.
     1566     *
     1567     * @returns nothing.
     1568     * @param   pvUser         The opaque user data passed on container creation.
     1569     * @param   pMetaXfer      The metadata transfer handle to release.
     1570     */
     1571    DECLR3CALLBACKMEMBER(void, pfnMetaXferRelease, (void *pvUser, PVDMETAXFER pMetaXfer));
    15511572
    15521573    /**
    15531574     * Initiates a async flush request.
    15541575     *
    1555      * @return  VBox statis code.
    1556      * @param   pvUser          The opaque data passed on container creation.
    1557      * @param   pStorage        The storage handle to flush.
    1558      * @param   pIoCtx          I/O context which triggered the flush.
     1576     * @return  VBox status code.
     1577     * @param   pvUser         The opaque data passed on container creation.
     1578     * @param   pStorage       The storage handle to flush.
     1579     * @param   pIoCtx         I/O context which triggered the flush.
     1580     * @param   pfnCompleted   Completion callback.
     1581     * @param   pvCompleteUser Opaque user data passed in the completion callback.
    15591582     */
    15601583    DECLR3CALLBACKMEMBER(int, pfnFlushAsync, (void *pvUser, PVDIOSTORAGE pStorage,
    1561                                               PVDIOCTX pIoCtx));
     1584                                              PVDIOCTX pIoCtx,
     1585                                              PFNVDXFERCOMPLETED pfnComplete,
     1586                                              void *pvCompleteUser));
    15621587
    15631588    /**
     
    15651590     *
    15661591     * @return Number of bytes copied.
    1567      * @param  pvUser          The opaque user data passed on conatiner creation.
     1592     * @param  pvUser          The opaque user data passed on container creation.
    15681593     * @param  pIoCtx          I/O context to copy the data to.
    15691594     * @param  pvBuf           Buffer to copy.
     
    15771602     *
    15781603     * @return Number of bytes copied.
    1579      * @param  pvUser          The opaque user data passed on conatiner creation.
     1604     * @param  pvUser          The opaque user data passed on container creation.
    15801605     * @param  pIoCtx          I/O context to copy the data from.
    15811606     * @param  pvBuf           Destination buffer.
     
    15891614     *
    15901615     * @return Number of bytes set.
    1591      * @param  pvUser          The opaque user data passed on conatiner creation.
     1616     * @param  pvUser          The opaque user data passed on container creation.
    15921617     * @param  pIoCtx          I/O context to copy the data from.
    15931618     * @param  ch              The byte to set.
     
    15971622                                               int ch, size_t cbSet));
    15981623
     1624    /**
     1625     * Marks the given number of bytes as completed and continues the I/O context.
     1626     *
     1627     * @returns nothing.
     1628     * @param   pvUser         The opaque user data passed on container creation.
     1629     * @param   pIoCtx         The I/O context.
     1630     * @param   cbCompleted    Number of bytes completed.
     1631     */
     1632    DECLR3CALLBACKMEMBER(void, pfnIoCtxCompleted, (void *pvUser, PVDIOCTX pIoCtx,
     1633                                                   size_t cbCompleted));
    15991634} VDINTERFACEIO, *PVDINTERFACEIO;
    16001635
  • trunk/include/VBox/err.h

    r30473 r30555  
    12361236/** The backend needs more metadata before it can continue. */
    12371237#define VERR_VD_NOT_ENOUGH_METADATA                 (-3272)
     1238/** Halt the current I/O context until further notification from the backend. */
     1239#define VERR_VD_IOCTX_HALT                          (-3273)
    12381240/** @} */
    12391241
  • trunk/src/VBox/Devices/Storage/RawHDDCore.cpp

    r28800 r30555  
    12281228    rc = pImage->pInterfaceIOCallbacks->pfnWriteUserAsync(pImage->pInterfaceIO->pvUser,
    12291229                                                         pImage->pStorage,
    1230                                                          uOffset, pIoCtx, cbWrite);
     1230                                                         uOffset, pIoCtx, cbWrite,
     1231                                                         NULL, NULL);
    12311232
    12321233    if (RT_SUCCESS(rc))
  • trunk/src/VBox/Devices/Storage/VBoxHDD.cpp

    r30481 r30555  
    3939#include <iprt/critsect.h>
    4040#include <iprt/list.h>
     41#include <iprt/avl.h>
    4142
    4243#include <VBox/VBoxHDD-Plugin.h>
     
    171172};
    172173
     174# define VD_THREAD_IS_CRITSECT_OWNER(Disk) \
     175    do \
     176    { \
     177        AssertMsg(RTCritSectIsOwner(&Disk->CritSect), \
     178                  ("Thread does not own critical section\n"));\
     179    } while(0)
    173180
    174181/**
     
    208215typedef struct VDIOCTX
    209216{
    210     /** Node in the list of deferred requests. */
    211     RTLISTNODE                   NodeWriteGrowing;
    212217    /** Disk this is request is for. */
    213218    PVBOXHDD                     pDisk;
     
    289294} VDIOCTX;
    290295
     296typedef struct VDIOCTXDEFERRED
     297{
     298    /** Node in the list of deferred requests.
     299     * A request can be deferred if the image is growing
     300     * and the request accesses the same range or if
     301     * the backend needs to read or write metadata from the disk
     302     * before it can continue. */
     303    RTLISTNODE NodeDeferred;
     304    /** I/O context this entry points to. */
     305    PVDIOCTX   pIoCtx;
     306} VDIOCTXDEFERRED, *PVDIOCTXDEFERRED;
     307
    291308/**
    292309 * I/O task.
     
    294311typedef struct VDIOTASK
    295312{
    296     /** Pointer to the I/O context the task belongs. */
    297     PVDIOCTX                     pIoCtx;
     313    /** Storage this task belongs to. */
     314    PVDIOSTORAGE                 pIoStorage;
     315    /** Optional completion callback. */
     316    PFNVDXFERCOMPLETED           pfnComplete;
     317    /** Opaque user data. */
     318    void                        *pvUser;
    298319    /** Flag whether this is a meta data transfer. */
    299320    bool                         fMeta;
     
    306327            /** Number of bytes this task transfered. */
    307328            uint32_t             cbTransfer;
     329            /** Pointer to the I/O context the task belongs. */
     330            PVDIOCTX             pIoCtx;
    308331        } User;
    309332        /** Meta data transfer. */
    310333        struct
    311334        {
    312             /** Transfer direction (Read/Write) */
    313             VDIOCTXTXDIR         enmTxDir;
    314             /** Completion callback from the backend */
    315             PFNVDMETACOMPLETED   pfnMetaComplete;
    316             /** User data */
    317             void                *pvMetaUser;
    318             /** Image the task was created for. */
    319             PVDIMAGE             pImage;
     335            /** Meta transfer this task is for. */
     336            PVDMETAXFER          pMetaXfer;
    320337        } Meta;
    321338    } Type;
     
    329346    /** Image this storage handle belongs to. */
    330347    PVDIMAGE                     pImage;
     348    /** AVL tree for pending async metadata transfers. */
     349    PAVLRFOFFTREE                pTreeMetaXfers;
    331350    union
    332351    {
     
    337356    } u;
    338357} VDIOSTORAGE;
     358
     359/**
     360 *  Metadata transfer.
     361 *
     362 *  @note This entry can't be freed if either the list is not empty or
     363 *  the reference counter is not 0.
     364 *  The assumption is that the backends don't need to read huge amounts of
     365 *  metadata to complete a transfer so the additional memory overhead should
     366 *  be relatively small.
     367 */
     368typedef struct VDMETAXFER
     369{
     370    /** AVL core for fast search (the file offset is the key) */
     371    AVLRFOFFNODECORE Core;
     372    /** I/O storage for this transfer. */
     373    PVDIOSTORAGE     pIoStorage;
     374    /** Flags. */
     375    uint32_t         fFlags;
     376    /** List of I/O contexts waiting for this metadata transfer to complete. */
     377    RTLISTNODE       ListIoCtxWaiting;
     378    /** Number of references to this entry. */
     379    unsigned         cRefs;
     380    /** Size of the data stored with this entry. */
     381    size_t           cbMeta;
     382    /** Data stored - variable size. */
     383    uint8_t          abData[1];
     384} VDMETAXFER;
     385
     386/**
     387 * The transfer direction for the metadata.
     388 */
     389#define VDMETAXFER_TXDIR_MASK  0x3
     390#define VDMETAXFER_TXDIR_NONE  0x0
     391#define VDMETAXFER_TXDIR_WRITE 0x1
     392#define VDMETAXFER_TXDIR_READ  0x2
     393#define VDMETAXFER_TXDIR_FLUSH 0x3
     394#define VDMETAXFER_TXDIR_GET(flags)      ((flags) & VDMETAXFER_TXDIR_MASK)
     395#define VDMETAXFER_TXDIR_SET(flags, dir) ((flags) = (flags & ~VDMETAXFER_TXDIR_MASK) | (dir))
    339396
    340397extern VBOXHDDBACKEND g_RawBackend;
     
    667724                                   paSeg, cSeg, pvAllocation, pfnIoCtxTransfer);
    668725
     726    AssertPtr(pIoCtxParent);
     727    Assert(!pIoCtxParent->pIoCtxParent);
     728
    669729    if (RT_LIKELY(pIoCtx))
    670730    {
     
    679739}
    680740
    681 DECLINLINE(PVDIOTASK) vdIoTaskUserAlloc(PVBOXHDD pDisk, PVDIOCTX pIoCtx, uint32_t cbTransfer)
     741DECLINLINE(PVDIOTASK) vdIoTaskUserAlloc(PVDIOSTORAGE pIoStorage, PFNVDXFERCOMPLETED pfnComplete, void *pvUser, PVDIOCTX pIoCtx, uint32_t cbTransfer)
    682742{
    683743    PVDIOTASK pIoTask = NULL;
    684744
    685     pIoTask = (PVDIOTASK)RTMemCacheAlloc(pDisk->hMemCacheIoTask);
     745    pIoTask = (PVDIOTASK)RTMemCacheAlloc(pIoStorage->pImage->pDisk->hMemCacheIoTask);
    686746    if (pIoTask)
    687747    {
    688         pIoTask->pIoCtx               = pIoCtx;
     748        pIoTask->pIoStorage           = pIoStorage;
     749        pIoTask->pfnComplete          = pfnComplete;
     750        pIoTask->pvUser               = pvUser;
    689751        pIoTask->fMeta                = false;
    690752        pIoTask->Type.User.cbTransfer = cbTransfer;
     753        pIoTask->Type.User.pIoCtx     = pIoCtx;
    691754    }
    692755
     
    694757}
    695758
    696 DECLINLINE(PVDIOTASK) vdIoTaskMetaAlloc(PVBOXHDD pDisk, PVDIOCTX pIoCtx, VDIOCTXTXDIR enmTxDir,
    697                                         PVDIMAGE pImage,
    698                                         PFNVDMETACOMPLETED pfnMetaComplete, void *pvMetaUser)
     759DECLINLINE(PVDIOTASK) vdIoTaskMetaAlloc(PVDIOSTORAGE pIoStorage, PFNVDXFERCOMPLETED pfnComplete, void *pvUser, PVDMETAXFER pMetaXfer)
    699760{
    700761    PVDIOTASK pIoTask = NULL;
    701762
    702     pIoTask = (PVDIOTASK)RTMemCacheAlloc(pDisk->hMemCacheIoTask);
     763    pIoTask = (PVDIOTASK)RTMemCacheAlloc(pIoStorage->pImage->pDisk->hMemCacheIoTask);
    703764    if (pIoTask)
    704765    {
    705         pIoTask->pIoCtx                      = pIoCtx;
    706         pIoTask->fMeta                       = true;
    707         pIoTask->Type.Meta.enmTxDir          = enmTxDir;
    708         pIoTask->Type.Meta.pfnMetaComplete   = pfnMetaComplete;
    709         pIoTask->Type.Meta.pvMetaUser        = pvMetaUser;
    710         pIoTask->Type.Meta.pImage            = pImage;
     766        pIoTask->pIoStorage          = pIoStorage;
     767        pIoTask->pfnComplete         = pfnComplete;
     768        pIoTask->pvUser              = pvUser;
     769        pIoTask->fMeta               = true;
     770        pIoTask->Type.Meta.pMetaXfer = pMetaXfer;
    711771    }
    712772
     
    723783DECLINLINE(void) vdIoTaskFree(PVBOXHDD pDisk, PVDIOTASK pIoTask)
    724784{
    725     pIoTask->pIoCtx = NULL;
    726785    RTMemCacheFree(pDisk->hMemCacheIoTask, pIoTask);
    727786}
     
    734793    pIoCtx->uOffset        = pIoCtx->Type.Child.uOffsetSaved;
    735794    pIoCtx->cbTransferLeft = pIoCtx->Type.Child.cbTransferLeftSaved;
     795}
     796
     797DECLINLINE(PVDMETAXFER) vdMetaXferAlloc(PVDIMAGE pImage, PVDIOSTORAGE pIoStorage, uint64_t uOffset, size_t cb)
     798{
     799    PVDMETAXFER pMetaXfer = (PVDMETAXFER)RTMemAlloc(RT_OFFSETOF(VDMETAXFER, abData[cb]));
     800
     801    if (RT_LIKELY(pMetaXfer))
     802    {
     803        pMetaXfer->Core.Key     = uOffset;
     804        pMetaXfer->Core.KeyLast = uOffset + cb - 1;
     805        pMetaXfer->fFlags       = VDMETAXFER_TXDIR_NONE;
     806        pMetaXfer->cbMeta       = cb;
     807        pMetaXfer->pIoStorage   = pIoStorage;
     808        pMetaXfer->cRefs        = 0;
     809        RTListInit(&pMetaXfer->ListIoCtxWaiting);
     810    }
     811    return pMetaXfer;
    736812}
    737813
     
    784860        return VINF_VD_ASYNC_IO_FINISHED;
    785861
     862    /* Don't change anything if there is a metadata transfer pending. */
     863    if (pIoCtx->cMetaTransfersPending)
     864        return VERR_VD_ASYNC_IO_IN_PROGRESS;
     865
    786866    if (pIoCtx->pfnIoCtxTransfer)
    787867    {
     
    809889        && !pIoCtx->cDataTransfersPending)
    810890        rc = VINF_VD_ASYNC_IO_FINISHED;
    811     else if (RT_SUCCESS(rc))
     891    else if (RT_SUCCESS(rc) || rc == VERR_VD_NOT_ENOUGH_METADATA)
    812892        rc = VERR_VD_ASYNC_IO_IN_PROGRESS;
    813893    else if (RT_FAILURE(rc) && (rc != VERR_VD_ASYNC_IO_IN_PROGRESS))
     
    881961            rc = VINF_SUCCESS;
    882962        }
     963        else if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
     964            rc = VINF_SUCCESS;
    883965
    884966        if (RT_FAILURE(rc))
     
    895977        pIoCtx->cbTransfer = cbToRead;
    896978        pIoCtx->pImage     = pCurrImage;
    897         rc = VERR_VD_ASYNC_IO_IN_PROGRESS;
    898979    }
    899980
     
    12831364
    12841365    AssertPtr(pIoCtxParent);
     1366    Assert(!pIoCtxParent->pIoCtxParent);
    12851367    Assert(!pIoCtx->cbTransferLeft && !pIoCtx->cMetaTransfersPending);
    12861368
     
    13471429    Assert(cbPreRead == 0);
    13481430    Assert(cbPostRead == 0);
     1431    if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
     1432        rc = VINF_SUCCESS;
    13491433
    13501434    return rc;
     
    13921476
    13931477    AssertPtr(pIoCtx->pIoCtxParent);
     1478    Assert(!pIoCtx->pIoCtxParent->pIoCtxParent);
    13941479
    13951480    if (cbPostRead)
     
    14641549            if (ASMAtomicReadBool(&pDisk->fGrowing))
    14651550            {
     1551                PVDIOCTXDEFERRED pDeferred = (PVDIOCTXDEFERRED)RTMemAllocZ(sizeof(VDIOCTXDEFERRED));
     1552                AssertPtr(pDeferred);
     1553
    14661554                LogFlowFunc(("Deferring write pIoCtx=%#p\n", pIoCtx));
    1467                 RTListAppend(&pDisk->ListWriteGrowing, &pIoCtx->NodeWriteGrowing);
     1555
     1556                RTListInit(&pDeferred->NodeDeferred);
     1557                pDeferred->pIoCtx = pIoCtx;
     1558                RTListAppend(&pDisk->ListWriteGrowing, &pDeferred->NodeDeferred);
    14681559                pIoCtx->fBlocked = true;
    1469                 Assert(pIoCtx->NodeWriteGrowing.pNext == &pDisk->ListWriteGrowing);
    1470                 Assert(pDisk->ListWriteGrowing.pPrev == &pIoCtx->NodeWriteGrowing);
    14711560                rc = VERR_VD_ASYNC_IO_IN_PROGRESS;
    14721561                break;
     
    15331622        }
    15341623
     1624        if (rc == VERR_VD_NOT_ENOUGH_METADATA)
     1625            break;
     1626
    15351627        cbWrite -= cbThisWrite;
    15361628        uOffset += cbThisWrite;
    1537     } while (cbWrite != 0 && RT_SUCCESS(rc));
    1538 
    1539     if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
     1629    } while (cbWrite != 0 && (RT_SUCCESS(rc) || rc == VERR_VD_ASYNC_IO_IN_PROGRESS));
     1630
     1631    if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS || rc == VERR_VD_NOT_ENOUGH_METADATA)
    15401632    {
    15411633        /*
     
    15641656    vdResetModifiedFlag(pDisk);
    15651657    rc = pImage->Backend->pfnAsyncFlush(pImage->pvBackendData, pIoCtx);
     1658    if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
     1659        rc = VINF_SUCCESS;
    15661660
    15671661    return rc;
     
    18181912}
    18191913
    1820 static int vdIOReqCompleted(void *pvUser, int rcReq)
    1821 {
     1914/**
     1915 * Internal - Continues an I/O context after
     1916 * it was halted because of an active transfer.
     1917 */
     1918static int vdIoCtxContinue(PVDIOCTX pIoCtx, int rcReq)
     1919{
     1920    PVBOXHDD pDisk = pIoCtx->pDisk;
    18221921    int rc = VINF_SUCCESS;
    1823     PVDIOTASK pIoTask = (PVDIOTASK)pvUser;
    1824     PVDIOCTX  pIoCtx  = pIoTask->pIoCtx;
    1825     PVBOXHDD  pDisk   = pIoCtx->pDisk;
    1826 
    1827     LogFlowFunc(("Task completed pIoTask=%#p pIoCtx=%#p pDisk=%#p\n",
    1828                  pIoTask, pIoCtx, pDisk));
    1829 
    1830     if (!pIoTask->fMeta)
    1831     {
    1832         ASMAtomicSubU32(&pIoCtx->cbTransferLeft, pIoTask->Type.User.cbTransfer);
    1833         ASMAtomicDecU32(&pIoCtx->cDataTransfersPending);
    1834     }
    1835     else
    1836     {
    1837         if (pIoTask->Type.Meta.pfnMetaComplete)
    1838             pIoTask->Type.Meta.pfnMetaComplete(pIoTask->Type.Meta.pImage->pvBackendData,
    1839                                                pIoCtx,
    1840                                                pIoTask->Type.Meta.pvMetaUser);
    1841         ASMAtomicDecU32(&pIoCtx->cMetaTransfersPending);
    1842     }
    1843 
    1844     vdIoTaskFree(pDisk, pIoTask);
    18451922
    18461923    if (RT_FAILURE(rcReq))
     
    18831960                    && ASMAtomicCmpXchgBool(&pIoCtxParent->fComplete, true, false))
    18841961                {
    1885                     LogFlowFunc(("Parent I/O context completed pIoCtxParent=%#p\n", pIoCtx));
     1962                    LogFlowFunc(("Parent I/O context completed pIoCtxParent=%#p rcReq=%Rrc\n", pIoCtxParent, pIoCtxParent->rcReq));
    18861963                    pIoCtxParent->Type.Root.pfnComplete(pIoCtxParent->Type.Root.pvUser1,
    18871964                                                        pIoCtxParent->Type.Root.pvUser2,
     
    19111988                    do
    19121989                    {
    1913                         PVDIOCTX pIoCtxWait = RTListNodeGetFirst(&ListTmp, VDIOCTX, NodeWriteGrowing);
     1990                        PVDIOCTXDEFERRED pDeferred = RTListNodeGetFirst(&ListTmp, VDIOCTXDEFERRED, NodeDeferred);
     1991                        PVDIOCTX pIoCtxWait = pDeferred->pIoCtx;
     1992
    19141993                        AssertPtr(pIoCtxWait);
    19151994
    1916                         RTListNodeRemove(&pIoCtxWait->NodeWriteGrowing);
     1995                        RTListNodeRemove(&pDeferred->NodeDeferred);
     1996                        RTMemFree(pDeferred);
    19171997
    19181998                        pIoCtxWait->fBlocked = false;
     
    19452025                    vdThreadFinishRead(pDisk);
    19462026
     2027                LogFlowFunc(("I/O context completed pIoCtx=%#p rcReq=%Rrc\n", pIoCtx, pIoCtx->rcReq));
    19472028                pIoCtx->Type.Root.pfnComplete(pIoCtx->Type.Root.pvUser1,
    19482029                                              pIoCtx->Type.Root.pvUser2,
     
    19582039
    19592040/**
     2041 * Internal - Called when user transfer completed.
     2042 */
     2043static int vdUserXferCompleted(PVDIOSTORAGE pIoStorage, PVDIOCTX pIoCtx,
     2044                               PFNVDXFERCOMPLETED pfnComplete, void *pvUser,
     2045                               size_t cbTransfer, int rcReq)
     2046{
     2047    int rc = VINF_SUCCESS;
     2048    bool fIoCtxContinue = true;
     2049    PVBOXHDD pDisk = pIoCtx->pDisk;
     2050
     2051    LogFlowFunc(("pIoStorage=%#p pIoCtx=%#p pfnComplete=%#p pvUser=%#p cbTransfer=%zu rcReq=%Rrc\n",
     2052                 pIoStorage, pIoCtx, pfnComplete, pvUser, cbTransfer, rcReq));
     2053
     2054    ASMAtomicSubU32(&pIoCtx->cbTransferLeft, cbTransfer);
     2055    ASMAtomicDecU32(&pIoCtx->cDataTransfersPending);
     2056
     2057    if (pfnComplete)
     2058        rc = pfnComplete(pIoStorage->pImage->pvBackendData, pIoCtx, pvUser, rcReq);
     2059
     2060    if (RT_SUCCESS(rc))
     2061        rc = vdIoCtxContinue(pIoCtx, rcReq);
     2062    else if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
     2063        rc = VINF_SUCCESS;
     2064
     2065    return rc;
     2066}
     2067
     2068/**
     2069 * Internal - Called when a meta transfer completed.
     2070 */
     2071static int vdMetaXferCompleted(PVDIOSTORAGE pIoStorage, PFNVDXFERCOMPLETED pfnComplete, void *pvUser,
     2072                               PVDMETAXFER pMetaXfer, int rcReq)
     2073{
     2074    PVBOXHDD pDisk = pIoStorage->pImage->pDisk;
     2075    RTLISTNODE ListIoCtxWaiting;
     2076    bool fFlush = VDMETAXFER_TXDIR_GET(pMetaXfer->fFlags) == VDMETAXFER_TXDIR_FLUSH;
     2077
     2078    LogFlowFunc(("pIoStorage=%#p pfnComplete=%#p pvUser=%#p pMetaXfer=%#p rcReq=%Rrc\n",
     2079                 pIoStorage, pfnComplete, pvUser, pMetaXfer, rcReq));
     2080
     2081    VDMETAXFER_TXDIR_SET(pMetaXfer->fFlags, VDMETAXFER_TXDIR_NONE);
     2082
     2083    if (!fFlush)
     2084    {
     2085        RTCritSectEnter(&pDisk->CritSect);
     2086
     2087        RTListMove(&ListIoCtxWaiting, &pMetaXfer->ListIoCtxWaiting);
     2088
     2089        if (RT_FAILURE(rcReq))
     2090        {
     2091            /* Remove from the AVL tree. */
     2092            bool fRemoved = RTAvlrFileOffsetRemove(pIoStorage->pTreeMetaXfers, pMetaXfer->Core.Key);
     2093            Assert(fRemoved);
     2094            RTMemFree(pMetaXfer);
     2095        }
     2096        else
     2097        {
     2098            /* Increase the reference counter to make sure it doesn't go away before the last context is processed. */
     2099            pMetaXfer->cRefs++;
     2100        }
     2101
     2102        RTCritSectLeave(&pDisk->CritSect);
     2103    }
     2104    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         */
     2110        RTListMove(&ListIoCtxWaiting, &pMetaXfer->ListIoCtxWaiting);
     2111    }
     2112
     2113    /* Go through the waiting list and continue the I/O contexts. */
     2114    while (!RTListIsEmpty(&ListIoCtxWaiting))
     2115    {
     2116        int rc = VINF_SUCCESS;
     2117        bool fContinue = true;
     2118        PVDIOCTXDEFERRED pDeferred = RTListNodeGetFirst(&ListIoCtxWaiting, VDIOCTXDEFERRED, NodeDeferred);
     2119        PVDIOCTX pIoCtx = pDeferred->pIoCtx;
     2120        RTListNodeRemove(&pDeferred->NodeDeferred);
     2121
     2122        RTMemFree(pDeferred);
     2123        ASMAtomicDecU32(&pIoCtx->cMetaTransfersPending);
     2124
     2125        if (pfnComplete)
     2126            rc = pfnComplete(pIoStorage->pImage->pvBackendData, pIoCtx, pvUser, rcReq);
     2127
     2128        LogFlow(("Completion callback for I/O context %#p returned %Rrc\n", pIoCtx, rc));
     2129
     2130        if (RT_SUCCESS(rc))
     2131        {
     2132            rc = vdIoCtxContinue(pIoCtx, rcReq);
     2133            AssertRC(rc);
     2134        }
     2135        else
     2136            Assert(rc == VERR_VD_ASYNC_IO_IN_PROGRESS);
     2137    }
     2138
     2139    /* Remove if not used anymore. */
     2140    if (RT_SUCCESS(rcReq) && !fFlush)
     2141    {
     2142        RTCritSectEnter(&pDisk->CritSect);
     2143        pMetaXfer->cRefs--;
     2144        if (!pMetaXfer->cRefs)
     2145        {
     2146            /* Remove from the AVL tree. */
     2147            bool fRemoved = RTAvlrFileOffsetRemove(pIoStorage->pTreeMetaXfers, pMetaXfer->Core.Key);
     2148            Assert(fRemoved);
     2149            RTMemFree(pMetaXfer);
     2150        }
     2151        RTCritSectLeave(&pDisk->CritSect);
     2152    }
     2153    else if (fFlush)
     2154        RTMemFree(pMetaXfer);
     2155
     2156    return VINF_SUCCESS;
     2157}
     2158
     2159static int vdIOReqCompleted(void *pvUser, int rcReq)
     2160{
     2161    int rc = VINF_SUCCESS;
     2162    PVDIOTASK pIoTask = (PVDIOTASK)pvUser;
     2163    PVDIOSTORAGE pIoStorage = pIoTask->pIoStorage;
     2164
     2165    LogFlowFunc(("Task completed pIoTask=%#p\n", pIoTask));
     2166
     2167    if (!pIoTask->fMeta)
     2168        rc = vdUserXferCompleted(pIoStorage, pIoTask->Type.User.pIoCtx,
     2169                                 pIoTask->pfnComplete, pIoTask->pvUser,
     2170                                 pIoTask->Type.User.cbTransfer, rcReq);
     2171    else
     2172        rc = vdMetaXferCompleted(pIoStorage, pIoTask->pfnComplete, pIoTask->pvUser,
     2173                                 pIoTask->Type.Meta.pMetaXfer, rcReq);
     2174
     2175    vdIoTaskFree(pIoStorage->pImage->pDisk, pIoTask);
     2176
     2177    return rc;
     2178}
     2179
     2180/**
    19602181 * VD I/O interface callback for opening a file.
    19612182 */
     
    19712192        return VERR_NO_MEMORY;
    19722193
    1973     rc = pDisk->pInterfaceAsyncIOCallbacks->pfnOpen(pDisk->pInterfaceAsyncIO->pvUser,
    1974                                                     pszLocation, uOpenFlags,
    1975                                                     vdIOReqCompleted,
    1976                                                     pDisk->pVDIfsDisk,
    1977                                                     &pIoStorage->u.pStorage);
    1978     if (RT_SUCCESS(rc))
    1979         *ppIoStorage = pIoStorage;
     2194    pIoStorage->pImage = pImage;
     2195
     2196    /* Create the AVl tree. */
     2197    pIoStorage->pTreeMetaXfers = (PAVLRFOFFTREE)RTMemAllocZ(sizeof(AVLRFOFFTREE));
     2198    if (pIoStorage->pTreeMetaXfers)
     2199    {
     2200        rc = pDisk->pInterfaceAsyncIOCallbacks->pfnOpen(pDisk->pInterfaceAsyncIO->pvUser,
     2201                                                        pszLocation, uOpenFlags,
     2202                                                        vdIOReqCompleted,
     2203                                                        pDisk->pVDIfsDisk,
     2204                                                        &pIoStorage->u.pStorage);
     2205        if (RT_SUCCESS(rc))
     2206        {
     2207            *ppIoStorage = pIoStorage;
     2208            return VINF_SUCCESS;
     2209        }
     2210
     2211        RTMemFree(pIoStorage->pTreeMetaXfers);
     2212    }
    19802213    else
    1981         RTMemFree(pIoStorage);
    1982 
     2214        rc = VERR_NO_MEMORY;
     2215
     2216    RTMemFree(pIoStorage);
    19832217    return rc;
     2218}
     2219
     2220static int vdIOTreeMetaXferDestroy(PAVLRFOFFNODECORE pNode, void *pvUser)
     2221{
     2222    AssertMsgFailed(("Tree should be empty at this point!\n"));
     2223    return VINF_SUCCESS;
    19842224}
    19852225
     
    19932233    AssertRC(rc);
    19942234
     2235    RTAvlrFileOffsetDestroy(pIoStorage->pTreeMetaXfers, vdIOTreeMetaXferDestroy, NULL);
     2236    RTMemFree(pIoStorage->pTreeMetaXfers);
    19952237    RTMemFree(pIoStorage);
    19962238    return VINF_SUCCESS;
     
    20632305                 pvUser, pIoStorage, uOffset, pIoCtx, cbRead));
    20642306
     2307    VD_THREAD_IS_CRITSECT_OWNER(pDisk);
     2308
    20652309    /* Build the S/G array and spawn a new I/O task */
    20662310    while (cbRead)
     
    20752319
    20762320        LogFlow(("Reading %u bytes into %u segments\n", cbTaskRead, cSegments));
     2321
     2322#ifdef RT_STRICT
     2323        for (unsigned i = 0; i < cSegments; i++)
     2324                AssertMsg(aSeg[i].pvSeg && !(aSeg[i].cbSeg % 512),
     2325                          ("Segment %u is invalid\n", i));
     2326#endif
     2327
     2328        PVDIOTASK pIoTask = vdIoTaskUserAlloc(pIoStorage, NULL, NULL, pIoCtx, cbTaskRead);
     2329
     2330        if (!pIoTask)
     2331            return VERR_NO_MEMORY;
     2332
     2333        ASMAtomicIncU32(&pIoCtx->cDataTransfersPending);
     2334
     2335        void *pvTask;
     2336        rc = pDisk->pInterfaceAsyncIOCallbacks->pfnReadAsync(pDisk->pInterfaceAsyncIO->pvUser,
     2337                                                             pIoStorage->u.pStorage,
     2338                                                             uOffset, aSeg, cSegments,
     2339                                                             cbTaskRead, pIoTask,
     2340                                                             &pvTask);
     2341        if (RT_SUCCESS(rc))
     2342        {
     2343            AssertMsg(cbTaskRead <= pIoCtx->cbTransferLeft, ("Impossible!\n"));
     2344            ASMAtomicSubU32(&pIoCtx->cbTransferLeft, cbTaskRead);
     2345            ASMAtomicDecU32(&pIoCtx->cDataTransfersPending);
     2346            vdIoTaskFree(pDisk, pIoTask);
     2347        }
     2348        else if (rc != VERR_VD_ASYNC_IO_IN_PROGRESS)
     2349        {
     2350            ASMAtomicDecU32(&pIoCtx->cDataTransfersPending);
     2351            break;
     2352        }
     2353
     2354        uOffset += cbTaskRead;
     2355        cbRead  -= cbTaskRead;
     2356    }
     2357
     2358    LogFlowFunc(("returns rc=%Rrc\n", rc));
     2359    return rc;
     2360}
     2361
     2362static int vdIOWriteUserAsync(void *pvUser, PVDIOSTORAGE pIoStorage,
     2363                              uint64_t uOffset, PVDIOCTX pIoCtx,
     2364                              size_t cbWrite,
     2365                              PFNVDXFERCOMPLETED pfnComplete,
     2366                              void *pvCompleteUser)
     2367{
     2368    int rc = VINF_SUCCESS;
     2369    PVDIMAGE pImage = (PVDIMAGE)pvUser;
     2370    PVBOXHDD pDisk  = pImage->pDisk;
     2371
     2372    LogFlowFunc(("pvUser=%#p pIoStorage=%#p uOffset=%llu pIoCtx=%#p cbWrite=%u\n",
     2373                 pvUser, pIoStorage, uOffset, pIoCtx, cbWrite));
     2374
     2375    VD_THREAD_IS_CRITSECT_OWNER(pDisk);
     2376
     2377    /* Build the S/G array and spawn a new I/O task */
     2378    while (cbWrite)
     2379    {
     2380        RTSGSEG  aSeg[VD_IO_TASK_SEGMENTS_MAX];
     2381        unsigned cSegments   = VD_IO_TASK_SEGMENTS_MAX;
     2382        size_t   cbTaskWrite = 0;
     2383
     2384        cbTaskWrite = RTSgBufSegArrayCreate(&pIoCtx->SgBuf, aSeg, &cSegments, cbWrite);
     2385
     2386        AssertMsg(cbTaskWrite <= cbWrite, ("Invalid number of bytes to write\n"));
     2387
     2388        LogFlow(("Writing %u bytes from %u segments\n", cbTaskWrite, cSegments));
    20772389
    20782390#ifdef DEBUG
     
    20822394#endif
    20832395
    2084         PVDIOTASK pIoTask = vdIoTaskUserAlloc(pDisk, pIoCtx, cbTaskRead);
     2396        PVDIOTASK pIoTask = vdIoTaskUserAlloc(pIoStorage, pfnComplete, pvCompleteUser, pIoCtx, cbTaskWrite);
    20852397
    20862398        if (!pIoTask)
     
    20902402
    20912403        void *pvTask;
    2092         int rc2 = pDisk->pInterfaceAsyncIOCallbacks->pfnReadAsync(pDisk->pInterfaceAsyncIO->pvUser,
    2093                                                                   pIoStorage->u.pStorage,
    2094                                                                   uOffset, aSeg, cSegments,
    2095                                                                   cbTaskRead, pIoTask,
    2096                                                                   &pvTask);
    2097         if (rc2 == VINF_SUCCESS)
    2098         {
    2099             AssertMsg(cbTaskRead <= pIoCtx->cbTransferLeft, ("Impossible!\n"));
    2100             ASMAtomicSubU32(&pIoCtx->cbTransferLeft, cbTaskRead);
    2101             ASMAtomicDecU32(&pIoCtx->cDataTransfersPending);
    2102             vdIoTaskFree(pDisk, pIoTask);
    2103         }
    2104         else if (rc2 == VERR_VD_ASYNC_IO_IN_PROGRESS)
    2105             rc = VINF_SUCCESS;
    2106         else if (RT_FAILURE(rc2))
    2107         {
    2108             rc = rc2;
    2109             break;
    2110         }
    2111 
    2112         uOffset += cbTaskRead;
    2113         cbRead  -= cbTaskRead;
    2114     }
    2115 
    2116     return rc;
    2117 }
    2118 
    2119 static int vdIOWriteUserAsync(void *pvUser, PVDIOSTORAGE pIoStorage,
    2120                               uint64_t uOffset, PVDIOCTX pIoCtx,
    2121                               size_t cbWrite)
    2122 {
    2123     int rc = VINF_SUCCESS;
    2124     PVDIMAGE pImage = (PVDIMAGE)pvUser;
    2125     PVBOXHDD pDisk  = pImage->pDisk;
    2126 
    2127     LogFlowFunc(("pvUser=%#p pIoStorage=%#p uOffset=%llu pIoCtx=%#p cbWrite=%u\n",
    2128                  pvUser, pIoStorage, uOffset, pIoCtx, cbWrite));
    2129 
    2130     /* Build the S/G array and spawn a new I/O task */
    2131     while (cbWrite)
    2132     {
    2133         RTSGSEG  aSeg[VD_IO_TASK_SEGMENTS_MAX];
    2134         unsigned cSegments   = VD_IO_TASK_SEGMENTS_MAX;
    2135         size_t   cbTaskWrite = 0;
    2136 
    2137         cbTaskWrite = RTSgBufSegArrayCreate(&pIoCtx->SgBuf, aSeg, &cSegments, cbWrite);
    2138 
    2139         AssertMsg(cbTaskWrite <= cbWrite, ("Invalid number of bytes to write\n"));
    2140 
    2141         LogFlow(("Writing %u bytes from %u segments\n", cbTaskWrite, cSegments));
    2142 
    2143 #ifdef DEBUG
    2144         for (unsigned i = 0; i < cSegments; i++)
    2145                 AssertMsg(aSeg[i].pvSeg && !(aSeg[i].cbSeg % 512),
    2146                           ("Segment %u is invalid\n", i));
    2147 #endif
    2148 
    2149         PVDIOTASK pIoTask = vdIoTaskUserAlloc(pDisk, pIoCtx, cbTaskWrite);
    2150 
    2151         if (!pIoTask)
    2152             return VERR_NO_MEMORY;
    2153 
    2154         ASMAtomicIncU32(&pIoCtx->cDataTransfersPending);
    2155 
    2156         void *pvTask;
    2157         int rc2 = pDisk->pInterfaceAsyncIOCallbacks->pfnWriteAsync(pDisk->pInterfaceAsyncIO->pvUser,
    2158                                                                    pIoStorage->u.pStorage,
    2159                                                                    uOffset, aSeg, cSegments,
    2160                                                                    cbTaskWrite, pIoTask,
    2161                                                                    &pvTask);
    2162         if (rc2 == VINF_SUCCESS)
     2404        rc = pDisk->pInterfaceAsyncIOCallbacks->pfnWriteAsync(pDisk->pInterfaceAsyncIO->pvUser,
     2405                                                              pIoStorage->u.pStorage,
     2406                                                              uOffset, aSeg, cSegments,
     2407                                                              cbTaskWrite, pIoTask,
     2408                                                              &pvTask);
     2409        if (RT_SUCCESS(rc))
    21632410        {
    21642411            AssertMsg(cbTaskWrite <= pIoCtx->cbTransferLeft, ("Impossible!\n"));
     
    21672414            vdIoTaskFree(pDisk, pIoTask);
    21682415        }
    2169         else if (rc2 == VERR_VD_ASYNC_IO_IN_PROGRESS)
    2170             rc = VINF_SUCCESS;
    2171         else if (RT_FAILURE(rc2))
    2172         {
    2173             rc = rc2;
     2416        else if (rc != VERR_VD_ASYNC_IO_IN_PROGRESS)
     2417        {
     2418            ASMAtomicDecU32(&pIoCtx->cDataTransfersPending);
    21742419            break;
    21752420        }
     
    21852430                             uint64_t uOffset, void *pvBuf,
    21862431                             size_t cbRead, PVDIOCTX pIoCtx,
    2187                              PFNVDMETACOMPLETED pfnMetaComplete,
    2188                              void *pvMetaUser)
     2432                             PPVDMETAXFER ppMetaXfer)
    21892433{
    21902434    PVDIMAGE pImage = (PVDIMAGE)pvUser;
     
    21932437    RTSGSEG Seg;
    21942438    PVDIOTASK pIoTask;
     2439    PVDMETAXFER pMetaXfer = NULL;
    21952440    void *pvTask = NULL;
    21962441
    2197     pIoTask = vdIoTaskMetaAlloc(pDisk, pIoCtx, VDIOCTXTXDIR_READ, pImage,
    2198                                 pfnMetaComplete, pvMetaUser);
    2199     if (!pIoTask)
    2200         return VERR_NO_MEMORY;
    2201 
    2202     Seg.cbSeg = cbRead;
    2203     Seg.pvSeg = pvBuf;
    2204 
    2205     ASMAtomicIncU32(&pIoCtx->cMetaTransfersPending);
    2206 
    2207     int rc2 = pDisk->pInterfaceAsyncIOCallbacks->pfnReadAsync(pDisk->pInterfaceAsyncIO->pvUser,
    2208                                                               pIoStorage->u.pStorage,
    2209                                                               uOffset, &Seg, 1,
    2210                                                               cbRead, pIoTask,
    2211                                                               &pvTask);
    2212     if (rc2 == VINF_SUCCESS)
    2213     {
    2214         ASMAtomicDecU32(&pIoCtx->cMetaTransfersPending);
    2215         vdIoTaskFree(pDisk, pIoTask);
    2216     }
    2217     else if (rc2 == VERR_VD_ASYNC_IO_IN_PROGRESS)
    2218         rc = VERR_VD_NOT_ENOUGH_METADATA;
    2219     else if (RT_FAILURE(rc2))
    2220         rc = rc2;
     2442    LogFlowFunc(("pvUser=%#p pIoStorage=%#p uOffset=%llu pvBuf=%#p cbRead=%u\n",
     2443                 pvUser, pIoStorage, uOffset, pvBuf, cbRead));
     2444
     2445    VD_THREAD_IS_CRITSECT_OWNER(pDisk);
     2446
     2447    pMetaXfer = (PVDMETAXFER)RTAvlrFileOffsetGet(pIoStorage->pTreeMetaXfers, uOffset);
     2448    if (!pMetaXfer)
     2449    {
     2450        /* Allocate a new meta transfer. */
     2451        pMetaXfer = vdMetaXferAlloc(pImage, pIoStorage, uOffset, cbRead);
     2452        if (!pMetaXfer)
     2453            return VERR_NO_MEMORY;
     2454
     2455        pIoTask = vdIoTaskMetaAlloc(pIoStorage, NULL, NULL, pMetaXfer);
     2456        if (!pIoTask)
     2457        {
     2458            RTMemFree(pMetaXfer);
     2459            return VERR_NO_MEMORY;
     2460        }
     2461
     2462        Seg.cbSeg = cbRead;
     2463        Seg.pvSeg = pMetaXfer->abData;
     2464
     2465        VDMETAXFER_TXDIR_SET(pMetaXfer->fFlags, VDMETAXFER_TXDIR_READ);
     2466        rc = pDisk->pInterfaceAsyncIOCallbacks->pfnReadAsync(pDisk->pInterfaceAsyncIO->pvUser,
     2467                                                             pIoStorage->u.pStorage,
     2468                                                             uOffset, &Seg, 1,
     2469                                                             cbRead, pIoTask,
     2470                                                             &pvTask);
     2471        if (RT_SUCCESS(rc))
     2472        {
     2473            VDMETAXFER_TXDIR_SET(pMetaXfer->fFlags, VDMETAXFER_TXDIR_NONE);
     2474            vdIoTaskFree(pDisk, pIoTask);
     2475        }
     2476        else if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
     2477            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);
     2486    }
     2487
     2488    Assert(VALID_PTR(pMetaXfer) || RT_FAILURE(rc));
     2489
     2490    if (RT_SUCCESS(rc) || rc == VERR_VD_NOT_ENOUGH_METADATA)
     2491    {
     2492        /* If it is pending add the request to the list. */
     2493        if (VDMETAXFER_TXDIR_GET(pMetaXfer->fFlags) == VDMETAXFER_TXDIR_READ)
     2494        {
     2495            PVDIOCTXDEFERRED pDeferred = (PVDIOCTXDEFERRED)RTMemAllocZ(sizeof(VDIOCTXDEFERRED));
     2496            AssertPtr(pDeferred);
     2497
     2498            RTListInit(&pDeferred->NodeDeferred);
     2499            pDeferred->pIoCtx = pIoCtx;
     2500
     2501            ASMAtomicIncU32(&pIoCtx->cMetaTransfersPending);
     2502            RTListAppend(&pMetaXfer->ListIoCtxWaiting, &pDeferred->NodeDeferred);
     2503            rc = VERR_VD_NOT_ENOUGH_METADATA;
     2504        }
     2505        else
     2506        {
     2507            /* Transfer the data. */
     2508            pMetaXfer->cRefs++;
     2509            Assert(pMetaXfer->cbMeta >= cbRead);
     2510            memcpy(pvBuf, pMetaXfer->abData, cbRead);
     2511            *ppMetaXfer = pMetaXfer;
     2512        }
     2513    }
    22212514
    22222515    return rc;
     
    22262519                              uint64_t uOffset, void *pvBuf,
    22272520                              size_t cbWrite, PVDIOCTX pIoCtx,
    2228                               PFNVDMETACOMPLETED pfnMetaComplete,
    2229                               void *pvMetaUser)
     2521                              PFNVDXFERCOMPLETED pfnComplete,
     2522                              void *pvCompleteUser)
    22302523{
    22312524    PVDIMAGE pImage = (PVDIMAGE)pvUser;
     
    22342527    RTSGSEG Seg;
    22352528    PVDIOTASK pIoTask;
     2529    PVDMETAXFER pMetaXfer = NULL;
    22362530    void *pvTask = NULL;
    22372531
    2238     pIoTask = vdIoTaskMetaAlloc(pDisk, pIoCtx, VDIOCTXTXDIR_WRITE, pImage,
    2239                                 pfnMetaComplete, pvMetaUser);
    2240     if (!pIoTask)
    2241         return VERR_NO_MEMORY;
    2242 
    2243     Seg.cbSeg = cbWrite;
    2244     Seg.pvSeg = pvBuf;
    2245 
    2246     ASMAtomicIncU32(&pIoCtx->cMetaTransfersPending);
    2247 
    2248     int rc2 = pDisk->pInterfaceAsyncIOCallbacks->pfnWriteAsync(pDisk->pInterfaceAsyncIO->pvUser,
    2249                                                                pIoStorage->u.pStorage,
    2250                                                                uOffset, &Seg, 1,
    2251                                                                cbWrite, pIoTask,
    2252                                                                &pvTask);
    2253     if (rc2 == VINF_SUCCESS)
    2254     {
    2255         ASMAtomicDecU32(&pIoCtx->cMetaTransfersPending);
    2256         vdIoTaskFree(pDisk, pIoTask);
    2257     }
    2258     else if (rc2 == VERR_VD_ASYNC_IO_IN_PROGRESS)
    2259         rc = VINF_SUCCESS;
    2260     else if (RT_FAILURE(rc2))
    2261         rc = rc2;
     2532    LogFlowFunc(("pvUser=%#p pIoStorage=%#p uOffset=%llu pvBuf=%#p cbWrite=%u\n",
     2533                 pvUser, pIoStorage, uOffset, pvBuf, cbWrite));
     2534
     2535    VD_THREAD_IS_CRITSECT_OWNER(pDisk);
     2536
     2537    pMetaXfer = (PVDMETAXFER)RTAvlrFileOffsetGet(pIoStorage->pTreeMetaXfers, uOffset);
     2538    if (!pMetaXfer)
     2539    {
     2540        /* Allocate a new meta transfer. */
     2541        pMetaXfer = vdMetaXferAlloc(pImage, pIoStorage, uOffset, cbWrite);
     2542        if (!pMetaXfer)
     2543            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);
     2569            RTMemFree(pMetaXfer);
     2570            pMetaXfer = NULL;
     2571        }
     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
     2580            bool fInserted = RTAvlrFileOffsetInsert(pIoStorage->pTreeMetaXfers, &pMetaXfer->Core);
     2581            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);
    22622593
    22632594    return rc;
    22642595}
    22652596
     2597static void vdIOMetaXferRelease(void *pvUser, PVDMETAXFER pMetaXfer)
     2598{
     2599    PVDIMAGE pImage = (PVDIMAGE)pvUser;
     2600    PVDIOSTORAGE pIoStorage = pMetaXfer->pIoStorage;
     2601
     2602    VD_THREAD_IS_CRITSECT_OWNER(pImage->pDisk);
     2603
     2604    Assert(   VDMETAXFER_TXDIR_GET(pMetaXfer->fFlags) == VDMETAXFER_TXDIR_NONE
     2605           || VDMETAXFER_TXDIR_GET(pMetaXfer->fFlags) == VDMETAXFER_TXDIR_WRITE);
     2606    Assert(pMetaXfer->cRefs > 0);
     2607
     2608    pMetaXfer->cRefs--;
     2609    if (   !pMetaXfer->cRefs
     2610        && RTListIsEmpty(&pMetaXfer->ListIoCtxWaiting)
     2611        && VDMETAXFER_TXDIR_GET(pMetaXfer->fFlags) == VDMETAXFER_TXDIR_NONE)
     2612    {
     2613        /* Free the meta data entry. */
     2614        bool fRemoved = RTAvlrFileOffsetRemove(pIoStorage->pTreeMetaXfers, pMetaXfer->Core.Key);
     2615        AssertMsg(fRemoved, ("Metadata transfer wasn't removed\n"));
     2616
     2617        RTMemFree(pMetaXfer);
     2618    }
     2619}
     2620
    22662621static int vdIOFlushAsync(void *pvUser, PVDIOSTORAGE pIoStorage,
    2267                           PVDIOCTX pIoCtx)
     2622                          PVDIOCTX pIoCtx,
     2623                          PFNVDXFERCOMPLETED pfnComplete,
     2624                          void *pvCompleteUser)
    22682625{
    22692626    PVDIMAGE pImage = (PVDIMAGE)pvUser;
     
    22712628    int rc = VINF_SUCCESS;
    22722629    PVDIOTASK pIoTask;
     2630    PVDMETAXFER pMetaXfer = NULL;
    22732631    void *pvTask = NULL;
    22742632
    2275     pIoTask = vdIoTaskMetaAlloc(pDisk, pIoCtx, VDIOCTXTXDIR_FLUSH, pImage,
    2276                                 NULL, NULL);
     2633    VD_THREAD_IS_CRITSECT_OWNER(pDisk);
     2634
     2635    LogFlowFunc(("pvUser=%#p pIoStorage=%#p pIoCtx=%#p\n",
     2636                 pvUser, pIoStorage, pIoCtx));
     2637
     2638    /* Allocate a new meta transfer. */
     2639    pMetaXfer = vdMetaXferAlloc(pImage, pIoStorage, 0, 0);
     2640    if (!pMetaXfer)
     2641        return VERR_NO_MEMORY;
     2642
     2643    pIoTask = vdIoTaskMetaAlloc(pIoStorage, pfnComplete, pvUser, pMetaXfer);
    22772644    if (!pIoTask)
     2645    {
     2646        RTMemFree(pMetaXfer);
    22782647        return VERR_NO_MEMORY;
     2648    }
    22792649
    22802650    ASMAtomicIncU32(&pIoCtx->cMetaTransfersPending);
    22812651
    2282     int rc2 = pDisk->pInterfaceAsyncIOCallbacks->pfnFlushAsync(pDisk->pInterfaceAsyncIO->pvUser,
    2283                                                                pIoStorage->u.pStorage,
    2284                                                                pIoTask,
    2285                                                                &pvTask);
    2286     if (rc2 == VINF_SUCCESS)
    2287     {
     2652    PVDIOCTXDEFERRED pDeferred = (PVDIOCTXDEFERRED)RTMemAllocZ(sizeof(VDIOCTXDEFERRED));
     2653    AssertPtr(pDeferred);
     2654
     2655    RTListInit(&pDeferred->NodeDeferred);
     2656    pDeferred->pIoCtx = pIoCtx;
     2657
     2658    RTListAppend(&pMetaXfer->ListIoCtxWaiting, &pDeferred->NodeDeferred);
     2659    VDMETAXFER_TXDIR_SET(pMetaXfer->fFlags, VDMETAXFER_TXDIR_FLUSH);
     2660    rc = pDisk->pInterfaceAsyncIOCallbacks->pfnFlushAsync(pDisk->pInterfaceAsyncIO->pvUser,
     2661                                                          pIoStorage->u.pStorage,
     2662                                                          pIoTask,
     2663                                                          &pvTask);
     2664    if (RT_SUCCESS(rc))
     2665    {
     2666        VDMETAXFER_TXDIR_SET(pMetaXfer->fFlags, VDMETAXFER_TXDIR_NONE);
    22882667        ASMAtomicDecU32(&pIoCtx->cMetaTransfersPending);
    22892668        vdIoTaskFree(pDisk, pIoTask);
    2290     }
    2291     else if (rc2 == VERR_VD_ASYNC_IO_IN_PROGRESS)
    2292         rc = VINF_SUCCESS;
    2293     else if (RT_FAILURE(rc2))
    2294         rc = rc2;
     2669        RTMemFree(pDeferred);
     2670        RTMemFree(pMetaXfer);
     2671    }
     2672    else if (rc != VERR_VD_ASYNC_IO_IN_PROGRESS)
     2673        RTMemFree(pMetaXfer);
    22952674
    22962675    return rc;
     
    23002679                              void *pvBuf, size_t cbBuf)
    23012680{
     2681    PVDIMAGE pImage = (PVDIMAGE)pvUser;
     2682    PVBOXHDD pDisk  = pImage->pDisk;
     2683
     2684    VD_THREAD_IS_CRITSECT_OWNER(pDisk);
     2685
    23022686    return vdIoCtxCopyTo(pIoCtx, (uint8_t *)pvBuf, cbBuf);
    23032687}
     
    23062690                                void *pvBuf, size_t cbBuf)
    23072691{
     2692    PVDIMAGE pImage = (PVDIMAGE)pvUser;
     2693    PVBOXHDD pDisk  = pImage->pDisk;
     2694
     2695    VD_THREAD_IS_CRITSECT_OWNER(pDisk);
     2696
    23082697    return vdIoCtxCopyFrom(pIoCtx, (uint8_t *)pvBuf, cbBuf);
    23092698}
     
    23122701                           int ch, size_t cb)
    23132702{
     2703    PVDIMAGE pImage = (PVDIMAGE)pvUser;
     2704    PVBOXHDD pDisk  = pImage->pDisk;
     2705
     2706    VD_THREAD_IS_CRITSECT_OWNER(pDisk);
     2707
    23142708    return vdIoCtxSet(pIoCtx, ch, cb);
    23152709}
     
    26363030
    26373031            /* Create the I/O callback table. */
    2638             pDisk->VDIIOCallbacks.cbSize            = sizeof(VDINTERFACEIO);
    2639             pDisk->VDIIOCallbacks.enmInterface      = VDINTERFACETYPE_IO;
    2640             pDisk->VDIIOCallbacks.pfnOpen           = vdIOOpen;
    2641             pDisk->VDIIOCallbacks.pfnClose          = vdIOClose;
    2642             pDisk->VDIIOCallbacks.pfnGetSize        = vdIOGetSize;
    2643             pDisk->VDIIOCallbacks.pfnSetSize        = vdIOSetSize;
    2644             pDisk->VDIIOCallbacks.pfnReadSync       = vdIOReadSync;
    2645             pDisk->VDIIOCallbacks.pfnWriteSync      = vdIOWriteSync;
    2646             pDisk->VDIIOCallbacks.pfnFlushSync      = vdIOFlushSync;
    2647             pDisk->VDIIOCallbacks.pfnReadUserAsync  = vdIOReadUserAsync;
    2648             pDisk->VDIIOCallbacks.pfnWriteUserAsync = vdIOWriteUserAsync;
    2649             pDisk->VDIIOCallbacks.pfnReadMetaAsync  = vdIOReadMetaAsync;
    2650             pDisk->VDIIOCallbacks.pfnWriteMetaAsync = vdIOWriteMetaAsync;
    2651             pDisk->VDIIOCallbacks.pfnFlushAsync     = vdIOFlushAsync;
    2652             pDisk->VDIIOCallbacks.pfnIoCtxCopyFrom  = vdIOIoCtxCopyFrom;
    2653             pDisk->VDIIOCallbacks.pfnIoCtxCopyTo    = vdIOIoCtxCopyTo;
    2654             pDisk->VDIIOCallbacks.pfnIoCtxSet       = vdIOIoCtxSet;
     3032            pDisk->VDIIOCallbacks.cbSize             = sizeof(VDINTERFACEIO);
     3033            pDisk->VDIIOCallbacks.enmInterface       = VDINTERFACETYPE_IO;
     3034            pDisk->VDIIOCallbacks.pfnOpen            = vdIOOpen;
     3035            pDisk->VDIIOCallbacks.pfnClose           = vdIOClose;
     3036            pDisk->VDIIOCallbacks.pfnGetSize         = vdIOGetSize;
     3037            pDisk->VDIIOCallbacks.pfnSetSize         = vdIOSetSize;
     3038            pDisk->VDIIOCallbacks.pfnReadSync        = vdIOReadSync;
     3039            pDisk->VDIIOCallbacks.pfnWriteSync       = vdIOWriteSync;
     3040            pDisk->VDIIOCallbacks.pfnFlushSync       = vdIOFlushSync;
     3041            pDisk->VDIIOCallbacks.pfnReadUserAsync   = vdIOReadUserAsync;
     3042            pDisk->VDIIOCallbacks.pfnWriteUserAsync  = vdIOWriteUserAsync;
     3043            pDisk->VDIIOCallbacks.pfnReadMetaAsync   = vdIOReadMetaAsync;
     3044            pDisk->VDIIOCallbacks.pfnWriteMetaAsync  = vdIOWriteMetaAsync;
     3045            pDisk->VDIIOCallbacks.pfnMetaXferRelease = vdIOMetaXferRelease;
     3046            pDisk->VDIIOCallbacks.pfnFlushAsync      = vdIOFlushAsync;
     3047            pDisk->VDIIOCallbacks.pfnIoCtxCopyFrom   = vdIOIoCtxCopyFrom;
     3048            pDisk->VDIIOCallbacks.pfnIoCtxCopyTo     = vdIOIoCtxCopyTo;
     3049            pDisk->VDIIOCallbacks.pfnIoCtxSet        = vdIOIoCtxSet;
    26553050
    26563051            *ppDisk = pDisk;
  • trunk/src/VBox/Devices/Storage/VDIHDDCore.cpp

    r28800 r30555  
    206206
    207207static int vdiFileWriteMetaAsync(PVDIIMAGEDESC pImage, uint64_t off, void *pcvBuf, size_t cbWrite,
    208                                  PVDIOCTX pIoCtx, PFNVDMETACOMPLETED pfnMetaComplete, void *pvMetaUser)
     208                                 PVDIOCTX pIoCtx)
    209209{
    210210    return pImage->pInterfaceIOCallbacks->pfnWriteMetaAsync(pImage->pInterfaceIO->pvUser,
    211211                                                            pImage->pStorage,
    212212                                                            off, pcvBuf, cbWrite, pIoCtx,
    213                                                             pfnMetaComplete, pvMetaUser);
     213                                                            NULL, NULL);
    214214}
    215215
    216216static int vdiFileReadMetaAsync(PVDIIMAGEDESC pImage, uint64_t off, void *pvBuf, size_t cbRead,
    217                                 PVDIOCTX pIoCtx, PFNVDMETACOMPLETED pfnMetaComplete, void *pvMetaUser)
     217                                PVDIOCTX pIoCtx)
    218218{
    219219    return pImage->pInterfaceIOCallbacks->pfnReadMetaAsync(pImage->pInterfaceIO->pvUser,
    220220                                                           pImage->pStorage,
    221221                                                           off, pvBuf, cbRead, pIoCtx,
    222                                                            pfnMetaComplete, pvMetaUser);
     222                                                           NULL);
    223223}
    224224
     
    235235{
    236236    return pImage->pInterfaceIOCallbacks->pfnFlushAsync(pImage->pInterfaceIO->pvUser,
    237                                                         pImage->pStorage, pIoCtx);
     237                                                        pImage->pStorage, pIoCtx,
     238                                                        NULL, NULL);
    238239}
    239240
     
    873874            rc = vdiFileWriteMetaAsync(pImage, sizeof(VDIPREHEADER),
    874875                                       &pImage->Header.u.v0, sizeof(pImage->Header.u.v0),
    875                                        pIoCtx, NULL, NULL);
     876                                       pIoCtx);
    876877            break;
    877878        case 1:
     
    879880                rc = vdiFileWriteMetaAsync(pImage, sizeof(VDIPREHEADER),
    880881                                           &pImage->Header.u.v1, sizeof(pImage->Header.u.v1),
    881                                            pIoCtx, NULL, NULL);
     882                                           pIoCtx);
    882883            else
    883884                rc = vdiFileWriteMetaAsync(pImage, sizeof(VDIPREHEADER),
    884885                                           &pImage->Header.u.v1plus, sizeof(pImage->Header.u.v1plus),
    885                                            pIoCtx, NULL, NULL);
     886                                           pIoCtx);
    886887            break;
    887888        default:
     
    889890            break;
    890891    }
    891     AssertMsgRC(rc, ("vdiUpdateHeader failed, filename=\"%s\" rc=%Rrc\n", pImage->pszFilename, rc));
     892    AssertMsg(RT_SUCCESS(rc) || rc == VERR_VD_ASYNC_IO_IN_PROGRESS,
     893              ("vdiUpdateHeader failed, filename=\"%s\" rc=%Rrc\n", pImage->pszFilename, rc));
    892894    return rc;
    893895}
     
    922924    /* Update image header. */
    923925    int rc = vdiUpdateHeaderAsync(pImage, pIoCtx);
    924     if (RT_SUCCESS(rc))
     926    if (RT_SUCCESS(rc) || rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
    925927    {
    926928        /* write only one block pointer. */
     
    929931                                   &pImage->paBlocks[uBlock],
    930932                                   sizeof(VDIIMAGEBLOCKPOINTER),
    931                                    pIoCtx,
    932                                    NULL, NULL);
    933         AssertMsgRC(rc, ("vdiUpdateBlockInfo failed to update block=%u, filename=\"%s\", rc=%Rrc\n",
    934                          uBlock, pImage->pszFilename, rc));
     933                                   pIoCtx);
     934        AssertMsg(RT_SUCCESS(rc) || rc == VERR_VD_ASYNC_IO_IN_PROGRESS,
     935                  ("vdiUpdateBlockInfo failed to update block=%u, filename=\"%s\", rc=%Rrc\n",
     936                  uBlock, pImage->pszFilename, rc));
    935937    }
    936938    return rc;
     
    955957 * Internal: Flush the image file to disk - async version.
    956958 */
    957 static void vdiFlushImageAsync(PVDIIMAGEDESC pImage, PVDIOCTX pIoCtx)
    958 {
     959static int vdiFlushImageAsync(PVDIIMAGEDESC pImage, PVDIOCTX pIoCtx)
     960{
     961    int rc = VINF_SUCCESS;
     962
    959963    if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY))
    960964    {
    961965        /* Save header. */
    962         int rc = vdiUpdateHeaderAsync(pImage, pIoCtx);
    963         AssertMsgRC(rc, ("vdiUpdateHeaderAsync() failed, filename=\"%s\", rc=%Rrc\n",
    964                          pImage->pszFilename, rc));
     966        rc = vdiUpdateHeaderAsync(pImage, pIoCtx);
     967        AssertMsg(RT_SUCCESS(rc) || rc == VERR_VD_ASYNC_IO_IN_PROGRESS,
     968                  ("vdiUpdateHeaderAsync() failed, filename=\"%s\", rc=%Rrc\n",
     969                  pImage->pszFilename, rc));
    965970        rc = vdiFileFlushAsync(pImage, pIoCtx);
    966         AssertMsgRC(rc, ("Flushing data to disk failed rc=%Rrc\n", rc));
    967     }
     971        AssertMsg(RT_SUCCESS(rc) || rc == VERR_VD_ASYNC_IO_IN_PROGRESS,
     972                  ("Flushing data to disk failed rc=%Rrc\n", rc));
     973    }
     974
     975    return rc;
    968976}
    969977
     
    22072215                                                                      pImage->pStorage,
    22082216                                                                      u64Offset,
    2209                                                                       pIoCtx, cbToWrite);
     2217                                                                      pIoCtx, cbToWrite,
     2218                                                                      NULL, NULL);
    22102219                if (RT_UNLIKELY(RT_FAILURE_NP(rc) && (rc != VERR_VD_ASYNC_IO_IN_PROGRESS)))
    22112220                    goto out;
     
    22142223
    22152224                rc = vdiUpdateBlockInfoAsync(pImage, uBlock, pIoCtx);
    2216                 if (RT_FAILURE(rc))
     2225                if (RT_FAILURE(rc) && (rc != VERR_VD_ASYNC_IO_IN_PROGRESS))
    22172226                    goto out;
    22182227
     
    22372246                                                                  pImage->pStorage,
    22382247                                                                  u64Offset,
    2239                                                                   pIoCtx, cbToWrite);
     2248                                                                  pIoCtx, cbToWrite,
     2249                                                                  NULL, NULL);
    22402250        }
    22412251    } while (0);
     
    22572267    Assert(pImage);
    22582268
    2259     vdiFlushImageAsync(pImage, pIoCtx);
     2269    rc = vdiFlushImageAsync(pImage, pIoCtx);
    22602270    LogFlowFunc(("returns %Rrc\n", rc));
    22612271    return rc;
  • trunk/src/VBox/Devices/Storage/VHDHDDCore.cpp

    r29250 r30555  
    198198} VHDIMAGE, *PVHDIMAGE;
    199199
     200/**
     201 * Structure tracking the expansion process of the image
     202 * for async access.
     203 */
     204typedef struct VHDIMAGEEXPAND
     205{
     206    /** Flag indicating the status of each step. */
     207    volatile uint32_t fFlags;
     208    /** The index in the  block allocation table which is written. */
     209    uint32_t          idxBatAllocated;
     210    /** Big endian representation of the block index
     211     * which is written in the BAT. */
     212    uint32_t          idxBlockBe;
     213    /** Old end of the file - used for rollback in case of an error. */
     214    uint64_t          cbEofOld;
     215    /** Sector bitmap written to the new block - variable in size. */
     216    uint8_t           au8Bitmap[1];
     217} VHDIMAGEEXPAND, *PVHDIMAGEEXPAND;
     218
     219/**
     220 * Flag defines
     221 */
     222#define VHDIMAGEEXPAND_STEP_IN_PROGRESS (0x0)
     223#define VHDIMAGEEXPAND_STEP_FAILED      (0x2)
     224#define VHDIMAGEEXPAND_STEP_SUCCESS     (0x3)
     225/** All steps completed successfully. */
     226#define VHDIMAGEEXPAND_ALL_SUCCESS      (0xff)
     227/** All steps completed (no success indicator) */
     228#define VHDIMAGEEXPAND_ALL_COMPLETE     (0xaa)
     229
     230/** Every status field has 2 bits so we can encode 4 steps in one byte. */
     231#define VHDIMAGEEXPAND_STATUS_MASK              0x03
     232#define VHDIMAGEEXPAND_BLOCKBITMAP_STATUS_SHIFT 0x00
     233#define VHDIMAGEEXPAND_USERBLOCK_STATUS_SHIFT   0x02
     234#define VHDIMAGEEXPAND_FOOTER_STATUS_SHIFT      0x04
     235#define VHDIMAGEEXPAND_BAT_STATUS_SHIFT         0x06
     236
     237/**
     238 * Helper macros to get and set the status field.
     239 */
     240#define VHDIMAGEEXPAND_STATUS_GET(fFlags, cShift) \
     241    (((fFlags) >> (cShift)) & VHDIMAGEEXPAND_STATUS_MASK)
     242#define VHDIMAGEEXPAND_STATUS_SET(fFlags, cShift, uVal) \
     243    ASMAtomicOrU32(&(fFlags), ((uVal) & VHDIMAGEEXPAND_STATUS_MASK) << (cShift))
     244
    200245/*******************************************************************************
    201246*   Static Variables                                                           *
     
    563608}
    564609
     610/**
     611 * Internal: called when the async expansion process completed (failure or success).
     612 *           Will do the necessary rollback if an error occurred.
     613 */
     614static int vhdAsyncExpansionComplete(PVHDIMAGE pImage, PVDIOCTX pIoCtx, PVHDIMAGEEXPAND pExpand)
     615{
     616    int rc = VINF_SUCCESS;
     617    uint32_t fFlags = ASMAtomicReadU32(&pExpand->fFlags);
     618    bool fIoInProgress = false;
     619
     620    /* Quick path, check if everything succeeded. */
     621    if (fFlags == VHDIMAGEEXPAND_ALL_SUCCESS)
     622    {
     623        RTMemFree(pExpand);
     624    }
     625    else
     626    {
     627        uint32_t uStatus;
     628
     629        uStatus = VHDIMAGEEXPAND_STATUS_GET(pExpand->fFlags, VHDIMAGEEXPAND_BAT_STATUS_SHIFT);
     630        if (   uStatus == VHDIMAGEEXPAND_STEP_FAILED
     631            || uStatus == VHDIMAGEEXPAND_STEP_SUCCESS)
     632        {
     633            /* Undo and restore the old value. */
     634            pImage->pBlockAllocationTable[pExpand->idxBatAllocated] == ~0U;
     635
     636            /* Restore the old value on the disk.
     637             * No need for a completion callback because we can't
     638             * do anything if this fails. */
     639            if (uStatus == VHDIMAGEEXPAND_STEP_SUCCESS)
     640            {
     641                rc = pImage->pInterfaceIOCallbacks->pfnWriteMetaAsync(pImage->pInterfaceIO->pvUser,
     642                                                                      pImage->pStorage,
     643                                                                      pImage->uBlockAllocationTableOffset + pExpand->idxBatAllocated * sizeof(uint32_t),
     644                                                                      &pImage->pBlockAllocationTable[pExpand->idxBatAllocated], sizeof(uint32_t), pIoCtx,
     645                                                                      NULL, NULL);
     646                fIoInProgress |= rc == VERR_VD_ASYNC_IO_IN_PROGRESS;
     647            }
     648        }
     649
     650        /* Restore old size (including the footer because another application might
     651         * fill up the free space making it impossible to add the footer)
     652         * and add the footer at the right place again. */
     653        rc = pImage->pInterfaceIOCallbacks->pfnSetSize(pImage->pInterfaceIO->pvUser,
     654                                                       pImage->pStorage,
     655                                                       pExpand->cbEofOld + sizeof(VHDFooter));
     656        AssertRC(rc);
     657
     658        pImage->uCurrentEndOfFile = pExpand->cbEofOld;
     659        rc = pImage->pInterfaceIOCallbacks->pfnWriteMetaAsync(pImage->pInterfaceIO->pvUser,
     660                                                              pImage->pStorage,
     661                                                              pImage->uCurrentEndOfFile,
     662                                                              &pImage->vhdFooterCopy, sizeof(VHDFooter), pIoCtx,
     663                                                              NULL, NULL);
     664        fIoInProgress |= rc == VERR_VD_ASYNC_IO_IN_PROGRESS;
     665    }
     666
     667    return fIoInProgress ? VERR_VD_ASYNC_IO_IN_PROGRESS : rc;
     668}
     669
     670static int vhdAsyncExpansionStepCompleted(void *pvBackendData, PVDIOCTX pIoCtx, void *pvUser, int rcReq, unsigned iStep)
     671{
     672   PVHDIMAGE pImage = (PVHDIMAGE)pvBackendData;
     673   PVHDIMAGEEXPAND pExpand = (PVHDIMAGEEXPAND)pvUser;
     674
     675   LogFlowFunc(("pvBackendData=%#p pIoCtx=%#p pvUser=%#p rcReq=%Rrc iStep=%u\n",
     676                pvBackendData, pIoCtx, pvUser, rcReq, iStep));
     677
     678   if (RT_SUCCESS(rcReq))
     679       VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, iStep, VHDIMAGEEXPAND_STEP_SUCCESS);
     680   else
     681       VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, iStep, VHDIMAGEEXPAND_STEP_FAILED);
     682
     683   if ((pExpand->fFlags & VHDIMAGEEXPAND_ALL_COMPLETE) == VHDIMAGEEXPAND_ALL_COMPLETE)
     684       return vhdAsyncExpansionComplete(pImage, pIoCtx, pExpand);
     685
     686   return VERR_VD_ASYNC_IO_IN_PROGRESS;
     687}
     688
     689static int vhdAsyncExpansionDataBlockBitmapComplete(void *pvBackendData, PVDIOCTX pIoCtx, void *pvUser, int rcReq)
     690{
     691    return vhdAsyncExpansionStepCompleted(pvBackendData, pIoCtx, pvUser, rcReq, VHDIMAGEEXPAND_BLOCKBITMAP_STATUS_SHIFT);
     692}
     693
     694static int vhdAsyncExpansionDataComplete(void *pvBackendData, PVDIOCTX pIoCtx, void *pvUser, int rcReq)
     695{
     696    return vhdAsyncExpansionStepCompleted(pvBackendData, pIoCtx, pvUser, rcReq, VHDIMAGEEXPAND_USERBLOCK_STATUS_SHIFT);
     697}
     698
     699static int vhdAsyncExpansionBatUpdateComplete(void *pvBackendData, PVDIOCTX pIoCtx, void *pvUser, int rcReq)
     700{
     701    return vhdAsyncExpansionStepCompleted(pvBackendData, pIoCtx, pvUser, rcReq, VHDIMAGEEXPAND_BAT_STATUS_SHIFT);
     702}
     703
     704static int vhdAsyncExpansionFooterUpdateComplete(void *pvBackendData, PVDIOCTX pIoCtx, void *pvUser, int rcReq)
     705{
     706    return vhdAsyncExpansionStepCompleted(pvBackendData, pIoCtx, pvUser, rcReq, VHDIMAGEEXPAND_FOOTER_STATUS_SHIFT);
     707}
    565708
    566709static int vhdOpenImage(PVHDIMAGE pImage, unsigned uOpenFlags)
     
    568711    uint64_t FileSize;
    569712    VHDFooter vhdFooter;
    570 
    571     if (uOpenFlags & VD_OPEN_FLAGS_ASYNC_IO)
    572         return VERR_NOT_SUPPORTED;
    573713
    574714    pImage->uOpenFlags = uOpenFlags;
     
    10931233 * Internal: Sets the given sector in the sector bitmap.
    10941234 */
    1095 DECLINLINE(void) vhdBlockBitmapSectorSet(PVHDIMAGE pImage, uint32_t cBlockBitmapEntry)
     1235DECLINLINE(bool) vhdBlockBitmapSectorSet(PVHDIMAGE pImage, uint8_t *pu8Bitmap, uint32_t cBlockBitmapEntry)
    10961236{
    10971237    uint32_t iBitmap = (cBlockBitmapEntry / 8); /* Byte in the block bitmap. */
     
    10991239    /*
    11001240     * The index of the bit in the byte of the data block bitmap.
    1101      * The most signifcant bit stands for a lower sector number.
     1241     * The most significant bit stands for a lower sector number.
    11021242     */
    11031243    uint8_t  iBitInByte = (8-1) - (cBlockBitmapEntry % 8);
    1104     uint8_t  *puBitmap  = pImage->pu8Bitmap + iBitmap;
    1105 
    1106     AssertMsg(puBitmap < (pImage->pu8Bitmap + pImage->cbDataBlockBitmap),
     1244    uint8_t  *puBitmap  = pu8Bitmap + iBitmap;
     1245
     1246    AssertMsg(puBitmap < (pu8Bitmap + pImage->cbDataBlockBitmap),
    11071247                ("VHD: Current bitmap position exceeds maximum size of the bitmap\n"));
    11081248
    1109     ASMBitSet(puBitmap, iBitInByte);
     1249    return !ASMBitTestAndSet(puBitmap, iBitInByte);
    11101250}
    11111251
     
    13131453        if (RT_SUCCESS(rc))
    13141454        {
     1455            bool fChanged = false;
     1456
    13151457            /* Set the bits for all sectors having been written. */
    13161458            for (uint32_t iSector = 0; iSector < (cbToWrite / VHD_SECTOR_SIZE); iSector++)
    13171459            {
    1318                 vhdBlockBitmapSectorSet(pImage, cBATEntryIndex);
     1460                fChanged |= vhdBlockBitmapSectorSet(pImage, pImage->pu8Bitmap, cBATEntryIndex);
    13191461                cBATEntryIndex++;
    13201462            }
    13211463
    1322             /* Write the bitmap back. */
    1323             rc = vhdFileWriteSync(pImage,
    1324                 ((uint64_t)pImage->pBlockAllocationTable[cBlockAllocationTableEntry]) * VHD_SECTOR_SIZE,
    1325                 pImage->pu8Bitmap, pImage->cbDataBlockBitmap, NULL);
     1464            if (fChanged)
     1465            {
     1466                /* Write the bitmap back. */
     1467                rc = vhdFileWriteSync(pImage,
     1468                                      ((uint64_t)pImage->pBlockAllocationTable[cBlockAllocationTableEntry]) * VHD_SECTOR_SIZE,
     1469                                      pImage->pu8Bitmap, pImage->cbDataBlockBitmap, NULL);
     1470            }
    13261471        }
    13271472    }
     
    21312276static bool vhdIsAsyncIOSupported(void *pvBackendData)
    21322277{
    2133     return false;
    2134 }
    2135 
    2136 static int vhdAsyncRead(void *pvBackendData, uint64_t uOffset, size_t cbRead,
     2278    return true;
     2279}
     2280
     2281static int vhdAsyncRead(void *pBackendData, uint64_t uOffset, size_t cbRead,
    21372282                        PVDIOCTX pIoCtx, size_t *pcbActuallyRead)
    21382283{
    2139     int rc = VERR_NOT_IMPLEMENTED;
    2140     LogFlowFunc(("returns %Rrc\n", rc));
    2141     return rc;
    2142 }
    2143 
    2144 static int vhdAsyncWrite(void *pvBackendData, uint64_t uOffset, size_t cbWrite,
     2284    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
     2285    int rc = VINF_SUCCESS;
     2286
     2287    LogFlowFunc(("pBackendData=%p uOffset=%#llx pIoCtx=%#p cbRead=%u pcbActuallyRead=%p\n", pBackendData, uOffset, pIoCtx, cbRead, pcbActuallyRead));
     2288
     2289    if (uOffset + cbRead > pImage->cbSize)
     2290        return VERR_INVALID_PARAMETER;
     2291
     2292    /*
     2293     * If we have a dynamic disk image, we need to find the data block and sector to read.
     2294     */
     2295    if (pImage->pBlockAllocationTable)
     2296    {
     2297        /*
     2298         * Get the data block first.
     2299         */
     2300        uint32_t cBlockAllocationTableEntry = (uOffset / VHD_SECTOR_SIZE) / pImage->cSectorsPerDataBlock;
     2301        uint32_t cBATEntryIndex = (uOffset / VHD_SECTOR_SIZE) % pImage->cSectorsPerDataBlock;
     2302        uint64_t uVhdOffset;
     2303
     2304        LogFlowFunc(("cBlockAllocationTableEntry=%u cBatEntryIndex=%u\n", cBlockAllocationTableEntry, cBATEntryIndex));
     2305        LogFlowFunc(("BlockAllocationEntry=%u\n", pImage->pBlockAllocationTable[cBlockAllocationTableEntry]));
     2306
     2307        /*
     2308         * If the block is not allocated the content of the entry is ~0
     2309         */
     2310        if (pImage->pBlockAllocationTable[cBlockAllocationTableEntry] == ~0U)
     2311        {
     2312            /* Return block size as read. */
     2313            *pcbActuallyRead = RT_MIN(cbRead, pImage->cSectorsPerDataBlock * VHD_SECTOR_SIZE);
     2314            return VERR_VD_BLOCK_FREE;
     2315        }
     2316
     2317        uVhdOffset = ((uint64_t)pImage->pBlockAllocationTable[cBlockAllocationTableEntry] + pImage->cDataBlockBitmapSectors + cBATEntryIndex) * VHD_SECTOR_SIZE;
     2318        LogFlowFunc(("uVhdOffset=%llu cbRead=%u\n", uVhdOffset, cbRead));
     2319
     2320        /*
     2321         * Clip read range to remain in this data block.
     2322         */
     2323        cbRead = RT_MIN(cbRead, (pImage->cbDataBlock - (cBATEntryIndex * VHD_SECTOR_SIZE)));
     2324
     2325        /* Read in the block's bitmap. */
     2326        PVDMETAXFER pMetaXfer;
     2327        rc = pImage->pInterfaceIOCallbacks->pfnReadMetaAsync(pImage->pInterfaceIO->pvUser,
     2328                                                             pImage->pStorage,
     2329                                                             ((uint64_t)pImage->pBlockAllocationTable[cBlockAllocationTableEntry]) * VHD_SECTOR_SIZE,
     2330                                                             pImage->pu8Bitmap, pImage->cbDataBlockBitmap, pIoCtx, &pMetaXfer);
     2331
     2332        if (RT_SUCCESS(rc))
     2333        {
     2334            uint32_t cSectors = 0;
     2335
     2336            pImage->pInterfaceIOCallbacks->pfnMetaXferRelease(pImage->pInterfaceIO->pvUser, pMetaXfer);
     2337            if (vhdBlockBitmapSectorContainsData(pImage, cBATEntryIndex))
     2338            {
     2339                cBATEntryIndex++;
     2340                cSectors = 1;
     2341
     2342                /*
     2343                 * The first sector being read is marked dirty, read as much as we
     2344                 * can from child. Note that only sectors that are marked dirty
     2345                 * must be read from child.
     2346                 */
     2347                while (   (cSectors < (cbRead / VHD_SECTOR_SIZE))
     2348                       && vhdBlockBitmapSectorContainsData(pImage, cBATEntryIndex))
     2349                {
     2350                    cBATEntryIndex++;
     2351                    cSectors++;
     2352                }
     2353
     2354                cbRead = cSectors * VHD_SECTOR_SIZE;
     2355
     2356                LogFlowFunc(("uVhdOffset=%llu cbRead=%u\n", uVhdOffset, cbRead));
     2357                rc = pImage->pInterfaceIOCallbacks->pfnReadUserAsync(pImage->pInterfaceIO->pvUser,
     2358                                                                     pImage->pStorage,
     2359                                                                     uVhdOffset, pIoCtx, cbRead);
     2360            }
     2361            else
     2362            {
     2363                /*
     2364                 * The first sector being read is marked clean, so we should read from
     2365                 * our parent instead, but only as much as there are the following
     2366                 * clean sectors, because the block may still contain dirty sectors
     2367                 * further on. We just need to compute the number of clean sectors
     2368                 * and pass it to our caller along with the notification that they
     2369                 * should be read from the parent.
     2370                 */
     2371                cBATEntryIndex++;
     2372                cSectors = 1;
     2373
     2374                while (   (cSectors < (cbRead / VHD_SECTOR_SIZE))
     2375                       && !vhdBlockBitmapSectorContainsData(pImage, cBATEntryIndex))
     2376                {
     2377                    cBATEntryIndex++;
     2378                    cSectors++;
     2379                }
     2380
     2381                cbRead = cSectors * VHD_SECTOR_SIZE;
     2382                Log(("%s: Sectors free: uVhdOffset=%llu cbRead=%u\n", __FUNCTION__, uVhdOffset, cbRead));
     2383                rc = VERR_VD_BLOCK_FREE;
     2384            }
     2385        }
     2386        else
     2387            AssertMsg(rc == VERR_VD_NOT_ENOUGH_METADATA, ("Reading block bitmap failed rc=%Rrc\n", rc));
     2388    }
     2389    else
     2390    {
     2391        rc = pImage->pInterfaceIOCallbacks->pfnReadUserAsync(pImage->pInterfaceIO->pvUser,
     2392                                                             pImage->pStorage,
     2393                                                             uOffset, pIoCtx, cbRead);
     2394    }
     2395
     2396    if (pcbActuallyRead)
     2397        *pcbActuallyRead = cbRead;
     2398
     2399    LogFlowFunc(("returns rc=%Rrc\n", rc));
     2400    return rc;
     2401}
     2402
     2403static int vhdAsyncWrite(void *pBackendData, uint64_t uOffset, size_t cbWrite,
    21452404                         PVDIOCTX pIoCtx,
    21462405                         size_t *pcbWriteProcess, size_t *pcbPreRead,
    21472406                         size_t *pcbPostRead, unsigned fWrite)
    21482407{
    2149     int rc = VERR_NOT_IMPLEMENTED;
    2150     LogFlowFunc(("returns %Rrc\n", rc));
     2408    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
     2409    int rc = VINF_SUCCESS;
     2410
     2411    LogFlowFunc(("pBackendData=%p uOffset=%llu pIoCtx=%#p cbWrite=%u pcbWriteProcess=%p pcbPreRead=%p pcbPostRead=%p fWrite=%u\n",
     2412             pBackendData, uOffset, pIoCtx, cbWrite, pcbWriteProcess, pcbPreRead, pcbPostRead, fWrite));
     2413
     2414    AssertPtr(pImage);
     2415    Assert(uOffset % VHD_SECTOR_SIZE == 0);
     2416    Assert(cbWrite % VHD_SECTOR_SIZE == 0);
     2417
     2418    if (pImage->pBlockAllocationTable)
     2419    {
     2420        /*
     2421         * Get the data block first.
     2422         */
     2423        uint32_t cSector = uOffset / VHD_SECTOR_SIZE;
     2424        uint32_t cBlockAllocationTableEntry = cSector / pImage->cSectorsPerDataBlock;
     2425        uint32_t cBATEntryIndex = cSector % pImage->cSectorsPerDataBlock;
     2426        uint64_t uVhdOffset;
     2427
     2428        /*
     2429         * Clip write range.
     2430         */
     2431        cbWrite = RT_MIN(cbWrite, (pImage->cbDataBlock - (cBATEntryIndex * VHD_SECTOR_SIZE)));
     2432
     2433        /*
     2434         * If the block is not allocated the content of the entry is ~0
     2435         * and we need to allocate a new block. Note that while blocks are
     2436         * allocated with a relatively big granularity, each sector has its
     2437         * own bitmap entry, indicating whether it has been written or not.
     2438         * So that means for the purposes of the higher level that the
     2439         * granularity is invisible. This means there's no need to return
     2440         * VERR_VD_BLOCK_FREE unless the block hasn't been allocated yet.
     2441         */
     2442        if (pImage->pBlockAllocationTable[cBlockAllocationTableEntry] == ~0U)
     2443        {
     2444            /* Check if the block allocation should be suppressed. */
     2445            if (fWrite & VD_WRITE_NO_ALLOC)
     2446            {
     2447                *pcbPreRead = cBATEntryIndex * VHD_SECTOR_SIZE;
     2448                *pcbPostRead = pImage->cSectorsPerDataBlock * VHD_SECTOR_SIZE - cbWrite - *pcbPreRead;
     2449
     2450                if (pcbWriteProcess)
     2451                    *pcbWriteProcess = cbWrite;
     2452                return VERR_VD_BLOCK_FREE;
     2453            }
     2454
     2455            PVHDIMAGEEXPAND pExpand = (PVHDIMAGEEXPAND)RTMemAllocZ(RT_OFFSETOF(VHDIMAGEEXPAND, au8Bitmap[pImage->cDataBlockBitmapSectors * VHD_SECTOR_SIZE]));
     2456            bool fIoInProgress = false;
     2457
     2458            if (!pExpand)
     2459                return VERR_NO_MEMORY;
     2460
     2461            pExpand->cbEofOld = pImage->uCurrentEndOfFile;
     2462            pExpand->idxBatAllocated = cBlockAllocationTableEntry;
     2463            pExpand->idxBlockBe = RT_H2BE_U32(pImage->uCurrentEndOfFile / VHD_SECTOR_SIZE);
     2464
     2465            /* Set the bits for all sectors having been written. */
     2466            for (uint32_t iSector = 0; iSector < (cbWrite / VHD_SECTOR_SIZE); iSector++)
     2467            {
     2468                /* No need to check for a changed value because this is an initial write. */
     2469                vhdBlockBitmapSectorSet(pImage, pExpand->au8Bitmap, cBATEntryIndex);
     2470                cBATEntryIndex++;
     2471            }
     2472
     2473            do
     2474            {
     2475                /*
     2476                 * Start with the sector bitmap.
     2477                 */
     2478                rc = pImage->pInterfaceIOCallbacks->pfnWriteMetaAsync(pImage->pInterfaceIO->pvUser,
     2479                                                                      pImage->pStorage,
     2480                                                                      pImage->uCurrentEndOfFile,
     2481                                                                      pExpand->au8Bitmap, pImage->cbDataBlockBitmap, pIoCtx,
     2482                                                                      vhdAsyncExpansionDataBlockBitmapComplete, pExpand);
     2483                if (RT_SUCCESS(rc))
     2484                    VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_BLOCKBITMAP_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_SUCCESS);
     2485                else if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
     2486                    fIoInProgress = true;
     2487                else
     2488                {
     2489                    VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_BLOCKBITMAP_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_FAILED);
     2490                    VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_USERBLOCK_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_FAILED);
     2491                    VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_BAT_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_FAILED);
     2492                    VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_FOOTER_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_FAILED);
     2493                    break;
     2494                }
     2495
     2496
     2497                /*
     2498                 * Write the new block at the current end of the file.
     2499                 */
     2500                rc = pImage->pInterfaceIOCallbacks->pfnWriteUserAsync(pImage->pInterfaceIO->pvUser,
     2501                                                                      pImage->pStorage,
     2502                                                                      pImage->uCurrentEndOfFile + pImage->cbDataBlockBitmap,
     2503                                                                      pIoCtx, cbWrite,
     2504                                                                      vhdAsyncExpansionDataComplete, pExpand);
     2505                if (RT_SUCCESS(rc))
     2506                    VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_USERBLOCK_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_SUCCESS);
     2507                else if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
     2508                    fIoInProgress = true;
     2509                else
     2510                {
     2511                    VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_USERBLOCK_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_FAILED);
     2512                    VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_BAT_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_FAILED);
     2513                    VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_FOOTER_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_FAILED);
     2514                    break;
     2515                }
     2516
     2517                /*
     2518                 * Write entry in the BAT.
     2519                 */
     2520                rc = pImage->pInterfaceIOCallbacks->pfnWriteMetaAsync(pImage->pInterfaceIO->pvUser,
     2521                                                                      pImage->pStorage,
     2522                                                                      pImage->uBlockAllocationTableOffset + cBlockAllocationTableEntry * sizeof(uint32_t),
     2523                                                                      &pExpand->idxBlockBe, sizeof(uint32_t), pIoCtx,
     2524                                                                      vhdAsyncExpansionBatUpdateComplete, pExpand);
     2525                if (RT_SUCCESS(rc))
     2526                    VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_BAT_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_SUCCESS);
     2527                else if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
     2528                    fIoInProgress = true;
     2529                else
     2530                {
     2531                    VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_BAT_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_FAILED);
     2532                    VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_FOOTER_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_FAILED);
     2533                    break;
     2534                }
     2535
     2536                /*
     2537                 * Set the new end of the file and link the new block into the BAT.
     2538                 */
     2539                pImage->pBlockAllocationTable[cBlockAllocationTableEntry] = pImage->uCurrentEndOfFile / VHD_SECTOR_SIZE;
     2540                pImage->uCurrentEndOfFile += pImage->cbDataBlockBitmap + pImage->cbDataBlock;
     2541
     2542                /* Update the footer. */
     2543                rc = pImage->pInterfaceIOCallbacks->pfnWriteMetaAsync(pImage->pInterfaceIO->pvUser,
     2544                                                                      pImage->pStorage,
     2545                                                                      pImage->uCurrentEndOfFile,
     2546                                                                      &pImage->vhdFooterCopy, sizeof(VHDFooter), pIoCtx,
     2547                                                                      vhdAsyncExpansionFooterUpdateComplete, pExpand);
     2548                if (RT_SUCCESS(rc))
     2549                    VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_FOOTER_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_SUCCESS);
     2550                else if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
     2551                    fIoInProgress = true;
     2552                else
     2553                {
     2554                    VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_FOOTER_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_FAILED);
     2555                    break;
     2556                }
     2557
     2558            } while (0);
     2559
     2560            if (!fIoInProgress)
     2561                vhdAsyncExpansionComplete(pImage, pIoCtx, pExpand);
     2562            else
     2563                rc = VERR_VD_ASYNC_IO_IN_PROGRESS;
     2564        }
     2565        else
     2566        {
     2567            /*
     2568             * Calculate the real offset in the file.
     2569             */
     2570            uVhdOffset = ((uint64_t)pImage->pBlockAllocationTable[cBlockAllocationTableEntry] + pImage->cDataBlockBitmapSectors + cBATEntryIndex) * VHD_SECTOR_SIZE;
     2571
     2572            /* Read in the block's bitmap. */
     2573            PVDMETAXFER pMetaXfer;
     2574            rc = pImage->pInterfaceIOCallbacks->pfnReadMetaAsync(pImage->pInterfaceIO->pvUser,
     2575                                                                 pImage->pStorage,
     2576                                                                 ((uint64_t)pImage->pBlockAllocationTable[cBlockAllocationTableEntry]) * VHD_SECTOR_SIZE,
     2577                                                                 pImage->pu8Bitmap, pImage->cbDataBlockBitmap, pIoCtx, &pMetaXfer);
     2578            if (RT_SUCCESS(rc))
     2579            {
     2580                pImage->pInterfaceIOCallbacks->pfnMetaXferRelease(pImage->pInterfaceIO->pvUser, pMetaXfer);
     2581
     2582                /* Write data. */
     2583                rc = pImage->pInterfaceIOCallbacks->pfnWriteUserAsync(pImage->pInterfaceIO->pvUser,
     2584                                                                      pImage->pStorage,
     2585                                                                      uVhdOffset, pIoCtx, cbWrite,
     2586                                                                      NULL, NULL);
     2587                if (RT_SUCCESS(rc) || rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
     2588                {
     2589                    bool fChanged = false;
     2590
     2591                    /* Set the bits for all sectors having been written. */
     2592                    for (uint32_t iSector = 0; iSector < (cbWrite / VHD_SECTOR_SIZE); iSector++)
     2593                    {
     2594                        fChanged |= vhdBlockBitmapSectorSet(pImage, pImage->pu8Bitmap, cBATEntryIndex);
     2595                        cBATEntryIndex++;
     2596                    }
     2597
     2598                    /* Only write the bitmap if it was changed. */
     2599                    if (fChanged)
     2600                    {
     2601                        /*
     2602                         * Write the bitmap back.
     2603                         *
     2604                         * @note We don't have a completion callback here because we
     2605                         * can't do anything if the write fails for some reason.
     2606                         * The error will propagated to the device/guest
     2607                         * by the generic VD layer already and we don't need
     2608                         * to rollback anything here.
     2609                         */
     2610                        rc = pImage->pInterfaceIOCallbacks->pfnWriteMetaAsync(pImage->pInterfaceIO->pvUser,
     2611                                                                              pImage->pStorage,
     2612                                                                              ((uint64_t)pImage->pBlockAllocationTable[cBlockAllocationTableEntry]) * VHD_SECTOR_SIZE,
     2613                                                                              pImage->pu8Bitmap, pImage->cbDataBlockBitmap, pIoCtx,
     2614                                                                              NULL, NULL);
     2615                    }
     2616                }
     2617            }
     2618        }
     2619    }
     2620    else
     2621    {
     2622        rc = pImage->pInterfaceIOCallbacks->pfnWriteUserAsync(pImage->pInterfaceIO->pvUser,
     2623                                                              pImage->pStorage,
     2624                                                              uOffset, pIoCtx, cbWrite,
     2625                                                              NULL, NULL);
     2626    }
     2627
     2628    if (pcbWriteProcess)
     2629        *pcbWriteProcess = cbWrite;
     2630
     2631    /* Stay on the safe side. Do not run the risk of confusing the higher
     2632     * level, as that can be pretty lethal to image consistency. */
     2633    *pcbPreRead = 0;
     2634    *pcbPostRead = 0;
     2635
    21512636    return rc;
    21522637}
     
    21542639static int vhdAsyncFlush(void *pvBackendData, PVDIOCTX pIoCtx)
    21552640{
    2156     int rc = VERR_NOT_IMPLEMENTED;
    2157     LogFlowFunc(("returns %Rrc\n", rc));
    2158     return rc;
     2641    PVHDIMAGE pImage = (PVHDIMAGE)pvBackendData;
     2642
     2643    /* No need to write anything here. Data is always updated on a write. */
     2644    return pImage->pInterfaceIOCallbacks->pfnFlushAsync(pImage->pInterfaceIO->pvUser,
     2645                                                        pImage->pStorage, pIoCtx,
     2646                                                        NULL, NULL);
    21592647}
    21602648
     
    21672655    /* uBackendCaps */
    21682656    VD_CAP_UUID | VD_CAP_DIFF | VD_CAP_FILE |
    2169     VD_CAP_CREATE_FIXED | VD_CAP_CREATE_DYNAMIC,
     2657    VD_CAP_CREATE_FIXED | VD_CAP_CREATE_DYNAMIC |
     2658    VD_CAP_ASYNC,
    21702659    /* papszFileExtensions */
    21712660    s_apszVhdFileExtensions,
  • trunk/src/VBox/Devices/Storage/VmdkHDDCore.cpp

    r29649 r30555  
    799799
    800800    return pImage->pInterfaceIOCallbacks->pfnFlushAsync(pImage->pInterfaceIO->pvUser,
    801                                                         pVmdkFile->pStorage, pIoCtx);
     801                                                        pVmdkFile->pStorage, pIoCtx,
     802                                                        NULL, NULL);
    802803}
    803804
     
    31173118    if (RT_LE2H_U32(u32Magic) == VMDK_SPARSE_MAGICNUMBER)
    31183119    {
    3119         /* Async I/IO is not supported with these files yet. So fail if opened in async I/O mode. */
    3120         if (uOpenFlags & VD_OPEN_FLAGS_ASYNC_IO)
    3121         {
    3122             rc = VERR_NOT_SUPPORTED;
    3123             goto out;
    3124         }
    3125 
    31263120        /* It's a hosted single-extent image. */
    31273121        rc = vmdkCreateExtents(pImage, 1);
     
    43634357        if (RT_FAILURE(rc))
    43644358            return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot read grain table entry in '%s'"), pExtent->pszFullname);
     4359        pGTCacheEntry->uExtent = pExtent->uExtent;
     4360        pGTCacheEntry->uGTBlock = uGTBlock;
     4361        for (unsigned i = 0; i < VMDK_GT_CACHELINE_SIZE; i++)
     4362            pGTCacheEntry->aGTData[i] = RT_LE2H_U32(aGTDataTmp[i]);
     4363    }
     4364    uGTBlockIndex = (uSector / pExtent->cSectorsPerGrain) % VMDK_GT_CACHELINE_SIZE;
     4365    uint32_t uGrainSector = pGTCacheEntry->aGTData[uGTBlockIndex];
     4366    if (uGrainSector)
     4367        *puExtentSector = uGrainSector + uSector % pExtent->cSectorsPerGrain;
     4368    else
     4369        *puExtentSector = 0;
     4370    return VINF_SUCCESS;
     4371}
     4372
     4373/**
     4374 * Internal. Get sector number in the extent file from the relative sector
     4375 * number in the extent - version for async access.
     4376 */
     4377static int vmdkGetSectorAsync(PVMDKIMAGE pImage, PVDIOCTX pIoCtx,
     4378                              PVMDKGTCACHE pCache, PVMDKEXTENT pExtent,
     4379                              uint64_t uSector, uint64_t *puExtentSector)
     4380{
     4381    uint64_t uGDIndex, uGTSector, uGTBlock;
     4382    uint32_t uGTHash, uGTBlockIndex;
     4383    PVMDKGTCACHEENTRY pGTCacheEntry;
     4384    uint32_t aGTDataTmp[VMDK_GT_CACHELINE_SIZE];
     4385    int rc;
     4386
     4387    uGDIndex = uSector / pExtent->cSectorsPerGDE;
     4388    if (uGDIndex >= pExtent->cGDEntries)
     4389        return VERR_OUT_OF_RANGE;
     4390    uGTSector = pExtent->pGD[uGDIndex];
     4391    if (!uGTSector)
     4392    {
     4393        /* There is no grain table referenced by this grain directory
     4394         * entry. So there is absolutely no data in this area. */
     4395        *puExtentSector = 0;
     4396        return VINF_SUCCESS;
     4397    }
     4398
     4399    uGTBlock = uSector / (pExtent->cSectorsPerGrain * VMDK_GT_CACHELINE_SIZE);
     4400    uGTHash = vmdkGTCacheHash(pCache, uGTBlock, pExtent->uExtent);
     4401    pGTCacheEntry = &pCache->aGTCache[uGTHash];
     4402    if (    pGTCacheEntry->uExtent != pExtent->uExtent
     4403        ||  pGTCacheEntry->uGTBlock != uGTBlock)
     4404    {
     4405        /* Cache miss, fetch data from disk. */
     4406        PVDMETAXFER pMetaXfer;
     4407        rc = pImage->pInterfaceIOCallbacks->pfnReadMetaAsync(pImage->pInterfaceIO->pvUser,
     4408                                                             pExtent->pFile->pStorage,
     4409                                                             VMDK_SECTOR2BYTE(uGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp),
     4410                                                             aGTDataTmp, sizeof(aGTDataTmp), pIoCtx, &pMetaXfer);
     4411        if (RT_FAILURE(rc))
     4412            return rc;
     4413        /* We can release the metadata transfer immediately. */
     4414        pImage->pInterfaceIOCallbacks->pfnMetaXferRelease(pImage->pInterfaceIO->pvUser, pMetaXfer);
    43654415        pGTCacheEntry->uExtent = pExtent->uExtent;
    43664416        pGTCacheEntry->uGTBlock = uGTBlock;
     
    60166066{
    60176067    PVMDKIMAGE pImage = (PVMDKIMAGE)pvBackendData;
     6068
     6069#if 1
    60186070    bool fAsyncIOSupported = false;
    60196071
     
    60336085
    60346086    return fAsyncIOSupported;
     6087#else
     6088    /* We do not support async I/O for stream optimized VMDK images. */
     6089    return (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED) == 0;
     6090#endif
    60356091}
    60366092
     
    60796135        case VMDKETYPE_ESX_SPARSE:
    60806136#endif /* VBOX_WITH_VMDK_ESX */
    6081             AssertMsgFailed(("Not supported\n"));
     6137            rc = vmdkGetSectorAsync(pImage, pIoCtx, pImage->pGTCache, pExtent,
     6138                                    uSectorExtentRel, &uSectorExtentAbs);
     6139            if (RT_FAILURE(rc))
     6140                goto out;
     6141            /* Clip read range to at most the rest of the grain. */
     6142            cbRead = RT_MIN(cbRead, VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain - uSectorExtentRel % pExtent->cSectorsPerGrain));
     6143            Assert(!(cbRead % 512));
     6144            if (uSectorExtentAbs == 0)
     6145                rc = VERR_VD_BLOCK_FREE;
     6146            else
     6147            {
     6148                AssertMsg(!(pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED), ("Async I/O is not supported for stream optimized VMDK's\n"));
     6149                rc = pImage->pInterfaceIOCallbacks->pfnReadUserAsync(pImage->pInterfaceIO->pvUser,
     6150                                                                     pExtent->pFile->pStorage,
     6151                                                                     VMDK_SECTOR2BYTE(uSectorExtentAbs),
     6152                                                                     pIoCtx, cbRead);
     6153            }
    60826154            break;
    60836155        case VMDKETYPE_VMFS:
     
    61616233        case VMDKETYPE_ESX_SPARSE:
    61626234#endif /* VBOX_WITH_VMDK_ESX */
    6163             AssertMsgFailed(("Not supported\n"));
     6235            rc = vmdkGetSectorAsync(pImage, pIoCtx, pImage->pGTCache, pExtent, uSectorExtentRel,
     6236                                    &uSectorExtentAbs);
     6237            if (RT_FAILURE(rc))
     6238                goto out;
     6239            /* Clip write range to at most the rest of the grain. */
     6240            cbWrite = RT_MIN(cbWrite, VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain - uSectorExtentRel % pExtent->cSectorsPerGrain));
     6241            if (    pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED
     6242                &&  uSectorExtentRel < (uint64_t)pExtent->uLastGrainWritten * pExtent->cSectorsPerGrain)
     6243            {
     6244                rc = VERR_VD_VMDK_INVALID_WRITE;
     6245                goto out;
     6246            }
     6247            if (uSectorExtentAbs == 0)
     6248            {
     6249                if (cbWrite == VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain))
     6250                {
     6251                    /* Full block write to a previously unallocated block.
     6252                     * Check if the caller wants to avoid the automatic alloc. */
     6253                    if (!(fWrite & VD_WRITE_NO_ALLOC))
     6254                    {
     6255                        AssertMsgFailed(("Implement\n"));
     6256#if 0
     6257                        /* Allocate GT and find out where to store the grain. */
     6258                        rc = vmdkAllocGrain(pImage->pGTCache, pExtent,
     6259                                            uSectorExtentRel, pvBuf, cbWrite);
     6260#endif
     6261                    }
     6262                    else
     6263                        rc = VERR_VD_BLOCK_FREE;
     6264                    *pcbPreRead = 0;
     6265                    *pcbPostRead = 0;
     6266                }
     6267                else
     6268                {
     6269                    /* Clip write range to remain in this extent. */
     6270                    cbWrite = RT_MIN(cbWrite, VMDK_SECTOR2BYTE(pExtent->uSectorOffset + pExtent->cNominalSectors - uSectorExtentRel));
     6271                    *pcbPreRead = VMDK_SECTOR2BYTE(uSectorExtentRel % pExtent->cSectorsPerGrain);
     6272                    *pcbPostRead = VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain) - cbWrite - *pcbPreRead;
     6273                    rc = VERR_VD_BLOCK_FREE;
     6274                }
     6275            }
     6276            else
     6277            {
     6278                Assert(!(pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED));
     6279                rc = pImage->pInterfaceIOCallbacks->pfnWriteUserAsync(pImage->pInterfaceIO->pvUser,
     6280                                                                      pExtent->pFile->pStorage,
     6281                                                                      VMDK_SECTOR2BYTE(uSectorExtentAbs),
     6282                                                                      pIoCtx, cbWrite,
     6283                                                                      NULL, NULL);
     6284            }
    61646285            break;
    61656286        case VMDKETYPE_VMFS:
     
    61706291                                                                  pExtent->pFile->pStorage,
    61716292                                                                  VMDK_SECTOR2BYTE(uSectorExtentRel),
    6172                                                                   pIoCtx, cbWrite);
     6293                                                                  pIoCtx, cbWrite, NULL, NULL);
    61736294            break;
    61746295        case VMDKETYPE_ZERO:
     
    62026323                case VMDKETYPE_ESX_SPARSE:
    62036324#endif /* VBOX_WITH_VMDK_ESX */
    6204                     /** Not supported atm. */
    6205                     AssertMsgFailed(("Async I/O not supported for sparse images\n"));
     6325                    /** @todo: Fake success for now */
     6326                    rc = VINF_SUCCESS;
    62066327                    break;
    62076328                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