Changeset 44242 in vbox for trunk/src/VBox/Storage
- Timestamp:
- Jan 7, 2013 8:19:15 PM (12 years ago)
- svn:sync-xref-src-repo-rev:
- 83098
- Location:
- trunk/src/VBox/Storage
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Storage/ISCSI.cpp
r44232 r44242 5280 5280 PVDIOCTX pIoCtx, size_t *pcbActuallyRead) 5281 5281 { 5282 PISCSIIMAGE pImage = (PISCSIIMAGE)pBackendData; 5283 int rc = VINF_SUCCESS; 5284 5282 5285 LogFlowFunc(("pBackendData=%p uOffset=%#llx pIoCtx=%#p cbToRead=%u pcbActuallyRead=%p\n", 5283 5286 pBackendData, uOffset, pIoCtx, cbToRead, pcbActuallyRead)); 5284 PISCSIIMAGE pImage = (PISCSIIMAGE)pBackendData; 5285 int rc = VINF_SUCCESS; 5286 5287 if (uOffset + cbToRead > pImage->cbSize) 5287 5288 if ( uOffset + cbToRead > pImage->cbSize 5289 || cbToRead == 0) 5288 5290 return VERR_INVALID_PARAMETER; 5289 5291 … … 5292 5294 */ 5293 5295 cbToRead = RT_MIN(cbToRead, pImage->cbRecvDataLength); 5296 5297 /** @todo: Remove iscsiRead and integrate properly. */ 5298 if (vdIfIoIntIoCtxIsSynchronous(pImage->pIfIo, pIoCtx)) 5299 { 5300 RTSGSEG Segment; 5301 unsigned cSegments = 1; 5302 size_t cbSegs; 5303 5304 cbSegs = pImage->pIfIo->pfnIoCtxSegArrayCreate(pImage->pIfIo->Core.pvUser, pIoCtx, 5305 &Segment, &cSegments, cbToRead); 5306 Assert(cbSegs == cbToRead); 5307 5308 return iscsiRead(pBackendData, uOffset, Segment.pvSeg, cbToRead, pcbActuallyRead); 5309 } 5294 5310 5295 5311 unsigned cT2ISegs = 0; … … 5418 5434 cbToWrite = RT_MIN(cbToWrite, pImage->cbSendDataLength); 5419 5435 5436 /** @todo: Remove iscsiWrite and integrate properly. */ 5437 if (vdIfIoIntIoCtxIsSynchronous(pImage->pIfIo, pIoCtx)) 5438 { 5439 RTSGSEG Segment; 5440 unsigned cSegments = 1; 5441 size_t cbSegs; 5442 5443 cbSegs = pImage->pIfIo->pfnIoCtxSegArrayCreate(pImage->pIfIo->Core.pvUser, pIoCtx, 5444 &Segment, &cSegments, cbToWrite); 5445 Assert(cbSegs == cbToWrite); 5446 5447 return iscsiWrite(pBackendData, uOffset, Segment.pvSeg, cbToWrite, 5448 pcbWriteProcess, pcbPreRead, pcbPostRead, fWrite); 5449 } 5450 5420 5451 unsigned cI2TSegs = 0; 5421 5452 size_t cbSegs = 0; … … 5526 5557 PISCSIIMAGE pImage = (PISCSIIMAGE)pBackendData; 5527 5558 int rc = VINF_SUCCESS; 5559 5560 /** @todo: Remove iscsiFlush and integrate properly. */ 5561 if (vdIfIoIntIoCtxIsSynchronous(pImage->pIfIo, pIoCtx)) 5562 return iscsiFlush(pBackendData); 5528 5563 5529 5564 PSCSIREQASYNC pReqAsync = (PSCSIREQASYNC)RTMemAllocZ(sizeof(SCSIREQASYNC)); -
trunk/src/VBox/Storage/VD.cpp
r44233 r44242 306 306 /** Return code. */ 307 307 int rcReq; 308 /** Flag whether the I/O context is blocked because it is in the growing list. */309 bool fBlocked;308 /** Various flags for the I/O context. */ 309 uint32_t fFlags; 310 310 /** Number of data transfers currently pending. */ 311 311 volatile uint32_t cDataTransfersPending; … … 410 410 } VDIOCTX; 411 411 412 /** Flag whether the context is blocked. */ 413 #define VDIOCTX_FLAGS_BLOCKED RT_BIT_32(0) 414 /** Flag whether the I/O context is using synchronous I/O. */ 415 #define VDIOCTX_FLAGS_SYNC RT_BIT_32(1) 416 412 417 /** 413 418 * List node for deferred I/O contexts. … … 763 768 } 764 769 return pImage; 770 } 771 772 /** 773 * Initialize the structure members of a given I/O context. 774 */ 775 DECLINLINE(void) vdIoCtxInit(PVDIOCTX pIoCtx, PVBOXHDD pDisk, VDIOCTXTXDIR enmTxDir, 776 uint64_t uOffset, size_t cbTransfer, PVDIMAGE pImageStart, 777 PCRTSGBUF pcSgBuf, void *pvAllocation, 778 PFNVDIOCTXTRANSFER pfnIoCtxTransfer, uint32_t fFlags) 779 { 780 pIoCtx->pDisk = pDisk; 781 pIoCtx->enmTxDir = enmTxDir; 782 pIoCtx->Req.Io.cbTransferLeft = cbTransfer; 783 pIoCtx->Req.Io.uOffset = uOffset; 784 pIoCtx->Req.Io.cbTransfer = cbTransfer; 785 pIoCtx->Req.Io.pImageStart = pImageStart; 786 pIoCtx->Req.Io.pImageCur = pImageStart; 787 pIoCtx->cDataTransfersPending = 0; 788 pIoCtx->cMetaTransfersPending = 0; 789 pIoCtx->fComplete = false; 790 pIoCtx->fFlags = fFlags; 791 pIoCtx->pvAllocation = pvAllocation; 792 pIoCtx->pfnIoCtxTransfer = pfnIoCtxTransfer; 793 pIoCtx->pfnIoCtxTransferNext = NULL; 794 pIoCtx->rcReq = VINF_SUCCESS; 795 796 /* There is no S/G list for a flush request. */ 797 if ( enmTxDir != VDIOCTXTXDIR_FLUSH 798 && enmTxDir != VDIOCTXTXDIR_DISCARD) 799 RTSgBufClone(&pIoCtx->Req.Io.SgBuf, pcSgBuf); 800 else 801 memset(&pIoCtx->Req.Io.SgBuf, 0, sizeof(RTSGBUF)); 765 802 } 766 803 … … 794 831 AssertPtr(pcbRead); 795 832 833 #if 0 /** @todo: Cache implementation update */ 796 834 rc = pCache->Backend->pfnRead(pCache->pBackendData, uOffset, pvBuf, 797 835 cbRead, pcbRead); 836 #endif 798 837 799 838 LogFlowFunc(("returns rc=%Rrc pcbRead=%zu\n", rc, *pcbRead)); … … 823 862 Assert(cbWrite > 0); 824 863 864 #if 0 /** @todo: Change cache implementation */ 825 865 if (pcbWritten) 826 866 rc = pCache->Backend->pfnWrite(pCache->pBackendData, uOffset, pcvBuf, … … 840 880 && RT_SUCCESS(rc)); 841 881 } 882 #endif 842 883 843 884 LogFlowFunc(("returns rc=%Rrc pcbWritten=%zu\n", … … 854 895 int rc = VINF_SUCCESS; 855 896 size_t cbThisRead = cbRead; 897 RTSGSEG SegmentBuf; 898 RTSGBUF SgBuf; 899 VDIOCTX IoCtx; 856 900 857 901 AssertPtr(pcbThisRead); 858 902 859 903 *pcbThisRead = 0; 904 905 SegmentBuf.pvSeg = pvBuf; 906 SegmentBuf.cbSeg = VD_MERGE_BUFFER_SIZE; 907 RTSgBufInit(&SgBuf, &SegmentBuf, 1); 908 vdIoCtxInit(&IoCtx, pDisk, VDIOCTXTXDIR_READ, 0, 0, NULL, 909 &SgBuf, NULL, NULL, VDIOCTX_FLAGS_SYNC); 860 910 861 911 /* … … 863 913 * If the block is not allocated read from override chain if present. 864 914 */ 865 rc = pImage->Backend->pfn Read(pImage->pBackendData,866 uOffset, pvBuf, cbThisRead,867 &cbThisRead);915 rc = pImage->Backend->pfnAsyncRead(pImage->pBackendData, 916 uOffset, cbThisRead, &IoCtx, 917 &cbThisRead); 868 918 869 919 if (rc == VERR_VD_BLOCK_FREE) … … 873 923 pCurrImage = pCurrImage->pPrev) 874 924 { 875 rc = pCurrImage->Backend->pfn Read(pCurrImage->pBackendData,876 uOffset, pvBuf, cbThisRead,877 &cbThisRead);925 rc = pCurrImage->Backend->pfnAsyncRead(pCurrImage->pBackendData, 926 uOffset, cbThisRead, &IoCtx, 927 &cbThisRead); 878 928 } 879 929 } … … 949 999 else 950 1000 { 951 /** @todo can be be replaced by vdDiskReadHelper if it proves to be reliable, 952 * don't want to be responsible for data corruption... 953 */ 1001 RTSGSEG SegmentBuf; 1002 RTSGBUF SgBuf; 1003 VDIOCTX IoCtx; 1004 1005 SegmentBuf.pvSeg = pvBuf; 1006 SegmentBuf.cbSeg = cbThisRead; 1007 RTSgBufInit(&SgBuf, &SegmentBuf, 1); 1008 vdIoCtxInit(&IoCtx, pDisk, VDIOCTXTXDIR_READ, 0, 0, NULL, 1009 &SgBuf, NULL, NULL, VDIOCTX_FLAGS_SYNC); 1010 954 1011 /* 955 1012 * Try to read from the given image. 956 1013 * If the block is not allocated read from override chain if present. 957 1014 */ 958 rc = pImage->Backend->pfn Read(pImage->pBackendData,959 uOffset, pvBuf, cbThisRead,960 &cbThisRead);1015 rc = pImage->Backend->pfnAsyncRead(pImage->pBackendData, 1016 uOffset, cbThisRead, &IoCtx, 1017 &cbThisRead); 961 1018 962 1019 if ( rc == VERR_VD_BLOCK_FREE … … 969 1026 pCurrImage = pCurrImage->pPrev) 970 1027 { 971 rc = pCurrImage->Backend->pfn Read(pCurrImage->pBackendData,972 uOffset, pvBuf, cbThisRead,973 &cbThisRead);1028 rc = pCurrImage->Backend->pfnAsyncRead(pCurrImage->pBackendData, 1029 uOffset, cbThisRead, 1030 &IoCtx, &cbThisRead); 974 1031 if (cImagesToProcess == 1) 975 1032 break; … … 1100 1157 cbThis = (idxEnd - idxStart) * 512; 1101 1158 1102 rc = pDisk->pLast->Backend->pfnDiscard(pDisk->pLast->pBackendData, offStart, 1103 cbThis, NULL, NULL, &cbThis, 1104 NULL, VD_DISCARD_MARK_UNUSED); 1159 1160 VDIOCTX IoCtx; 1161 vdIoCtxInit(&IoCtx, pDisk, VDIOCTXTXDIR_DISCARD, 0, 0, NULL, 1162 NULL, NULL, NULL, VDIOCTX_FLAGS_SYNC); 1163 rc = pDisk->pLast->Backend->pfnAsyncDiscard(pDisk->pLast->pBackendData, 1164 &IoCtx, offStart, cbThis, NULL, 1165 NULL, &cbThis, NULL, 1166 VD_DISCARD_MARK_UNUSED); 1105 1167 if (RT_FAILURE(rc)) 1106 1168 break; … … 1190 1252 1191 1253 /* No block found, try to discard using the backend first. */ 1192 rc = pDisk->pLast->Backend->pfnDiscard(pDisk->pLast->pBackendData, offStart, 1193 cbThisDiscard, &cbPreAllocated, 1194 &cbPostAllocated, &cbThisDiscard, 1195 &pbmAllocated, 0); 1254 VDIOCTX IoCtx; 1255 1256 vdIoCtxInit(&IoCtx, pDisk, VDIOCTXTXDIR_DISCARD, 0, 0, NULL, 1257 NULL, NULL, NULL, VDIOCTX_FLAGS_SYNC); 1258 rc = pDisk->pLast->Backend->pfnAsyncDiscard(pDisk->pLast->pBackendData, 1259 &IoCtx, offStart, 1260 cbThisDiscard, &cbPreAllocated, 1261 &cbPostAllocated, &cbThisDiscard, 1262 &pbmAllocated, 0); 1196 1263 if (rc == VERR_VD_DISCARD_ALIGNMENT_NOT_MET) 1197 1264 { … … 1241 1308 if (ASMBitFirstSet((volatile void *)pBlock->pbmAllocated, pBlock->cbDiscard / 512) == -1) 1242 1309 { 1310 VDIOCTX IoCtx; 1243 1311 size_t cbPreAllocated, cbPostAllocated, cbActuallyDiscarded; 1244 1312 1245 rc = pDisk->pLast->Backend->pfnDiscard(pDisk->pLast->pBackendData, pBlock->Core.Key, 1246 pBlock->cbDiscard, &cbPreAllocated, 1247 &cbPostAllocated, &cbActuallyDiscarded, 1248 NULL, 0); 1313 vdIoCtxInit(&IoCtx, pDisk, VDIOCTXTXDIR_DISCARD, 0, 0, NULL, 1314 NULL, NULL, NULL, VDIOCTX_FLAGS_SYNC); 1315 rc = pDisk->pLast->Backend->pfnAsyncDiscard(pDisk->pLast->pBackendData, 1316 &IoCtx, pBlock->Core.Key, 1317 pBlock->cbDiscard, &cbPreAllocated, 1318 &cbPostAllocated, &cbActuallyDiscarded, 1319 NULL, 0); 1249 1320 Assert(rc != VERR_VD_DISCARD_ALIGNMENT_NOT_MET); 1250 1321 Assert(!cbPreAllocated); … … 1369 1440 DECLINLINE(PVDIOCTX) vdIoCtxAlloc(PVBOXHDD pDisk, VDIOCTXTXDIR enmTxDir, 1370 1441 uint64_t uOffset, size_t cbTransfer, 1371 PVDIMAGE pImageStart, 1372 PCRTSGBUF pcSgBuf, void *pvAllocation,1373 PFNVDIOCTXTRANSFER pfnIoCtxTransfer)1442 PVDIMAGE pImageStart,PCRTSGBUF pcSgBuf, 1443 void *pvAllocation, PFNVDIOCTXTRANSFER pfnIoCtxTransfer, 1444 uint32_t fFlags) 1374 1445 { 1375 1446 PVDIOCTX pIoCtx = NULL; … … 1378 1449 if (RT_LIKELY(pIoCtx)) 1379 1450 { 1380 pIoCtx->pDisk = pDisk; 1381 pIoCtx->enmTxDir = enmTxDir; 1382 pIoCtx->Req.Io.cbTransferLeft = cbTransfer; 1383 pIoCtx->Req.Io.uOffset = uOffset; 1384 pIoCtx->Req.Io.cbTransfer = cbTransfer; 1385 pIoCtx->Req.Io.pImageStart = pImageStart; 1386 pIoCtx->Req.Io.pImageCur = pImageStart; 1387 pIoCtx->cDataTransfersPending = 0; 1388 pIoCtx->cMetaTransfersPending = 0; 1389 pIoCtx->fComplete = false; 1390 pIoCtx->fBlocked = false; 1391 pIoCtx->pvAllocation = pvAllocation; 1392 pIoCtx->pfnIoCtxTransfer = pfnIoCtxTransfer; 1393 pIoCtx->pfnIoCtxTransferNext = NULL; 1394 pIoCtx->rcReq = VINF_SUCCESS; 1395 1396 /* There is no S/G list for a flush request. */ 1397 if (enmTxDir != VDIOCTXTXDIR_FLUSH) 1398 RTSgBufClone(&pIoCtx->Req.Io.SgBuf, pcSgBuf); 1399 else 1400 memset(&pIoCtx->Req.Io.SgBuf, 0, sizeof(RTSGBUF)); 1451 vdIoCtxInit(pIoCtx, pDisk, enmTxDir, uOffset, cbTransfer, pImageStart, 1452 pcSgBuf, pvAllocation, pfnIoCtxTransfer, fFlags); 1401 1453 } 1402 1454 … … 1413 1465 { 1414 1466 PVDIOCTX pIoCtx = vdIoCtxAlloc(pDisk, enmTxDir, uOffset, cbTransfer, pImageStart, 1415 pcSgBuf, pvAllocation, pfnIoCtxTransfer );1467 pcSgBuf, pvAllocation, pfnIoCtxTransfer, 0); 1416 1468 1417 1469 if (RT_LIKELY(pIoCtx)) … … 1445 1497 pIoCtx->cMetaTransfersPending = 0; 1446 1498 pIoCtx->fComplete = false; 1447 pIoCtx->f Blocked = false;1499 pIoCtx->fFlags = 0; 1448 1500 pIoCtx->pvAllocation = pvAllocation; 1449 1501 pIoCtx->pfnIoCtxTransfer = pfnIoCtxTransfer; … … 1475 1527 { 1476 1528 PVDIOCTX pIoCtx = vdIoCtxAlloc(pDisk, enmTxDir, uOffset, cbTransfer, pImageStart, 1477 pcSgBuf, pvAllocation, pfnIoCtxTransfer );1529 pcSgBuf, pvAllocation, pfnIoCtxTransfer, 0); 1478 1530 1479 1531 AssertPtr(pIoCtxParent); … … 1579 1631 LogFlowFunc(("Deferring write pIoCtx=%#p\n", pIoCtx)); 1580 1632 1581 Assert(!pIoCtx->pIoCtxParent && ! pIoCtx->fBlocked);1633 Assert(!pIoCtx->pIoCtxParent && !(pIoCtx->fFlags & VDIOCTX_FLAGS_BLOCKED)); 1582 1634 1583 1635 RTListInit(&pDeferred->NodeDeferred); 1584 1636 pDeferred->pIoCtx = pIoCtx; 1585 1637 RTListAppend(&pDisk->ListWriteLocked, &pDeferred->NodeDeferred); 1586 pIoCtx->f Blocked = true;1638 pIoCtx->fFlags |= VDIOCTX_FLAGS_BLOCKED; 1587 1639 return VINF_SUCCESS; 1588 1640 } … … 1651 1703 /* Don't change anything if there is a metadata transfer pending or we are blocked. */ 1652 1704 if ( pIoCtx->cMetaTransfersPending 1653 || pIoCtx->fBlocked)1705 || (pIoCtx->fFlags & VDIOCTX_FLAGS_BLOCKED)) 1654 1706 { 1655 1707 rc = VERR_VD_ASYNC_IO_IN_PROGRESS; … … 1955 2007 Assert(!pIoCtxWait->pIoCtxParent); 1956 2008 1957 pIoCtxWait->f Blocked = false;2009 pIoCtxWait->fFlags &= ~VDIOCTX_FLAGS_BLOCKED; 1958 2010 LogFlowFunc(("Processing waiting I/O context pIoCtxWait=%#p\n", pIoCtxWait)); 1959 2011 … … 2032 2084 uOffset += cbThisRead; 2033 2085 cbToRead -= cbThisRead; 2034 pIoCtx->f Blocked = true;2086 pIoCtx->fFlags |= VDIOCTX_FLAGS_BLOCKED; 2035 2087 } 2036 2088 … … 2105 2157 2106 2158 if (!(pDisk->uModified & VD_IMAGE_MODIFIED_DISABLE_UUID_UPDATE)) 2107 pDisk->pLast->Backend->pfnFlush(pDisk->pLast->pBackendData); 2159 { 2160 VDIOCTX IoCtx; 2161 vdIoCtxInit(&IoCtx, pDisk, VDIOCTXTXDIR_FLUSH, 0, 0, NULL, 2162 NULL, NULL, NULL, VDIOCTX_FLAGS_SYNC); 2163 pDisk->pLast->Backend->pfnAsyncFlush(pDisk->pLast->pBackendData, &IoCtx); 2164 } 2108 2165 } 2109 2166 } … … 2183 2240 2184 2241 /* Write the full block to the virtual disk. */ 2185 rc = pImage->Backend->pfnWrite(pImage->pBackendData, 2186 uOffset - cbPreRead, pvTmp, 2187 cbPreRead + cbThisWrite + cbPostRead, 2188 NULL, &cbPreRead, &cbPostRead, 0); 2242 RTSGSEG SegmentBuf; 2243 RTSGBUF SgBuf; 2244 VDIOCTX IoCtx; 2245 2246 SegmentBuf.pvSeg = pvTmp; 2247 SegmentBuf.cbSeg = cbPreRead + cbThisWrite + cbPostRead; 2248 RTSgBufInit(&SgBuf, &SegmentBuf, 1); 2249 vdIoCtxInit(&IoCtx, pDisk, VDIOCTXTXDIR_WRITE, 0, 0, NULL, 2250 &SgBuf, NULL, NULL, VDIOCTX_FLAGS_SYNC); 2251 rc = pImage->Backend->pfnAsyncWrite(pImage->pBackendData, uOffset - cbPreRead, 2252 cbPreRead + cbThisWrite + cbPostRead, 2253 &IoCtx, NULL, &cbPreRead, &cbPostRead, 0); 2189 2254 Assert(rc != VERR_VD_BLOCK_FREE); 2190 2255 Assert(cbPreRead == 0); … … 2265 2330 2266 2331 /* Write the full block to the virtual disk. */ 2267 rc = pImage->Backend->pfnWrite(pImage->pBackendData, 2268 uOffset - cbPreRead, pvTmp, 2269 cbPreRead + cbThisWrite + cbPostRead, 2270 NULL, &cbPreRead, &cbPostRead, 0); 2332 RTSGSEG SegmentBuf; 2333 RTSGBUF SgBuf; 2334 VDIOCTX IoCtx; 2335 2336 SegmentBuf.pvSeg = pvTmp; 2337 SegmentBuf.cbSeg = cbPreRead + cbThisWrite + cbPostRead; 2338 RTSgBufInit(&SgBuf, &SegmentBuf, 1); 2339 vdIoCtxInit(&IoCtx, pDisk, VDIOCTXTXDIR_WRITE, 0, 0, NULL, 2340 &SgBuf, NULL, NULL, VDIOCTX_FLAGS_SYNC); 2341 rc = pImage->Backend->pfnAsyncWrite(pImage->pBackendData, uOffset - cbPreRead, 2342 cbPreRead + cbThisWrite + cbPostRead, 2343 &IoCtx, NULL, &cbPreRead, &cbPostRead, 0); 2271 2344 Assert(rc != VERR_VD_BLOCK_FREE); 2272 2345 Assert(cbPreRead == 0); … … 2292 2365 size_t cbWriteCur = cbWrite; 2293 2366 const void *pcvBufCur = pvBuf; 2367 RTSGSEG SegmentBuf; 2368 RTSGBUF SgBuf; 2369 VDIOCTX IoCtx; 2294 2370 2295 2371 /* Loop until all written. */ … … 2305 2381 fWrite = (pImage->uOpenFlags & VD_OPEN_FLAGS_HONOR_SAME) 2306 2382 ? 0 : VD_WRITE_NO_ALLOC; 2307 rc = pImage->Backend->pfnWrite(pImage->pBackendData, uOffsetCur, pcvBufCur, 2308 cbThisWrite, &cbThisWrite, &cbPreRead, 2309 &cbPostRead, fWrite); 2383 2384 SegmentBuf.pvSeg = (void *)pcvBufCur; 2385 SegmentBuf.cbSeg = cbWrite; 2386 RTSgBufInit(&SgBuf, &SegmentBuf, 1); 2387 vdIoCtxInit(&IoCtx, pDisk, VDIOCTXTXDIR_WRITE, 0, 0, NULL, 2388 &SgBuf, NULL, NULL, VDIOCTX_FLAGS_SYNC); 2389 rc = pImage->Backend->pfnAsyncWrite(pImage->pBackendData, uOffsetCur, cbThisWrite, 2390 &IoCtx, &cbThisWrite, &cbPreRead, 2391 &cbPostRead, fWrite); 2310 2392 if (rc == VERR_VD_BLOCK_FREE) 2311 2393 { … … 2408 2490 if (fBlockwiseCopy) 2409 2491 { 2492 RTSGSEG SegmentBuf; 2493 RTSGBUF SgBuf; 2494 VDIOCTX IoCtx; 2495 2496 SegmentBuf.pvSeg = pvBuf; 2497 SegmentBuf.cbSeg = VD_MERGE_BUFFER_SIZE; 2498 RTSgBufInit(&SgBuf, &SegmentBuf, 1); 2499 vdIoCtxInit(&IoCtx, pDiskFrom, VDIOCTXTXDIR_READ, 0, 0, NULL, 2500 &SgBuf, NULL, NULL, VDIOCTX_FLAGS_SYNC); 2501 2410 2502 /* Read the source data. */ 2411 rc = pImageFrom->Backend->pfn Read(pImageFrom->pBackendData,2412 uOffset, pvBuf, cbThisRead,2413 &cbThisRead);2503 rc = pImageFrom->Backend->pfnAsyncRead(pImageFrom->pBackendData, 2504 uOffset, cbThisRead, &IoCtx, 2505 &cbThisRead); 2414 2506 2415 2507 if ( rc == VERR_VD_BLOCK_FREE … … 2422 2514 pCurrImage = pCurrImage->pPrev) 2423 2515 { 2424 rc = pCurrImage->Backend->pfn Read(pCurrImage->pBackendData,2425 uOffset, pvBuf, cbThisRead,2426 &cbThisRead);2516 rc = pCurrImage->Backend->pfnAsyncRead(pCurrImage->pBackendData, 2517 uOffset, cbThisRead, 2518 &IoCtx, &cbThisRead); 2427 2519 if (cImagesToProcess == 1) 2428 2520 break; … … 2558 2650 { 2559 2651 ASMAtomicIncU32(&pIoCtx->cDataTransfersPending); 2560 pIoCtx->f Blocked = true;2652 pIoCtx->fFlags |= VDIOCTX_FLAGS_BLOCKED; 2561 2653 } 2562 2654 else /* Another error */ … … 2686 2778 else if (rc == VERR_VD_IOCTX_HALT) 2687 2779 { 2688 pIoCtx->f Blocked = true;2780 pIoCtx->fFlags |= VDIOCTX_FLAGS_BLOCKED; 2689 2781 rc = VINF_SUCCESS; 2690 2782 } … … 2948 3040 LogFlow(("Child write pending\n")); 2949 3041 ASMAtomicIncU32(&pIoCtx->cDataTransfersPending); 2950 pIoCtx->f Blocked = true;3042 pIoCtx->fFlags |= VDIOCTX_FLAGS_BLOCKED; 2951 3043 rc = VERR_VD_ASYNC_IO_IN_PROGRESS; 2952 3044 cbWrite -= cbThisWrite; … … 2966 3058 cbWrite -= cbThisWrite; 2967 3059 uOffset += cbThisWrite; 2968 pIoCtx->f Blocked = true;3060 pIoCtx->fFlags |= VDIOCTX_FLAGS_BLOCKED; 2969 3061 break; 2970 3062 } … … 3751 3843 ASMAtomicCmpXchgS32(&pIoCtx->rcReq, rcReq, VINF_SUCCESS); 3752 3844 3753 if (! pIoCtx->fBlocked)3845 if (!(pIoCtx->fFlags & VDIOCTX_FLAGS_BLOCKED)) 3754 3846 { 3755 3847 /* Continue the transfer */ … … 3789 3881 3790 3882 /* Unblock the parent */ 3791 pIoCtxParent->f Blocked = false;3883 pIoCtxParent->fFlags &= ~VDIOCTX_FLAGS_BLOCKED; 3792 3884 3793 3885 rc = vdIoCtxProcess(pIoCtxParent); … … 3835 3927 Assert(!pIoCtxWait->pIoCtxParent); 3836 3928 3837 pIoCtxWait->f Blocked = false;3929 pIoCtxWait->fFlags &= ~VDIOCTX_FLAGS_BLOCKED; 3838 3930 LogFlowFunc(("Processing waiting I/O context pIoCtxWait=%#p\n", pIoCtxWait)); 3839 3931 … … 4138 4230 pvUser, pIoStorage, uOffset, pIoCtx, cbRead)); 4139 4231 4140 VD_THREAD_IS_CRITSECT_OWNER(pDisk);4141 4142 /** @todo: Handle synchronous I/O contexts. */4232 /** @todo: Enable check for sync I/O later. */ 4233 if (!(pIoCtx->fFlags & VDIOCTX_FLAGS_SYNC)) 4234 VD_THREAD_IS_CRITSECT_OWNER(pDisk); 4143 4235 4144 4236 Assert(cbRead > 0); 4145 4237 4146 /* Build the S/G array and spawn a new I/O task */ 4147 while (cbRead) 4148 { 4149 RTSGSEG aSeg[VD_IO_TASK_SEGMENTS_MAX]; 4150 unsigned cSegments = VD_IO_TASK_SEGMENTS_MAX; 4151 size_t cbTaskRead = 0; 4152 4153 cbTaskRead = RTSgBufSegArrayCreate(&pIoCtx->Req.Io.SgBuf, aSeg, &cSegments, cbRead); 4154 4155 Assert(cSegments > 0); 4156 Assert(cbTaskRead > 0); 4157 AssertMsg(cbTaskRead <= cbRead, ("Invalid number of bytes to read\n")); 4158 4159 LogFlow(("Reading %u bytes into %u segments\n", cbTaskRead, cSegments)); 4238 if (pIoCtx->fFlags & VDIOCTX_FLAGS_SYNC) 4239 { 4240 RTSGSEG Seg; 4241 unsigned cSegments = 1; 4242 size_t cbTaskRead = 0; 4243 4244 /* Synchronous I/O contexts only have one buffer segment. */ 4245 AssertMsgReturn(pIoCtx->Req.Io.SgBuf.cSegs == 1, 4246 ("Invalid number of buffer segments for synchronous I/O context"), 4247 VERR_INVALID_PARAMETER); 4248 4249 cbTaskRead = RTSgBufSegArrayCreate(&pIoCtx->Req.Io.SgBuf, &Seg, &cSegments, cbRead); 4250 Assert(cbRead == cbTaskRead); 4251 Assert(cSegments == 1); 4252 rc = pVDIo->pInterfaceIo->pfnReadSync(pVDIo->pInterfaceIo->Core.pvUser, 4253 pIoStorage->pStorage, uOffset, 4254 Seg.pvSeg, cbRead, NULL); 4255 } 4256 else 4257 { 4258 /* Build the S/G array and spawn a new I/O task */ 4259 while (cbRead) 4260 { 4261 RTSGSEG aSeg[VD_IO_TASK_SEGMENTS_MAX]; 4262 unsigned cSegments = VD_IO_TASK_SEGMENTS_MAX; 4263 size_t cbTaskRead = 0; 4264 4265 cbTaskRead = RTSgBufSegArrayCreate(&pIoCtx->Req.Io.SgBuf, aSeg, &cSegments, cbRead); 4266 4267 Assert(cSegments > 0); 4268 Assert(cbTaskRead > 0); 4269 AssertMsg(cbTaskRead <= cbRead, ("Invalid number of bytes to read\n")); 4270 4271 LogFlow(("Reading %u bytes into %u segments\n", cbTaskRead, cSegments)); 4160 4272 4161 4273 #ifdef RT_STRICT 4162 for (unsigned i = 0; i < cSegments; i++)4163 AssertMsg(aSeg[i].pvSeg && !(aSeg[i].cbSeg % 512),4164 ("Segment %u is invalid\n", i));4274 for (unsigned i = 0; i < cSegments; i++) 4275 AssertMsg(aSeg[i].pvSeg && !(aSeg[i].cbSeg % 512), 4276 ("Segment %u is invalid\n", i)); 4165 4277 #endif 4166 4278 4167 PVDIOTASK pIoTask = vdIoTaskUserAlloc(pIoStorage, NULL, NULL, pIoCtx, cbTaskRead); 4168 4169 if (!pIoTask) 4170 return VERR_NO_MEMORY; 4171 4172 ASMAtomicIncU32(&pIoCtx->cDataTransfersPending); 4173 4174 void *pvTask; 4175 rc = pVDIo->pInterfaceIo->pfnReadAsync(pVDIo->pInterfaceIo->Core.pvUser, 4176 pIoStorage->pStorage, uOffset, 4177 aSeg, cSegments, cbTaskRead, pIoTask, 4178 &pvTask); 4179 if (RT_SUCCESS(rc)) 4180 { 4181 AssertMsg(cbTaskRead <= pIoCtx->Req.Io.cbTransferLeft, ("Impossible!\n")); 4182 ASMAtomicSubU32(&pIoCtx->Req.Io.cbTransferLeft, cbTaskRead); 4183 ASMAtomicDecU32(&pIoCtx->cDataTransfersPending); 4184 vdIoTaskFree(pDisk, pIoTask); 4185 } 4186 else if (rc != VERR_VD_ASYNC_IO_IN_PROGRESS) 4187 { 4188 ASMAtomicDecU32(&pIoCtx->cDataTransfersPending); 4189 vdIoTaskFree(pDisk, pIoTask); 4190 break; 4191 } 4192 4193 uOffset += cbTaskRead; 4194 cbRead -= cbTaskRead; 4279 PVDIOTASK pIoTask = vdIoTaskUserAlloc(pIoStorage, NULL, NULL, pIoCtx, cbTaskRead); 4280 4281 if (!pIoTask) 4282 return VERR_NO_MEMORY; 4283 4284 ASMAtomicIncU32(&pIoCtx->cDataTransfersPending); 4285 4286 void *pvTask; 4287 rc = pVDIo->pInterfaceIo->pfnReadAsync(pVDIo->pInterfaceIo->Core.pvUser, 4288 pIoStorage->pStorage, uOffset, 4289 aSeg, cSegments, cbTaskRead, pIoTask, 4290 &pvTask); 4291 if (RT_SUCCESS(rc)) 4292 { 4293 AssertMsg(cbTaskRead <= pIoCtx->Req.Io.cbTransferLeft, ("Impossible!\n")); 4294 ASMAtomicSubU32(&pIoCtx->Req.Io.cbTransferLeft, cbTaskRead); 4295 ASMAtomicDecU32(&pIoCtx->cDataTransfersPending); 4296 vdIoTaskFree(pDisk, pIoTask); 4297 } 4298 else if (rc != VERR_VD_ASYNC_IO_IN_PROGRESS) 4299 { 4300 ASMAtomicDecU32(&pIoCtx->cDataTransfersPending); 4301 vdIoTaskFree(pDisk, pIoTask); 4302 break; 4303 } 4304 4305 uOffset += cbTaskRead; 4306 cbRead -= cbTaskRead; 4307 } 4195 4308 } 4196 4309 … … 4210 4323 pvUser, pIoStorage, uOffset, pIoCtx, cbWrite)); 4211 4324 4212 VD_THREAD_IS_CRITSECT_OWNER(pDisk);4213 4214 /** @todo: Handle synchronous I/O contexts. */4325 /** @todo: Enable check for sync I/O later. */ 4326 if (!(pIoCtx->fFlags & VDIOCTX_FLAGS_SYNC)) 4327 VD_THREAD_IS_CRITSECT_OWNER(pDisk); 4215 4328 4216 4329 Assert(cbWrite > 0); 4217 4330 4218 /* Build the S/G array and spawn a new I/O task */ 4219 while (cbWrite) 4220 { 4221 RTSGSEG aSeg[VD_IO_TASK_SEGMENTS_MAX]; 4222 unsigned cSegments = VD_IO_TASK_SEGMENTS_MAX; 4223 size_t cbTaskWrite = 0; 4224 4225 cbTaskWrite = RTSgBufSegArrayCreate(&pIoCtx->Req.Io.SgBuf, aSeg, &cSegments, cbWrite); 4226 4227 Assert(cSegments > 0); 4228 Assert(cbTaskWrite > 0); 4229 AssertMsg(cbTaskWrite <= cbWrite, ("Invalid number of bytes to write\n")); 4230 4231 LogFlow(("Writing %u bytes from %u segments\n", cbTaskWrite, cSegments)); 4331 if (pIoCtx->fFlags & VDIOCTX_FLAGS_SYNC) 4332 { 4333 RTSGSEG Seg; 4334 unsigned cSegments = 1; 4335 size_t cbTaskWrite = 0; 4336 4337 /* Synchronous I/O contexts only have one buffer segment. */ 4338 AssertMsgReturn(pIoCtx->Req.Io.SgBuf.cSegs == 1, 4339 ("Invalid number of buffer segments for synchronous I/O context"), 4340 VERR_INVALID_PARAMETER); 4341 4342 cbTaskWrite = RTSgBufSegArrayCreate(&pIoCtx->Req.Io.SgBuf, &Seg, &cSegments, cbWrite); 4343 Assert(cbWrite == cbTaskWrite); 4344 Assert(cSegments == 1); 4345 rc = pVDIo->pInterfaceIo->pfnWriteSync(pVDIo->pInterfaceIo->Core.pvUser, 4346 pIoStorage->pStorage, uOffset, 4347 Seg.pvSeg, cbWrite, NULL); 4348 } 4349 else 4350 { 4351 /* Build the S/G array and spawn a new I/O task */ 4352 while (cbWrite) 4353 { 4354 RTSGSEG aSeg[VD_IO_TASK_SEGMENTS_MAX]; 4355 unsigned cSegments = VD_IO_TASK_SEGMENTS_MAX; 4356 size_t cbTaskWrite = 0; 4357 4358 cbTaskWrite = RTSgBufSegArrayCreate(&pIoCtx->Req.Io.SgBuf, aSeg, &cSegments, cbWrite); 4359 4360 Assert(cSegments > 0); 4361 Assert(cbTaskWrite > 0); 4362 AssertMsg(cbTaskWrite <= cbWrite, ("Invalid number of bytes to write\n")); 4363 4364 LogFlow(("Writing %u bytes from %u segments\n", cbTaskWrite, cSegments)); 4232 4365 4233 4366 #ifdef DEBUG 4234 for (unsigned i = 0; i < cSegments; i++)4235 AssertMsg(aSeg[i].pvSeg && !(aSeg[i].cbSeg % 512),4236 ("Segment %u is invalid\n", i));4367 for (unsigned i = 0; i < cSegments; i++) 4368 AssertMsg(aSeg[i].pvSeg && !(aSeg[i].cbSeg % 512), 4369 ("Segment %u is invalid\n", i)); 4237 4370 #endif 4238 4371 4239 PVDIOTASK pIoTask = vdIoTaskUserAlloc(pIoStorage, pfnComplete, pvCompleteUser, pIoCtx, cbTaskWrite); 4240 4241 if (!pIoTask) 4242 return VERR_NO_MEMORY; 4243 4244 ASMAtomicIncU32(&pIoCtx->cDataTransfersPending); 4245 4246 void *pvTask; 4247 rc = pVDIo->pInterfaceIo->pfnWriteAsync(pVDIo->pInterfaceIo->Core.pvUser, 4248 pIoStorage->pStorage, 4249 uOffset, aSeg, cSegments, 4250 cbTaskWrite, pIoTask, &pvTask); 4251 if (RT_SUCCESS(rc)) 4252 { 4253 AssertMsg(cbTaskWrite <= pIoCtx->Req.Io.cbTransferLeft, ("Impossible!\n")); 4254 ASMAtomicSubU32(&pIoCtx->Req.Io.cbTransferLeft, cbTaskWrite); 4255 ASMAtomicDecU32(&pIoCtx->cDataTransfersPending); 4256 vdIoTaskFree(pDisk, pIoTask); 4257 } 4258 else if (rc != VERR_VD_ASYNC_IO_IN_PROGRESS) 4259 { 4260 ASMAtomicDecU32(&pIoCtx->cDataTransfersPending); 4261 vdIoTaskFree(pDisk, pIoTask); 4262 break; 4263 } 4264 4265 uOffset += cbTaskWrite; 4266 cbWrite -= cbTaskWrite; 4267 } 4268 4372 PVDIOTASK pIoTask = vdIoTaskUserAlloc(pIoStorage, pfnComplete, pvCompleteUser, pIoCtx, cbTaskWrite); 4373 4374 if (!pIoTask) 4375 return VERR_NO_MEMORY; 4376 4377 ASMAtomicIncU32(&pIoCtx->cDataTransfersPending); 4378 4379 void *pvTask; 4380 rc = pVDIo->pInterfaceIo->pfnWriteAsync(pVDIo->pInterfaceIo->Core.pvUser, 4381 pIoStorage->pStorage, 4382 uOffset, aSeg, cSegments, 4383 cbTaskWrite, pIoTask, &pvTask); 4384 if (RT_SUCCESS(rc)) 4385 { 4386 AssertMsg(cbTaskWrite <= pIoCtx->Req.Io.cbTransferLeft, ("Impossible!\n")); 4387 ASMAtomicSubU32(&pIoCtx->Req.Io.cbTransferLeft, cbTaskWrite); 4388 ASMAtomicDecU32(&pIoCtx->cDataTransfersPending); 4389 vdIoTaskFree(pDisk, pIoTask); 4390 } 4391 else if (rc != VERR_VD_ASYNC_IO_IN_PROGRESS) 4392 { 4393 ASMAtomicDecU32(&pIoCtx->cDataTransfersPending); 4394 vdIoTaskFree(pDisk, pIoTask); 4395 break; 4396 } 4397 4398 uOffset += cbTaskWrite; 4399 cbWrite -= cbTaskWrite; 4400 } 4401 } 4402 4403 LogFlowFunc(("returns rc=%Rrc\n", rc)); 4269 4404 return rc; 4270 4405 } … … 4291 4426 VERR_INVALID_POINTER); 4292 4427 4293 if (!pIoCtx) 4428 /** @todo: Enable check for sync I/O later. */ 4429 if ( pIoCtx 4430 && !(pIoCtx->fFlags & VDIOCTX_FLAGS_SYNC)) 4431 VD_THREAD_IS_CRITSECT_OWNER(pDisk); 4432 4433 if ( !pIoCtx 4434 || pIoCtx->fFlags & VDIOCTX_FLAGS_SYNC) 4294 4435 { 4295 4436 /* Handle synchronous metadata I/O. */ 4296 4437 /** @todo: Integrate with metadata transfers below. */ 4297 return pVDIo->pInterfaceIo->pfnReadSync(pVDIo->pInterfaceIo->Core.pvUser, 4298 pIoStorage->pStorage, uOffset, 4299 pvBuf, cbRead, NULL); 4300 } 4301 4302 VD_THREAD_IS_CRITSECT_OWNER(pDisk); 4303 4304 pMetaXfer = (PVDMETAXFER)RTAvlrFileOffsetGet(pIoStorage->pTreeMetaXfers, uOffset); 4305 if (!pMetaXfer) 4306 { 4438 rc = pVDIo->pInterfaceIo->pfnReadSync(pVDIo->pInterfaceIo->Core.pvUser, 4439 pIoStorage->pStorage, uOffset, 4440 pvBuf, cbRead, NULL); 4441 if (ppMetaXfer) 4442 *ppMetaXfer = NULL; 4443 } 4444 else 4445 { 4446 pMetaXfer = (PVDMETAXFER)RTAvlrFileOffsetGet(pIoStorage->pTreeMetaXfers, uOffset); 4447 if (!pMetaXfer) 4448 { 4307 4449 #ifdef RT_STRICT 4308 pMetaXfer = (PVDMETAXFER)RTAvlrFileOffsetGetBestFit(pIoStorage->pTreeMetaXfers, uOffset, false /* fAbove */);4309 AssertMsg(!pMetaXfer || (pMetaXfer->Core.Key + (RTFOFF)pMetaXfer->cbMeta <= (RTFOFF)uOffset),4310 ("Overlapping meta transfers!\n"));4450 pMetaXfer = (PVDMETAXFER)RTAvlrFileOffsetGetBestFit(pIoStorage->pTreeMetaXfers, uOffset, false /* fAbove */); 4451 AssertMsg(!pMetaXfer || (pMetaXfer->Core.Key + (RTFOFF)pMetaXfer->cbMeta <= (RTFOFF)uOffset), 4452 ("Overlapping meta transfers!\n")); 4311 4453 #endif 4312 4454 4313 /* Allocate a new meta transfer. */ 4314 pMetaXfer = vdMetaXferAlloc(pIoStorage, uOffset, cbRead); 4315 if (!pMetaXfer) 4316 return VERR_NO_MEMORY; 4317 4318 pIoTask = vdIoTaskMetaAlloc(pIoStorage, pfnComplete, pvCompleteUser, pMetaXfer); 4319 if (!pIoTask) 4320 { 4321 RTMemFree(pMetaXfer); 4322 return VERR_NO_MEMORY; 4323 } 4324 4325 Seg.cbSeg = cbRead; 4326 Seg.pvSeg = pMetaXfer->abData; 4327 4328 VDMETAXFER_TXDIR_SET(pMetaXfer->fFlags, VDMETAXFER_TXDIR_READ); 4329 rc = pVDIo->pInterfaceIo->pfnReadAsync(pVDIo->pInterfaceIo->Core.pvUser, 4330 pIoStorage->pStorage, 4331 uOffset, &Seg, 1, 4332 cbRead, pIoTask, &pvTask); 4333 4334 if (RT_SUCCESS(rc) || rc == VERR_VD_ASYNC_IO_IN_PROGRESS) 4335 { 4336 bool fInserted = RTAvlrFileOffsetInsert(pIoStorage->pTreeMetaXfers, &pMetaXfer->Core); 4337 Assert(fInserted); 4338 } 4339 else 4340 RTMemFree(pMetaXfer); 4341 4342 if (RT_SUCCESS(rc)) 4343 { 4344 VDMETAXFER_TXDIR_SET(pMetaXfer->fFlags, VDMETAXFER_TXDIR_NONE); 4345 vdIoTaskFree(pDisk, pIoTask); 4346 } 4347 else if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS && !pfnComplete) 4348 rc = VERR_VD_NOT_ENOUGH_METADATA; 4349 } 4350 4351 Assert(VALID_PTR(pMetaXfer) || RT_FAILURE(rc)); 4352 4353 if (RT_SUCCESS(rc) || rc == VERR_VD_NOT_ENOUGH_METADATA || rc == VERR_VD_ASYNC_IO_IN_PROGRESS) 4354 { 4355 /* If it is pending add the request to the list. */ 4356 if (VDMETAXFER_TXDIR_GET(pMetaXfer->fFlags) == VDMETAXFER_TXDIR_READ) 4357 { 4358 PVDIOCTXDEFERRED pDeferred = (PVDIOCTXDEFERRED)RTMemAllocZ(sizeof(VDIOCTXDEFERRED)); 4359 AssertPtr(pDeferred); 4360 4361 RTListInit(&pDeferred->NodeDeferred); 4362 pDeferred->pIoCtx = pIoCtx; 4363 4364 ASMAtomicIncU32(&pIoCtx->cMetaTransfersPending); 4365 RTListAppend(&pMetaXfer->ListIoCtxWaiting, &pDeferred->NodeDeferred); 4366 rc = VERR_VD_NOT_ENOUGH_METADATA; 4367 } 4368 else 4369 { 4370 /* Transfer the data. */ 4371 pMetaXfer->cRefs++; 4372 Assert(pMetaXfer->cbMeta >= cbRead); 4373 Assert(pMetaXfer->Core.Key == (RTFOFF)uOffset); 4374 memcpy(pvBuf, pMetaXfer->abData, cbRead); 4375 *ppMetaXfer = pMetaXfer; 4376 } 4377 } 4378 4455 /* Allocate a new meta transfer. */ 4456 pMetaXfer = vdMetaXferAlloc(pIoStorage, uOffset, cbRead); 4457 if (!pMetaXfer) 4458 return VERR_NO_MEMORY; 4459 4460 pIoTask = vdIoTaskMetaAlloc(pIoStorage, pfnComplete, pvCompleteUser, pMetaXfer); 4461 if (!pIoTask) 4462 { 4463 RTMemFree(pMetaXfer); 4464 return VERR_NO_MEMORY; 4465 } 4466 4467 Seg.cbSeg = cbRead; 4468 Seg.pvSeg = pMetaXfer->abData; 4469 4470 VDMETAXFER_TXDIR_SET(pMetaXfer->fFlags, VDMETAXFER_TXDIR_READ); 4471 rc = pVDIo->pInterfaceIo->pfnReadAsync(pVDIo->pInterfaceIo->Core.pvUser, 4472 pIoStorage->pStorage, 4473 uOffset, &Seg, 1, 4474 cbRead, pIoTask, &pvTask); 4475 4476 if (RT_SUCCESS(rc) || rc == VERR_VD_ASYNC_IO_IN_PROGRESS) 4477 { 4478 bool fInserted = RTAvlrFileOffsetInsert(pIoStorage->pTreeMetaXfers, &pMetaXfer->Core); 4479 Assert(fInserted); 4480 } 4481 else 4482 RTMemFree(pMetaXfer); 4483 4484 if (RT_SUCCESS(rc)) 4485 { 4486 VDMETAXFER_TXDIR_SET(pMetaXfer->fFlags, VDMETAXFER_TXDIR_NONE); 4487 vdIoTaskFree(pDisk, pIoTask); 4488 } 4489 else if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS && !pfnComplete) 4490 rc = VERR_VD_NOT_ENOUGH_METADATA; 4491 } 4492 4493 Assert(VALID_PTR(pMetaXfer) || RT_FAILURE(rc)); 4494 4495 if (RT_SUCCESS(rc) || rc == VERR_VD_NOT_ENOUGH_METADATA || rc == VERR_VD_ASYNC_IO_IN_PROGRESS) 4496 { 4497 /* If it is pending add the request to the list. */ 4498 if (VDMETAXFER_TXDIR_GET(pMetaXfer->fFlags) == VDMETAXFER_TXDIR_READ) 4499 { 4500 PVDIOCTXDEFERRED pDeferred = (PVDIOCTXDEFERRED)RTMemAllocZ(sizeof(VDIOCTXDEFERRED)); 4501 AssertPtr(pDeferred); 4502 4503 RTListInit(&pDeferred->NodeDeferred); 4504 pDeferred->pIoCtx = pIoCtx; 4505 4506 ASMAtomicIncU32(&pIoCtx->cMetaTransfersPending); 4507 RTListAppend(&pMetaXfer->ListIoCtxWaiting, &pDeferred->NodeDeferred); 4508 rc = VERR_VD_NOT_ENOUGH_METADATA; 4509 } 4510 else 4511 { 4512 /* Transfer the data. */ 4513 pMetaXfer->cRefs++; 4514 Assert(pMetaXfer->cbMeta >= cbRead); 4515 Assert(pMetaXfer->Core.Key == (RTFOFF)uOffset); 4516 memcpy(pvBuf, pMetaXfer->abData, cbRead); 4517 *ppMetaXfer = pMetaXfer; 4518 } 4519 } 4520 } 4521 4522 LogFlowFunc(("returns rc=%Rrc\n", rc)); 4379 4523 return rc; 4380 4524 } … … 4401 4545 VERR_INVALID_POINTER); 4402 4546 4403 if (!pIoCtx) 4547 /** @todo: Enable check for sync I/O later. */ 4548 if ( pIoCtx 4549 && !(pIoCtx->fFlags & VDIOCTX_FLAGS_SYNC)) 4550 VD_THREAD_IS_CRITSECT_OWNER(pDisk); 4551 4552 if ( !pIoCtx 4553 || pIoCtx->fFlags & VDIOCTX_FLAGS_SYNC) 4404 4554 { 4405 4555 /* Handle synchronous metadata I/O. */ 4406 4556 /** @todo: Integrate with metadata transfers below. */ 4407 return pVDIo->pInterfaceIo->pfnWriteSync(pVDIo->pInterfaceIo->Core.pvUser, 4408 pIoStorage->pStorage, uOffset, 4409 pvBuf, cbWrite, NULL); 4410 } 4411 4412 VD_THREAD_IS_CRITSECT_OWNER(pDisk); 4413 4414 pMetaXfer = (PVDMETAXFER)RTAvlrFileOffsetGet(pIoStorage->pTreeMetaXfers, uOffset); 4415 if (!pMetaXfer) 4416 { 4417 /* Allocate a new meta transfer. */ 4418 pMetaXfer = vdMetaXferAlloc(pIoStorage, uOffset, cbWrite); 4557 rc = pVDIo->pInterfaceIo->pfnWriteSync(pVDIo->pInterfaceIo->Core.pvUser, 4558 pIoStorage->pStorage, uOffset, 4559 pvBuf, cbWrite, NULL); 4560 } 4561 else 4562 { 4563 pMetaXfer = (PVDMETAXFER)RTAvlrFileOffsetGet(pIoStorage->pTreeMetaXfers, uOffset); 4419 4564 if (!pMetaXfer) 4565 { 4566 /* Allocate a new meta transfer. */ 4567 pMetaXfer = vdMetaXferAlloc(pIoStorage, uOffset, cbWrite); 4568 if (!pMetaXfer) 4569 return VERR_NO_MEMORY; 4570 } 4571 else 4572 { 4573 Assert(pMetaXfer->cbMeta >= cbWrite); 4574 Assert(pMetaXfer->Core.Key == (RTFOFF)uOffset); 4575 fInTree = true; 4576 } 4577 4578 Assert(VDMETAXFER_TXDIR_GET(pMetaXfer->fFlags) == VDMETAXFER_TXDIR_NONE); 4579 4580 pIoTask = vdIoTaskMetaAlloc(pIoStorage, pfnComplete, pvCompleteUser, pMetaXfer); 4581 if (!pIoTask) 4582 { 4583 RTMemFree(pMetaXfer); 4420 4584 return VERR_NO_MEMORY; 4421 } 4422 else 4423 { 4424 Assert(pMetaXfer->cbMeta >= cbWrite); 4425 Assert(pMetaXfer->Core.Key == (RTFOFF)uOffset); 4426 fInTree = true; 4427 } 4428 4429 Assert(VDMETAXFER_TXDIR_GET(pMetaXfer->fFlags) == VDMETAXFER_TXDIR_NONE); 4430 4431 pIoTask = vdIoTaskMetaAlloc(pIoStorage, pfnComplete, pvCompleteUser, pMetaXfer); 4432 if (!pIoTask) 4433 { 4434 RTMemFree(pMetaXfer); 4435 return VERR_NO_MEMORY; 4436 } 4437 4438 memcpy(pMetaXfer->abData, pvBuf, cbWrite); 4439 Seg.cbSeg = cbWrite; 4440 Seg.pvSeg = pMetaXfer->abData; 4441 4442 ASMAtomicIncU32(&pIoCtx->cMetaTransfersPending); 4443 4444 VDMETAXFER_TXDIR_SET(pMetaXfer->fFlags, VDMETAXFER_TXDIR_WRITE); 4445 rc = pVDIo->pInterfaceIo->pfnWriteAsync(pVDIo->pInterfaceIo->Core.pvUser, 4446 pIoStorage->pStorage, 4447 uOffset, &Seg, 1, cbWrite, pIoTask, 4448 &pvTask); 4449 if (RT_SUCCESS(rc)) 4450 { 4451 VDMETAXFER_TXDIR_SET(pMetaXfer->fFlags, VDMETAXFER_TXDIR_NONE); 4452 ASMAtomicDecU32(&pIoCtx->cMetaTransfersPending); 4453 vdIoTaskFree(pDisk, pIoTask); 4454 if (fInTree && !pMetaXfer->cRefs) 4455 { 4456 LogFlow(("Removing meta xfer=%#p\n", pMetaXfer)); 4457 bool fRemoved = RTAvlrFileOffsetRemove(pIoStorage->pTreeMetaXfers, pMetaXfer->Core.Key) != NULL; 4458 AssertMsg(fRemoved, ("Metadata transfer wasn't removed\n")); 4585 } 4586 4587 memcpy(pMetaXfer->abData, pvBuf, cbWrite); 4588 Seg.cbSeg = cbWrite; 4589 Seg.pvSeg = pMetaXfer->abData; 4590 4591 ASMAtomicIncU32(&pIoCtx->cMetaTransfersPending); 4592 4593 VDMETAXFER_TXDIR_SET(pMetaXfer->fFlags, VDMETAXFER_TXDIR_WRITE); 4594 rc = pVDIo->pInterfaceIo->pfnWriteAsync(pVDIo->pInterfaceIo->Core.pvUser, 4595 pIoStorage->pStorage, 4596 uOffset, &Seg, 1, cbWrite, pIoTask, 4597 &pvTask); 4598 if (RT_SUCCESS(rc)) 4599 { 4600 VDMETAXFER_TXDIR_SET(pMetaXfer->fFlags, VDMETAXFER_TXDIR_NONE); 4601 ASMAtomicDecU32(&pIoCtx->cMetaTransfersPending); 4602 vdIoTaskFree(pDisk, pIoTask); 4603 if (fInTree && !pMetaXfer->cRefs) 4604 { 4605 LogFlow(("Removing meta xfer=%#p\n", pMetaXfer)); 4606 bool fRemoved = RTAvlrFileOffsetRemove(pIoStorage->pTreeMetaXfers, pMetaXfer->Core.Key) != NULL; 4607 AssertMsg(fRemoved, ("Metadata transfer wasn't removed\n")); 4608 RTMemFree(pMetaXfer); 4609 pMetaXfer = NULL; 4610 } 4611 } 4612 else if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS) 4613 { 4614 PVDIOCTXDEFERRED pDeferred = (PVDIOCTXDEFERRED)RTMemAllocZ(sizeof(VDIOCTXDEFERRED)); 4615 AssertPtr(pDeferred); 4616 4617 RTListInit(&pDeferred->NodeDeferred); 4618 pDeferred->pIoCtx = pIoCtx; 4619 4620 if (!fInTree) 4621 { 4622 bool fInserted = RTAvlrFileOffsetInsert(pIoStorage->pTreeMetaXfers, &pMetaXfer->Core); 4623 Assert(fInserted); 4624 } 4625 4626 RTListAppend(&pMetaXfer->ListIoCtxWaiting, &pDeferred->NodeDeferred); 4627 } 4628 else 4629 { 4459 4630 RTMemFree(pMetaXfer); 4460 4631 pMetaXfer = NULL; 4461 4632 } 4462 4633 } 4463 else if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS) 4464 { 4465 PVDIOCTXDEFERRED pDeferred = (PVDIOCTXDEFERRED)RTMemAllocZ(sizeof(VDIOCTXDEFERRED)); 4466 AssertPtr(pDeferred); 4467 4468 RTListInit(&pDeferred->NodeDeferred); 4469 pDeferred->pIoCtx = pIoCtx; 4470 4471 if (!fInTree) 4472 { 4473 bool fInserted = RTAvlrFileOffsetInsert(pIoStorage->pTreeMetaXfers, &pMetaXfer->Core); 4474 Assert(fInserted); 4475 } 4476 4477 RTListAppend(&pMetaXfer->ListIoCtxWaiting, &pDeferred->NodeDeferred); 4478 } 4479 else 4480 { 4481 RTMemFree(pMetaXfer); 4482 pMetaXfer = NULL; 4483 } 4484 4634 4635 LogFlowFunc(("returns rc=%Rrc\n", rc)); 4485 4636 return rc; 4486 4637 } … … 4490 4641 PVDIO pVDIo = (PVDIO)pvUser; 4491 4642 PVBOXHDD pDisk = pVDIo->pDisk; 4492 PVDIOSTORAGE pIoStorage = pMetaXfer->pIoStorage; 4643 PVDIOSTORAGE pIoStorage; 4644 4645 /* 4646 * It is possible that we get called with a NULL metadata xfer handle 4647 * for synchronous I/O. Just exit. 4648 */ 4649 if (!pMetaXfer) 4650 return; 4651 4652 pIoStorage = pMetaXfer->pIoStorage; 4493 4653 4494 4654 VD_THREAD_IS_CRITSECT_OWNER(pDisk); … … 4530 4690 VERR_INVALID_POINTER); 4531 4691 4532 if (!pIoCtx) 4692 /** @todo: Enable check for sync I/O later. */ 4693 if ( pIoCtx 4694 && !(pIoCtx->fFlags & VDIOCTX_FLAGS_SYNC)) 4695 VD_THREAD_IS_CRITSECT_OWNER(pDisk); 4696 4697 if (pVDIo->fIgnoreFlush) 4698 return VINF_SUCCESS; 4699 4700 if ( !pIoCtx 4701 || pIoCtx->fFlags & VDIOCTX_FLAGS_SYNC) 4533 4702 { 4534 4703 /* Handle synchronous flushes. */ 4535 4704 /** @todo: Integrate with metadata transfers below. */ 4536 return pVDIo->pInterfaceIo->pfnFlushSync(pVDIo->pInterfaceIo->Core.pvUser, 4537 pIoStorage->pStorage); 4538 } 4539 4540 VD_THREAD_IS_CRITSECT_OWNER(pDisk); 4541 4542 if (pVDIo->fIgnoreFlush) 4543 return VINF_SUCCESS; 4544 4545 /* Allocate a new meta transfer. */ 4546 pMetaXfer = vdMetaXferAlloc(pIoStorage, 0, 0); 4547 if (!pMetaXfer) 4548 return VERR_NO_MEMORY; 4549 4550 pIoTask = vdIoTaskMetaAlloc(pIoStorage, pfnComplete, pvUser, pMetaXfer); 4551 if (!pIoTask) 4552 { 4553 RTMemFree(pMetaXfer); 4554 return VERR_NO_MEMORY; 4555 } 4556 4557 ASMAtomicIncU32(&pIoCtx->cMetaTransfersPending); 4558 4559 PVDIOCTXDEFERRED pDeferred = (PVDIOCTXDEFERRED)RTMemAllocZ(sizeof(VDIOCTXDEFERRED)); 4560 AssertPtr(pDeferred); 4561 4562 RTListInit(&pDeferred->NodeDeferred); 4563 pDeferred->pIoCtx = pIoCtx; 4564 4565 RTListAppend(&pMetaXfer->ListIoCtxWaiting, &pDeferred->NodeDeferred); 4566 VDMETAXFER_TXDIR_SET(pMetaXfer->fFlags, VDMETAXFER_TXDIR_FLUSH); 4567 rc = pVDIo->pInterfaceIo->pfnFlushAsync(pVDIo->pInterfaceIo->Core.pvUser, 4568 pIoStorage->pStorage, 4569 pIoTask, &pvTask); 4570 if (RT_SUCCESS(rc)) 4571 { 4572 VDMETAXFER_TXDIR_SET(pMetaXfer->fFlags, VDMETAXFER_TXDIR_NONE); 4573 ASMAtomicDecU32(&pIoCtx->cMetaTransfersPending); 4574 vdIoTaskFree(pDisk, pIoTask); 4575 RTMemFree(pDeferred); 4576 RTMemFree(pMetaXfer); 4577 } 4578 else if (rc != VERR_VD_ASYNC_IO_IN_PROGRESS) 4579 RTMemFree(pMetaXfer); 4580 4705 rc = pVDIo->pInterfaceIo->pfnFlushSync(pVDIo->pInterfaceIo->Core.pvUser, 4706 pIoStorage->pStorage); 4707 } 4708 else 4709 { 4710 /* Allocate a new meta transfer. */ 4711 pMetaXfer = vdMetaXferAlloc(pIoStorage, 0, 0); 4712 if (!pMetaXfer) 4713 return VERR_NO_MEMORY; 4714 4715 pIoTask = vdIoTaskMetaAlloc(pIoStorage, pfnComplete, pvUser, pMetaXfer); 4716 if (!pIoTask) 4717 { 4718 RTMemFree(pMetaXfer); 4719 return VERR_NO_MEMORY; 4720 } 4721 4722 ASMAtomicIncU32(&pIoCtx->cMetaTransfersPending); 4723 4724 PVDIOCTXDEFERRED pDeferred = (PVDIOCTXDEFERRED)RTMemAllocZ(sizeof(VDIOCTXDEFERRED)); 4725 AssertPtr(pDeferred); 4726 4727 RTListInit(&pDeferred->NodeDeferred); 4728 pDeferred->pIoCtx = pIoCtx; 4729 4730 RTListAppend(&pMetaXfer->ListIoCtxWaiting, &pDeferred->NodeDeferred); 4731 VDMETAXFER_TXDIR_SET(pMetaXfer->fFlags, VDMETAXFER_TXDIR_FLUSH); 4732 rc = pVDIo->pInterfaceIo->pfnFlushAsync(pVDIo->pInterfaceIo->Core.pvUser, 4733 pIoStorage->pStorage, 4734 pIoTask, &pvTask); 4735 if (RT_SUCCESS(rc)) 4736 { 4737 VDMETAXFER_TXDIR_SET(pMetaXfer->fFlags, VDMETAXFER_TXDIR_NONE); 4738 ASMAtomicDecU32(&pIoCtx->cMetaTransfersPending); 4739 vdIoTaskFree(pDisk, pIoTask); 4740 RTMemFree(pDeferred); 4741 RTMemFree(pMetaXfer); 4742 } 4743 else if (rc != VERR_VD_ASYNC_IO_IN_PROGRESS) 4744 RTMemFree(pMetaXfer); 4745 } 4746 4747 LogFlowFunc(("returns rc=%Rrc\n", rc)); 4581 4748 return rc; 4582 4749 } … … 4589 4756 size_t cbCopied = 0; 4590 4757 4591 VD_THREAD_IS_CRITSECT_OWNER(pDisk); 4758 /** @todo: Enable check for sync I/O later. */ 4759 if (!(pIoCtx->fFlags & VDIOCTX_FLAGS_SYNC)) 4760 VD_THREAD_IS_CRITSECT_OWNER(pDisk); 4592 4761 4593 4762 cbCopied = vdIoCtxCopyTo(pIoCtx, (uint8_t *)pvBuf, cbBuf); … … 4606 4775 size_t cbCopied = 0; 4607 4776 4608 VD_THREAD_IS_CRITSECT_OWNER(pDisk); 4777 /** @todo: Enable check for sync I/O later. */ 4778 if (!(pIoCtx->fFlags & VDIOCTX_FLAGS_SYNC)) 4779 VD_THREAD_IS_CRITSECT_OWNER(pDisk); 4609 4780 4610 4781 cbCopied = vdIoCtxCopyFrom(pIoCtx, (uint8_t *)pvBuf, cbBuf); … … 4622 4793 size_t cbSet = 0; 4623 4794 4624 VD_THREAD_IS_CRITSECT_OWNER(pDisk); 4795 /** @todo: Enable check for sync I/O later. */ 4796 if (!(pIoCtx->fFlags & VDIOCTX_FLAGS_SYNC)) 4797 VD_THREAD_IS_CRITSECT_OWNER(pDisk); 4625 4798 4626 4799 cbSet = vdIoCtxSet(pIoCtx, ch, cb); … … 4640 4813 size_t cbCreated = 0; 4641 4814 4642 VD_THREAD_IS_CRITSECT_OWNER(pDisk); 4815 /** @todo: Enable check for sync I/O later. */ 4816 if (!(pIoCtx->fFlags & VDIOCTX_FLAGS_SYNC)) 4817 VD_THREAD_IS_CRITSECT_OWNER(pDisk); 4643 4818 4644 4819 cbCreated = RTSgBufSegArrayCreate(&pIoCtx->Req.Io.SgBuf, paSeg, pcSeg, cbData); … … 4659 4834 * Example is that iSCSI is doing an asynchronous write but calls us already 4660 4835 * while the other thread is still hanging in vdWriteHelperAsync and couldn't update 4661 * the fBlocked state yet.4836 * the blocked state yet. 4662 4837 * It can overwrite the state to true before we call vdIoCtxContinue and the 4663 4838 * the request would hang indefinite. … … 4667 4842 4668 4843 /* Continue */ 4669 pIoCtx->f Blocked = false;4844 pIoCtx->fFlags &= ~VDIOCTX_FLAGS_BLOCKED; 4670 4845 ASMAtomicSubU32(&pIoCtx->Req.Io.cbTransferLeft, cbCompleted); 4671 4846 … … 4678 4853 4679 4854 vdDiskCritSectLeave(pDisk, NULL); 4855 } 4856 4857 static DECLCALLBACK(bool) vdIOIntIoCtxIsSynchronous(void *pvUser, PVDIOCTX pIoCtx) 4858 { 4859 NOREF(pvUser); 4860 return !!(pIoCtx->fFlags & VDIOCTX_FLAGS_SYNC); 4861 } 4862 4863 static DECLCALLBACK(bool) vdIOIntIoCtxIsZero(void *pvUser, PVDIOCTX pIoCtx, size_t cbCheck, 4864 bool fAdvance) 4865 { 4866 NOREF(pvUser); 4867 4868 bool fIsZero = RTSgBufIsZero(&pIoCtx->Req.Io.SgBuf, cbCheck); 4869 if (fIsZero && fAdvance) 4870 RTSgBufAdvance(&pIoCtx->Req.Io.SgBuf, cbCheck); 4871 4872 return fIsZero; 4680 4873 } 4681 4874 … … 4962 5155 pIfIoInt->pfnIoCtxSegArrayCreate = vdIOIntIoCtxSegArrayCreate; 4963 5156 pIfIoInt->pfnIoCtxCompleted = vdIOIntIoCtxCompleted; 5157 pIfIoInt->pfnIoCtxIsSynchronous = vdIOIntIoCtxIsSynchronous; 5158 pIfIoInt->pfnIoCtxIsZero = vdIOIntIoCtxIsZero; 4964 5159 } 4965 5160 … … 6748 6943 { 6749 6944 size_t cbThisRead = RT_MIN(VD_MERGE_BUFFER_SIZE, cbRemaining); 6945 RTSGSEG SegmentBuf; 6946 RTSGBUF SgBuf; 6947 VDIOCTX IoCtx; 6948 6949 SegmentBuf.pvSeg = pvBuf; 6950 SegmentBuf.cbSeg = VD_MERGE_BUFFER_SIZE; 6951 RTSgBufInit(&SgBuf, &SegmentBuf, 1); 6952 vdIoCtxInit(&IoCtx, pDisk, VDIOCTXTXDIR_READ, 0, 0, NULL, 6953 &SgBuf, NULL, NULL, VDIOCTX_FLAGS_SYNC); 6750 6954 6751 6955 /* Need to hold the write lock during a read-write operation. */ … … 6754 6958 fLockWrite = true; 6755 6959 6756 rc = pImageTo->Backend->pfn Read(pImageTo->pBackendData,6757 uOffset, pvBuf, cbThisRead,6758 &cbThisRead);6960 rc = pImageTo->Backend->pfnAsyncRead(pImageTo->pBackendData, 6961 uOffset, cbThisRead, 6962 &IoCtx, &cbThisRead); 6759 6963 if (rc == VERR_VD_BLOCK_FREE) 6760 6964 { … … 6767 6971 pCurrImage = pCurrImage->pPrev) 6768 6972 { 6769 rc = pCurrImage->Backend->pfnRead(pCurrImage->pBackendData, 6770 uOffset, pvBuf, 6771 cbThisRead, 6772 &cbThisRead); 6973 rc = pCurrImage->Backend->pfnAsyncRead(pCurrImage->pBackendData, 6974 uOffset, cbThisRead, 6975 &IoCtx, &cbThisRead); 6773 6976 } 6774 6977 … … 6869 7072 { 6870 7073 size_t cbThisRead = RT_MIN(VD_MERGE_BUFFER_SIZE, cbRemaining); 7074 RTSGSEG SegmentBuf; 7075 RTSGBUF SgBuf; 7076 VDIOCTX IoCtx; 7077 6871 7078 rc = VERR_VD_BLOCK_FREE; 7079 7080 SegmentBuf.pvSeg = pvBuf; 7081 SegmentBuf.cbSeg = VD_MERGE_BUFFER_SIZE; 7082 RTSgBufInit(&SgBuf, &SegmentBuf, 1); 7083 vdIoCtxInit(&IoCtx, pDisk, VDIOCTXTXDIR_READ, 0, 0, NULL, 7084 &SgBuf, NULL, NULL, VDIOCTX_FLAGS_SYNC); 6872 7085 6873 7086 /* Need to hold the write lock during a read-write operation. */ … … 6884 7097 pCurrImage = pCurrImage->pPrev) 6885 7098 { 6886 rc = pCurrImage->Backend->pfn Read(pCurrImage->pBackendData,6887 uOffset, pvBuf,6888 cbThisRead, &cbThisRead);7099 rc = pCurrImage->Backend->pfnAsyncRead(pCurrImage->pBackendData, 7100 uOffset, cbThisRead, 7101 &IoCtx, &cbThisRead); 6889 7102 } 6890 7103 … … 8081 8294 8082 8295 vdResetModifiedFlag(pDisk); 8083 rc = pImage->Backend->pfnFlush(pImage->pBackendData); 8084 8296 8297 VDIOCTX IoCtx; 8298 vdIoCtxInit(&IoCtx, pDisk, VDIOCTXTXDIR_FLUSH, 0, 0, NULL, 8299 NULL, NULL, NULL, VDIOCTX_FLAGS_SYNC); 8300 rc = pImage->Backend->pfnAsyncFlush(pImage->pBackendData, &IoCtx); 8301 8302 #if 0 /** @todo: Change cache implementation. */ 8085 8303 if ( RT_SUCCESS(rc) 8086 8304 && pDisk->pCache) 8087 8305 rc = pDisk->pCache->Backend->pfnFlush(pDisk->pCache->pBackendData); 8306 #endif 8088 8307 } while (0); 8089 8308 -
trunk/src/VBox/Storage/VDI.cpp
r44233 r44242 2548 2548 || cbToWrite == getImageBlockSize(&pImage->Header))) 2549 2549 { 2550 #if 0 /** @todo Provide interface to check an I/O context for a specific value */2551 2550 /* If the destination block is unallocated at this point, it's 2552 2551 * either a zero block or a block which hasn't been used so far 2553 2552 * (which also means that it's a zero block. Don't need to write 2554 2553 * anything to this block if the data consists of just zeroes. */ 2555 Assert(!(cbToWrite % 4)); 2556 Assert(cbToWrite * 8 <= UINT32_MAX); 2557 if (ASMBitFirstSet((volatile void *)pvBuf, (uint32_t)cbToWrite * 8) == -1) 2554 if (vdIfIoIntIoCtxIsZero(pImage->pIfIo, pIoCtx, cbToWrite, true)) 2558 2555 { 2559 2556 pImage->paBlocks[uBlock] = VDI_IMAGE_BLOCK_ZERO; 2557 *pcbPreRead = 0; 2558 *pcbPostRead = 0; 2560 2559 break; 2561 2560 } 2562 #endif2563 2561 } 2564 2562
Note:
See TracChangeset
for help on using the changeset viewer.