- Timestamp:
- Apr 4, 2010 7:21:59 PM (15 years ago)
- Location:
- trunk/src/VBox/Devices/Storage
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Storage/DrvSCSI.cpp
r27671 r27977 258 258 (PPDMDATASEG)paSeg, cSeg, cbTransfer, 259 259 hVScsiIoReq); 260 if (RT_FAILURE(rc) )260 if (RT_FAILURE(rc) && rc != VERR_VD_ASYNC_IO_IN_PROGRESS) 261 261 AssertMsgFailed(("%s: Failed to read data %Rrc\n", __FUNCTION__, rc)); 262 262 STAM_REL_COUNTER_ADD(&pThis->StatBytesRead, cbTransfer); … … 268 268 (PPDMDATASEG)paSeg, cSeg, cbTransfer, 269 269 hVScsiIoReq); 270 if (RT_FAILURE(rc) )270 if (RT_FAILURE(rc) && rc != VERR_VD_ASYNC_IO_IN_PROGRESS) 271 271 AssertMsgFailed(("%s: Failed to write data %Rrc\n", __FUNCTION__, rc)); 272 272 STAM_REL_COUNTER_ADD(&pThis->StatBytesWritten, cbTransfer); … … 284 284 VSCSIIoReqCompleted(hVScsiIoReq, VINF_SUCCESS); 285 285 } 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)); 286 301 287 302 break; -
trunk/src/VBox/Devices/Storage/DrvVD.cpp
r27976 r27977 300 300 else 301 301 { 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); 309 307 310 308 /* If thread synchronization is active, then signal the end of the … … 317 315 AssertRC(rc2); 318 316 } 319 320 if (rc == VINF_VD_ASYNC_IO_FINISHED)321 {322 rc = pThis->pDrvMediaAsyncPort->pfnTransferCompleteNotify(pThis->pDrvMediaAsyncPort, pvCallerUser);323 AssertRC(rc);324 }325 else326 AssertMsg(rc == VERR_VD_ASYNC_IO_IN_PROGRESS, ("Invalid return code from disk backend rc=%Rrc\n", rc));327 317 } 328 318 } … … 1482 1472 } 1483 1473 1484 #if 0 /* Temporary disabled. WIP */ 1485 if (pThis->pDrvMediaAsyncPort) 1474 if (pThis->pDrvMediaAsyncPort && fUseNewIo) 1486 1475 pThis->fAsyncIOSupported = true; 1487 #else1488 pThis->fAsyncIOSupported = false;1489 #endif1490 1476 1491 1477 unsigned iImageIdx = 0; -
trunk/src/VBox/Devices/Storage/VBoxHDD.cpp
r27815 r27977 49 49 #define VD_MERGE_BUFFER_SIZE (16 * _1M) 50 50 51 /** Maximum number of segments in one I/O task. */ 52 #define VD_IO_TASK_SEGMENTS_MAX 64 53 51 54 /** 52 55 * VD async I/O interface storage descriptor. … … 152 155 /** Memory cache for I/O contexts */ 153 156 RTMEMCACHE hMemCacheIoCtx; 157 /** Memory cache for I/O tasks. */ 158 RTMEMCACHE hMemCacheIoTask; 154 159 }; 155 160 … … 192 197 /** User argument 1 passed on completion. */ 193 198 void *pvUser2; 199 /** Disk this is request is for. */ 200 PVBOXHDD pDisk; 201 /** Return code. */ 202 int rcReq; 194 203 /** Transfer direction */ 195 204 VDIOCTXTXDIR enmTxDir; … … 208 217 /** Number of bytes left in the current buffer. */ 209 218 size_t cbBufLeft; 219 /** How many meta data transfers are pending. */ 220 volatile uint32_t cMetaTransfersPending; 210 221 } VDIOCTX; 222 223 /** 224 * I/O task. 225 */ 226 typedef 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; 211 253 212 254 /** … … 482 524 pIoCtx->pvUser1 = pvUser1; 483 525 pIoCtx->pvUser2 = pvUser2; 526 pIoCtx->pDisk = pDisk; 484 527 pIoCtx->enmTxDir = enmTxDir; 485 528 pIoCtx->cbTransferLeft = cbTransfer; … … 490 533 pIoCtx->pbBuf = (uint8_t *)pIoCtx->paDataSeg[0].pvSeg; 491 534 pIoCtx->cbBufLeft = pIoCtx->paDataSeg[0].cbSeg; 535 pIoCtx->cMetaTransfersPending = 0; 492 536 } 493 537 … … 495 539 } 496 540 541 static 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 556 static 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 497 574 static void vdIoCtxFree(PVBOXHDD pDisk, PVDIOCTX pIoCtx) 498 575 { 499 576 RTMemCacheFree(pDisk->hMemCacheIoCtx, pIoCtx); 577 } 578 579 static void vdIoTaskFree(PVBOXHDD pDisk, PVDIOTASK pIoTask) 580 { 581 pIoTask->pIoCtx = NULL; 582 RTMemCacheFree(pDisk->hMemCacheIoTask, pIoTask); 500 583 } 501 584 … … 932 1015 } 933 1016 1017 /** 1018 * internal: write buffer to the image, taking care of block boundaries and 1019 * write optimizations - async version. 1020 */ 1021 static 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 } 934 1091 935 1092 /** … … 1183 1340 } 1184 1341 1185 static int vdIOReqCompleted(void *pvUser, void **ppvCaller) 1186 { 1342 static 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 1187 1360 return VINF_SUCCESS; 1188 1361 } … … 1280 1453 size_t cbRead) 1281 1454 { 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; 1283 1503 } 1284 1504 … … 1287 1507 size_t cbWrite) 1288 1508 { 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; 1290 1557 } 1291 1558 … … 1585 1852 pDisk->pInterfaceThreadSyncCallbacks = NULL; 1586 1853 1587 /* Create the memcache */1854 /* Create the I/O ctx cache */ 1588 1855 rc = RTMemCacheCreate(&pDisk->hMemCacheIoCtx, sizeof(VDIOCTX), 0, UINT32_MAX, 1589 1856 NULL, NULL, NULL, 0); … … 1593 1860 break; 1594 1861 } 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 1595 1873 1596 1874 pDisk->pInterfaceError = VDInterfaceGet(pVDIfsDisk, VDINTERFACETYPE_ERROR); … … 1683 1961 VDCloseAll(pDisk); 1684 1962 RTMemCacheDestroy(pDisk->hMemCacheIoCtx); 1963 RTMemCacheDestroy(pDisk->hMemCacheIoTask); 1685 1964 RTMemFree(pDisk); 1686 1965 } while (0); … … 4975 5254 int rc2; 4976 5255 bool fLockRead = false; 5256 PVDIOCTX pIoCtx; 4977 5257 4978 5258 LogFlowFunc(("pDisk=%#p uOffset=%llu paSeg=%p cSeg=%u cbRead=%zu\n", … … 5004 5284 rc = VERR_INVALID_PARAMETER); 5005 5285 5006 PVDIOCTXpIoCtx = vdIoCtxAlloc(pDisk, VDIOCTXTXDIR_READ, uOffset,5007 5008 5286 pIoCtx = vdIoCtxAlloc(pDisk, VDIOCTXTXDIR_READ, uOffset, 5287 cbRead, paSeg, cSeg, 5288 pfnComplete, pvUser1, pvUser2); 5009 5289 if (!pIoCtx) 5010 5290 { … … 5026 5306 5027 5307 if (rc == VINF_SUCCESS) 5308 { 5309 vdIoCtxFree(pDisk, pIoCtx); 5028 5310 rc = VINF_VD_ASYNC_IO_FINISHED; 5311 } 5029 5312 5030 5313 LogFlowFunc(("returns %Rrc\n", rc)); … … 5041 5324 int rc2; 5042 5325 bool fLockWrite = false; 5326 PVDIOCTX pIoCtx; 5043 5327 5044 5328 LogFlowFunc(("pDisk=%#p uOffset=%llu paSeg=%p cSeg=%u cbWrite=%zu\n", … … 5060 5344 ("cSeg=%zu\n", cSeg), 5061 5345 rc = VERR_INVALID_PARAMETER); 5062 #if 0 5346 5063 5347 rc2 = vdThreadStartWrite(pDisk); 5064 5348 AssertRC(rc2); … … 5070 5354 rc = VERR_INVALID_PARAMETER); 5071 5355 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 5072 5365 PVDIMAGE pImage = pDisk->pLast; 5073 5366 AssertPtrBreakStmt(pImage, rc = VERR_VD_NOT_OPENED); 5074 5367 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 5080 5370 } while (0); 5081 5371 … … 5087 5377 5088 5378 if (rc == VINF_SUCCESS) 5379 { 5380 vdIoCtxFree(pDisk, pIoCtx); 5089 5381 rc = VINF_VD_ASYNC_IO_FINISHED; 5382 } 5090 5383 5091 5384 LogFlowFunc(("returns %Rrc\n", rc)); -
trunk/src/VBox/Devices/Storage/VDIHDDCore.cpp
r27976 r27977 1976 1976 static bool vdiIsAsyncIOSupported(void *pBackendData) 1977 1977 { 1978 #if 0 1979 return true; 1980 #else 1978 1981 return false; 1979 } 1980 1981 static int vdiAsyncRead(void *pvBackendData, uint64_t uOffset, size_t cbRead, 1982 #endif 1983 } 1984 1985 static int vdiAsyncRead(void *pvBackendData, uint64_t uOffset, size_t cbToRead, 1982 1986 PVDIOCTX pIoCtx, size_t *pcbActuallyRead) 1983 1987 { 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 2041 out: 1985 2042 LogFlowFunc(("returns %Rrc\n", rc)); 1986 2043 return rc; 1987 2044 } 1988 2045 1989 static int vdiAsyncWrite(void *pvBackendData, uint64_t uOffset, size_t cb Write,2046 static int vdiAsyncWrite(void *pvBackendData, uint64_t uOffset, size_t cbToWrite, 1990 2047 PVDIOCTX pIoCtx, 1991 2048 size_t *pcbWriteProcess, size_t *pcbPreRead, 1992 2049 size_t *pcbPostRead, unsigned fWrite) 1993 2050 { 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 2159 out: 1995 2160 LogFlowFunc(("returns %Rrc\n", rc)); 1996 2161 return rc; … … 2247 2412 /* uBackendCaps */ 2248 2413 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 , 2250 2419 /* papszFileExtensions */ 2251 2420 s_apszVdiFileExtensions, -
trunk/src/VBox/Devices/Storage/VmdkHDDCore.cpp
r27808 r27977 5856 5856 static bool vmdkIsAsyncIOSupported(void *pvBackendData) 5857 5857 { 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; 5859 5876 } 5860 5877 … … 5862 5879 PVDIOCTX pIoCtx, size_t *pcbActuallyRead) 5863 5880 { 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 5944 out: 5865 5945 LogFlowFunc(("returns %Rrc\n", rc)); 5866 5946 return rc; … … 5872 5952 size_t *pcbPostRead, unsigned fWrite) 5873 5953 { 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 6023 out: 5875 6024 LogFlowFunc(("returns %Rrc\n", rc)); 5876 6025 return rc;
Note:
See TracChangeset
for help on using the changeset viewer.