VirtualBox

Changeset 27977 in vbox for trunk/src


Ignore:
Timestamp:
Apr 4, 2010 7:21:59 PM (15 years ago)
Author:
vboxsync
Message:

VBoxHDD: Async I/O for flat images are back

Location:
trunk/src/VBox/Devices/Storage
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Storage/DrvSCSI.cpp

    r27671 r27977  
    258258                                                             (PPDMDATASEG)paSeg, cSeg, cbTransfer,
    259259                                                             hVScsiIoReq);
    260                     if (RT_FAILURE(rc))
     260                    if (RT_FAILURE(rc) && rc != VERR_VD_ASYNC_IO_IN_PROGRESS)
    261261                        AssertMsgFailed(("%s: Failed to read data %Rrc\n", __FUNCTION__, rc));
    262262                    STAM_REL_COUNTER_ADD(&pThis->StatBytesRead, cbTransfer);
     
    268268                                                              (PPDMDATASEG)paSeg, cSeg, cbTransfer,
    269269                                                              hVScsiIoReq);
    270                     if (RT_FAILURE(rc))
     270                    if (RT_FAILURE(rc) && rc != VERR_VD_ASYNC_IO_IN_PROGRESS)
    271271                        AssertMsgFailed(("%s: Failed to write data %Rrc\n", __FUNCTION__, rc));
    272272                    STAM_REL_COUNTER_ADD(&pThis->StatBytesWritten, cbTransfer);
     
    284284                    VSCSIIoReqCompleted(hVScsiIoReq, VINF_SUCCESS);
    285285                }
     286                else if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
     287                    rc = VINF_SUCCESS;
     288                else if (RT_FAILURE(rc))
     289                {
     290                    if (enmTxDir == VSCSIIOREQTXDIR_READ)
     291                        pThis->pLed->Actual.s.fReading = 0;
     292                    else if (enmTxDir == VSCSIIOREQTXDIR_WRITE)
     293                        pThis->pLed->Actual.s.fWriting = 0;
     294                    else
     295                        AssertMsgFailed(("Invalid transfer direction %u\n", enmTxDir));
     296                    ASMAtomicDecU32(&pThis->StatIoDepth);
     297                    VSCSIIoReqCompleted(hVScsiIoReq, rc);
     298                }
     299                else
     300                    AssertMsgFailed(("Invalid return coe rc=%Rrc\n", rc));
    286301
    287302                break;
  • trunk/src/VBox/Devices/Storage/DrvVD.cpp

    r27976 r27977  
    300300    else
    301301    {
    302         int rc = VINF_VD_ASYNC_IO_FINISHED;
    303         void *pvCallerUser = NULL;
    304 
    305         if (pStorageBackend->pfnCompleted)
    306             rc = pStorageBackend->pfnCompleted(pvUser, &pvCallerUser);
    307         else
    308             pvCallerUser = pvUser;
     302        int rc;
     303
     304        AssertPtr(pStorageBackend->pfnCompleted);
     305        rc = pStorageBackend->pfnCompleted(pvUser);
     306        AssertRC(rc);
    309307
    310308        /* If thread synchronization is active, then signal the end of the
     
    317315            AssertRC(rc2);
    318316        }
    319 
    320         if (rc == VINF_VD_ASYNC_IO_FINISHED)
    321         {
    322             rc = pThis->pDrvMediaAsyncPort->pfnTransferCompleteNotify(pThis->pDrvMediaAsyncPort, pvCallerUser);
    323             AssertRC(rc);
    324         }
    325         else
    326             AssertMsg(rc == VERR_VD_ASYNC_IO_IN_PROGRESS, ("Invalid return code from disk backend rc=%Rrc\n", rc));
    327317    }
    328318}
     
    14821472    }
    14831473
    1484 #if 0 /* Temporary disabled. WIP */
    1485     if (pThis->pDrvMediaAsyncPort)
     1474    if (pThis->pDrvMediaAsyncPort && fUseNewIo)
    14861475        pThis->fAsyncIOSupported = true;
    1487 #else
    1488     pThis->fAsyncIOSupported = false;
    1489 #endif
    14901476
    14911477    unsigned iImageIdx = 0;
  • trunk/src/VBox/Devices/Storage/VBoxHDD.cpp

    r27815 r27977  
    4949#define VD_MERGE_BUFFER_SIZE    (16 * _1M)
    5050
     51/** Maximum number of segments in one I/O task. */
     52#define VD_IO_TASK_SEGMENTS_MAX 64
     53
    5154/**
    5255 * VD async I/O interface storage descriptor.
     
    152155    /** Memory cache for I/O contexts */
    153156    RTMEMCACHE          hMemCacheIoCtx;
     157    /** Memory cache for I/O tasks. */
     158    RTMEMCACHE          hMemCacheIoTask;
    154159};
    155160
     
    192197    /** User argument 1 passed on completion. */
    193198    void                        *pvUser2;
     199    /** Disk this is request is for. */
     200    PVBOXHDD                     pDisk;
     201    /** Return code. */
     202    int                          rcReq;
    194203    /** Transfer direction */
    195204    VDIOCTXTXDIR                 enmTxDir;
     
    208217    /** Number of bytes left in the current buffer. */
    209218    size_t                       cbBufLeft;
     219    /** How many meta data transfers are pending. */
     220    volatile uint32_t            cMetaTransfersPending;
    210221} VDIOCTX;
     222
     223/**
     224 * I/O task.
     225 */
     226typedef struct VDIOTASK
     227{
     228    /** Pointer to the I/O context the task belongs. */
     229    PVDIOCTX                     pIoCtx;
     230    /** Flag whether this is a meta data transfer. */
     231    bool                         fMeta;
     232    /** Type dependent data. */
     233    union
     234    {
     235        /** User data transfer. */
     236        struct
     237        {
     238            /** Number of bytes this task transfered. */
     239            uint32_t             cbTransfer;
     240        } User;
     241        /** Meta data transfer. */
     242        struct
     243        {
     244            /** Transfer direction (Read/Write) */
     245            VDIOCTXTXDIR         enmTxDir;
     246            /** Completion callback from the backend */
     247            PFNVDMETACOMPLETED   pfnMetaComplete;
     248            /** User data */
     249            void                *pvMetaUser;
     250        } Meta;
     251    } Type;
     252} VDIOTASK, *PVDIOTASK;
    211253
    212254/**
     
    482524        pIoCtx->pvUser1        = pvUser1;
    483525        pIoCtx->pvUser2        = pvUser2;
     526        pIoCtx->pDisk          = pDisk;
    484527        pIoCtx->enmTxDir       = enmTxDir;
    485528        pIoCtx->cbTransferLeft = cbTransfer;
     
    490533        pIoCtx->pbBuf          = (uint8_t *)pIoCtx->paDataSeg[0].pvSeg;
    491534        pIoCtx->cbBufLeft      = pIoCtx->paDataSeg[0].cbSeg;
     535        pIoCtx->cMetaTransfersPending = 0;
    492536    }
    493537
     
    495539}
    496540
     541static PVDIOTASK vdIoTaskUserAlloc(PVBOXHDD pDisk, PVDIOCTX pIoCtx, uint32_t cbTransfer)
     542{
     543    PVDIOTASK pIoTask = NULL;
     544
     545    pIoTask = (PVDIOTASK)RTMemCacheAlloc(pDisk->hMemCacheIoTask);
     546    if (pIoTask)
     547    {
     548        pIoTask->pIoCtx               = pIoCtx;
     549        pIoTask->fMeta                = false;
     550        pIoTask->Type.User.cbTransfer = cbTransfer;
     551    }
     552
     553    return pIoTask;
     554}
     555
     556static PVDIOTASK vdIoTaskMetaAlloc(PVBOXHDD pDisk, PVDIOCTX pIoCtx, VDIOCTXTXDIR enmTxDir,
     557                                   PFNVDMETACOMPLETED pfnMetaComplete, void *pvMetaUser)
     558{
     559    PVDIOTASK pIoTask = NULL;
     560
     561    pIoTask = (PVDIOTASK)RTMemCacheAlloc(pDisk->hMemCacheIoTask);
     562    if (pIoTask)
     563    {
     564        pIoTask->pIoCtx                      = pIoCtx;
     565        pIoTask->fMeta                       = true;
     566        pIoTask->Type.Meta.enmTxDir          = enmTxDir;
     567        pIoTask->Type.Meta.pfnMetaComplete   = pfnMetaComplete;
     568        pIoTask->Type.Meta.pvMetaUser        = pvMetaUser;
     569    }
     570
     571    return pIoTask;
     572}
     573
    497574static void vdIoCtxFree(PVBOXHDD pDisk, PVDIOCTX pIoCtx)
    498575{
    499576    RTMemCacheFree(pDisk->hMemCacheIoCtx, pIoCtx);
     577}
     578
     579static void vdIoTaskFree(PVBOXHDD pDisk, PVDIOTASK pIoTask)
     580{
     581    pIoTask->pIoCtx = NULL;
     582    RTMemCacheFree(pDisk->hMemCacheIoTask, pIoTask);
    500583}
    501584
     
    9321015}
    9331016
     1017/**
     1018 * internal: write buffer to the image, taking care of block boundaries and
     1019 * write optimizations - async version.
     1020 */
     1021static int vdWriteHelperAsync(PVBOXHDD pDisk, PVDIMAGE pImage, PVDIMAGE pImageParentOverride,
     1022                              PVDIOCTX pIoCtx, uint64_t uOffset, size_t cbWrite)
     1023{
     1024    int rc;
     1025    unsigned fWrite;
     1026    size_t cbThisWrite;
     1027    size_t cbPreRead, cbPostRead;
     1028
     1029    /* Loop until all written. */
     1030    do
     1031    {
     1032        /* Try to write the possibly partial block to the last opened image.
     1033         * This works when the block is already allocated in this image or
     1034         * if it is a full-block write (and allocation isn't suppressed below).
     1035         * For image formats which don't support zero blocks, it's beneficial
     1036         * to avoid unnecessarily allocating unchanged blocks. This prevents
     1037         * unwanted expanding of images. VMDK is an example. */
     1038        cbThisWrite = cbWrite;
     1039        fWrite =   (pImage->uOpenFlags & VD_OPEN_FLAGS_HONOR_SAME)
     1040                 ? 0 : VD_WRITE_NO_ALLOC;
     1041        rc = pImage->Backend->pfnAsyncWrite(pImage->pvBackendData, uOffset,
     1042                                            cbThisWrite, pIoCtx,
     1043                                            &cbThisWrite, &cbPreRead,
     1044                                            &cbPostRead, fWrite);
     1045#if 0
     1046        if (rc == VERR_VD_BLOCK_FREE)
     1047        {
     1048            void *pvTmp = RTMemTmpAlloc(cbPreRead + cbThisWrite + cbPostRead);
     1049            AssertBreakStmt(VALID_PTR(pvTmp), rc = VERR_NO_MEMORY);
     1050
     1051            if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_HONOR_SAME))
     1052            {
     1053                /* Optimized write, suppress writing to a so far unallocated
     1054                 * block if the data is in fact not changed. */
     1055                rc = vdWriteHelperOptimized(pDisk, pImage, pImageParentOverride,
     1056                                            uOffset, cbWrite,
     1057                                            cbThisWrite, cbPreRead, cbPostRead,
     1058                                            pvBuf, pvTmp);
     1059            }
     1060            else
     1061            {
     1062                /* Normal write, not optimized in any way. The block will
     1063                 * be written no matter what. This will usually (unless the
     1064                 * backend has some further optimization enabled) cause the
     1065                 * block to be allocated. */
     1066                rc = vdWriteHelperStandard(pDisk, pImage, pImageParentOverride,
     1067                                           uOffset, cbWrite,
     1068                                           cbThisWrite, cbPreRead, cbPostRead,
     1069                                           pvBuf, pvTmp);
     1070            }
     1071            RTMemTmpFree(pvTmp);
     1072            if (RT_FAILURE(rc))
     1073                break;
     1074        }
     1075#endif
     1076
     1077        if (RT_SUCCESS(rc))
     1078        {
     1079            /* Success and no async task is pending. */
     1080            Assert(rc == VINF_SUCCESS);
     1081            ASMAtomicSubU32(&pIoCtx->cbTransferLeft, cbThisWrite);
     1082        }
     1083
     1084        cbWrite -= cbThisWrite;
     1085        uOffset += cbThisWrite;
     1086    } while (cbWrite != 0 && (   RT_SUCCESS(rc)
     1087                              || rc == VERR_VD_ASYNC_IO_IN_PROGRESS));
     1088
     1089    return rc;
     1090}
    9341091
    9351092/**
     
    11831340}
    11841341
    1185 static int vdIOReqCompleted(void *pvUser, void **ppvCaller)
    1186 {
     1342static int vdIOReqCompleted(void *pvUser)
     1343{
     1344    PVDIOTASK pIoTask = (PVDIOTASK)pvUser;
     1345    PVDIOCTX  pIoCtx  = pIoTask->pIoCtx;
     1346    PVBOXHDD  pDisk   = pIoCtx->pDisk;
     1347    uint32_t  cbLeft  = ASMAtomicSubU32(&pIoCtx->cbTransferLeft, pIoTask->Type.User.cbTransfer);
     1348
     1349    Assert(!pIoTask->fMeta); /* No meta tasks spawned at the moment. */
     1350
     1351    if (cbLeft == pIoTask->Type.User.cbTransfer)
     1352    {
     1353        vdIoTaskFree(pDisk, pIoTask);
     1354        pIoCtx->pfnComplete(pIoCtx->pvUser1, pIoCtx->pvUser2);
     1355        vdIoCtxFree(pDisk, pIoCtx);
     1356    }
     1357    else
     1358        vdIoTaskFree(pDisk, pIoTask);
     1359
    11871360    return VINF_SUCCESS;
    11881361}
     
    12801453                             size_t cbRead)
    12811454{
    1282     return VERR_NOT_IMPLEMENTED;
     1455    int rc = VINF_SUCCESS;
     1456    PVBOXHDD pDisk = (PVBOXHDD)pvUser;
     1457
     1458    /* Build the S/G array and spawn a new I/O task */
     1459    while (cbRead)
     1460    {
     1461        PDMDATASEG  aSeg[VD_IO_TASK_SEGMENTS_MAX];
     1462        unsigned    cSegments  = 0;
     1463        unsigned    cbTaskRead = 0;
     1464
     1465        while (   cbRead
     1466               && cSegments < VD_IO_TASK_SEGMENTS_MAX)
     1467        {
     1468
     1469            size_t      cbThisSeg = cbRead;
     1470            uint8_t    *pbBuf     = NULL;
     1471
     1472            pbBuf = vdIoCtxGetBuffer(pIoCtx, &cbThisSeg);
     1473
     1474            aSeg[cSegments].cbSeg = cbThisSeg;
     1475            aSeg[cSegments].pvSeg = pbBuf;
     1476            cSegments++;
     1477            cbRead     -= cbThisSeg;
     1478            cbTaskRead += cbThisSeg;
     1479        }
     1480
     1481        PVDIOTASK pIoTask = vdIoTaskUserAlloc(pDisk, pIoCtx, cbTaskRead);
     1482
     1483        if (!pIoTask)
     1484            return VERR_NO_MEMORY;
     1485
     1486        void *pvTask;
     1487        int rc2 = pDisk->pInterfaceAsyncIOCallbacks->pfnReadAsync(pDisk->pInterfaceAsyncIO->pvUser,
     1488                                                                  pIoStorage->u.pStorage,
     1489                                                                  uOffset, aSeg, cSegments,
     1490                                                                  cbTaskRead, pIoTask,
     1491                                                                  &pvTask);
     1492        if (rc2 == VINF_SUCCESS)
     1493            vdIoTaskFree(pDisk, pIoTask);
     1494        else if (rc2 == VERR_VD_ASYNC_IO_IN_PROGRESS)
     1495            rc = VERR_VD_ASYNC_IO_IN_PROGRESS;
     1496        else if (RT_FAILURE(rc2))
     1497            rc = rc2;
     1498
     1499        uOffset += cbTaskRead;
     1500    }
     1501
     1502    return rc;
    12831503}
    12841504
     
    12871507                              size_t cbWrite)
    12881508{
    1289     return VERR_NOT_IMPLEMENTED;
     1509    int rc = VINF_SUCCESS;
     1510    PVBOXHDD pDisk = (PVBOXHDD)pvUser;
     1511
     1512    /* Build the S/G array and spawn a new I/O task */
     1513    while (cbWrite)
     1514    {
     1515        PDMDATASEG  aSeg[VD_IO_TASK_SEGMENTS_MAX];
     1516        unsigned    cSegments   = 0;
     1517        unsigned    cbTaskWrite = 0;
     1518
     1519        while (   cbWrite
     1520               && cSegments < VD_IO_TASK_SEGMENTS_MAX)
     1521        {
     1522
     1523            size_t      cbThisSeg = cbWrite;
     1524            uint8_t    *pbBuf     = NULL;
     1525
     1526            pbBuf = vdIoCtxGetBuffer(pIoCtx, &cbThisSeg);
     1527
     1528            aSeg[cSegments].cbSeg = cbThisSeg;
     1529            aSeg[cSegments].pvSeg = pbBuf;
     1530            cSegments++;
     1531            cbWrite     -= cbThisSeg;
     1532            cbTaskWrite += cbThisSeg;
     1533        }
     1534
     1535        PVDIOTASK pIoTask = vdIoTaskUserAlloc(pDisk, pIoCtx, cbTaskWrite);
     1536
     1537        if (!pIoTask)
     1538            return VERR_NO_MEMORY;
     1539
     1540        void *pvTask;
     1541        int rc2 = pDisk->pInterfaceAsyncIOCallbacks->pfnWriteAsync(pDisk->pInterfaceAsyncIO->pvUser,
     1542                                                                   pIoStorage->u.pStorage,
     1543                                                                   uOffset, aSeg, cSegments,
     1544                                                                   cbTaskWrite, pIoTask,
     1545                                                                   &pvTask);
     1546        if (rc2 == VINF_SUCCESS)
     1547            vdIoTaskFree(pDisk, pIoTask);
     1548        else if (rc2 == VERR_VD_ASYNC_IO_IN_PROGRESS)
     1549            rc = VERR_VD_ASYNC_IO_IN_PROGRESS;
     1550        else if (RT_FAILURE(rc2))
     1551            rc = rc2;
     1552
     1553        uOffset += cbTaskWrite;
     1554    }
     1555
     1556    return rc;
    12901557}
    12911558
     
    15851852            pDisk->pInterfaceThreadSyncCallbacks = NULL;
    15861853
    1587             /* Create the mem cache */
     1854            /* Create the I/O ctx cache */
    15881855            rc = RTMemCacheCreate(&pDisk->hMemCacheIoCtx, sizeof(VDIOCTX), 0, UINT32_MAX,
    15891856                                  NULL, NULL, NULL, 0);
     
    15931860                break;
    15941861            }
     1862
     1863            /* Create the I/O task cache */
     1864            rc = RTMemCacheCreate(&pDisk->hMemCacheIoTask, sizeof(VDIOTASK), 0, UINT32_MAX,
     1865                                  NULL, NULL, NULL, 0);
     1866            if (RT_FAILURE(rc))
     1867            {
     1868                RTMemCacheDestroy(pDisk->hMemCacheIoCtx);
     1869                RTMemFree(pDisk);
     1870                break;
     1871            }
     1872
    15951873
    15961874            pDisk->pInterfaceError = VDInterfaceGet(pVDIfsDisk, VDINTERFACETYPE_ERROR);
     
    16831961        VDCloseAll(pDisk);
    16841962        RTMemCacheDestroy(pDisk->hMemCacheIoCtx);
     1963        RTMemCacheDestroy(pDisk->hMemCacheIoTask);
    16851964        RTMemFree(pDisk);
    16861965    } while (0);
     
    49755254    int rc2;
    49765255    bool fLockRead = false;
     5256    PVDIOCTX pIoCtx;
    49775257
    49785258    LogFlowFunc(("pDisk=%#p uOffset=%llu paSeg=%p cSeg=%u cbRead=%zu\n",
     
    50045284                           rc = VERR_INVALID_PARAMETER);
    50055285
    5006         PVDIOCTX pIoCtx = vdIoCtxAlloc(pDisk, VDIOCTXTXDIR_READ, uOffset,
    5007                                        cbRead, paSeg, cSeg,
    5008                                        pfnComplete, pvUser1, pvUser2);
     5286        pIoCtx = vdIoCtxAlloc(pDisk, VDIOCTXTXDIR_READ, uOffset,
     5287                              cbRead, paSeg, cSeg,
     5288                              pfnComplete, pvUser1, pvUser2);
    50095289        if (!pIoCtx)
    50105290        {
     
    50265306
    50275307    if (rc == VINF_SUCCESS)
     5308    {
     5309        vdIoCtxFree(pDisk, pIoCtx);
    50285310        rc = VINF_VD_ASYNC_IO_FINISHED;
     5311    }
    50295312
    50305313    LogFlowFunc(("returns %Rrc\n", rc));
     
    50415324    int rc2;
    50425325    bool fLockWrite = false;
     5326    PVDIOCTX pIoCtx;
    50435327
    50445328    LogFlowFunc(("pDisk=%#p uOffset=%llu paSeg=%p cSeg=%u cbWrite=%zu\n",
     
    50605344                           ("cSeg=%zu\n", cSeg),
    50615345                           rc = VERR_INVALID_PARAMETER);
    5062 #if 0
     5346
    50635347        rc2 = vdThreadStartWrite(pDisk);
    50645348        AssertRC(rc2);
     
    50705354                           rc = VERR_INVALID_PARAMETER);
    50715355
     5356        pIoCtx = vdIoCtxAlloc(pDisk, VDIOCTXTXDIR_READ, uOffset,
     5357                              cbWrite, paSeg, cSeg,
     5358                              pfnComplete, pvUser1, pvUser2);
     5359        if (!pIoCtx)
     5360        {
     5361            rc = VERR_NO_MEMORY;
     5362            break;
     5363        }
     5364
    50725365        PVDIMAGE pImage = pDisk->pLast;
    50735366        AssertPtrBreakStmt(pImage, rc = VERR_VD_NOT_OPENED);
    50745367
    5075         vdSetModifiedFlag(pDisk);
    5076         rc = pImage->Backend->pfnAsyncWrite(pImage->pvBackendData,
    5077                                             uOffset, cbWrite,
    5078                                             paSeg, cSeg, pvUser);
    5079 #endif
     5368        rc = vdWriteHelperAsync(pDisk, pImage, NULL, pIoCtx, uOffset, cbWrite);
     5369
    50805370    } while (0);
    50815371
     
    50875377
    50885378    if (rc == VINF_SUCCESS)
     5379    {
     5380        vdIoCtxFree(pDisk, pIoCtx);
    50895381        rc = VINF_VD_ASYNC_IO_FINISHED;
     5382    }
    50905383
    50915384    LogFlowFunc(("returns %Rrc\n", rc));
  • trunk/src/VBox/Devices/Storage/VDIHDDCore.cpp

    r27976 r27977  
    19761976static bool vdiIsAsyncIOSupported(void *pBackendData)
    19771977{
     1978#if 0
     1979    return true;
     1980#else
    19781981    return false;
    1979 }
    1980 
    1981 static int vdiAsyncRead(void *pvBackendData, uint64_t uOffset, size_t cbRead,
     1982#endif
     1983}
     1984
     1985static int vdiAsyncRead(void *pvBackendData, uint64_t uOffset, size_t cbToRead,
    19821986                        PVDIOCTX pIoCtx, size_t *pcbActuallyRead)
    19831987{
    1984     int rc = VERR_NOT_IMPLEMENTED;
     1988    LogFlowFunc(("pvBackendData=%#p uOffset=%llu pIoCtx=%#p cbToRead=%zu pcbActuallyRead=%#p\n",
     1989                 pvBackendData, uOffset, pIoCtx, cbToRead, pcbActuallyRead));
     1990    PVDIIMAGEDESC pImage = (PVDIIMAGEDESC)pvBackendData;
     1991    unsigned uBlock;
     1992    unsigned offRead;
     1993    int rc;
     1994
     1995    AssertPtr(pImage);
     1996    Assert(!(uOffset % 512));
     1997    Assert(!(cbToRead % 512));
     1998
     1999    if (   uOffset + cbToRead > getImageDiskSize(&pImage->Header)
     2000        || !VALID_PTR(pIoCtx)
     2001        || !cbToRead)
     2002    {
     2003        rc = VERR_INVALID_PARAMETER;
     2004        goto out;
     2005    }
     2006
     2007    /* Calculate starting block number and offset inside it. */
     2008    uBlock = (unsigned)(uOffset >> pImage->uShiftOffset2Index);
     2009    offRead = (unsigned)uOffset & pImage->uBlockMask;
     2010
     2011    /* Clip read range to at most the rest of the block. */
     2012    cbToRead = RT_MIN(cbToRead, getImageBlockSize(&pImage->Header) - offRead);
     2013    Assert(!(cbToRead % 512));
     2014
     2015    if (pImage->paBlocks[uBlock] == VDI_IMAGE_BLOCK_FREE)
     2016        rc = VERR_VD_BLOCK_FREE;
     2017    else if (pImage->paBlocks[uBlock] == VDI_IMAGE_BLOCK_ZERO)
     2018    {
     2019        size_t cbSet;
     2020
     2021        cbSet = pImage->pInterfaceIOCallbacks->pfnIoCtxSet(pImage->pInterfaceIO->pvUser,
     2022                                                           pIoCtx, 0, cbToRead);
     2023        Assert(cbSet == cbToRead);
     2024
     2025        rc = VINF_SUCCESS;
     2026    }
     2027    else
     2028    {
     2029        /* Block present in image file, read relevant data. */
     2030        uint64_t u64Offset = (uint64_t)pImage->paBlocks[uBlock] * pImage->cbTotalBlockData
     2031                           + (pImage->offStartData + pImage->offStartBlockData + offRead);
     2032        rc = pImage->pInterfaceIOCallbacks->pfnReadUserAsync(pImage->pInterfaceIO->pvUser,
     2033                                                             pImage->pStorage,
     2034                                                             u64Offset,
     2035                                                             pIoCtx, cbToRead);
     2036    }
     2037
     2038    if (pcbActuallyRead)
     2039        *pcbActuallyRead = cbToRead;
     2040
     2041out:
    19852042    LogFlowFunc(("returns %Rrc\n", rc));
    19862043    return rc;
    19872044}
    19882045
    1989 static int vdiAsyncWrite(void *pvBackendData, uint64_t uOffset, size_t cbWrite,
     2046static int vdiAsyncWrite(void *pvBackendData, uint64_t uOffset, size_t cbToWrite,
    19902047                         PVDIOCTX pIoCtx,
    19912048                         size_t *pcbWriteProcess, size_t *pcbPreRead,
    19922049                         size_t *pcbPostRead, unsigned fWrite)
    19932050{
    1994     int rc = VERR_NOT_IMPLEMENTED;
     2051    LogFlowFunc(("pvBackendData=%#p uOffset=%llu pIoCtx=%#p cbToWrite=%zu pcbWriteProcess=%#p pcbPreRead=%#p pcbPostRead=%#p\n",
     2052                 pvBackendData, uOffset, pIoCtx, cbToWrite, pcbWriteProcess, pcbPreRead, pcbPostRead));
     2053    PVDIIMAGEDESC pImage = (PVDIIMAGEDESC)pvBackendData;
     2054    unsigned uBlock;
     2055    unsigned offWrite;
     2056    int rc = VINF_SUCCESS;
     2057
     2058    AssertPtr(pImage);
     2059    Assert(!(uOffset % 512));
     2060    Assert(!(cbToWrite % 512));
     2061
     2062    if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
     2063    {
     2064        rc = VERR_VD_IMAGE_READ_ONLY;
     2065        goto out;
     2066    }
     2067
     2068    if (!VALID_PTR(pIoCtx) || !cbToWrite)
     2069    {
     2070        rc = VERR_INVALID_PARAMETER;
     2071        goto out;
     2072    }
     2073
     2074    /* No size check here, will do that later.  For dynamic images which are
     2075     * not multiples of the block size in length, this would prevent writing to
     2076     * the last grain. */
     2077
     2078    /* Calculate starting block number and offset inside it. */
     2079    uBlock = (unsigned)(uOffset >> pImage->uShiftOffset2Index);
     2080    offWrite = (unsigned)uOffset & pImage->uBlockMask;
     2081
     2082    /* Clip write range to at most the rest of the block. */
     2083    cbToWrite = RT_MIN(cbToWrite, getImageBlockSize(&pImage->Header) - offWrite);
     2084    Assert(!(cbToWrite % 512));
     2085
     2086    do
     2087    {
     2088        if (!IS_VDI_IMAGE_BLOCK_ALLOCATED(pImage->paBlocks[uBlock]))
     2089        {
     2090            /* Block is either free or zero. */
     2091            if (   !(pImage->uOpenFlags & VD_OPEN_FLAGS_HONOR_ZEROES)
     2092                && (   pImage->paBlocks[uBlock] == VDI_IMAGE_BLOCK_ZERO
     2093                    || cbToWrite == getImageBlockSize(&pImage->Header)))
     2094            {
     2095#if 0 /** @todo Provide interface to check an I/O context for a specific value */
     2096                /* If the destination block is unallocated at this point, it's
     2097                 * either a zero block or a block which hasn't been used so far
     2098                 * (which also means that it's a zero block. Don't need to write
     2099                 * anything to this block  if the data consists of just zeroes. */
     2100                Assert(!(cbToWrite % 4));
     2101                Assert(cbToWrite * 8 <= UINT32_MAX);
     2102                if (ASMBitFirstSet((volatile void *)pvBuf, (uint32_t)cbToWrite * 8) == -1)
     2103                {
     2104                    pImage->paBlocks[uBlock] = VDI_IMAGE_BLOCK_ZERO;
     2105                    break;
     2106                }
     2107#endif
     2108            }
     2109
     2110            if (cbToWrite == getImageBlockSize(&pImage->Header))
     2111            {
     2112                /* Full block write to previously unallocated block.
     2113                 * Allocate block and write data. */
     2114                Assert(!offWrite);
     2115                unsigned cBlocksAllocated = getImageBlocksAllocated(&pImage->Header);
     2116                uint64_t u64Offset = (uint64_t)cBlocksAllocated * pImage->cbTotalBlockData
     2117                                   + (pImage->offStartData + pImage->offStartBlockData);
     2118                rc = pImage->pInterfaceIOCallbacks->pfnWriteUserAsync(pImage->pInterfaceIO->pvUser,
     2119                                                                      pImage->pStorage,
     2120                                                                      u64Offset,
     2121                                                                      pIoCtx, cbToWrite);
     2122                if (RT_UNLIKELY(RT_FAILURE_NP(rc) && (rc != VERR_VD_ASYNC_IO_IN_PROGRESS)))
     2123                    goto out;
     2124                pImage->paBlocks[uBlock] = cBlocksAllocated;
     2125                setImageBlocksAllocated(&pImage->Header, cBlocksAllocated + 1);
     2126
     2127                /** @todo Async */
     2128                rc = vdiUpdateBlockInfo(pImage, uBlock);
     2129                if (RT_FAILURE(rc))
     2130                    goto out;
     2131
     2132                *pcbPreRead = 0;
     2133                *pcbPostRead = 0;
     2134            }
     2135            else
     2136            {
     2137                /* Trying to do a partial write to an unallocated block. Don't do
     2138                 * anything except letting the upper layer know what to do. */
     2139                *pcbPreRead = offWrite % getImageBlockSize(&pImage->Header);
     2140                *pcbPostRead = getImageBlockSize(&pImage->Header) - cbToWrite - *pcbPreRead;
     2141                rc = VERR_VD_BLOCK_FREE;
     2142            }
     2143        }
     2144        else
     2145        {
     2146            /* Block present in image file, write relevant data. */
     2147            uint64_t u64Offset = (uint64_t)pImage->paBlocks[uBlock] * pImage->cbTotalBlockData
     2148                               + (pImage->offStartData + pImage->offStartBlockData + offWrite);
     2149            rc = pImage->pInterfaceIOCallbacks->pfnWriteUserAsync(pImage->pInterfaceIO->pvUser,
     2150                                                                  pImage->pStorage,
     2151                                                                  u64Offset,
     2152                                                                  pIoCtx, cbToWrite);
     2153        }
     2154    } while (0);
     2155
     2156    if (pcbWriteProcess)
     2157        *pcbWriteProcess = cbToWrite;
     2158
     2159out:
    19952160    LogFlowFunc(("returns %Rrc\n", rc));
    19962161    return rc;
     
    22472412    /* uBackendCaps */
    22482413      VD_CAP_UUID | VD_CAP_CREATE_FIXED | VD_CAP_CREATE_DYNAMIC
    2249     | VD_CAP_DIFF | VD_CAP_FILE,
     2414    | VD_CAP_DIFF | VD_CAP_FILE
     2415#if 0
     2416    | VD_CAP_ASYNC
     2417#endif
     2418    ,
    22502419    /* papszFileExtensions */
    22512420    s_apszVdiFileExtensions,
  • trunk/src/VBox/Devices/Storage/VmdkHDDCore.cpp

    r27808 r27977  
    58565856static bool vmdkIsAsyncIOSupported(void *pvBackendData)
    58575857{
    5858     return false;
     5858    PVMDKIMAGE pImage = (PVMDKIMAGE)pvBackendData;
     5859    bool fAsyncIOSupported = false;
     5860
     5861    if (pImage)
     5862    {
     5863        fAsyncIOSupported = true;
     5864        for (unsigned i = 0; i < pImage->cExtents; i++)
     5865        {
     5866            if  (    pImage->pExtents[i].enmType != VMDKETYPE_FLAT
     5867                 &&  pImage->pExtents[i].enmType != VMDKETYPE_ZERO)
     5868            {
     5869                fAsyncIOSupported = false;
     5870                break; /* Stop search */
     5871            }
     5872        }
     5873    }
     5874
     5875    return fAsyncIOSupported;
    58595876}
    58605877
     
    58625879                         PVDIOCTX pIoCtx, size_t *pcbActuallyRead)
    58635880{
    5864     int rc = VERR_NOT_IMPLEMENTED;
     5881    LogFlowFunc(("pvBackendData=%#p uOffset=%llu pIoCtx=%#p cbToRead=%zu pcbActuallyRead=%#p\n",
     5882                 pvBackendData, uOffset, pIoCtx, cbRead, pcbActuallyRead));
     5883    PVMDKIMAGE pImage = (PVMDKIMAGE)pvBackendData;
     5884    PVMDKEXTENT pExtent;
     5885    uint64_t uSectorExtentRel;
     5886    uint64_t uSectorExtentAbs;
     5887    int rc;
     5888
     5889    AssertPtr(pImage);
     5890    Assert(uOffset % 512 == 0);
     5891    Assert(cbRead % 512 == 0);
     5892
     5893    if (   uOffset + cbRead > pImage->cbSize
     5894        || cbRead == 0)
     5895    {
     5896        rc = VERR_INVALID_PARAMETER;
     5897        goto out;
     5898    }
     5899
     5900    rc = vmdkFindExtent(pImage, VMDK_BYTE2SECTOR(uOffset),
     5901                        &pExtent, &uSectorExtentRel);
     5902    if (RT_FAILURE(rc))
     5903        goto out;
     5904
     5905    /* Check access permissions as defined in the extent descriptor. */
     5906    if (pExtent->enmAccess == VMDKACCESS_NOACCESS)
     5907    {
     5908        rc = VERR_VD_VMDK_INVALID_STATE;
     5909        goto out;
     5910    }
     5911
     5912    /* Clip read range to remain in this extent. */
     5913    cbRead = RT_MIN(cbRead, VMDK_SECTOR2BYTE(pExtent->uSectorOffset + pExtent->cNominalSectors - uSectorExtentRel));
     5914
     5915    /* Handle the read according to the current extent type. */
     5916    switch (pExtent->enmType)
     5917    {
     5918        case VMDKETYPE_HOSTED_SPARSE:
     5919#ifdef VBOX_WITH_VMDK_ESX
     5920        case VMDKETYPE_ESX_SPARSE:
     5921#endif /* VBOX_WITH_VMDK_ESX */
     5922            AssertMsgFailed(("Not supported\n"));
     5923            break;
     5924        case VMDKETYPE_VMFS:
     5925        case VMDKETYPE_FLAT:
     5926            rc = pImage->pInterfaceIOCallbacks->pfnReadUserAsync(pImage->pInterfaceIO->pvUser,
     5927                                                                 pExtent->pFile->pStorage,
     5928                                                                 VMDK_SECTOR2BYTE(uSectorExtentRel),
     5929                                                                 pIoCtx, cbRead);
     5930            break;
     5931        case VMDKETYPE_ZERO:
     5932            size_t cbSet;
     5933
     5934            cbSet = pImage->pInterfaceIOCallbacks->pfnIoCtxSet(pImage->pInterfaceIO->pvUser,
     5935                                                               pIoCtx, 0, cbRead);
     5936            Assert(cbSet == cbRead);
     5937
     5938            rc = VINF_SUCCESS;
     5939            break;
     5940    }
     5941    if (pcbActuallyRead)
     5942        *pcbActuallyRead = cbRead;
     5943
     5944out:
    58655945    LogFlowFunc(("returns %Rrc\n", rc));
    58665946    return rc;
     
    58725952                          size_t *pcbPostRead, unsigned fWrite)
    58735953{
    5874     int rc = VERR_NOT_IMPLEMENTED;
     5954    LogFlowFunc(("pvBackendData=%#p uOffset=%llu pIoCtx=%#p cbToWrite=%zu pcbWriteProcess=%#p pcbPreRead=%#p pcbPostRead=%#p\n",
     5955                 pvBackendData, uOffset, pIoCtx, cbWrite, pcbWriteProcess, pcbPreRead, pcbPostRead));
     5956    PVMDKIMAGE pImage = (PVMDKIMAGE)pvBackendData;
     5957    PVMDKEXTENT pExtent;
     5958    uint64_t uSectorExtentRel;
     5959    uint64_t uSectorExtentAbs;
     5960    int rc;
     5961
     5962    AssertPtr(pImage);
     5963    Assert(uOffset % 512 == 0);
     5964    Assert(cbWrite % 512 == 0);
     5965
     5966    if (pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
     5967    {
     5968        rc = VERR_VD_IMAGE_READ_ONLY;
     5969        goto out;
     5970    }
     5971
     5972    if (cbWrite == 0)
     5973    {
     5974        rc = VERR_INVALID_PARAMETER;
     5975        goto out;
     5976    }
     5977
     5978    /* No size check here, will do that later when the extent is located.
     5979     * There are sparse images out there which according to the spec are
     5980     * invalid, because the total size is not a multiple of the grain size.
     5981     * Also for sparse images which are stitched together in odd ways (not at
     5982     * grain boundaries, and with the nominal size not being a multiple of the
     5983     * grain size), this would prevent writing to the last grain. */
     5984
     5985    rc = vmdkFindExtent(pImage, VMDK_BYTE2SECTOR(uOffset),
     5986                        &pExtent, &uSectorExtentRel);
     5987    if (RT_FAILURE(rc))
     5988        goto out;
     5989
     5990    /* Check access permissions as defined in the extent descriptor. */
     5991    if (pExtent->enmAccess != VMDKACCESS_READWRITE)
     5992    {
     5993        rc = VERR_VD_VMDK_INVALID_STATE;
     5994        goto out;
     5995    }
     5996
     5997    /* Handle the write according to the current extent type. */
     5998    switch (pExtent->enmType)
     5999    {
     6000        case VMDKETYPE_HOSTED_SPARSE:
     6001#ifdef VBOX_WITH_VMDK_ESX
     6002        case VMDKETYPE_ESX_SPARSE:
     6003#endif /* VBOX_WITH_VMDK_ESX */
     6004            AssertMsgFailed(("Not supported\n"));
     6005            break;
     6006        case VMDKETYPE_VMFS:
     6007        case VMDKETYPE_FLAT:
     6008            /* Clip write range to remain in this extent. */
     6009            cbWrite = RT_MIN(cbWrite, VMDK_SECTOR2BYTE(pExtent->uSectorOffset + pExtent->cNominalSectors - uSectorExtentRel));
     6010            rc = pImage->pInterfaceIOCallbacks->pfnWriteUserAsync(pImage->pInterfaceIO->pvUser,
     6011                                                                  pExtent->pFile->pStorage,
     6012                                                                  VMDK_SECTOR2BYTE(uSectorExtentRel),
     6013                                                                  pIoCtx, cbWrite);
     6014            break;
     6015        case VMDKETYPE_ZERO:
     6016            /* Clip write range to remain in this extent. */
     6017            cbWrite = RT_MIN(cbWrite, VMDK_SECTOR2BYTE(pExtent->uSectorOffset + pExtent->cNominalSectors - uSectorExtentRel));
     6018            break;
     6019    }
     6020    if (pcbWriteProcess)
     6021        *pcbWriteProcess = cbWrite;
     6022
     6023out:
    58756024    LogFlowFunc(("returns %Rrc\n", rc));
    58766025    return rc;
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