Changeset 38876 in vbox
- Timestamp:
- Sep 27, 2011 9:03:15 AM (14 years ago)
- svn:sync-xref-src-repo-rev:
- 74198
- Location:
- trunk
- Files:
-
- 15 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/VBox/vd-plugin.h
r38621 r38876 601 601 unsigned fDiscard)); 602 602 603 /** 604 * Discards the given amount of bytes decreasing the size of the image if possible 605 * callback version for asynchronous I/O. 606 * 607 * @returns VBox status code. 608 * @retval VERR_VD_DISCARD_ALIGNMENT_NOT_MET if the range doesn't meet the required alignment 609 * for the discard. 610 * @param pBackendData Opaque state data for this image. 611 * @param pIoCtx I/O context associated with this request. 612 * @param uOffset The offset of the first byte to discard. 613 * @param cbDiscard How many bytes to discard. 614 * @param pcbPreAllocated Pointer to the returned amount of bytes that must 615 * be discarded before the range to perform a full 616 * block discard. 617 * @param pcbPostAllocated Pointer to the returned amount of bytes that must 618 * be discarded after the range to perform a full 619 * block discard. 620 * @param pcbActuallyDiscarded Pointer to the returned amount of bytes which 621 * could be actually discarded. 622 * @param ppbmAllocationBitmap Where to store the pointer to the allocation bitmap 623 * if VERR_VD_DISCARD_ALIGNMENT_NOT_MET is returned or NULL 624 * if the allocation bitmap should be returned. 625 * @param fDiscard Flags which affect discard behavior. Combination 626 * of the VD_DISCARD_* flags. 627 */ 628 DECLR3CALLBACKMEMBER(int, pfnAsyncDiscard, (void *pBackendData, PVDIOCTX pIoCtx, 629 uint64_t uOffset, size_t cbDiscard, 630 size_t *pcbPreAllocated, 631 size_t *pcbPostAllocated, 632 size_t *pcbActuallyDiscarded, 633 void **ppbmAllocationBitmap, 634 unsigned fDiscard)); 635 603 636 } VBOXHDDBACKEND; 604 637 -
trunk/include/VBox/vd.h
r38621 r38876 398 398 399 399 /** 400 * VD range descriptor.401 */402 typedef struct VDRANGE403 {404 /** Start offset in bytes, multiple of 512. */405 uint64_t offStart;406 /** Amount of bytes described by this range, multiple of 512. */407 size_t cbRange;408 } VDRANGE;409 410 /** Pointer to a range descriptor. */411 typedef VDRANGE *PVDRANGE;412 /** Pointer to a constant range descriptor. */413 typedef const VDRANGE *PCVDRANGE;414 415 /**416 400 * VBox HDD Container main structure. 417 401 */ … … 1122 1106 * appear to contain data. This method is mainly used to implement TRIM support. 1123 1107 */ 1124 VBOXDDU_DECL(int) VDDiscardRanges(PVBOXHDD pDisk, PC VDRANGE paRanges, unsigned cRanges);1108 VBOXDDU_DECL(int) VDDiscardRanges(PVBOXHDD pDisk, PCRTRANGE paRanges, unsigned cRanges); 1125 1109 1126 1110 … … 1170 1154 PFNVDASYNCTRANSFERCOMPLETE pfnComplete, 1171 1155 void *pvUser1, void *pvUser2); 1156 1157 /** 1158 * Start an asynchronous discard request. 1159 * 1160 * @return VBox status code. 1161 * @param pDisk Pointer to HDD container. 1162 * @param paRanges The array of ranges to discard. 1163 * @param cRanges Number of entries in the array. 1164 * @param pfnComplete Completion callback. 1165 * @param pvUser1 User data which is passed on completion. 1166 * @param pvUser2 User data which is passed on completion. 1167 */ 1168 VBOXDDU_DECL(int) VDAsyncDiscardRanges(PVBOXHDD pDisk, PCRTRANGE paRanges, unsigned cRanges, 1169 PFNVDASYNCTRANSFERCOMPLETE pfnComplete, 1170 void *pvUser1, void *pvUser); 1171 1172 1172 RT_C_DECLS_END 1173 1173 -
trunk/include/VBox/vddbg.h
r38632 r38876 175 175 * @param phIoLogEntry Where to store the I/O log entry handle on success. 176 176 */ 177 VBOXDDU_DECL(int) VDDbgIoLogStartDiscard(VDIOLOGGER hIoLogger, bool fAsync, P VDRANGE paRanges, unsigned cRanges,177 VBOXDDU_DECL(int) VDDbgIoLogStartDiscard(VDIOLOGGER hIoLogger, bool fAsync, PCRTRANGE paRanges, unsigned cRanges, 178 178 PVDIOLOGENT phIoLogEntry); 179 179 … … 239 239 */ 240 240 VBOXDDU_DECL(int) VDDbgIoLogEventGetStartDiscard(VDIOLOGGER hIoLogger, uint64_t *pidEvent, bool *pfAsync, 241 P VDRANGE *ppaRanges, unsigned *pcRanges);241 PRTRANGE *ppaRanges, unsigned *pcRanges); 242 242 243 243 /** -
trunk/src/VBox/Storage/DMG.cpp
r38623 r38876 2334 2334 NULL, 2335 2335 /* pfnDiscard */ 2336 NULL, 2337 /* pfnAsyncDiscard */ 2336 2338 NULL 2337 2339 }; -
trunk/src/VBox/Storage/Debug/VDDbgIoLog.cpp
r38644 r38876 449 449 } 450 450 451 VBOXDDU_DECL(int) VDDbgIoLogStartDiscard(VDIOLOGGER hIoLogger, bool fAsync, P VDRANGE paRanges, unsigned cRanges,451 VBOXDDU_DECL(int) VDDbgIoLogStartDiscard(VDIOLOGGER hIoLogger, bool fAsync, PCRTRANGE paRanges, unsigned cRanges, 452 452 PVDIOLOGENT phIoLogEntry) 453 453 { … … 697 697 698 698 VBOXDDU_DECL(int) VDDbgIoLogEventGetStartDiscard(VDIOLOGGER hIoLogger, uint64_t *pidEvent, bool *pfAsync, 699 P VDRANGE *ppaRanges, unsigned *pcRanges)699 PRTRANGE *ppaRanges, unsigned *pcRanges) 700 700 { 701 701 int rc = VINF_SUCCESS; … … 716 716 if (RT_SUCCESS(rc)) 717 717 { 718 P VDRANGE paRanges = NULL;718 PRTRANGE paRanges = NULL; 719 719 IoLogEntryDiscard DiscardRange; 720 720 … … 724 724 *pcRanges = RT_LE2H_U32(Entry.Discard.cRanges); 725 725 726 paRanges = (P VDRANGE)RTMemAllocZ(*pcRanges * sizeof(VDRANGE));726 paRanges = (PRTRANGE)RTMemAllocZ(*pcRanges * sizeof(RTRANGE)); 727 727 if (paRanges) 728 728 { -
trunk/src/VBox/Storage/ISCSI.cpp
r38621 r38876 5572 5572 NULL, 5573 5573 /* pfnDiscard */ 5574 NULL, 5575 /* pfnAsyncDiscard */ 5574 5576 NULL 5575 5577 }; -
trunk/src/VBox/Storage/QCOW.cpp
r38875 r38876 2854 2854 NULL, 2855 2855 /* pfnDiscard */ 2856 NULL, 2857 /* pfnAsyncDiscard */ 2856 2858 NULL 2857 2859 }; -
trunk/src/VBox/Storage/QED.cpp
r38623 r38876 2921 2921 qedResize, 2922 2922 /* pfnDiscard */ 2923 NULL, 2924 /* pfnAsyncDiscard */ 2923 2925 NULL 2924 2926 }; -
trunk/src/VBox/Storage/RAW.cpp
r38621 r38876 1292 1292 NULL, 1293 1293 /* pfnDiscard */ 1294 NULL, 1295 /* pfnAsyncDiscard */ 1294 1296 NULL 1295 1297 }; -
trunk/src/VBox/Storage/VD.cpp
r38673 r38876 273 273 /** Flush */ 274 274 VDIOCTXTXDIR_FLUSH, 275 /** Discard */ 276 VDIOCTXTXDIR_DISCARD, 275 277 /** 32bit hack */ 276 278 VDIOCTXTXDIR_32BIT_HACK = 0x7fffffff … … 291 293 /** Return code. */ 292 294 int rcReq; 293 /** Transfer direction */294 VDIOCTXTXDIR enmTxDir;295 /** Number of bytes left until this context completes. */296 volatile uint32_t cbTransferLeft;297 /** Current offset */298 volatile uint64_t uOffset;299 /** Number of bytes to transfer */300 volatile size_t cbTransfer;301 /** Current image in the chain. */302 PVDIMAGE pImageCur;303 /** Start image to read from. pImageCur is reset to this304 * value after it reached the first image in the chain. */305 PVDIMAGE pImageStart;306 /** S/G buffer */307 RTSGBUF SgBuf;308 295 /** Flag whether the I/O context is blocked because it is in the growing list. */ 309 296 bool fBlocked; … … 321 308 /** Next transfer part after the current one completed. */ 322 309 PFNVDIOCTXTRANSFER pfnIoCtxTransferNext; 310 /** Transfer direction */ 311 VDIOCTXTXDIR enmTxDir; 312 /** Request type dependent data. */ 313 union 314 { 315 /** I/O request (read/write). */ 316 struct 317 { 318 /** Number of bytes left until this context completes. */ 319 volatile uint32_t cbTransferLeft; 320 /** Current offset */ 321 volatile uint64_t uOffset; 322 /** Number of bytes to transfer */ 323 volatile size_t cbTransfer; 324 /** Current image in the chain. */ 325 PVDIMAGE pImageCur; 326 /** Start image to read from. pImageCur is reset to this 327 * value after it reached the first image in the chain. */ 328 PVDIMAGE pImageStart; 329 /** S/G buffer */ 330 RTSGBUF SgBuf; 331 } Io; 332 /** Discard requests. */ 333 struct 334 { 335 /** Pointer to the range descriptor array. */ 336 PCRTRANGE paRanges; 337 /** Number of ranges in the array. */ 338 unsigned cRanges; 339 /** Range descriptor index which is processed. */ 340 unsigned idxRange; 341 /** Start offset to discard currently. */ 342 uint64_t offCur; 343 /** How many bytes left to discard in the current range. */ 344 size_t cbDiscardLeft; 345 /** How many bytes to discard in the current block (<= cbDiscardLeft). */ 346 size_t cbThisDiscard; 347 /** Discard block handled currently. */ 348 PVDDISCARDBLOCK pBlock; 349 } Discard; 350 } Req; 323 351 /** Parent I/O context if any. Sets the type of the context (root/child) */ 324 352 PVDIOCTX pIoCtxParent; … … 333 361 /** User argument 1 passed on completion. */ 334 362 void *pvUser1; 335 /** User argument 1passed on completion. */363 /** User argument 2 passed on completion. */ 336 364 void *pvUser2; 337 365 } Root; … … 369 397 } VDIOCTX; 370 398 399 /** 400 * List node for deferred I/O contexts. 401 */ 371 402 typedef struct VDIOCTXDEFERRED 372 403 { … … 501 532 &g_VciCacheBackend 502 533 }; 534 535 /** Forward declaration of the async discard helper. */ 536 static int vdDiscardHelperAsync(PVDIOCTX pIoCtx); 503 537 504 538 /** … … 1163 1197 } 1164 1198 else 1199 { 1200 RTMemFree(pbmAllocated); 1165 1201 rc = VERR_NO_MEMORY; 1202 } 1166 1203 } 1167 1204 } … … 1169 1206 { 1170 1207 /* Range lies partly in the block, update allocation bitmap. */ 1208 int32_t idxStart, idxEnd; 1209 1171 1210 cbThisDiscard = RT_MIN(cbDiscard, pBlock->Core.KeyLast - offStart + 1); 1172 rc = VERR_VD_DISCARD_ALIGNMENT_NOT_MET;1173 }1174 1175 Assert(cbDiscard >= cbThisDiscard);1176 1177 if (rc == VERR_VD_DISCARD_ALIGNMENT_NOT_MET)1178 {1179 int32_t idxStart, idxEnd;1180 1211 1181 1212 AssertPtr(pBlock); … … 1241 1272 * @param cRanges The number of ranges in the array. 1242 1273 */ 1243 static int vdDiscardHelper(PVBOXHDD pDisk, PC VDRANGE paRanges, unsigned cRanges)1274 static int vdDiscardHelper(PVBOXHDD pDisk, PCRTRANGE paRanges, unsigned cRanges) 1244 1275 { 1245 1276 int rc = VINF_SUCCESS; … … 1331 1362 pIoCtx->pDisk = pDisk; 1332 1363 pIoCtx->enmTxDir = enmTxDir; 1333 pIoCtx-> cbTransferLeft= cbTransfer;1334 pIoCtx-> uOffset= uOffset;1335 pIoCtx-> cbTransfer= cbTransfer;1336 pIoCtx-> pImageStart= pImageStart;1337 pIoCtx-> pImageCur= pImageStart;1364 pIoCtx->Req.Io.cbTransferLeft = cbTransfer; 1365 pIoCtx->Req.Io.uOffset = uOffset; 1366 pIoCtx->Req.Io.cbTransfer = cbTransfer; 1367 pIoCtx->Req.Io.pImageStart = pImageStart; 1368 pIoCtx->Req.Io.pImageCur = pImageStart; 1338 1369 pIoCtx->cDataTransfersPending = 0; 1339 1370 pIoCtx->cMetaTransfersPending = 0; … … 1347 1378 /* There is no S/G list for a flush request. */ 1348 1379 if (enmTxDir != VDIOCTXTXDIR_FLUSH) 1349 RTSgBufClone(&pIoCtx-> SgBuf, pcSgBuf);1380 RTSgBufClone(&pIoCtx->Req.Io.SgBuf, pcSgBuf); 1350 1381 else 1351 memset(&pIoCtx-> SgBuf, 0, sizeof(RTSGBUF));1382 memset(&pIoCtx->Req.Io.SgBuf, 0, sizeof(RTSGBUF)); 1352 1383 } 1353 1384 … … 1378 1409 } 1379 1410 1411 DECLINLINE(PVDIOCTX) vdIoCtxDiscardAlloc(PVBOXHDD pDisk, PCRTRANGE paRanges, 1412 unsigned cRanges, 1413 PFNVDASYNCTRANSFERCOMPLETE pfnComplete, 1414 void *pvUser1, void *pvUser2, 1415 void *pvAllocation, 1416 PFNVDIOCTXTRANSFER pfnIoCtxTransfer) 1417 { 1418 PVDIOCTX pIoCtx = NULL; 1419 1420 pIoCtx = (PVDIOCTX)RTMemCacheAlloc(pDisk->hMemCacheIoCtx); 1421 if (RT_LIKELY(pIoCtx)) 1422 { 1423 pIoCtx->pDisk = pDisk; 1424 pIoCtx->enmTxDir = VDIOCTXTXDIR_DISCARD; 1425 pIoCtx->cDataTransfersPending = 0; 1426 pIoCtx->cMetaTransfersPending = 0; 1427 pIoCtx->fComplete = false; 1428 pIoCtx->fBlocked = false; 1429 pIoCtx->pvAllocation = pvAllocation; 1430 pIoCtx->pfnIoCtxTransfer = pfnIoCtxTransfer; 1431 pIoCtx->pfnIoCtxTransferNext = NULL; 1432 pIoCtx->rcReq = VINF_SUCCESS; 1433 pIoCtx->Req.Discard.paRanges = paRanges; 1434 pIoCtx->Req.Discard.cRanges = cRanges; 1435 pIoCtx->Req.Discard.idxRange = 0; 1436 pIoCtx->Req.Discard.cbDiscardLeft = 0; 1437 pIoCtx->Req.Discard.offCur = 0; 1438 pIoCtx->Req.Discard.cbThisDiscard = 0; 1439 1440 pIoCtx->pIoCtxParent = NULL; 1441 pIoCtx->Type.Root.pfnComplete = pfnComplete; 1442 pIoCtx->Type.Root.pvUser1 = pvUser1; 1443 pIoCtx->Type.Root.pvUser2 = pvUser2; 1444 } 1445 1446 LogFlow(("Allocated discard I/O context %#p\n", pIoCtx)); 1447 return pIoCtx; 1448 } 1449 1380 1450 DECLINLINE(PVDIOCTX) vdIoCtxChildAlloc(PVBOXHDD pDisk, VDIOCTXTXDIR enmTxDir, 1381 1451 uint64_t uOffset, size_t cbTransfer, … … 1459 1529 AssertPtr(pIoCtx->pIoCtxParent); 1460 1530 1461 RTSgBufReset(&pIoCtx-> SgBuf);1462 pIoCtx-> uOffset = pIoCtx->Type.Child.uOffsetSaved;1463 pIoCtx-> cbTransferLeft = pIoCtx->Type.Child.cbTransferLeftSaved;1531 RTSgBufReset(&pIoCtx->Req.Io.SgBuf); 1532 pIoCtx->Req.Io.uOffset = pIoCtx->Type.Child.uOffsetSaved; 1533 pIoCtx->Req.Io.cbTransferLeft = pIoCtx->Type.Child.cbTransferLeftSaved; 1464 1534 } 1465 1535 … … 1501 1571 static size_t vdIoCtxCopy(PVDIOCTX pIoCtxDst, PVDIOCTX pIoCtxSrc, size_t cbData) 1502 1572 { 1503 return RTSgBufCopy(&pIoCtxDst-> SgBuf, &pIoCtxSrc->SgBuf, cbData);1573 return RTSgBufCopy(&pIoCtxDst->Req.Io.SgBuf, &pIoCtxSrc->Req.Io.SgBuf, cbData); 1504 1574 } 1505 1575 1506 1576 static int vdIoCtxCmp(PVDIOCTX pIoCtx1, PVDIOCTX pIoCtx2, size_t cbData) 1507 1577 { 1508 return RTSgBufCmp(&pIoCtx1-> SgBuf, &pIoCtx2->SgBuf, cbData);1578 return RTSgBufCmp(&pIoCtx1->Req.Io.SgBuf, &pIoCtx2->Req.Io.SgBuf, cbData); 1509 1579 } 1510 1580 1511 1581 static size_t vdIoCtxCopyTo(PVDIOCTX pIoCtx, uint8_t *pbData, size_t cbData) 1512 1582 { 1513 return RTSgBufCopyToBuf(&pIoCtx-> SgBuf, pbData, cbData);1583 return RTSgBufCopyToBuf(&pIoCtx->Req.Io.SgBuf, pbData, cbData); 1514 1584 } 1515 1585 … … 1517 1587 static size_t vdIoCtxCopyFrom(PVDIOCTX pIoCtx, uint8_t *pbData, size_t cbData) 1518 1588 { 1519 return RTSgBufCopyFromBuf(&pIoCtx-> SgBuf, pbData, cbData);1589 return RTSgBufCopyFromBuf(&pIoCtx->Req.Io.SgBuf, pbData, cbData); 1520 1590 } 1521 1591 1522 1592 static size_t vdIoCtxSet(PVDIOCTX pIoCtx, uint8_t ch, size_t cbData) 1523 1593 { 1524 return RTSgBufSet(&pIoCtx-> SgBuf, ch, cbData);1594 return RTSgBufSet(&pIoCtx->Req.Io.SgBuf, ch, cbData); 1525 1595 } 1526 1596 … … 1534 1604 RTCritSectEnter(&pDisk->CritSect); 1535 1605 1536 if ( !pIoCtx->cbTransferLeft 1537 && !pIoCtx->cMetaTransfersPending 1606 if ( !pIoCtx->cMetaTransfersPending 1538 1607 && !pIoCtx->cDataTransfersPending 1539 1608 && !pIoCtx->pfnIoCtxTransfer) … … 1567 1636 /* Call the transfer function advancing to the next while there is no error. */ 1568 1637 while ( pIoCtx->pfnIoCtxTransfer 1638 && !pIoCtx->cMetaTransfersPending 1569 1639 && RT_SUCCESS(rc)) 1570 1640 { … … 1582 1652 1583 1653 if ( RT_SUCCESS(rc) 1584 && !pIoCtx->cbTransferLeft1585 1654 && !pIoCtx->cMetaTransfersPending 1586 1655 && !pIoCtx->cDataTransfersPending) … … 1607 1676 RTCritSectLeave(&pDisk->CritSect); 1608 1677 1609 LogFlowFunc(("pIoCtx=%#p rc=%Rrc c bTransferLeft=%u cMetaTransfersPending=%u fComplete=%RTbool\n",1610 pIoCtx, rc, pIoCtx->c bTransferLeft, pIoCtx->cMetaTransfersPending,1678 LogFlowFunc(("pIoCtx=%#p rc=%Rrc cDataTransfersPending=%u cMetaTransfersPending=%u fComplete=%RTbool\n", 1679 pIoCtx, rc, pIoCtx->cDataTransfersPending, pIoCtx->cMetaTransfersPending, 1611 1680 pIoCtx->fComplete)); 1612 1681 … … 1711 1780 { 1712 1781 int rc; 1713 size_t cbToRead = pIoCtx-> cbTransfer;1714 uint64_t uOffset = pIoCtx-> uOffset;1782 size_t cbToRead = pIoCtx->Req.Io.cbTransfer; 1783 uint64_t uOffset = pIoCtx->Req.Io.uOffset; 1715 1784 PVDIMAGE pCurrImage = NULL; 1716 1785 size_t cbThisRead; … … 1719 1788 do 1720 1789 { 1721 pCurrImage = pIoCtx-> pImageCur;1790 pCurrImage = pIoCtx->Req.Io.pImageCur; 1722 1791 1723 1792 /* Search for image with allocated block. Do not attempt to read more … … 1751 1820 /* No image in the chain contains the data for the block. */ 1752 1821 vdIoCtxSet(pIoCtx, '\0', cbThisRead); 1753 ASMAtomicSubU32(&pIoCtx-> cbTransferLeft, cbThisRead);1822 ASMAtomicSubU32(&pIoCtx->Req.Io.cbTransferLeft, cbThisRead); 1754 1823 rc = VINF_SUCCESS; 1755 1824 } … … 1774 1843 { 1775 1844 /* Save the current state. */ 1776 pIoCtx-> uOffset = uOffset;1777 pIoCtx-> cbTransfer = cbToRead;1778 pIoCtx-> pImageCur = pCurrImage ? pCurrImage : pIoCtx->pImageStart;1845 pIoCtx->Req.Io.uOffset = uOffset; 1846 pIoCtx->Req.Io.cbTransfer = cbToRead; 1847 pIoCtx->Req.Io.pImageCur = pCurrImage ? pCurrImage : pIoCtx->Req.Io.pImageStart; 1779 1848 } 1780 1849 … … 2240 2309 int rc = VINF_SUCCESS; 2241 2310 PVBOXHDD pDisk = pIoCtx->pDisk; 2242 PVDIMAGE pImage = pIoCtx-> pImageCur;2311 PVDIMAGE pImage = pIoCtx->Req.Io.pImageCur; 2243 2312 2244 2313 rc = pImage->Backend->pfnAsyncFlush(pImage->pBackendData, pIoCtx); … … 2284 2353 else if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS) 2285 2354 { 2355 ASMAtomicIncU32(&pIoCtx->cDataTransfersPending); 2286 2356 pIoCtx->fBlocked = true; 2287 2357 } … … 2394 2464 static int vdWriteHelperOptimizedCommitAsync(PVDIOCTX pIoCtx) 2395 2465 { 2396 int rc = VINF_SUCCESS;2397 PVDIMAGE pImage = pIoCtx->pImageStart;2398 size_t cbPreRead 2399 size_t cbPostRead 2400 size_t cbThisWrite 2466 int rc = VINF_SUCCESS; 2467 PVDIMAGE pImage = pIoCtx->Req.Io.pImageStart; 2468 size_t cbPreRead = pIoCtx->Type.Child.cbPreRead; 2469 size_t cbPostRead = pIoCtx->Type.Child.cbPostRead; 2470 size_t cbThisWrite = pIoCtx->Type.Child.cbTransferParent; 2401 2471 2402 2472 LogFlowFunc(("pIoCtx=%#p\n", pIoCtx)); 2403 2473 rc = pImage->Backend->pfnAsyncWrite(pImage->pBackendData, 2404 pIoCtx-> uOffset - cbPreRead,2474 pIoCtx->Req.Io.uOffset - cbPreRead, 2405 2475 cbPreRead + cbThisWrite + cbPostRead, 2406 2476 pIoCtx, NULL, &cbPreRead, &cbPostRead, 0); … … 2423 2493 { 2424 2494 int rc = VINF_SUCCESS; 2425 PVDIMAGE pImage = pIoCtx->pImageCur;2495 PVDIMAGE pImage = pIoCtx->Req.Io.pImageCur; 2426 2496 size_t cbThisWrite = 0; 2427 2497 size_t cbPreRead = pIoCtx->Type.Child.cbPreRead; … … 2436 2506 AssertPtr(pIoCtxParent); 2437 2507 Assert(!pIoCtxParent->pIoCtxParent); 2438 Assert(!pIoCtx-> cbTransferLeft && !pIoCtx->cMetaTransfersPending);2508 Assert(!pIoCtx->Req.Io.cbTransferLeft && !pIoCtx->cMetaTransfersPending); 2439 2509 2440 2510 vdIoCtxChildReset(pIoCtx); 2441 2511 cbThisWrite = pIoCtx->Type.Child.cbTransferParent; 2442 RTSgBufAdvance(&pIoCtx-> SgBuf, cbPreRead);2512 RTSgBufAdvance(&pIoCtx->Req.Io.SgBuf, cbPreRead); 2443 2513 2444 2514 /* Check if the write would modify anything in this block. */ 2445 if (!RTSgBufCmp(&pIoCtx-> SgBuf, &pIoCtxParent->SgBuf, cbThisWrite))2515 if (!RTSgBufCmp(&pIoCtx->Req.Io.SgBuf, &pIoCtxParent->Req.Io.SgBuf, cbThisWrite)) 2446 2516 { 2447 2517 RTSGBUF SgBufSrcTmp; 2448 2518 2449 RTSgBufClone(&SgBufSrcTmp, &pIoCtxParent-> SgBuf);2519 RTSgBufClone(&SgBufSrcTmp, &pIoCtxParent->Req.Io.SgBuf); 2450 2520 RTSgBufAdvance(&SgBufSrcTmp, cbThisWrite); 2451 RTSgBufAdvance(&pIoCtx-> SgBuf, cbThisWrite);2452 2453 if (!cbWriteCopy || !RTSgBufCmp(&pIoCtx-> SgBuf, &SgBufSrcTmp, cbWriteCopy))2521 RTSgBufAdvance(&pIoCtx->Req.Io.SgBuf, cbThisWrite); 2522 2523 if (!cbWriteCopy || !RTSgBufCmp(&pIoCtx->Req.Io.SgBuf, &SgBufSrcTmp, cbWriteCopy)) 2454 2524 { 2455 2525 /* Block is completely unchanged, so no need to write anything. */ 2456 2526 LogFlowFunc(("Block didn't changed\n")); 2457 ASMAtomicWriteU32(&pIoCtx-> cbTransferLeft, 0);2458 RTSgBufAdvance(&pIoCtxParent-> SgBuf, cbThisWrite);2527 ASMAtomicWriteU32(&pIoCtx->Req.Io.cbTransferLeft, 0); 2528 RTSgBufAdvance(&pIoCtxParent->Req.Io.SgBuf, cbThisWrite); 2459 2529 return VINF_VD_ASYNC_IO_FINISHED; 2460 2530 } … … 2462 2532 2463 2533 /* Copy the data to the right place in the buffer. */ 2464 RTSgBufReset(&pIoCtx-> SgBuf);2465 RTSgBufAdvance(&pIoCtx-> SgBuf, cbPreRead);2534 RTSgBufReset(&pIoCtx->Req.Io.SgBuf); 2535 RTSgBufAdvance(&pIoCtx->Req.Io.SgBuf, cbPreRead); 2466 2536 vdIoCtxCopy(pIoCtx, pIoCtxParent, cbThisWrite); 2467 2537 … … 2478 2548 RTSGBUF SgBufParentTmp; 2479 2549 2480 RTSgBufClone(&SgBufParentTmp, &pIoCtxParent-> SgBuf);2481 RTSgBufCopy(&pIoCtx-> SgBuf, &SgBufParentTmp, cbWriteCopy);2550 RTSgBufClone(&SgBufParentTmp, &pIoCtxParent->Req.Io.SgBuf); 2551 RTSgBufCopy(&pIoCtx->Req.Io.SgBuf, &SgBufParentTmp, cbWriteCopy); 2482 2552 } 2483 2553 … … 2486 2556 if (cbFill) 2487 2557 { 2488 RTSgBufAdvance(&pIoCtx-> SgBuf, cbReadImage);2558 RTSgBufAdvance(&pIoCtx->Req.Io.SgBuf, cbReadImage); 2489 2559 vdIoCtxSet(pIoCtx, '\0', cbFill); 2490 2560 } … … 2492 2562 2493 2563 /* Write the full block to the virtual disk. */ 2494 RTSgBufReset(&pIoCtx-> SgBuf);2564 RTSgBufReset(&pIoCtx->Req.Io.SgBuf); 2495 2565 pIoCtx->pfnIoCtxTransferNext = vdWriteHelperOptimizedCommitAsync; 2496 2566 … … 2504 2574 LogFlowFunc(("pIoCtx=%#p\n", pIoCtx)); 2505 2575 2506 if (pIoCtx-> cbTransferLeft)2576 if (pIoCtx->Req.Io.cbTransferLeft) 2507 2577 rc = vdReadHelperAsync(pIoCtx); 2508 2578 2509 2579 if ( RT_SUCCESS(rc) 2510 && ( pIoCtx-> cbTransferLeft2580 && ( pIoCtx->Req.Io.cbTransferLeft 2511 2581 || pIoCtx->cMetaTransfersPending)) 2512 2582 rc = VERR_VD_ASYNC_IO_IN_PROGRESS; … … 2563 2633 /* Read the entire data of the block so that we can compare whether it will 2564 2634 * be modified by the write or not. */ 2565 pIoCtx-> cbTransferLeft = cbPreRead + cbThisWrite + cbPostRead - cbFill;2566 pIoCtx-> cbTransfer = pIoCtx->cbTransferLeft;2567 pIoCtx-> uOffset -= cbPreRead;2635 pIoCtx->Req.Io.cbTransferLeft = cbPreRead + cbThisWrite + cbPostRead - cbFill; 2636 pIoCtx->Req.Io.cbTransfer = pIoCtx->Req.Io.cbTransferLeft; 2637 pIoCtx->Req.Io.uOffset -= cbPreRead; 2568 2638 2569 2639 /* Next step */ … … 2579 2649 { 2580 2650 int rc; 2581 size_t cbWrite = pIoCtx-> cbTransfer;2582 uint64_t uOffset = pIoCtx-> uOffset;2583 PVDIMAGE pImage = pIoCtx-> pImageCur;2651 size_t cbWrite = pIoCtx->Req.Io.cbTransfer; 2652 uint64_t uOffset = pIoCtx->Req.Io.uOffset; 2653 PVDIMAGE pImage = pIoCtx->Req.Io.pImageCur; 2584 2654 PVBOXHDD pDisk = pIoCtx->pDisk; 2585 2655 unsigned fWrite; … … 2589 2659 rc = vdSetModifiedFlagAsync(pDisk, pIoCtx); 2590 2660 if (RT_FAILURE(rc)) /* Includes I/O in progress. */ 2661 return rc; 2662 2663 rc = vdDiscardSetRangeAllocated(pDisk, uOffset, cbWrite); 2664 if (RT_FAILURE(rc)) 2591 2665 return rc; 2592 2666 … … 2659 2733 { 2660 2734 LogFlow(("Child write request completed\n")); 2661 Assert(pIoCtx-> cbTransferLeft >= cbThisWrite);2662 ASMAtomicSubU32(&pIoCtx-> cbTransferLeft, cbThisWrite);2735 Assert(pIoCtx->Req.Io.cbTransferLeft >= cbThisWrite); 2736 ASMAtomicSubU32(&pIoCtx->Req.Io.cbTransferLeft, cbThisWrite); 2663 2737 vdIoCtxUnlockDisk(pDisk, pIoCtx, false /* fProcessDeferredReqs*/ ); 2664 2738 vdIoCtxFree(pDisk, pIoCtxWrite); … … 2669 2743 { 2670 2744 LogFlow(("Child write pending\n")); 2745 ASMAtomicIncU32(&pIoCtx->cDataTransfersPending); 2671 2746 pIoCtx->fBlocked = true; 2672 2747 rc = VERR_VD_ASYNC_IO_IN_PROGRESS; … … 2708 2783 rc = VINF_SUCCESS; 2709 2784 2710 pIoCtx-> uOffset = uOffset;2711 pIoCtx-> cbTransfer = cbWrite;2785 pIoCtx->Req.Io.uOffset = uOffset; 2786 pIoCtx->Req.Io.cbTransfer = cbWrite; 2712 2787 } 2713 2788 … … 2722 2797 int rc = VINF_SUCCESS; 2723 2798 PVBOXHDD pDisk = pIoCtx->pDisk; 2724 PVDIMAGE pImage = pIoCtx-> pImageCur;2799 PVDIMAGE pImage = pIoCtx->Req.Io.pImageCur; 2725 2800 2726 2801 rc = vdIoCtxLockDisk(pDisk, pIoCtx); … … 2735 2810 } 2736 2811 2812 return rc; 2813 } 2814 2815 /** 2816 * Async discard helper - discards a whole block which is recorded in the block 2817 * tree. 2818 * 2819 * @returns VBox status code. 2820 * @param pIoCtx The I/O context to operate on. 2821 */ 2822 static int vdDiscardWholeBlockAsync(PVDIOCTX pIoCtx) 2823 { 2824 int rc = VINF_SUCCESS; 2825 PVBOXHDD pDisk = pIoCtx->pDisk; 2826 PVDDISCARDSTATE pDiscard = pDisk->pDiscard; 2827 PVDDISCARDBLOCK pBlock = pIoCtx->Req.Discard.pBlock; 2828 size_t cbPreAllocated, cbPostAllocated, cbActuallyDiscarded; 2829 2830 LogFlowFunc(("pIoCtx=%#p\n", pIoCtx)); 2831 2832 AssertPtr(pBlock); 2833 2834 rc = pDisk->pLast->Backend->pfnAsyncDiscard(pDisk->pLast->pBackendData, pIoCtx, 2835 pBlock->Core.Key, pBlock->cbDiscard, 2836 &cbPreAllocated, &cbPostAllocated, 2837 &cbActuallyDiscarded, NULL, 0); 2838 Assert(rc != VERR_VD_DISCARD_ALIGNMENT_NOT_MET); 2839 Assert(!cbPreAllocated); 2840 Assert(!cbPostAllocated); 2841 Assert(cbActuallyDiscarded == pBlock->cbDiscard || RT_FAILURE(rc)); 2842 2843 /* Remove the block on success. */ 2844 if ( RT_SUCCESS(rc) 2845 || rc == VERR_VD_ASYNC_IO_IN_PROGRESS) 2846 { 2847 PVDDISCARDBLOCK pBlockRemove = (PVDDISCARDBLOCK)RTAvlrU64RangeRemove(pDiscard->pTreeBlocks, pBlock->Core.Key); 2848 Assert(pBlockRemove == pBlock); 2849 2850 pDiscard->cbDiscarding -= pBlock->cbDiscard; 2851 RTListNodeRemove(&pBlock->NodeLru); 2852 RTMemFree(pBlock->pbmAllocated); 2853 RTMemFree(pBlock); 2854 pIoCtx->Req.Discard.pBlock = NULL;/* Safety precaution. */ 2855 pIoCtx->pfnIoCtxTransferNext = vdDiscardHelperAsync; /* Next part. */ 2856 rc = VINF_SUCCESS; 2857 } 2858 2859 LogFlowFunc(("returns rc=%Rrc\n", rc)); 2860 return rc; 2861 } 2862 2863 /** 2864 * Removes the least recently used blocks from the waiting list until 2865 * the new value is reached - version for async I/O. 2866 * 2867 * @returns VBox status code. 2868 * @param pDisk VD disk container. 2869 * @param pDiscard The discard state. 2870 * @param cbDiscardingNew How many bytes should be waiting on success. 2871 * The number of bytes waiting can be less. 2872 */ 2873 static int vdDiscardRemoveBlocksAsync(PVBOXHDD pDisk, PVDIOCTX pIoCtx, size_t cbDiscardingNew) 2874 { 2875 int rc = VINF_SUCCESS; 2876 PVDDISCARDSTATE pDiscard = pDisk->pDiscard; 2877 2878 LogFlowFunc(("pDisk=%#p pDiscard=%#p cbDiscardingNew=%zu\n", 2879 pDisk, pDiscard, cbDiscardingNew)); 2880 2881 while (pDiscard->cbDiscarding > cbDiscardingNew) 2882 { 2883 PVDDISCARDBLOCK pBlock = RTListGetLast(&pDiscard->ListLru, VDDISCARDBLOCK, NodeLru); 2884 2885 Assert(!RTListIsEmpty(&pDiscard->ListLru)); 2886 2887 /* Go over the allocation bitmap and mark all discarded sectors as unused. */ 2888 uint64_t offStart = pBlock->Core.Key; 2889 uint32_t idxStart = 0; 2890 size_t cbLeft = pBlock->cbDiscard; 2891 bool fAllocated = ASMBitTest(pBlock->pbmAllocated, idxStart); 2892 uint32_t cSectors = pBlock->cbDiscard / 512; 2893 2894 while (cbLeft > 0) 2895 { 2896 int32_t idxEnd; 2897 size_t cbThis = cbLeft; 2898 2899 if (fAllocated) 2900 { 2901 /* Check for the first unallocated bit. */ 2902 idxEnd = ASMBitNextClear(pBlock->pbmAllocated, cSectors, idxStart); 2903 if (idxEnd != -1) 2904 { 2905 cbThis = (idxEnd - idxStart) * 512; 2906 fAllocated = false; 2907 } 2908 } 2909 else 2910 { 2911 /* Mark as unused and check for the first set bit. */ 2912 idxEnd = ASMBitNextSet(pBlock->pbmAllocated, cSectors, idxStart); 2913 if (idxEnd != -1) 2914 cbThis = (idxEnd - idxStart) * 512; 2915 2916 rc = pDisk->pLast->Backend->pfnAsyncDiscard(pDisk->pLast->pBackendData, pIoCtx, 2917 offStart, cbThis, NULL, NULL, &cbThis, 2918 NULL, VD_DISCARD_MARK_UNUSED); 2919 if ( RT_FAILURE(rc) 2920 && rc != VERR_VD_ASYNC_IO_IN_PROGRESS) 2921 break; 2922 2923 fAllocated = true; 2924 } 2925 2926 idxStart = idxEnd; 2927 offStart += cbThis; 2928 cbLeft -= cbThis; 2929 } 2930 2931 if ( RT_FAILURE(rc) 2932 && rc != VERR_VD_ASYNC_IO_IN_PROGRESS) 2933 break; 2934 2935 PVDDISCARDBLOCK pBlockRemove = (PVDDISCARDBLOCK)RTAvlrU64RangeRemove(pDiscard->pTreeBlocks, pBlock->Core.Key); 2936 Assert(pBlockRemove == pBlock); 2937 RTListNodeRemove(&pBlock->NodeLru); 2938 2939 pDiscard->cbDiscarding -= pBlock->cbDiscard; 2940 RTMemFree(pBlock->pbmAllocated); 2941 RTMemFree(pBlock); 2942 } 2943 2944 if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS) 2945 rc = VINF_SUCCESS; 2946 2947 Assert(RT_FAILURE(rc) || pDiscard->cbDiscarding <= cbDiscardingNew); 2948 2949 LogFlowFunc(("returns rc=%Rrc\n", rc)); 2950 return rc; 2951 } 2952 2953 /** 2954 * Async discard helper - discards the current range if there is no matching 2955 * block in the tree. 2956 * 2957 * @returns VBox status code. 2958 * @param pIoCtx The I/O context to operate on. 2959 */ 2960 static int vdDiscardCurrentRangeAsync(PVDIOCTX pIoCtx) 2961 { 2962 PVBOXHDD pDisk = pIoCtx->pDisk; 2963 PVDDISCARDSTATE pDiscard = pDisk->pDiscard; 2964 uint64_t offStart = pIoCtx->Req.Discard.offCur; 2965 size_t cbThisDiscard = pIoCtx->Req.Discard.cbThisDiscard; 2966 void *pbmAllocated = NULL; 2967 size_t cbPreAllocated, cbPostAllocated; 2968 int rc = VINF_SUCCESS; 2969 2970 LogFlowFunc(("pIoCtx=%#p\n", pIoCtx)); 2971 2972 /* No block found, try to discard using the backend first. */ 2973 rc = pDisk->pLast->Backend->pfnAsyncDiscard(pDisk->pLast->pBackendData, pIoCtx, 2974 offStart, cbThisDiscard, &cbPreAllocated, 2975 &cbPostAllocated, &cbThisDiscard, 2976 &pbmAllocated, 0); 2977 if (rc == VERR_VD_DISCARD_ALIGNMENT_NOT_MET) 2978 { 2979 /* Create new discard block. */ 2980 PVDDISCARDBLOCK pBlock = (PVDDISCARDBLOCK)RTMemAllocZ(sizeof(VDDISCARDBLOCK)); 2981 if (pBlock) 2982 { 2983 pBlock->Core.Key = offStart - cbPreAllocated; 2984 pBlock->Core.KeyLast = offStart + cbThisDiscard + cbPostAllocated - 1; 2985 pBlock->cbDiscard = cbPreAllocated + cbThisDiscard + cbPostAllocated; 2986 pBlock->pbmAllocated = pbmAllocated; 2987 bool fInserted = RTAvlrU64Insert(pDiscard->pTreeBlocks, &pBlock->Core); 2988 Assert(fInserted); 2989 2990 RTListPrepend(&pDiscard->ListLru, &pBlock->NodeLru); 2991 pDiscard->cbDiscarding += pBlock->cbDiscard; 2992 2993 Assert(pIoCtx->Req.Discard.cbDiscardLeft >= cbThisDiscard); 2994 pIoCtx->Req.Discard.cbDiscardLeft -= cbThisDiscard; 2995 pIoCtx->Req.Discard.offCur += cbThisDiscard; 2996 pIoCtx->Req.Discard.cbThisDiscard = cbThisDiscard; 2997 2998 if (pDiscard->cbDiscarding > VD_DISCARD_REMOVE_THRESHOLD) 2999 rc = vdDiscardRemoveBlocksAsync(pDisk, pIoCtx, VD_DISCARD_REMOVE_THRESHOLD); 3000 else 3001 rc = VINF_SUCCESS; 3002 3003 if (RT_SUCCESS(rc)) 3004 pIoCtx->pfnIoCtxTransferNext = vdDiscardHelperAsync; /* Next part. */ 3005 } 3006 else 3007 { 3008 RTMemFree(pbmAllocated); 3009 rc = VERR_NO_MEMORY; 3010 } 3011 } 3012 else if ( RT_SUCCESS(rc) 3013 || rc == VERR_VD_ASYNC_IO_IN_PROGRESS) /* Save state and andvance to next range. */ 3014 { 3015 Assert(pIoCtx->Req.Discard.cbDiscardLeft >= cbThisDiscard); 3016 pIoCtx->Req.Discard.cbDiscardLeft -= cbThisDiscard; 3017 pIoCtx->Req.Discard.offCur += cbThisDiscard; 3018 pIoCtx->Req.Discard.cbThisDiscard = cbThisDiscard; 3019 pIoCtx->pfnIoCtxTransferNext = vdDiscardHelperAsync; 3020 rc = VINF_SUCCESS; 3021 } 3022 3023 LogFlowFunc(("returns rc=%Rrc\n", rc)); 3024 return rc; 3025 } 3026 3027 /** 3028 * Async discard helper - entry point. 3029 * 3030 * @returns VBox status code. 3031 * @param pIoCtx The I/O context to operate on. 3032 */ 3033 static int vdDiscardHelperAsync(PVDIOCTX pIoCtx) 3034 { 3035 int rc = VINF_SUCCESS; 3036 PVBOXHDD pDisk = pIoCtx->pDisk; 3037 PCRTRANGE paRanges = pIoCtx->Req.Discard.paRanges; 3038 unsigned cRanges = pIoCtx->Req.Discard.cRanges; 3039 PVDDISCARDSTATE pDiscard = pDisk->pDiscard; 3040 3041 LogFlowFunc(("pIoCtx=%#p\n", pIoCtx)); 3042 3043 /* Check if the I/O context processed all ranges. */ 3044 if ( pIoCtx->Req.Discard.idxRange == cRanges 3045 && !pIoCtx->Req.Discard.cbDiscardLeft) 3046 { 3047 LogFlowFunc(("All ranges discarded, completing\n")); 3048 vdIoCtxUnlockDisk(pDisk, pIoCtx, true /* fProcessDeferredReqs*/); 3049 return VINF_SUCCESS; 3050 } 3051 3052 if (pDisk->pIoCtxLockOwner != pIoCtx) 3053 rc = vdIoCtxLockDisk(pDisk, pIoCtx); 3054 3055 if (RT_SUCCESS(rc)) 3056 { 3057 uint64_t offStart = pIoCtx->Req.Discard.offCur; 3058 size_t cbDiscardLeft = pIoCtx->Req.Discard.cbDiscardLeft; 3059 size_t cbThisDiscard; 3060 3061 if (RT_UNLIKELY(!pDiscard)) 3062 { 3063 pDiscard = vdDiscardStateCreate(); 3064 if (!pDiscard) 3065 return VERR_NO_MEMORY; 3066 3067 pDisk->pDiscard = pDiscard; 3068 } 3069 3070 if (!pIoCtx->Req.Discard.cbDiscardLeft) 3071 { 3072 offStart = paRanges[pIoCtx->Req.Discard.idxRange].offStart; 3073 cbDiscardLeft = paRanges[pIoCtx->Req.Discard.idxRange].cbRange; 3074 LogFlowFunc(("New range descriptor loaded (%u) offStart=%llu cbDiscard=%zu\n", 3075 pIoCtx->Req.Discard.idxRange, offStart, cbDiscardLeft)); 3076 pIoCtx->Req.Discard.idxRange++; 3077 } 3078 3079 /* Look for a matching block in the AVL tree first. */ 3080 PVDDISCARDBLOCK pBlock = (PVDDISCARDBLOCK)RTAvlrU64GetBestFit(pDiscard->pTreeBlocks, offStart, false); 3081 if (!pBlock || pBlock->Core.KeyLast < offStart) 3082 { 3083 PVDDISCARDBLOCK pBlockAbove = (PVDDISCARDBLOCK)RTAvlrU64GetBestFit(pDiscard->pTreeBlocks, offStart, true); 3084 3085 /* Clip range to remain in the current block. */ 3086 if (pBlockAbove) 3087 cbThisDiscard = RT_MIN(cbDiscardLeft, pBlockAbove->Core.KeyLast - offStart + 1); 3088 else 3089 cbThisDiscard = cbDiscardLeft; 3090 3091 Assert(!(cbThisDiscard % 512)); 3092 pIoCtx->Req.Discard.pBlock = NULL; 3093 pIoCtx->pfnIoCtxTransferNext = vdDiscardCurrentRangeAsync; 3094 } 3095 else 3096 { 3097 /* Range lies partly in the block, update allocation bitmap. */ 3098 int32_t idxStart, idxEnd; 3099 3100 cbThisDiscard = RT_MIN(cbDiscardLeft, pBlock->Core.KeyLast - offStart + 1); 3101 3102 AssertPtr(pBlock); 3103 3104 Assert(!(cbThisDiscard % 512)); 3105 Assert(!((offStart - pBlock->Core.Key) % 512)); 3106 3107 idxStart = (offStart - pBlock->Core.Key) / 512; 3108 idxEnd = idxStart + (cbThisDiscard / 512); 3109 3110 ASMBitClearRange(pBlock->pbmAllocated, idxStart, idxEnd); 3111 3112 cbDiscardLeft -= cbThisDiscard; 3113 offStart += cbThisDiscard; 3114 3115 /* Call the backend to discard the block if it is completely unallocated now. */ 3116 if (ASMBitFirstSet((volatile void *)pBlock->pbmAllocated, pBlock->cbDiscard / 512) == -1) 3117 { 3118 pIoCtx->Req.Discard.pBlock = pBlock; 3119 pIoCtx->pfnIoCtxTransferNext = vdDiscardWholeBlockAsync; 3120 rc = VINF_SUCCESS; 3121 } 3122 else 3123 { 3124 RTListNodeRemove(&pBlock->NodeLru); 3125 RTListPrepend(&pDiscard->ListLru, &pBlock->NodeLru); 3126 3127 /* Start with next range. */ 3128 pIoCtx->pfnIoCtxTransferNext = vdDiscardHelperAsync; 3129 rc = VINF_SUCCESS; 3130 } 3131 } 3132 3133 /* Save state in the context. */ 3134 pIoCtx->Req.Discard.offCur = offStart; 3135 pIoCtx->Req.Discard.cbDiscardLeft = cbDiscardLeft; 3136 pIoCtx->Req.Discard.cbThisDiscard = cbThisDiscard; 3137 } 3138 3139 LogFlowFunc(("returns rc=%Rrc\n", rc)); 2737 3140 return rc; 2738 3141 } … … 3160 3563 ASMAtomicCmpXchgS32(&pIoCtxParent->rcReq, pIoCtx->rcReq, VINF_SUCCESS); 3161 3564 3565 ASMAtomicDecU32(&pIoCtxParent->cDataTransfersPending); 3566 3162 3567 if (pIoCtx->enmTxDir == VDIOCTXTXDIR_WRITE) 3163 3568 { … … 3166 3571 3167 3572 /* Update the parent state. */ 3168 Assert(pIoCtxParent-> cbTransferLeft >= pIoCtx->Type.Child.cbTransferParent);3169 ASMAtomicSubU32(&pIoCtxParent-> cbTransferLeft, pIoCtx->Type.Child.cbTransferParent);3573 Assert(pIoCtxParent->Req.Io.cbTransferLeft >= pIoCtx->Type.Child.cbTransferParent); 3574 ASMAtomicSubU32(&pIoCtxParent->Req.Io.cbTransferLeft, pIoCtx->Type.Child.cbTransferParent); 3170 3575 } 3171 3576 else … … 3251 3656 vdThreadFinishWrite(pDisk); 3252 3657 } 3253 else if (pIoCtx->enmTxDir == VDIOCTXTXDIR_WRITE) 3658 else if ( pIoCtx->enmTxDir == VDIOCTXTXDIR_WRITE 3659 || pIoCtx->enmTxDir == VDIOCTXTXDIR_DISCARD) 3254 3660 vdThreadFinishWrite(pDisk); 3255 3661 else … … 3289 3695 3290 3696 RTCritSectEnter(&pDisk->CritSect); 3291 Assert(pIoCtx-> cbTransferLeft >= cbTransfer);3292 ASMAtomicSubU32(&pIoCtx-> cbTransferLeft, cbTransfer);3697 Assert(pIoCtx->Req.Io.cbTransferLeft >= cbTransfer); 3698 ASMAtomicSubU32(&pIoCtx->Req.Io.cbTransferLeft, cbTransfer); 3293 3699 ASMAtomicDecU32(&pIoCtx->cDataTransfersPending); 3294 3700 … … 3565 3971 size_t cbTaskRead = 0; 3566 3972 3567 cbTaskRead = RTSgBufSegArrayCreate(&pIoCtx-> SgBuf, aSeg, &cSegments, cbRead);3973 cbTaskRead = RTSgBufSegArrayCreate(&pIoCtx->Req.Io.SgBuf, aSeg, &cSegments, cbRead); 3568 3974 3569 3975 Assert(cSegments > 0); … … 3593 3999 if (RT_SUCCESS(rc)) 3594 4000 { 3595 AssertMsg(cbTaskRead <= pIoCtx-> cbTransferLeft, ("Impossible!\n"));3596 ASMAtomicSubU32(&pIoCtx-> cbTransferLeft, cbTaskRead);4001 AssertMsg(cbTaskRead <= pIoCtx->Req.Io.cbTransferLeft, ("Impossible!\n")); 4002 ASMAtomicSubU32(&pIoCtx->Req.Io.cbTransferLeft, cbTaskRead); 3597 4003 ASMAtomicDecU32(&pIoCtx->cDataTransfersPending); 3598 4004 vdIoTaskFree(pDisk, pIoTask); … … 3637 4043 size_t cbTaskWrite = 0; 3638 4044 3639 cbTaskWrite = RTSgBufSegArrayCreate(&pIoCtx-> SgBuf, aSeg, &cSegments, cbWrite);4045 cbTaskWrite = RTSgBufSegArrayCreate(&pIoCtx->Req.Io.SgBuf, aSeg, &cSegments, cbWrite); 3640 4046 3641 4047 Assert(cSegments > 0); … … 3665 4071 if (RT_SUCCESS(rc)) 3666 4072 { 3667 AssertMsg(cbTaskWrite <= pIoCtx-> cbTransferLeft, ("Impossible!\n"));3668 ASMAtomicSubU32(&pIoCtx-> cbTransferLeft, cbTaskWrite);4073 AssertMsg(cbTaskWrite <= pIoCtx->Req.Io.cbTransferLeft, ("Impossible!\n")); 4074 ASMAtomicSubU32(&pIoCtx->Req.Io.cbTransferLeft, cbTaskWrite); 3669 4075 ASMAtomicDecU32(&pIoCtx->cDataTransfersPending); 3670 4076 vdIoTaskFree(pDisk, pIoTask); … … 3969 4375 Assert(cbCopied == cbBuf); 3970 4376 3971 ASMAtomicSubU32(&pIoCtx-> cbTransferLeft, cbCopied);4377 ASMAtomicSubU32(&pIoCtx->Req.Io.cbTransferLeft, cbCopied); 3972 4378 3973 4379 return cbCopied; … … 3986 4392 Assert(cbCopied == cbBuf); 3987 4393 3988 ASMAtomicSubU32(&pIoCtx-> cbTransferLeft, cbCopied);4394 ASMAtomicSubU32(&pIoCtx->Req.Io.cbTransferLeft, cbCopied); 3989 4395 3990 4396 return cbCopied; … … 4002 4408 Assert(cbSet == cb); 4003 4409 4004 ASMAtomicSubU32(&pIoCtx-> cbTransferLeft, cbSet);4410 ASMAtomicSubU32(&pIoCtx->Req.Io.cbTransferLeft, cbSet); 4005 4411 4006 4412 return cbSet; … … 4017 4423 VD_THREAD_IS_CRITSECT_OWNER(pDisk); 4018 4424 4019 cbCreated = RTSgBufSegArrayCreate(&pIoCtx-> SgBuf, paSeg, pcSeg, cbData);4425 cbCreated = RTSgBufSegArrayCreate(&pIoCtx->Req.Io.SgBuf, paSeg, pcSeg, cbData); 4020 4426 Assert(!paSeg || cbData == cbCreated); 4021 4427 … … 4043 4449 /* Continue */ 4044 4450 pIoCtx->fBlocked = false; 4045 ASMAtomicSubU32(&pIoCtx-> cbTransferLeft, cbCompleted);4451 ASMAtomicSubU32(&pIoCtx->Req.Io.cbTransferLeft, cbCompleted); 4046 4452 4047 4453 /* Clear the pointer to next transfer function in case we have nothing to transfer anymore. 4048 4454 * @todo: Find a better way to prevent vdIoCtxContinue from calling the read/write helper again. */ 4049 if (!pIoCtx-> cbTransferLeft)4455 if (!pIoCtx->Req.Io.cbTransferLeft) 4050 4456 pIoCtx->pfnIoCtxTransfer = NULL; 4051 4457 … … 8617 9023 8618 9024 8619 VBOXDDU_DECL(int) VDDiscardRanges(PVBOXHDD pDisk, PC VDRANGE paRanges, unsigned cRanges)9025 VBOXDDU_DECL(int) VDDiscardRanges(PVBOXHDD pDisk, PCRTRANGE paRanges, unsigned cRanges) 8620 9026 { 8621 9027 int rc; … … 8861 9267 } 8862 9268 9269 VBOXDDU_DECL(int) VDAsyncDiscardRanges(PVBOXHDD pDisk, PCRTRANGE paRanges, unsigned cRanges, 9270 PFNVDASYNCTRANSFERCOMPLETE pfnComplete, 9271 void *pvUser1, void *pvUser2) 9272 { 9273 int rc; 9274 int rc2; 9275 bool fLockWrite = false; 9276 PVDIOCTX pIoCtx = NULL; 9277 9278 LogFlowFunc(("pDisk=%#p\n", pDisk)); 9279 9280 do 9281 { 9282 /* sanity check */ 9283 AssertPtrBreakStmt(pDisk, rc = VERR_INVALID_PARAMETER); 9284 AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature)); 9285 9286 rc2 = vdThreadStartWrite(pDisk); 9287 AssertRC(rc2); 9288 fLockWrite = true; 9289 9290 AssertPtrBreakStmt(pDisk->pLast, rc = VERR_VD_NOT_OPENED); 9291 9292 pIoCtx = vdIoCtxDiscardAlloc(pDisk, paRanges, cRanges, 9293 pfnComplete, pvUser1, pvUser2, NULL, 9294 vdDiscardHelperAsync); 9295 if (!pIoCtx) 9296 { 9297 rc = VERR_NO_MEMORY; 9298 break; 9299 } 9300 9301 rc = vdIoCtxProcess(pIoCtx); 9302 if (rc == VINF_VD_ASYNC_IO_FINISHED) 9303 { 9304 if (ASMAtomicCmpXchgBool(&pIoCtx->fComplete, true, false)) 9305 vdIoCtxFree(pDisk, pIoCtx); 9306 else 9307 rc = VERR_VD_ASYNC_IO_IN_PROGRESS; /* Let the other handler complete the request. */ 9308 } 9309 else if (rc != VERR_VD_ASYNC_IO_IN_PROGRESS) /* Another error */ 9310 vdIoCtxFree(pDisk, pIoCtx); 9311 } while (0); 9312 9313 if (RT_UNLIKELY(fLockWrite) && ( rc == VINF_VD_ASYNC_IO_FINISHED 9314 || rc != VERR_VD_ASYNC_IO_IN_PROGRESS)) 9315 { 9316 rc2 = vdThreadFinishWrite(pDisk); 9317 AssertRC(rc2); 9318 } 9319 9320 LogFlowFunc(("returns %Rrc\n", rc)); 9321 return rc; 9322 } 9323 -
trunk/src/VBox/Storage/VDI.cpp
r38676 r38876 57 57 static int vdiUpdateBlockInfo(PVDIIMAGEDESC pImage, unsigned uBlock); 58 58 static int vdiUpdateHeaderAsync(PVDIIMAGEDESC pImage, PVDIOCTX pIoCtx); 59 static int vdiUpdateBlockInfoAsync(PVDIIMAGEDESC pImage, unsigned uBlock, PVDIOCTX pIoCtx); 59 static int vdiUpdateBlockInfoAsync(PVDIIMAGEDESC pImage, unsigned uBlock, PVDIOCTX pIoCtx, 60 bool fUpdateHdr); 60 61 61 62 /** … … 849 850 */ 850 851 static int vdiUpdateBlockInfoAsync(PVDIIMAGEDESC pImage, unsigned uBlock, 851 PVDIOCTX pIoCtx) 852 { 852 PVDIOCTX pIoCtx, bool fUpdateHdr) 853 { 854 int rc = VINF_SUCCESS; 855 853 856 /* Update image header. */ 854 int rc = vdiUpdateHeaderAsync(pImage, pIoCtx); 857 if (fUpdateHdr) 858 rc = vdiUpdateHeaderAsync(pImage, pIoCtx); 859 855 860 if (RT_SUCCESS(rc) || rc == VERR_VD_ASYNC_IO_IN_PROGRESS) 856 861 { … … 964 969 rc = vdIfIoIntFileSetSize(pImage->pIfIo, pImage->pStorage, cbImage - pImage->cbTotalBlockData); 965 970 } while (0); 971 972 LogFlowFunc(("returns rc=%Rrc\n", rc)); 973 return rc; 974 } 975 976 /** 977 * Completion callback for meta/userdata reads or writes. 978 * 979 * @return VBox status code. 980 * VINF_SUCCESS if everything was successful and the transfer can continue. 981 * VERR_VD_ASYNC_IO_IN_PROGRESS if there is another data transfer pending. 982 * @param pBackendData The opaque backend data. 983 * @param pIoCtx I/O context associated with this request. 984 * @param pvUser Opaque user data passed during a read/write request. 985 * @param rcReq Status code for the completed request. 986 */ 987 static DECLCALLBACK(int) vdiDiscardBlockAsyncUpdate(void *pBackendData, PVDIOCTX pIoCtx, void *pvUser, int rcReq) 988 { 989 int rc = VINF_SUCCESS; 990 PVDIIMAGEDESC pImage = (PVDIIMAGEDESC)pBackendData; 991 PVDIBLOCKDISCARDASYNC pDiscardAsync = (PVDIBLOCKDISCARDASYNC)pvUser; 992 993 switch (pDiscardAsync->enmState) 994 { 995 case VDIBLOCKDISCARDSTATE_READ_BLOCK: 996 { 997 PVDMETAXFER pMetaXfer; 998 uint64_t u64Offset = (uint64_t)pDiscardAsync->idxLastBlock * pImage->cbTotalBlockData + pImage->offStartData; 999 rc = vdIfIoIntFileReadMetaAsync(pImage->pIfIo, pImage->pStorage, u64Offset, 1000 pDiscardAsync->pvBlock, pImage->cbTotalBlockData, pIoCtx, 1001 &pMetaXfer, vdiDiscardBlockAsyncUpdate, pDiscardAsync); 1002 if (RT_FAILURE(rc)) 1003 break; 1004 1005 /* Release immediately and go to next step. */ 1006 vdIfIoIntMetaXferRelease(pImage->pIfIo, pMetaXfer); 1007 pDiscardAsync->enmState = VDIBLOCKDISCARDSTATE_WRITE_BLOCK; 1008 } 1009 case VDIBLOCKDISCARDSTATE_WRITE_BLOCK: 1010 { 1011 /* Block read complete. Write to the new location (discarded block). */ 1012 uint64_t u64Offset = (uint64_t)pDiscardAsync->ptrBlockDiscard * pImage->cbTotalBlockData + pImage->offStartData; 1013 rc = vdIfIoIntFileWriteMetaAsync(pImage->pIfIo, pImage->pStorage, u64Offset, 1014 pDiscardAsync->pvBlock, pImage->cbTotalBlockData, pIoCtx, 1015 vdiDiscardBlockAsyncUpdate, pDiscardAsync); 1016 1017 pDiscardAsync->enmState = VDIBLOCKDISCARDSTATE_UPDATE_METADATA; 1018 if (RT_FAILURE(rc)) 1019 break; 1020 } 1021 case VDIBLOCKDISCARDSTATE_UPDATE_METADATA: 1022 { 1023 int rc2; 1024 uint64_t cbImage; 1025 1026 /* Block write complete. Update metadata. */ 1027 pImage->paBlocksRev[pDiscardAsync->idxLastBlock] = VDI_IMAGE_BLOCK_FREE; 1028 pImage->paBlocks[pDiscardAsync->uBlock] = VDI_IMAGE_BLOCK_ZERO; 1029 1030 if (pDiscardAsync->idxLastBlock != pDiscardAsync->ptrBlockDiscard) 1031 { 1032 pImage->paBlocks[pDiscardAsync->uBlockLast] = pDiscardAsync->ptrBlockDiscard; 1033 pImage->paBlocksRev[pDiscardAsync->ptrBlockDiscard] = pDiscardAsync->uBlockLast; 1034 1035 rc = vdiUpdateBlockInfoAsync(pImage, pDiscardAsync->uBlockLast, pIoCtx, false /* fUpdateHdr */); 1036 if ( RT_FAILURE(rc) 1037 && rc != VERR_VD_ASYNC_IO_IN_PROGRESS) 1038 break; 1039 } 1040 1041 setImageBlocksAllocated(&pImage->Header, pDiscardAsync->idxLastBlock); 1042 rc = vdiUpdateBlockInfoAsync(pImage, pDiscardAsync->uBlock, pIoCtx, true /* fUpdateHdr */); 1043 if ( RT_FAILURE(rc) 1044 && rc != VERR_VD_ASYNC_IO_IN_PROGRESS) 1045 break; 1046 1047 /* Set new file size. */ 1048 rc2 = vdIfIoIntFileGetSize(pImage->pIfIo, pImage->pStorage, &cbImage); 1049 if (RT_FAILURE(rc2)) 1050 break; 1051 1052 LogFlowFunc(("Set new size %llu\n", cbImage - pImage->cbTotalBlockData)); 1053 rc2 = vdIfIoIntFileSetSize(pImage->pIfIo, pImage->pStorage, cbImage - pImage->cbTotalBlockData); 1054 if (RT_FAILURE(rc2)) 1055 rc = rc2; 1056 1057 /* Free discard state. */ 1058 RTMemFree(pDiscardAsync->pvBlock); 1059 RTMemFree(pDiscardAsync); 1060 break; 1061 } 1062 default: 1063 AssertMsgFailed(("Invalid state %d\n", pDiscardAsync->enmState)); 1064 } 1065 1066 if (rc == VERR_VD_NOT_ENOUGH_METADATA) 1067 rc = VERR_VD_ASYNC_IO_IN_PROGRESS; 1068 1069 return rc; 1070 } 1071 1072 /** 1073 * Internal: Discard a whole block from the image filling the created hole with 1074 * data from another block - async I/O version. 1075 * 1076 * @returns VBox status code. 1077 * @param pImage VDI image instance data. 1078 * @param pIoCtx I/O context associated with this request. 1079 * @param uBlock The block to discard. 1080 * @param pvBlock Memory to use for the I/O. 1081 */ 1082 static int vdiDiscardBlockAsync(PVDIIMAGEDESC pImage, PVDIOCTX pIoCtx, 1083 unsigned uBlock, void *pvBlock) 1084 { 1085 int rc = VINF_SUCCESS; 1086 PVDIBLOCKDISCARDASYNC pDiscardAsync = NULL; 1087 1088 LogFlowFunc(("pImage=%#p uBlock=%u pvBlock=%#p\n", 1089 pImage, uBlock, pvBlock)); 1090 1091 pDiscardAsync = (PVDIBLOCKDISCARDASYNC)RTMemAllocZ(sizeof(VDIBLOCKDISCARDASYNC)); 1092 if (RT_UNLIKELY(!pDiscardAsync)) 1093 return VERR_NO_MEMORY; 1094 1095 /* Init block discard state. */ 1096 pDiscardAsync->uBlock = uBlock; 1097 pDiscardAsync->pvBlock = pvBlock; 1098 pDiscardAsync->ptrBlockDiscard = pImage->paBlocks[uBlock]; 1099 pDiscardAsync->idxLastBlock = getImageBlocksAllocated(&pImage->Header) - 1; 1100 pDiscardAsync->uBlockLast = pImage->paBlocksRev[pDiscardAsync->idxLastBlock]; 1101 1102 /* 1103 * The block is empty, remove it. 1104 * Read the last block of the image first. 1105 */ 1106 if (pDiscardAsync->idxLastBlock != pDiscardAsync->ptrBlockDiscard) 1107 { 1108 LogFlowFunc(("Moving block [%u]=%u into [%u]=%u\n", 1109 pDiscardAsync->uBlockLast, pDiscardAsync->idxLastBlock, 1110 uBlock, pImage->paBlocks[uBlock])); 1111 pDiscardAsync->enmState = VDIBLOCKDISCARDSTATE_READ_BLOCK; 1112 } 1113 else 1114 { 1115 pDiscardAsync->enmState = VDIBLOCKDISCARDSTATE_UPDATE_METADATA; /* Start immediately to shrink the image. */ 1116 LogFlowFunc(("Discard last block [%u]=%u\n", uBlock, pImage->paBlocks[uBlock])); 1117 } 1118 1119 /* Call the update callback directly. */ 1120 rc = vdiDiscardBlockAsyncUpdate(pImage, pIoCtx, pDiscardAsync, VINF_SUCCESS); 966 1121 967 1122 LogFlowFunc(("returns rc=%Rrc\n", rc)); … … 2181 2336 setImageBlocksAllocated(&pImage->Header, cBlocksAllocated + 1); 2182 2337 2183 rc = vdiUpdateBlockInfoAsync(pImage, uBlock, pIoCtx );2338 rc = vdiUpdateBlockInfoAsync(pImage, uBlock, pIoCtx, true /* fUpdateHdr */); 2184 2339 if (RT_FAILURE(rc) && (rc != VERR_VD_ASYNC_IO_IN_PROGRESS)) 2185 2340 goto out; … … 2780 2935 if (pvBlock) 2781 2936 RTMemFree(pvBlock); 2937 2938 LogFlowFunc(("returns %Rrc\n", rc)); 2939 return rc; 2940 } 2941 2942 /** @copydoc VBOXHDDBACKEND::pfnDiscard */ 2943 static DECLCALLBACK(int) vdiAsyncDiscard(void *pBackendData, PVDIOCTX pIoCtx, 2944 uint64_t uOffset, size_t cbDiscard, 2945 size_t *pcbPreAllocated, 2946 size_t *pcbPostAllocated, 2947 size_t *pcbActuallyDiscarded, 2948 void **ppbmAllocationBitmap, 2949 unsigned fDiscard) 2950 { 2951 PVDIIMAGEDESC pImage = (PVDIIMAGEDESC)pBackendData; 2952 unsigned uBlock; 2953 unsigned offDiscard; 2954 int rc = VINF_SUCCESS; 2955 void *pvBlock = NULL; 2956 2957 LogFlowFunc(("pBackendData=%#p pIoCtx=%#p uOffset=%llu cbDiscard=%zu pcbPreAllocated=%#p pcbPostAllocated=%#p pcbActuallyDiscarded=%#p ppbmAllocationBitmap=%#p fDiscard=%#x\n", 2958 pBackendData, pIoCtx, uOffset, cbDiscard, pcbPreAllocated, pcbPostAllocated, pcbActuallyDiscarded, ppbmAllocationBitmap, fDiscard)); 2959 2960 AssertPtr(pImage); 2961 Assert(!(uOffset % 512)); 2962 Assert(!(cbDiscard % 512)); 2963 2964 AssertMsgReturn(!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY), 2965 ("Image is readonly\n"), VERR_VD_IMAGE_READ_ONLY); 2966 AssertMsgReturn( uOffset + cbDiscard <= getImageDiskSize(&pImage->Header) 2967 && cbDiscard, 2968 ("Invalid parameters uOffset=%llu cbDiscard=%zu\n", 2969 uOffset, cbDiscard), 2970 VERR_INVALID_PARAMETER); 2971 2972 do 2973 { 2974 AssertMsgBreakStmt(!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY), 2975 ("Image is opened readonly\n"), 2976 rc = VERR_VD_IMAGE_READ_ONLY); 2977 2978 AssertMsgBreakStmt(cbDiscard, 2979 ("cbDiscard=%u\n", cbDiscard), 2980 rc = VERR_INVALID_PARAMETER); 2981 2982 /* Calculate starting block number and offset inside it. */ 2983 uBlock = (unsigned)(uOffset >> pImage->uShiftOffset2Index); 2984 offDiscard = (unsigned)uOffset & pImage->uBlockMask; 2985 2986 /* Clip range to at most the rest of the block. */ 2987 cbDiscard = RT_MIN(cbDiscard, getImageBlockSize(&pImage->Header) - offDiscard); 2988 Assert(!(cbDiscard % 512)); 2989 2990 if (pcbPreAllocated) 2991 *pcbPreAllocated = 0; 2992 2993 if (pcbPostAllocated) 2994 *pcbPostAllocated = 0; 2995 2996 if (IS_VDI_IMAGE_BLOCK_ALLOCATED(pImage->paBlocks[uBlock])) 2997 { 2998 uint8_t *pbBlockData; 2999 size_t cbPreAllocated, cbPostAllocated; 3000 3001 cbPreAllocated = offDiscard % getImageBlockSize(&pImage->Header); 3002 cbPostAllocated = getImageBlockSize(&pImage->Header) - cbDiscard - cbPreAllocated; 3003 3004 /* Read the block data. */ 3005 pvBlock = RTMemAlloc(pImage->cbTotalBlockData); 3006 if (!pvBlock) 3007 { 3008 rc = VERR_NO_MEMORY; 3009 break; 3010 } 3011 3012 if (!cbPreAllocated && !cbPostAllocated) 3013 { 3014 /* 3015 * Discarding a whole block, don't check for allocated sectors. 3016 * It is possible to just remove the whole block which avoids 3017 * one read and checking the whole block for data. 3018 */ 3019 rc = vdiDiscardBlockAsync(pImage, pIoCtx, uBlock, pvBlock); 3020 } 3021 else if (fDiscard & VD_DISCARD_MARK_UNUSED) 3022 { 3023 /* Just zero out the given range. */ 3024 memset(pvBlock, 0, cbDiscard); 3025 3026 uint64_t u64Offset = (uint64_t)pImage->paBlocks[uBlock] * pImage->cbTotalBlockData + pImage->offStartData + offDiscard; 3027 rc = vdIfIoIntFileWriteMetaAsync(pImage->pIfIo, pImage->pStorage, 3028 u64Offset, pvBlock, cbDiscard, pIoCtx, 3029 NULL, NULL); 3030 RTMemFree(pvBlock); 3031 } 3032 else 3033 { 3034 /* 3035 * Read complete block as metadata, the I/O context has no memory buffer 3036 * and we need to access the content directly anyway. 3037 */ 3038 PVDMETAXFER pMetaXfer; 3039 pbBlockData = (uint8_t *)pvBlock + pImage->offStartBlockData; 3040 3041 uint64_t u64Offset = (uint64_t)pImage->paBlocks[uBlock] * pImage->cbTotalBlockData + pImage->offStartData; 3042 rc = vdIfIoIntFileReadMetaAsync(pImage->pIfIo, pImage->pStorage, u64Offset, 3043 pbBlockData, pImage->cbTotalBlockData, 3044 pIoCtx, &pMetaXfer, NULL, NULL); 3045 if (RT_FAILURE(rc)) 3046 break; 3047 3048 vdIfIoIntMetaXferRelease(pImage->pIfIo, pMetaXfer); 3049 3050 /* Clear data. */ 3051 memset(pbBlockData + offDiscard , 0, cbDiscard); 3052 3053 Assert(!(cbDiscard % 4)); 3054 Assert(getImageBlockSize(&pImage->Header) * 8 <= UINT32_MAX); 3055 if (ASMBitFirstSet((volatile void *)pbBlockData, getImageBlockSize(&pImage->Header) * 8) == -1) 3056 rc = vdiDiscardBlockAsync(pImage, pIoCtx, uBlock, pvBlock); 3057 else 3058 { 3059 /* Block has data, create allocation bitmap. */ 3060 *pcbPreAllocated = cbPreAllocated; 3061 *pcbPostAllocated = cbPostAllocated; 3062 *ppbmAllocationBitmap = vdiAllocationBitmapCreate(pbBlockData, getImageBlockSize(&pImage->Header)); 3063 if (RT_UNLIKELY(!*ppbmAllocationBitmap)) 3064 rc = VERR_NO_MEMORY; 3065 else 3066 rc = VERR_VD_DISCARD_ALIGNMENT_NOT_MET; 3067 3068 RTMemFree(pvBlock); 3069 } 3070 } /* if: no complete block discarded */ 3071 } /* if: Block is allocated. */ 3072 /* else: nothing to do. */ 3073 } while (0); 3074 3075 if (pcbActuallyDiscarded) 3076 *pcbActuallyDiscarded = cbDiscard; 2782 3077 2783 3078 LogFlowFunc(("returns %Rrc\n", rc)); … … 2883 3178 vdiResize, 2884 3179 /* pfnDiscard */ 2885 vdiDiscard 3180 vdiDiscard, 3181 /* pfnAsyncDiscard */ 3182 vdiAsyncDiscard 2886 3183 }; -
trunk/src/VBox/Storage/VDICore.h
r38621 r38876 556 556 } VDIIMAGEDESC, *PVDIIMAGEDESC; 557 557 558 /** 559 * Async block discard states. 560 */ 561 typedef enum VDIBLOCKDISCARDSTATE 562 { 563 /** Invalid. */ 564 VDIBLOCKDISCARDSTATE_INVALID = 0, 565 /** Read the last block. */ 566 VDIBLOCKDISCARDSTATE_READ_BLOCK, 567 /** Write block into the hole. */ 568 VDIBLOCKDISCARDSTATE_WRITE_BLOCK, 569 /** Update metadata. */ 570 VDIBLOCKDISCARDSTATE_UPDATE_METADATA, 571 /** 32bit hack. */ 572 VDIBLOCKDISCARDSTATE_32BIT_HACK = 0x7fffffff 573 } VDIBLOCKDISCARDSTATE; 574 575 /** 576 * Async block discard structure. 577 */ 578 typedef struct VDIBLOCKDISCARDASYNC 579 { 580 /** State of the block discard. */ 581 VDIBLOCKDISCARDSTATE enmState; 582 /** Pointer to the block data. */ 583 void *pvBlock; 584 /** Block index in the block table. */ 585 unsigned uBlock; 586 /** Block pointer to the block to discard. */ 587 VDIIMAGEBLOCKPOINTER ptrBlockDiscard; 588 /** Index of the last block in the reverse block table. */ 589 unsigned idxLastBlock; 590 /** Index of the last block in the block table (gathered from the reverse block table). */ 591 unsigned uBlockLast; 592 } VDIBLOCKDISCARDASYNC, *PVDIBLOCKDISCARDASYNC; 593 558 594 #endif 559 595 -
trunk/src/VBox/Storage/VHD.cpp
r38621 r38876 3141 3141 vhdResize, 3142 3142 /* pfnDiscard */ 3143 NULL, 3144 /* pfnAsyncDiscard */ 3143 3145 NULL 3144 3146 }; -
trunk/src/VBox/Storage/VMDK.cpp
r38819 r38876 7192 7192 NULL, 7193 7193 /* pfnDiscard */ 7194 NULL, 7195 /* pfnAsyncDiscard */ 7194 7196 NULL 7195 7197 }; -
trunk/src/VBox/Storage/testcase/tstVDIo.cpp
r38644 r38876 134 134 VDIOREQTXDIR_READ = 0, 135 135 VDIOREQTXDIR_WRITE, 136 VDIOREQTXDIR_FLUSH 136 VDIOREQTXDIR_FLUSH, 137 VDIOREQTXDIR_DISCARD 137 138 } VDIOREQTXDIR; 138 139 … … 143 144 { 144 145 /** Transfer type. */ 145 VDIOREQTXDIR enmTxDir;146 VDIOREQTXDIR enmTxDir; 146 147 /** slot index. */ 147 unsigned idx;148 unsigned idx; 148 149 /** Start offset. */ 149 uint64_t off;150 uint64_t off; 150 151 /** Size to transfer. */ 151 size_t cbReq;152 size_t cbReq; 152 153 /** S/G Buffer */ 153 RTSGBUF SgBuf;154 RTSGBUF SgBuf; 154 155 /** Data segment */ 155 RTSGSEG DataSeg;156 RTSGSEG DataSeg; 156 157 /** Flag whether the request is outstanding or not. */ 157 158 volatile bool fOutstanding; … … 385 386 /* pcszName chId enmType fFlags */ 386 387 {"disk", 'd', VDSCRIPTARGTYPE_STRING, VDSCRIPTARGDESC_FLAG_MANDATORY}, 387 {" off", 'o', VDSCRIPTARGTYPE_UNSIGNED_NUMBER, VDSCRIPTARGDESC_FLAG_MANDATORY},388 {" size", 's', VDSCRIPTARGTYPE_UNSIGNED_NUMBER, VDSCRIPTARGDESC_FLAG_MANDATORY},388 {"async", 'a', VDSCRIPTARGTYPE_BOOL, 0}, 389 {"ranges", 'r', VDSCRIPTARGTYPE_STRING, VDSCRIPTARGDESC_FLAG_MANDATORY} 389 390 }; 390 391 … … 955 956 break; 956 957 } 958 case VDIOREQTXDIR_DISCARD: 959 AssertMsgFailed(("Invalid\n")); 957 960 } 958 961 … … 983 986 break; 984 987 } 988 case VDIOREQTXDIR_DISCARD: 989 AssertMsgFailed(("Invalid\n")); 985 990 } 986 991 … … 1028 1033 case VDIOREQTXDIR_FLUSH: 1029 1034 break; 1035 case VDIOREQTXDIR_DISCARD: 1036 AssertMsgFailed(("Invalid\n")); 1030 1037 } 1031 1038 … … 1264 1271 const char *pcszDisk = NULL; 1265 1272 PVDDISK pDisk = NULL; 1266 uint64_t off;1267 size_t cbDiscard;1273 bool fAsync = false; 1274 const char *pcszRanges = NULL; 1268 1275 1269 1276 for (unsigned i = 0; i < cScriptArgs; i++) … … 1276 1283 break; 1277 1284 } 1278 case 'o': 1279 { 1280 off = paScriptArgs[i].u.u64; 1281 break; 1282 } 1283 case 's': 1284 { 1285 cbDiscard = paScriptArgs[i].u.u64; 1286 break; 1287 } 1288 1285 case 'a': 1286 { 1287 fAsync = paScriptArgs[i].u.fFlag; 1288 break; 1289 } 1290 case 'r': 1291 { 1292 pcszRanges = paScriptArgs[i].u.pcszString; 1293 break; 1294 } 1289 1295 default: 1290 1296 AssertMsgFailed(("Invalid argument given!\n")); 1291 1297 } 1292 1293 if (RT_FAILURE(rc)) 1294 break; 1295 } 1296 1297 if (RT_SUCCESS(rc)) 1298 { 1299 pDisk = tstVDIoGetDiskByName(pGlob, pcszDisk); 1300 if (!pDisk) 1301 rc = VERR_NOT_FOUND; 1302 else 1303 { 1304 VDRANGE Range; 1305 1306 Range.offStart = off; 1307 Range.cbRange = cbDiscard; 1308 1309 rc = VDDiscardRanges(pDisk->pVD, &Range, 1); 1298 } 1299 1300 pDisk = tstVDIoGetDiskByName(pGlob, pcszDisk); 1301 if (!pDisk) 1302 rc = VERR_NOT_FOUND; 1303 else 1304 { 1305 unsigned cRanges = 0; 1306 PRTRANGE paRanges = NULL; 1307 1308 /* 1309 * Parse the range string which should look like this: 1310 * n,off1,cb1,off2,cb2,... 1311 * 1312 * <n> gives the number of ranges in the string and every off<i>,cb<i> 1313 * pair afterwards is a start offset + number of bytes to discard entry. 1314 */ 1315 do 1316 { 1317 rc = RTStrToUInt32Ex(pcszRanges, (char **)&pcszRanges, 10, &cRanges); 1318 if (RT_FAILURE(rc) && (rc != VWRN_TRAILING_CHARS)) 1319 break; 1320 1321 if (!cRanges) 1322 { 1323 rc = VERR_INVALID_PARAMETER; 1324 break; 1325 } 1326 1327 paRanges = (PRTRANGE)RTMemAllocZ(cRanges * sizeof(RTRANGE)); 1328 if (!paRanges) 1329 { 1330 rc = VERR_NO_MEMORY; 1331 break; 1332 } 1333 1334 if (*pcszRanges != ',') 1335 { 1336 rc = VERR_INVALID_PARAMETER; 1337 break; 1338 } 1339 1340 pcszRanges++; 1341 1342 /* Retrieve each pair from the string. */ 1343 for (unsigned i = 0; i < cRanges; i++) 1344 { 1345 uint64_t off; 1346 uint32_t cb; 1347 1348 rc = RTStrToUInt64Ex(pcszRanges, (char **)&pcszRanges, 10, &off); 1349 if (RT_FAILURE(rc) && (rc != VWRN_TRAILING_CHARS)) 1350 break; 1351 1352 if (*pcszRanges != ',') 1353 { 1354 switch (*pcszRanges) 1355 { 1356 case 'k': 1357 case 'K': 1358 { 1359 off *= _1K; 1360 break; 1361 } 1362 case 'm': 1363 case 'M': 1364 { 1365 off *= _1M; 1366 break; 1367 } 1368 case 'g': 1369 case 'G': 1370 { 1371 off *= _1G; 1372 break; 1373 } 1374 default: 1375 { 1376 RTPrintf("Invalid size suffix '%s'\n", pcszRanges); 1377 rc = VERR_INVALID_PARAMETER; 1378 } 1379 } 1380 if (RT_SUCCESS(rc)) 1381 pcszRanges++; 1382 } 1383 1384 if (*pcszRanges != ',') 1385 { 1386 rc = VERR_INVALID_PARAMETER; 1387 break; 1388 } 1389 1390 pcszRanges++; 1391 1392 rc = RTStrToUInt32Ex(pcszRanges, (char **)&pcszRanges, 10, &cb); 1393 if (RT_FAILURE(rc) && (rc != VWRN_TRAILING_CHARS)) 1394 break; 1395 1396 if (*pcszRanges != ',') 1397 { 1398 switch (*pcszRanges) 1399 { 1400 case 'k': 1401 case 'K': 1402 { 1403 cb *= _1K; 1404 break; 1405 } 1406 case 'm': 1407 case 'M': 1408 { 1409 cb *= _1M; 1410 break; 1411 } 1412 case 'g': 1413 case 'G': 1414 { 1415 cb *= _1G; 1416 break; 1417 } 1418 default: 1419 { 1420 RTPrintf("Invalid size suffix '%s'\n", pcszRanges); 1421 rc = VERR_INVALID_PARAMETER; 1422 } 1423 } 1424 if (RT_SUCCESS(rc)) 1425 pcszRanges++; 1426 } 1427 1428 if ( *pcszRanges != ',' 1429 && !(i == cRanges - 1 && *pcszRanges == '\0')) 1430 { 1431 rc = VERR_INVALID_PARAMETER; 1432 break; 1433 } 1434 1435 pcszRanges++; 1436 1437 paRanges[i].offStart = off; 1438 paRanges[i].cbRange = cb; 1439 } 1440 } while (0); 1441 1442 if (RT_SUCCESS(rc)) 1443 { 1444 if (!fAsync) 1445 rc = VDDiscardRanges(pDisk->pVD, paRanges, cRanges); 1446 else 1447 { 1448 VDIOREQ IoReq; 1449 RTSEMEVENT EventSem; 1450 1451 rc = RTSemEventCreate(&EventSem); 1452 if (RT_SUCCESS(rc)) 1453 { 1454 memset(&IoReq, 0, sizeof(VDIOREQ)); 1455 IoReq.enmTxDir = VDIOREQTXDIR_FLUSH; 1456 IoReq.pvUser = pDisk; 1457 IoReq.idx = 0; 1458 rc = VDAsyncDiscardRanges(pDisk->pVD, paRanges, cRanges, tstVDIoTestReqComplete, &IoReq, EventSem); 1459 if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS) 1460 { 1461 rc = RTSemEventWait(EventSem, RT_INDEFINITE_WAIT); 1462 AssertRC(rc); 1463 } 1464 else if (rc == VINF_VD_ASYNC_IO_FINISHED) 1465 rc = VINF_SUCCESS; 1466 1467 RTSemEventDestroy(EventSem); 1468 } 1469 } 1470 1310 1471 if ( RT_SUCCESS(rc) 1311 1472 && pDisk->pMemDiskVerify) 1312 1473 { 1313 void *pv = RTMemAllocZ(cbDiscard); 1314 if (pv) 1474 for (unsigned i = 0; i < cRanges; i++) 1315 1475 { 1316 RTSGSEG SgSeg; 1317 RTSGBUF SgBuf; 1318 1319 SgSeg.pvSeg = pv; 1320 SgSeg.cbSeg = cbDiscard; 1321 RTSgBufInit(&SgBuf, &SgSeg, 1); 1322 rc = VDMemDiskWrite(pDisk->pMemDiskVerify, off, cbDiscard, &SgBuf); 1323 RTMemFree(pv); 1476 void *pv = RTMemAllocZ(paRanges[i].cbRange); 1477 if (pv) 1478 { 1479 RTSGSEG SgSeg; 1480 RTSGBUF SgBuf; 1481 1482 SgSeg.pvSeg = pv; 1483 SgSeg.cbSeg = paRanges[i].cbRange; 1484 RTSgBufInit(&SgBuf, &SgSeg, 1); 1485 rc = VDMemDiskWrite(pDisk->pMemDiskVerify, paRanges[i].offStart, paRanges[i].cbRange, &SgBuf); 1486 RTMemFree(pv); 1487 } 1488 else 1489 { 1490 rc = VERR_NO_MEMORY; 1491 break; 1492 } 1324 1493 } 1325 else 1326 rc = VERR_NO_MEMORY; 1327 } 1328 } 1494 } 1495 } 1496 1497 if (paRanges) 1498 RTMemFree(paRanges); 1329 1499 } 1330 1500 … … 1647 1817 case VDDBGIOLOGREQ_DISCARD: 1648 1818 { 1649 P VDRANGE paRanges = NULL;1819 PRTRANGE paRanges = NULL; 1650 1820 unsigned cRanges = 0; 1651 1821 … … 2726 2896 } 2727 2897 case VDIOREQTXDIR_FLUSH: 2898 case VDIOREQTXDIR_DISCARD: 2728 2899 break; 2729 2900 }
Note:
See TracChangeset
for help on using the changeset viewer.