Changeset 30555 in vbox
- Timestamp:
- Jul 1, 2010 1:43:04 PM (15 years ago)
- Location:
- trunk
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/VBox/VBoxHDD.h
r30309 r30555 1365 1365 1366 1366 /** 1367 * Completion callback for metadata reads or writes. 1368 * 1369 * @return nothing. 1367 * Completion callback for meta/userdata reads or writes. 1368 * 1369 * @return VBox status code. 1370 * VINF_SUCCESS if everything was successful and the transfer can continue. 1371 * VERR_VD_ASYNC_IO_IN_PROGRESS if there is another data transfer pending. 1370 1372 * @param pvBackendData The opaque backend data. 1371 1373 * @param pIoCtx I/O context associated with this request. 1372 * @param pvMetaUser Opaque user data passed during a metadata read/write request. 1373 */ 1374 typedef DECLCALLBACK(void) FNVDMETACOMPLETED(void *pvBackendData, PVDIOCTX pIoCtx, void *pvMetaUser); 1375 /** Pointer to FNVDCOMPLETED() */ 1376 typedef FNVDMETACOMPLETED *PFNVDMETACOMPLETED; 1374 * @param pvUser Opaque user data passed during a read/write request. 1375 * @param rcReq Status code for the completed request. 1376 */ 1377 typedef DECLCALLBACK(int) FNVDXFERCOMPLETED(void *pvBackendData, PVDIOCTX pIoCtx, void *pvUser, int rcReq); 1378 /** Pointer to FNVDXFERCOMPLETED() */ 1379 typedef FNVDXFERCOMPLETED *PFNVDXFERCOMPLETED; 1380 1381 /** Metadata transfer handle. */ 1382 typedef struct VDMETAXFER *PVDMETAXFER; 1383 /** Pointer to a metadata transfer handle. */ 1384 typedef PVDMETAXFER *PPVDMETAXFER; 1385 1377 1386 1378 1387 /** … … 1475 1484 * Flush data to the storage backend. 1476 1485 * 1477 * @return VBox stat is code.1486 * @return VBox status code. 1478 1487 * @param pvUser The opaque data passed on container creation. 1479 1488 * @param pStorage The storage handle to flush. … … 1487 1496 * 1488 1497 * @return VBox status code. 1489 * @param pvUser The op qaue user data passed on container creation.1498 * @param pvUser The opaque user data passed on container creation. 1490 1499 * @param pStorage The storage handle. 1491 1500 * @param uOffset The offset to start reading from. … … 1506 1515 * @param pIoCtx I/O context passed in VDAsyncRead/Write 1507 1516 * @param cbWrite How many bytes to write. 1517 * @param pfnCompleted Completion callback. 1518 * @param pvCompleteUser Opaque user data passed in the completion callback. 1508 1519 */ 1509 1520 DECLR3CALLBACKMEMBER(int, pfnWriteUserAsync, (void *pvUser, PVDIOSTORAGE pStorage, 1510 1521 uint64_t uOffset, PVDIOCTX pIoCtx, 1511 size_t cbWrite)); 1522 size_t cbWrite, 1523 PFNVDXFERCOMPLETED pfnComplete, 1524 void *pvCompleteUser)); 1512 1525 1513 1526 /** … … 1516 1529 * 1517 1530 * @returns VBox status code. 1518 * @param pvUser The opaque user data passed on container creation. 1519 * @param pStorage The storage handle. 1520 * @param uOffset Offsete to start reading from. 1521 * @param pvBuf Where to store the data. 1522 * @param cbRead How many bytes to read. 1523 * @param pIoCtx The I/O context which triggered the read. 1524 * @param pfnMetaCompleted Callback to call when the read completes. 1525 * @param pvMetaUser Opaque user data which is passed in the callback. 1531 * @param pvUser The opaque user data passed on container creation. 1532 * @param pStorage The storage handle. 1533 * @param uOffset Offset to start reading from. 1534 * @param pvBuf Where to store the data. 1535 * @param cbRead How many bytes to read. 1536 * @param pIoCtx The I/O context which triggered the read. 1537 * @param ppMetaXfer Where to store the metadata transfer handle on success. 1526 1538 */ 1527 1539 DECLR3CALLBACKMEMBER(int, pfnReadMetaAsync, (void *pvUser, PVDIOSTORAGE pStorage, 1528 1540 uint64_t uOffset, void *pvBuf, 1529 1541 size_t cbRead, PVDIOCTX pIoCtx, 1530 PFNVDMETACOMPLETED pfnMetaCompleted, 1531 void *pvMetaUser)); 1542 PPVDMETAXFER ppMetaXfer)); 1532 1543 1533 1544 /** … … 1535 1546 * 1536 1547 * @returns VBox status code. 1537 * @param pvUser 1538 * @param pStorage 1539 * @param uOffset Offseteto start writing to.1540 * @param pvBuf 1541 * @param cbWrite 1542 * @param pIoCtx 1543 * @param pfn MetaCompleted Callback to call when the write completes.1544 * @param pv MetaUser Opaque user data which is passed in thecallback.1548 * @param pvUser The opaque user data passed on container creation. 1549 * @param pStorage The storage handle. 1550 * @param uOffset Offset to start writing to. 1551 * @param pvBuf Written data. 1552 * @param cbWrite How many bytes to write. 1553 * @param pIoCtx The I/O context which triggered the write. 1554 * @param pfnCompleted Completion callback. 1555 * @param pvCompleteUser Opaque user data passed in the completion callback. 1545 1556 */ 1546 1557 DECLR3CALLBACKMEMBER(int, pfnWriteMetaAsync, (void *pvUser, PVDIOSTORAGE pStorage, 1547 1558 uint64_t uOffset, void *pvBuf, 1548 1559 size_t cbWrite, PVDIOCTX pIoCtx, 1549 PFNVDMETACOMPLETED pfnMetaCompleted, 1550 void *pvMetaUser)); 1560 PFNVDXFERCOMPLETED pfnComplete, 1561 void *pvCompleteUser)); 1562 1563 /** 1564 * Releases a metadata transfer handle. 1565 * The free space can be used for another transfer. 1566 * 1567 * @returns nothing. 1568 * @param pvUser The opaque user data passed on container creation. 1569 * @param pMetaXfer The metadata transfer handle to release. 1570 */ 1571 DECLR3CALLBACKMEMBER(void, pfnMetaXferRelease, (void *pvUser, PVDMETAXFER pMetaXfer)); 1551 1572 1552 1573 /** 1553 1574 * Initiates a async flush request. 1554 1575 * 1555 * @return VBox statis code. 1556 * @param pvUser The opaque data passed on container creation. 1557 * @param pStorage The storage handle to flush. 1558 * @param pIoCtx I/O context which triggered the flush. 1576 * @return VBox status code. 1577 * @param pvUser The opaque data passed on container creation. 1578 * @param pStorage The storage handle to flush. 1579 * @param pIoCtx I/O context which triggered the flush. 1580 * @param pfnCompleted Completion callback. 1581 * @param pvCompleteUser Opaque user data passed in the completion callback. 1559 1582 */ 1560 1583 DECLR3CALLBACKMEMBER(int, pfnFlushAsync, (void *pvUser, PVDIOSTORAGE pStorage, 1561 PVDIOCTX pIoCtx)); 1584 PVDIOCTX pIoCtx, 1585 PFNVDXFERCOMPLETED pfnComplete, 1586 void *pvCompleteUser)); 1562 1587 1563 1588 /** … … 1565 1590 * 1566 1591 * @return Number of bytes copied. 1567 * @param pvUser The opaque user data passed on con atiner creation.1592 * @param pvUser The opaque user data passed on container creation. 1568 1593 * @param pIoCtx I/O context to copy the data to. 1569 1594 * @param pvBuf Buffer to copy. … … 1577 1602 * 1578 1603 * @return Number of bytes copied. 1579 * @param pvUser The opaque user data passed on con atiner creation.1604 * @param pvUser The opaque user data passed on container creation. 1580 1605 * @param pIoCtx I/O context to copy the data from. 1581 1606 * @param pvBuf Destination buffer. … … 1589 1614 * 1590 1615 * @return Number of bytes set. 1591 * @param pvUser The opaque user data passed on con atiner creation.1616 * @param pvUser The opaque user data passed on container creation. 1592 1617 * @param pIoCtx I/O context to copy the data from. 1593 1618 * @param ch The byte to set. … … 1597 1622 int ch, size_t cbSet)); 1598 1623 1624 /** 1625 * Marks the given number of bytes as completed and continues the I/O context. 1626 * 1627 * @returns nothing. 1628 * @param pvUser The opaque user data passed on container creation. 1629 * @param pIoCtx The I/O context. 1630 * @param cbCompleted Number of bytes completed. 1631 */ 1632 DECLR3CALLBACKMEMBER(void, pfnIoCtxCompleted, (void *pvUser, PVDIOCTX pIoCtx, 1633 size_t cbCompleted)); 1599 1634 } VDINTERFACEIO, *PVDINTERFACEIO; 1600 1635 -
trunk/include/VBox/err.h
r30473 r30555 1236 1236 /** The backend needs more metadata before it can continue. */ 1237 1237 #define VERR_VD_NOT_ENOUGH_METADATA (-3272) 1238 /** Halt the current I/O context until further notification from the backend. */ 1239 #define VERR_VD_IOCTX_HALT (-3273) 1238 1240 /** @} */ 1239 1241 -
trunk/src/VBox/Devices/Storage/RawHDDCore.cpp
r28800 r30555 1228 1228 rc = pImage->pInterfaceIOCallbacks->pfnWriteUserAsync(pImage->pInterfaceIO->pvUser, 1229 1229 pImage->pStorage, 1230 uOffset, pIoCtx, cbWrite); 1230 uOffset, pIoCtx, cbWrite, 1231 NULL, NULL); 1231 1232 1232 1233 if (RT_SUCCESS(rc)) -
trunk/src/VBox/Devices/Storage/VBoxHDD.cpp
r30481 r30555 39 39 #include <iprt/critsect.h> 40 40 #include <iprt/list.h> 41 #include <iprt/avl.h> 41 42 42 43 #include <VBox/VBoxHDD-Plugin.h> … … 171 172 }; 172 173 174 # define VD_THREAD_IS_CRITSECT_OWNER(Disk) \ 175 do \ 176 { \ 177 AssertMsg(RTCritSectIsOwner(&Disk->CritSect), \ 178 ("Thread does not own critical section\n"));\ 179 } while(0) 173 180 174 181 /** … … 208 215 typedef struct VDIOCTX 209 216 { 210 /** Node in the list of deferred requests. */211 RTLISTNODE NodeWriteGrowing;212 217 /** Disk this is request is for. */ 213 218 PVBOXHDD pDisk; … … 289 294 } VDIOCTX; 290 295 296 typedef struct VDIOCTXDEFERRED 297 { 298 /** Node in the list of deferred requests. 299 * A request can be deferred if the image is growing 300 * and the request accesses the same range or if 301 * the backend needs to read or write metadata from the disk 302 * before it can continue. */ 303 RTLISTNODE NodeDeferred; 304 /** I/O context this entry points to. */ 305 PVDIOCTX pIoCtx; 306 } VDIOCTXDEFERRED, *PVDIOCTXDEFERRED; 307 291 308 /** 292 309 * I/O task. … … 294 311 typedef struct VDIOTASK 295 312 { 296 /** Pointer to the I/O context the task belongs. */ 297 PVDIOCTX pIoCtx; 313 /** Storage this task belongs to. */ 314 PVDIOSTORAGE pIoStorage; 315 /** Optional completion callback. */ 316 PFNVDXFERCOMPLETED pfnComplete; 317 /** Opaque user data. */ 318 void *pvUser; 298 319 /** Flag whether this is a meta data transfer. */ 299 320 bool fMeta; … … 306 327 /** Number of bytes this task transfered. */ 307 328 uint32_t cbTransfer; 329 /** Pointer to the I/O context the task belongs. */ 330 PVDIOCTX pIoCtx; 308 331 } User; 309 332 /** Meta data transfer. */ 310 333 struct 311 334 { 312 /** Transfer direction (Read/Write) */ 313 VDIOCTXTXDIR enmTxDir; 314 /** Completion callback from the backend */ 315 PFNVDMETACOMPLETED pfnMetaComplete; 316 /** User data */ 317 void *pvMetaUser; 318 /** Image the task was created for. */ 319 PVDIMAGE pImage; 335 /** Meta transfer this task is for. */ 336 PVDMETAXFER pMetaXfer; 320 337 } Meta; 321 338 } Type; … … 329 346 /** Image this storage handle belongs to. */ 330 347 PVDIMAGE pImage; 348 /** AVL tree for pending async metadata transfers. */ 349 PAVLRFOFFTREE pTreeMetaXfers; 331 350 union 332 351 { … … 337 356 } u; 338 357 } VDIOSTORAGE; 358 359 /** 360 * Metadata transfer. 361 * 362 * @note This entry can't be freed if either the list is not empty or 363 * the reference counter is not 0. 364 * The assumption is that the backends don't need to read huge amounts of 365 * metadata to complete a transfer so the additional memory overhead should 366 * be relatively small. 367 */ 368 typedef struct VDMETAXFER 369 { 370 /** AVL core for fast search (the file offset is the key) */ 371 AVLRFOFFNODECORE Core; 372 /** I/O storage for this transfer. */ 373 PVDIOSTORAGE pIoStorage; 374 /** Flags. */ 375 uint32_t fFlags; 376 /** List of I/O contexts waiting for this metadata transfer to complete. */ 377 RTLISTNODE ListIoCtxWaiting; 378 /** Number of references to this entry. */ 379 unsigned cRefs; 380 /** Size of the data stored with this entry. */ 381 size_t cbMeta; 382 /** Data stored - variable size. */ 383 uint8_t abData[1]; 384 } VDMETAXFER; 385 386 /** 387 * The transfer direction for the metadata. 388 */ 389 #define VDMETAXFER_TXDIR_MASK 0x3 390 #define VDMETAXFER_TXDIR_NONE 0x0 391 #define VDMETAXFER_TXDIR_WRITE 0x1 392 #define VDMETAXFER_TXDIR_READ 0x2 393 #define VDMETAXFER_TXDIR_FLUSH 0x3 394 #define VDMETAXFER_TXDIR_GET(flags) ((flags) & VDMETAXFER_TXDIR_MASK) 395 #define VDMETAXFER_TXDIR_SET(flags, dir) ((flags) = (flags & ~VDMETAXFER_TXDIR_MASK) | (dir)) 339 396 340 397 extern VBOXHDDBACKEND g_RawBackend; … … 667 724 paSeg, cSeg, pvAllocation, pfnIoCtxTransfer); 668 725 726 AssertPtr(pIoCtxParent); 727 Assert(!pIoCtxParent->pIoCtxParent); 728 669 729 if (RT_LIKELY(pIoCtx)) 670 730 { … … 679 739 } 680 740 681 DECLINLINE(PVDIOTASK) vdIoTaskUserAlloc(PV BOXHDD pDisk, PVDIOCTX pIoCtx, uint32_t cbTransfer)741 DECLINLINE(PVDIOTASK) vdIoTaskUserAlloc(PVDIOSTORAGE pIoStorage, PFNVDXFERCOMPLETED pfnComplete, void *pvUser, PVDIOCTX pIoCtx, uint32_t cbTransfer) 682 742 { 683 743 PVDIOTASK pIoTask = NULL; 684 744 685 pIoTask = (PVDIOTASK)RTMemCacheAlloc(p Disk->hMemCacheIoTask);745 pIoTask = (PVDIOTASK)RTMemCacheAlloc(pIoStorage->pImage->pDisk->hMemCacheIoTask); 686 746 if (pIoTask) 687 747 { 688 pIoTask->pIoCtx = pIoCtx; 748 pIoTask->pIoStorage = pIoStorage; 749 pIoTask->pfnComplete = pfnComplete; 750 pIoTask->pvUser = pvUser; 689 751 pIoTask->fMeta = false; 690 752 pIoTask->Type.User.cbTransfer = cbTransfer; 753 pIoTask->Type.User.pIoCtx = pIoCtx; 691 754 } 692 755 … … 694 757 } 695 758 696 DECLINLINE(PVDIOTASK) vdIoTaskMetaAlloc(PVBOXHDD pDisk, PVDIOCTX pIoCtx, VDIOCTXTXDIR enmTxDir, 697 PVDIMAGE pImage, 698 PFNVDMETACOMPLETED pfnMetaComplete, void *pvMetaUser) 759 DECLINLINE(PVDIOTASK) vdIoTaskMetaAlloc(PVDIOSTORAGE pIoStorage, PFNVDXFERCOMPLETED pfnComplete, void *pvUser, PVDMETAXFER pMetaXfer) 699 760 { 700 761 PVDIOTASK pIoTask = NULL; 701 762 702 pIoTask = (PVDIOTASK)RTMemCacheAlloc(p Disk->hMemCacheIoTask);763 pIoTask = (PVDIOTASK)RTMemCacheAlloc(pIoStorage->pImage->pDisk->hMemCacheIoTask); 703 764 if (pIoTask) 704 765 { 705 pIoTask->pIoCtx = pIoCtx; 706 pIoTask->fMeta = true; 707 pIoTask->Type.Meta.enmTxDir = enmTxDir; 708 pIoTask->Type.Meta.pfnMetaComplete = pfnMetaComplete; 709 pIoTask->Type.Meta.pvMetaUser = pvMetaUser; 710 pIoTask->Type.Meta.pImage = pImage; 766 pIoTask->pIoStorage = pIoStorage; 767 pIoTask->pfnComplete = pfnComplete; 768 pIoTask->pvUser = pvUser; 769 pIoTask->fMeta = true; 770 pIoTask->Type.Meta.pMetaXfer = pMetaXfer; 711 771 } 712 772 … … 723 783 DECLINLINE(void) vdIoTaskFree(PVBOXHDD pDisk, PVDIOTASK pIoTask) 724 784 { 725 pIoTask->pIoCtx = NULL;726 785 RTMemCacheFree(pDisk->hMemCacheIoTask, pIoTask); 727 786 } … … 734 793 pIoCtx->uOffset = pIoCtx->Type.Child.uOffsetSaved; 735 794 pIoCtx->cbTransferLeft = pIoCtx->Type.Child.cbTransferLeftSaved; 795 } 796 797 DECLINLINE(PVDMETAXFER) vdMetaXferAlloc(PVDIMAGE pImage, PVDIOSTORAGE pIoStorage, uint64_t uOffset, size_t cb) 798 { 799 PVDMETAXFER pMetaXfer = (PVDMETAXFER)RTMemAlloc(RT_OFFSETOF(VDMETAXFER, abData[cb])); 800 801 if (RT_LIKELY(pMetaXfer)) 802 { 803 pMetaXfer->Core.Key = uOffset; 804 pMetaXfer->Core.KeyLast = uOffset + cb - 1; 805 pMetaXfer->fFlags = VDMETAXFER_TXDIR_NONE; 806 pMetaXfer->cbMeta = cb; 807 pMetaXfer->pIoStorage = pIoStorage; 808 pMetaXfer->cRefs = 0; 809 RTListInit(&pMetaXfer->ListIoCtxWaiting); 810 } 811 return pMetaXfer; 736 812 } 737 813 … … 784 860 return VINF_VD_ASYNC_IO_FINISHED; 785 861 862 /* Don't change anything if there is a metadata transfer pending. */ 863 if (pIoCtx->cMetaTransfersPending) 864 return VERR_VD_ASYNC_IO_IN_PROGRESS; 865 786 866 if (pIoCtx->pfnIoCtxTransfer) 787 867 { … … 809 889 && !pIoCtx->cDataTransfersPending) 810 890 rc = VINF_VD_ASYNC_IO_FINISHED; 811 else if (RT_SUCCESS(rc) )891 else if (RT_SUCCESS(rc) || rc == VERR_VD_NOT_ENOUGH_METADATA) 812 892 rc = VERR_VD_ASYNC_IO_IN_PROGRESS; 813 893 else if (RT_FAILURE(rc) && (rc != VERR_VD_ASYNC_IO_IN_PROGRESS)) … … 881 961 rc = VINF_SUCCESS; 882 962 } 963 else if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS) 964 rc = VINF_SUCCESS; 883 965 884 966 if (RT_FAILURE(rc)) … … 895 977 pIoCtx->cbTransfer = cbToRead; 896 978 pIoCtx->pImage = pCurrImage; 897 rc = VERR_VD_ASYNC_IO_IN_PROGRESS;898 979 } 899 980 … … 1283 1364 1284 1365 AssertPtr(pIoCtxParent); 1366 Assert(!pIoCtxParent->pIoCtxParent); 1285 1367 Assert(!pIoCtx->cbTransferLeft && !pIoCtx->cMetaTransfersPending); 1286 1368 … … 1347 1429 Assert(cbPreRead == 0); 1348 1430 Assert(cbPostRead == 0); 1431 if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS) 1432 rc = VINF_SUCCESS; 1349 1433 1350 1434 return rc; … … 1392 1476 1393 1477 AssertPtr(pIoCtx->pIoCtxParent); 1478 Assert(!pIoCtx->pIoCtxParent->pIoCtxParent); 1394 1479 1395 1480 if (cbPostRead) … … 1464 1549 if (ASMAtomicReadBool(&pDisk->fGrowing)) 1465 1550 { 1551 PVDIOCTXDEFERRED pDeferred = (PVDIOCTXDEFERRED)RTMemAllocZ(sizeof(VDIOCTXDEFERRED)); 1552 AssertPtr(pDeferred); 1553 1466 1554 LogFlowFunc(("Deferring write pIoCtx=%#p\n", pIoCtx)); 1467 RTListAppend(&pDisk->ListWriteGrowing, &pIoCtx->NodeWriteGrowing); 1555 1556 RTListInit(&pDeferred->NodeDeferred); 1557 pDeferred->pIoCtx = pIoCtx; 1558 RTListAppend(&pDisk->ListWriteGrowing, &pDeferred->NodeDeferred); 1468 1559 pIoCtx->fBlocked = true; 1469 Assert(pIoCtx->NodeWriteGrowing.pNext == &pDisk->ListWriteGrowing);1470 Assert(pDisk->ListWriteGrowing.pPrev == &pIoCtx->NodeWriteGrowing);1471 1560 rc = VERR_VD_ASYNC_IO_IN_PROGRESS; 1472 1561 break; … … 1533 1622 } 1534 1623 1624 if (rc == VERR_VD_NOT_ENOUGH_METADATA) 1625 break; 1626 1535 1627 cbWrite -= cbThisWrite; 1536 1628 uOffset += cbThisWrite; 1537 } while (cbWrite != 0 && RT_SUCCESS(rc));1538 1539 if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS )1629 } while (cbWrite != 0 && (RT_SUCCESS(rc) || rc == VERR_VD_ASYNC_IO_IN_PROGRESS)); 1630 1631 if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS || rc == VERR_VD_NOT_ENOUGH_METADATA) 1540 1632 { 1541 1633 /* … … 1564 1656 vdResetModifiedFlag(pDisk); 1565 1657 rc = pImage->Backend->pfnAsyncFlush(pImage->pvBackendData, pIoCtx); 1658 if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS) 1659 rc = VINF_SUCCESS; 1566 1660 1567 1661 return rc; … … 1818 1912 } 1819 1913 1820 static int vdIOReqCompleted(void *pvUser, int rcReq) 1821 { 1914 /** 1915 * Internal - Continues an I/O context after 1916 * it was halted because of an active transfer. 1917 */ 1918 static int vdIoCtxContinue(PVDIOCTX pIoCtx, int rcReq) 1919 { 1920 PVBOXHDD pDisk = pIoCtx->pDisk; 1822 1921 int rc = VINF_SUCCESS; 1823 PVDIOTASK pIoTask = (PVDIOTASK)pvUser;1824 PVDIOCTX pIoCtx = pIoTask->pIoCtx;1825 PVBOXHDD pDisk = pIoCtx->pDisk;1826 1827 LogFlowFunc(("Task completed pIoTask=%#p pIoCtx=%#p pDisk=%#p\n",1828 pIoTask, pIoCtx, pDisk));1829 1830 if (!pIoTask->fMeta)1831 {1832 ASMAtomicSubU32(&pIoCtx->cbTransferLeft, pIoTask->Type.User.cbTransfer);1833 ASMAtomicDecU32(&pIoCtx->cDataTransfersPending);1834 }1835 else1836 {1837 if (pIoTask->Type.Meta.pfnMetaComplete)1838 pIoTask->Type.Meta.pfnMetaComplete(pIoTask->Type.Meta.pImage->pvBackendData,1839 pIoCtx,1840 pIoTask->Type.Meta.pvMetaUser);1841 ASMAtomicDecU32(&pIoCtx->cMetaTransfersPending);1842 }1843 1844 vdIoTaskFree(pDisk, pIoTask);1845 1922 1846 1923 if (RT_FAILURE(rcReq)) … … 1883 1960 && ASMAtomicCmpXchgBool(&pIoCtxParent->fComplete, true, false)) 1884 1961 { 1885 LogFlowFunc(("Parent I/O context completed pIoCtxParent=%#p \n", pIoCtx));1962 LogFlowFunc(("Parent I/O context completed pIoCtxParent=%#p rcReq=%Rrc\n", pIoCtxParent, pIoCtxParent->rcReq)); 1886 1963 pIoCtxParent->Type.Root.pfnComplete(pIoCtxParent->Type.Root.pvUser1, 1887 1964 pIoCtxParent->Type.Root.pvUser2, … … 1911 1988 do 1912 1989 { 1913 PVDIOCTX pIoCtxWait = RTListNodeGetFirst(&ListTmp, VDIOCTX, NodeWriteGrowing); 1990 PVDIOCTXDEFERRED pDeferred = RTListNodeGetFirst(&ListTmp, VDIOCTXDEFERRED, NodeDeferred); 1991 PVDIOCTX pIoCtxWait = pDeferred->pIoCtx; 1992 1914 1993 AssertPtr(pIoCtxWait); 1915 1994 1916 RTListNodeRemove(&pIoCtxWait->NodeWriteGrowing); 1995 RTListNodeRemove(&pDeferred->NodeDeferred); 1996 RTMemFree(pDeferred); 1917 1997 1918 1998 pIoCtxWait->fBlocked = false; … … 1945 2025 vdThreadFinishRead(pDisk); 1946 2026 2027 LogFlowFunc(("I/O context completed pIoCtx=%#p rcReq=%Rrc\n", pIoCtx, pIoCtx->rcReq)); 1947 2028 pIoCtx->Type.Root.pfnComplete(pIoCtx->Type.Root.pvUser1, 1948 2029 pIoCtx->Type.Root.pvUser2, … … 1958 2039 1959 2040 /** 2041 * Internal - Called when user transfer completed. 2042 */ 2043 static int vdUserXferCompleted(PVDIOSTORAGE pIoStorage, PVDIOCTX pIoCtx, 2044 PFNVDXFERCOMPLETED pfnComplete, void *pvUser, 2045 size_t cbTransfer, int rcReq) 2046 { 2047 int rc = VINF_SUCCESS; 2048 bool fIoCtxContinue = true; 2049 PVBOXHDD pDisk = pIoCtx->pDisk; 2050 2051 LogFlowFunc(("pIoStorage=%#p pIoCtx=%#p pfnComplete=%#p pvUser=%#p cbTransfer=%zu rcReq=%Rrc\n", 2052 pIoStorage, pIoCtx, pfnComplete, pvUser, cbTransfer, rcReq)); 2053 2054 ASMAtomicSubU32(&pIoCtx->cbTransferLeft, cbTransfer); 2055 ASMAtomicDecU32(&pIoCtx->cDataTransfersPending); 2056 2057 if (pfnComplete) 2058 rc = pfnComplete(pIoStorage->pImage->pvBackendData, pIoCtx, pvUser, rcReq); 2059 2060 if (RT_SUCCESS(rc)) 2061 rc = vdIoCtxContinue(pIoCtx, rcReq); 2062 else if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS) 2063 rc = VINF_SUCCESS; 2064 2065 return rc; 2066 } 2067 2068 /** 2069 * Internal - Called when a meta transfer completed. 2070 */ 2071 static int vdMetaXferCompleted(PVDIOSTORAGE pIoStorage, PFNVDXFERCOMPLETED pfnComplete, void *pvUser, 2072 PVDMETAXFER pMetaXfer, int rcReq) 2073 { 2074 PVBOXHDD pDisk = pIoStorage->pImage->pDisk; 2075 RTLISTNODE ListIoCtxWaiting; 2076 bool fFlush = VDMETAXFER_TXDIR_GET(pMetaXfer->fFlags) == VDMETAXFER_TXDIR_FLUSH; 2077 2078 LogFlowFunc(("pIoStorage=%#p pfnComplete=%#p pvUser=%#p pMetaXfer=%#p rcReq=%Rrc\n", 2079 pIoStorage, pfnComplete, pvUser, pMetaXfer, rcReq)); 2080 2081 VDMETAXFER_TXDIR_SET(pMetaXfer->fFlags, VDMETAXFER_TXDIR_NONE); 2082 2083 if (!fFlush) 2084 { 2085 RTCritSectEnter(&pDisk->CritSect); 2086 2087 RTListMove(&ListIoCtxWaiting, &pMetaXfer->ListIoCtxWaiting); 2088 2089 if (RT_FAILURE(rcReq)) 2090 { 2091 /* Remove from the AVL tree. */ 2092 bool fRemoved = RTAvlrFileOffsetRemove(pIoStorage->pTreeMetaXfers, pMetaXfer->Core.Key); 2093 Assert(fRemoved); 2094 RTMemFree(pMetaXfer); 2095 } 2096 else 2097 { 2098 /* Increase the reference counter to make sure it doesn't go away before the last context is processed. */ 2099 pMetaXfer->cRefs++; 2100 } 2101 2102 RTCritSectLeave(&pDisk->CritSect); 2103 } 2104 else 2105 { 2106 /* 2107 * Flushes don't need the critical section because they are never accessed concurrently 2108 * (they also have only one context attached). 2109 */ 2110 RTListMove(&ListIoCtxWaiting, &pMetaXfer->ListIoCtxWaiting); 2111 } 2112 2113 /* Go through the waiting list and continue the I/O contexts. */ 2114 while (!RTListIsEmpty(&ListIoCtxWaiting)) 2115 { 2116 int rc = VINF_SUCCESS; 2117 bool fContinue = true; 2118 PVDIOCTXDEFERRED pDeferred = RTListNodeGetFirst(&ListIoCtxWaiting, VDIOCTXDEFERRED, NodeDeferred); 2119 PVDIOCTX pIoCtx = pDeferred->pIoCtx; 2120 RTListNodeRemove(&pDeferred->NodeDeferred); 2121 2122 RTMemFree(pDeferred); 2123 ASMAtomicDecU32(&pIoCtx->cMetaTransfersPending); 2124 2125 if (pfnComplete) 2126 rc = pfnComplete(pIoStorage->pImage->pvBackendData, pIoCtx, pvUser, rcReq); 2127 2128 LogFlow(("Completion callback for I/O context %#p returned %Rrc\n", pIoCtx, rc)); 2129 2130 if (RT_SUCCESS(rc)) 2131 { 2132 rc = vdIoCtxContinue(pIoCtx, rcReq); 2133 AssertRC(rc); 2134 } 2135 else 2136 Assert(rc == VERR_VD_ASYNC_IO_IN_PROGRESS); 2137 } 2138 2139 /* Remove if not used anymore. */ 2140 if (RT_SUCCESS(rcReq) && !fFlush) 2141 { 2142 RTCritSectEnter(&pDisk->CritSect); 2143 pMetaXfer->cRefs--; 2144 if (!pMetaXfer->cRefs) 2145 { 2146 /* Remove from the AVL tree. */ 2147 bool fRemoved = RTAvlrFileOffsetRemove(pIoStorage->pTreeMetaXfers, pMetaXfer->Core.Key); 2148 Assert(fRemoved); 2149 RTMemFree(pMetaXfer); 2150 } 2151 RTCritSectLeave(&pDisk->CritSect); 2152 } 2153 else if (fFlush) 2154 RTMemFree(pMetaXfer); 2155 2156 return VINF_SUCCESS; 2157 } 2158 2159 static int vdIOReqCompleted(void *pvUser, int rcReq) 2160 { 2161 int rc = VINF_SUCCESS; 2162 PVDIOTASK pIoTask = (PVDIOTASK)pvUser; 2163 PVDIOSTORAGE pIoStorage = pIoTask->pIoStorage; 2164 2165 LogFlowFunc(("Task completed pIoTask=%#p\n", pIoTask)); 2166 2167 if (!pIoTask->fMeta) 2168 rc = vdUserXferCompleted(pIoStorage, pIoTask->Type.User.pIoCtx, 2169 pIoTask->pfnComplete, pIoTask->pvUser, 2170 pIoTask->Type.User.cbTransfer, rcReq); 2171 else 2172 rc = vdMetaXferCompleted(pIoStorage, pIoTask->pfnComplete, pIoTask->pvUser, 2173 pIoTask->Type.Meta.pMetaXfer, rcReq); 2174 2175 vdIoTaskFree(pIoStorage->pImage->pDisk, pIoTask); 2176 2177 return rc; 2178 } 2179 2180 /** 1960 2181 * VD I/O interface callback for opening a file. 1961 2182 */ … … 1971 2192 return VERR_NO_MEMORY; 1972 2193 1973 rc = pDisk->pInterfaceAsyncIOCallbacks->pfnOpen(pDisk->pInterfaceAsyncIO->pvUser, 1974 pszLocation, uOpenFlags, 1975 vdIOReqCompleted, 1976 pDisk->pVDIfsDisk, 1977 &pIoStorage->u.pStorage); 1978 if (RT_SUCCESS(rc)) 1979 *ppIoStorage = pIoStorage; 2194 pIoStorage->pImage = pImage; 2195 2196 /* Create the AVl tree. */ 2197 pIoStorage->pTreeMetaXfers = (PAVLRFOFFTREE)RTMemAllocZ(sizeof(AVLRFOFFTREE)); 2198 if (pIoStorage->pTreeMetaXfers) 2199 { 2200 rc = pDisk->pInterfaceAsyncIOCallbacks->pfnOpen(pDisk->pInterfaceAsyncIO->pvUser, 2201 pszLocation, uOpenFlags, 2202 vdIOReqCompleted, 2203 pDisk->pVDIfsDisk, 2204 &pIoStorage->u.pStorage); 2205 if (RT_SUCCESS(rc)) 2206 { 2207 *ppIoStorage = pIoStorage; 2208 return VINF_SUCCESS; 2209 } 2210 2211 RTMemFree(pIoStorage->pTreeMetaXfers); 2212 } 1980 2213 else 1981 RTMemFree(pIoStorage); 1982 2214 rc = VERR_NO_MEMORY; 2215 2216 RTMemFree(pIoStorage); 1983 2217 return rc; 2218 } 2219 2220 static int vdIOTreeMetaXferDestroy(PAVLRFOFFNODECORE pNode, void *pvUser) 2221 { 2222 AssertMsgFailed(("Tree should be empty at this point!\n")); 2223 return VINF_SUCCESS; 1984 2224 } 1985 2225 … … 1993 2233 AssertRC(rc); 1994 2234 2235 RTAvlrFileOffsetDestroy(pIoStorage->pTreeMetaXfers, vdIOTreeMetaXferDestroy, NULL); 2236 RTMemFree(pIoStorage->pTreeMetaXfers); 1995 2237 RTMemFree(pIoStorage); 1996 2238 return VINF_SUCCESS; … … 2063 2305 pvUser, pIoStorage, uOffset, pIoCtx, cbRead)); 2064 2306 2307 VD_THREAD_IS_CRITSECT_OWNER(pDisk); 2308 2065 2309 /* Build the S/G array and spawn a new I/O task */ 2066 2310 while (cbRead) … … 2075 2319 2076 2320 LogFlow(("Reading %u bytes into %u segments\n", cbTaskRead, cSegments)); 2321 2322 #ifdef RT_STRICT 2323 for (unsigned i = 0; i < cSegments; i++) 2324 AssertMsg(aSeg[i].pvSeg && !(aSeg[i].cbSeg % 512), 2325 ("Segment %u is invalid\n", i)); 2326 #endif 2327 2328 PVDIOTASK pIoTask = vdIoTaskUserAlloc(pIoStorage, NULL, NULL, pIoCtx, cbTaskRead); 2329 2330 if (!pIoTask) 2331 return VERR_NO_MEMORY; 2332 2333 ASMAtomicIncU32(&pIoCtx->cDataTransfersPending); 2334 2335 void *pvTask; 2336 rc = pDisk->pInterfaceAsyncIOCallbacks->pfnReadAsync(pDisk->pInterfaceAsyncIO->pvUser, 2337 pIoStorage->u.pStorage, 2338 uOffset, aSeg, cSegments, 2339 cbTaskRead, pIoTask, 2340 &pvTask); 2341 if (RT_SUCCESS(rc)) 2342 { 2343 AssertMsg(cbTaskRead <= pIoCtx->cbTransferLeft, ("Impossible!\n")); 2344 ASMAtomicSubU32(&pIoCtx->cbTransferLeft, cbTaskRead); 2345 ASMAtomicDecU32(&pIoCtx->cDataTransfersPending); 2346 vdIoTaskFree(pDisk, pIoTask); 2347 } 2348 else if (rc != VERR_VD_ASYNC_IO_IN_PROGRESS) 2349 { 2350 ASMAtomicDecU32(&pIoCtx->cDataTransfersPending); 2351 break; 2352 } 2353 2354 uOffset += cbTaskRead; 2355 cbRead -= cbTaskRead; 2356 } 2357 2358 LogFlowFunc(("returns rc=%Rrc\n", rc)); 2359 return rc; 2360 } 2361 2362 static int vdIOWriteUserAsync(void *pvUser, PVDIOSTORAGE pIoStorage, 2363 uint64_t uOffset, PVDIOCTX pIoCtx, 2364 size_t cbWrite, 2365 PFNVDXFERCOMPLETED pfnComplete, 2366 void *pvCompleteUser) 2367 { 2368 int rc = VINF_SUCCESS; 2369 PVDIMAGE pImage = (PVDIMAGE)pvUser; 2370 PVBOXHDD pDisk = pImage->pDisk; 2371 2372 LogFlowFunc(("pvUser=%#p pIoStorage=%#p uOffset=%llu pIoCtx=%#p cbWrite=%u\n", 2373 pvUser, pIoStorage, uOffset, pIoCtx, cbWrite)); 2374 2375 VD_THREAD_IS_CRITSECT_OWNER(pDisk); 2376 2377 /* Build the S/G array and spawn a new I/O task */ 2378 while (cbWrite) 2379 { 2380 RTSGSEG aSeg[VD_IO_TASK_SEGMENTS_MAX]; 2381 unsigned cSegments = VD_IO_TASK_SEGMENTS_MAX; 2382 size_t cbTaskWrite = 0; 2383 2384 cbTaskWrite = RTSgBufSegArrayCreate(&pIoCtx->SgBuf, aSeg, &cSegments, cbWrite); 2385 2386 AssertMsg(cbTaskWrite <= cbWrite, ("Invalid number of bytes to write\n")); 2387 2388 LogFlow(("Writing %u bytes from %u segments\n", cbTaskWrite, cSegments)); 2077 2389 2078 2390 #ifdef DEBUG … … 2082 2394 #endif 2083 2395 2084 PVDIOTASK pIoTask = vdIoTaskUserAlloc(p Disk, pIoCtx, cbTaskRead);2396 PVDIOTASK pIoTask = vdIoTaskUserAlloc(pIoStorage, pfnComplete, pvCompleteUser, pIoCtx, cbTaskWrite); 2085 2397 2086 2398 if (!pIoTask) … … 2090 2402 2091 2403 void *pvTask; 2092 int rc2 = pDisk->pInterfaceAsyncIOCallbacks->pfnReadAsync(pDisk->pInterfaceAsyncIO->pvUser, 2093 pIoStorage->u.pStorage, 2094 uOffset, aSeg, cSegments, 2095 cbTaskRead, pIoTask, 2096 &pvTask); 2097 if (rc2 == VINF_SUCCESS) 2098 { 2099 AssertMsg(cbTaskRead <= pIoCtx->cbTransferLeft, ("Impossible!\n")); 2100 ASMAtomicSubU32(&pIoCtx->cbTransferLeft, cbTaskRead); 2101 ASMAtomicDecU32(&pIoCtx->cDataTransfersPending); 2102 vdIoTaskFree(pDisk, pIoTask); 2103 } 2104 else if (rc2 == VERR_VD_ASYNC_IO_IN_PROGRESS) 2105 rc = VINF_SUCCESS; 2106 else if (RT_FAILURE(rc2)) 2107 { 2108 rc = rc2; 2109 break; 2110 } 2111 2112 uOffset += cbTaskRead; 2113 cbRead -= cbTaskRead; 2114 } 2115 2116 return rc; 2117 } 2118 2119 static int vdIOWriteUserAsync(void *pvUser, PVDIOSTORAGE pIoStorage, 2120 uint64_t uOffset, PVDIOCTX pIoCtx, 2121 size_t cbWrite) 2122 { 2123 int rc = VINF_SUCCESS; 2124 PVDIMAGE pImage = (PVDIMAGE)pvUser; 2125 PVBOXHDD pDisk = pImage->pDisk; 2126 2127 LogFlowFunc(("pvUser=%#p pIoStorage=%#p uOffset=%llu pIoCtx=%#p cbWrite=%u\n", 2128 pvUser, pIoStorage, uOffset, pIoCtx, cbWrite)); 2129 2130 /* Build the S/G array and spawn a new I/O task */ 2131 while (cbWrite) 2132 { 2133 RTSGSEG aSeg[VD_IO_TASK_SEGMENTS_MAX]; 2134 unsigned cSegments = VD_IO_TASK_SEGMENTS_MAX; 2135 size_t cbTaskWrite = 0; 2136 2137 cbTaskWrite = RTSgBufSegArrayCreate(&pIoCtx->SgBuf, aSeg, &cSegments, cbWrite); 2138 2139 AssertMsg(cbTaskWrite <= cbWrite, ("Invalid number of bytes to write\n")); 2140 2141 LogFlow(("Writing %u bytes from %u segments\n", cbTaskWrite, cSegments)); 2142 2143 #ifdef DEBUG 2144 for (unsigned i = 0; i < cSegments; i++) 2145 AssertMsg(aSeg[i].pvSeg && !(aSeg[i].cbSeg % 512), 2146 ("Segment %u is invalid\n", i)); 2147 #endif 2148 2149 PVDIOTASK pIoTask = vdIoTaskUserAlloc(pDisk, pIoCtx, cbTaskWrite); 2150 2151 if (!pIoTask) 2152 return VERR_NO_MEMORY; 2153 2154 ASMAtomicIncU32(&pIoCtx->cDataTransfersPending); 2155 2156 void *pvTask; 2157 int rc2 = pDisk->pInterfaceAsyncIOCallbacks->pfnWriteAsync(pDisk->pInterfaceAsyncIO->pvUser, 2158 pIoStorage->u.pStorage, 2159 uOffset, aSeg, cSegments, 2160 cbTaskWrite, pIoTask, 2161 &pvTask); 2162 if (rc2 == VINF_SUCCESS) 2404 rc = pDisk->pInterfaceAsyncIOCallbacks->pfnWriteAsync(pDisk->pInterfaceAsyncIO->pvUser, 2405 pIoStorage->u.pStorage, 2406 uOffset, aSeg, cSegments, 2407 cbTaskWrite, pIoTask, 2408 &pvTask); 2409 if (RT_SUCCESS(rc)) 2163 2410 { 2164 2411 AssertMsg(cbTaskWrite <= pIoCtx->cbTransferLeft, ("Impossible!\n")); … … 2167 2414 vdIoTaskFree(pDisk, pIoTask); 2168 2415 } 2169 else if (rc2 == VERR_VD_ASYNC_IO_IN_PROGRESS) 2170 rc = VINF_SUCCESS; 2171 else if (RT_FAILURE(rc2)) 2172 { 2173 rc = rc2; 2416 else if (rc != VERR_VD_ASYNC_IO_IN_PROGRESS) 2417 { 2418 ASMAtomicDecU32(&pIoCtx->cDataTransfersPending); 2174 2419 break; 2175 2420 } … … 2185 2430 uint64_t uOffset, void *pvBuf, 2186 2431 size_t cbRead, PVDIOCTX pIoCtx, 2187 PFNVDMETACOMPLETED pfnMetaComplete, 2188 void *pvMetaUser) 2432 PPVDMETAXFER ppMetaXfer) 2189 2433 { 2190 2434 PVDIMAGE pImage = (PVDIMAGE)pvUser; … … 2193 2437 RTSGSEG Seg; 2194 2438 PVDIOTASK pIoTask; 2439 PVDMETAXFER pMetaXfer = NULL; 2195 2440 void *pvTask = NULL; 2196 2441 2197 pIoTask = vdIoTaskMetaAlloc(pDisk, pIoCtx, VDIOCTXTXDIR_READ, pImage, 2198 pfnMetaComplete, pvMetaUser); 2199 if (!pIoTask) 2200 return VERR_NO_MEMORY; 2201 2202 Seg.cbSeg = cbRead; 2203 Seg.pvSeg = pvBuf; 2204 2205 ASMAtomicIncU32(&pIoCtx->cMetaTransfersPending); 2206 2207 int rc2 = pDisk->pInterfaceAsyncIOCallbacks->pfnReadAsync(pDisk->pInterfaceAsyncIO->pvUser, 2208 pIoStorage->u.pStorage, 2209 uOffset, &Seg, 1, 2210 cbRead, pIoTask, 2211 &pvTask); 2212 if (rc2 == VINF_SUCCESS) 2213 { 2214 ASMAtomicDecU32(&pIoCtx->cMetaTransfersPending); 2215 vdIoTaskFree(pDisk, pIoTask); 2216 } 2217 else if (rc2 == VERR_VD_ASYNC_IO_IN_PROGRESS) 2218 rc = VERR_VD_NOT_ENOUGH_METADATA; 2219 else if (RT_FAILURE(rc2)) 2220 rc = rc2; 2442 LogFlowFunc(("pvUser=%#p pIoStorage=%#p uOffset=%llu pvBuf=%#p cbRead=%u\n", 2443 pvUser, pIoStorage, uOffset, pvBuf, cbRead)); 2444 2445 VD_THREAD_IS_CRITSECT_OWNER(pDisk); 2446 2447 pMetaXfer = (PVDMETAXFER)RTAvlrFileOffsetGet(pIoStorage->pTreeMetaXfers, uOffset); 2448 if (!pMetaXfer) 2449 { 2450 /* Allocate a new meta transfer. */ 2451 pMetaXfer = vdMetaXferAlloc(pImage, pIoStorage, uOffset, cbRead); 2452 if (!pMetaXfer) 2453 return VERR_NO_MEMORY; 2454 2455 pIoTask = vdIoTaskMetaAlloc(pIoStorage, NULL, NULL, pMetaXfer); 2456 if (!pIoTask) 2457 { 2458 RTMemFree(pMetaXfer); 2459 return VERR_NO_MEMORY; 2460 } 2461 2462 Seg.cbSeg = cbRead; 2463 Seg.pvSeg = pMetaXfer->abData; 2464 2465 VDMETAXFER_TXDIR_SET(pMetaXfer->fFlags, VDMETAXFER_TXDIR_READ); 2466 rc = pDisk->pInterfaceAsyncIOCallbacks->pfnReadAsync(pDisk->pInterfaceAsyncIO->pvUser, 2467 pIoStorage->u.pStorage, 2468 uOffset, &Seg, 1, 2469 cbRead, pIoTask, 2470 &pvTask); 2471 if (RT_SUCCESS(rc)) 2472 { 2473 VDMETAXFER_TXDIR_SET(pMetaXfer->fFlags, VDMETAXFER_TXDIR_NONE); 2474 vdIoTaskFree(pDisk, pIoTask); 2475 } 2476 else if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS) 2477 rc = VERR_VD_NOT_ENOUGH_METADATA; 2478 2479 if (RT_SUCCESS(rc) || rc == VERR_VD_NOT_ENOUGH_METADATA) 2480 { 2481 bool fInserted = RTAvlrFileOffsetInsert(pIoStorage->pTreeMetaXfers, &pMetaXfer->Core); 2482 Assert(fInserted); 2483 } 2484 else 2485 RTMemFree(pMetaXfer); 2486 } 2487 2488 Assert(VALID_PTR(pMetaXfer) || RT_FAILURE(rc)); 2489 2490 if (RT_SUCCESS(rc) || rc == VERR_VD_NOT_ENOUGH_METADATA) 2491 { 2492 /* If it is pending add the request to the list. */ 2493 if (VDMETAXFER_TXDIR_GET(pMetaXfer->fFlags) == VDMETAXFER_TXDIR_READ) 2494 { 2495 PVDIOCTXDEFERRED pDeferred = (PVDIOCTXDEFERRED)RTMemAllocZ(sizeof(VDIOCTXDEFERRED)); 2496 AssertPtr(pDeferred); 2497 2498 RTListInit(&pDeferred->NodeDeferred); 2499 pDeferred->pIoCtx = pIoCtx; 2500 2501 ASMAtomicIncU32(&pIoCtx->cMetaTransfersPending); 2502 RTListAppend(&pMetaXfer->ListIoCtxWaiting, &pDeferred->NodeDeferred); 2503 rc = VERR_VD_NOT_ENOUGH_METADATA; 2504 } 2505 else 2506 { 2507 /* Transfer the data. */ 2508 pMetaXfer->cRefs++; 2509 Assert(pMetaXfer->cbMeta >= cbRead); 2510 memcpy(pvBuf, pMetaXfer->abData, cbRead); 2511 *ppMetaXfer = pMetaXfer; 2512 } 2513 } 2221 2514 2222 2515 return rc; … … 2226 2519 uint64_t uOffset, void *pvBuf, 2227 2520 size_t cbWrite, PVDIOCTX pIoCtx, 2228 PFNVD METACOMPLETED pfnMetaComplete,2229 void *pv MetaUser)2521 PFNVDXFERCOMPLETED pfnComplete, 2522 void *pvCompleteUser) 2230 2523 { 2231 2524 PVDIMAGE pImage = (PVDIMAGE)pvUser; … … 2234 2527 RTSGSEG Seg; 2235 2528 PVDIOTASK pIoTask; 2529 PVDMETAXFER pMetaXfer = NULL; 2236 2530 void *pvTask = NULL; 2237 2531 2238 pIoTask = vdIoTaskMetaAlloc(pDisk, pIoCtx, VDIOCTXTXDIR_WRITE, pImage, 2239 pfnMetaComplete, pvMetaUser); 2240 if (!pIoTask) 2241 return VERR_NO_MEMORY; 2242 2243 Seg.cbSeg = cbWrite; 2244 Seg.pvSeg = pvBuf; 2245 2246 ASMAtomicIncU32(&pIoCtx->cMetaTransfersPending); 2247 2248 int rc2 = pDisk->pInterfaceAsyncIOCallbacks->pfnWriteAsync(pDisk->pInterfaceAsyncIO->pvUser, 2249 pIoStorage->u.pStorage, 2250 uOffset, &Seg, 1, 2251 cbWrite, pIoTask, 2252 &pvTask); 2253 if (rc2 == VINF_SUCCESS) 2254 { 2255 ASMAtomicDecU32(&pIoCtx->cMetaTransfersPending); 2256 vdIoTaskFree(pDisk, pIoTask); 2257 } 2258 else if (rc2 == VERR_VD_ASYNC_IO_IN_PROGRESS) 2259 rc = VINF_SUCCESS; 2260 else if (RT_FAILURE(rc2)) 2261 rc = rc2; 2532 LogFlowFunc(("pvUser=%#p pIoStorage=%#p uOffset=%llu pvBuf=%#p cbWrite=%u\n", 2533 pvUser, pIoStorage, uOffset, pvBuf, cbWrite)); 2534 2535 VD_THREAD_IS_CRITSECT_OWNER(pDisk); 2536 2537 pMetaXfer = (PVDMETAXFER)RTAvlrFileOffsetGet(pIoStorage->pTreeMetaXfers, uOffset); 2538 if (!pMetaXfer) 2539 { 2540 /* Allocate a new meta transfer. */ 2541 pMetaXfer = vdMetaXferAlloc(pImage, pIoStorage, uOffset, cbWrite); 2542 if (!pMetaXfer) 2543 return VERR_NO_MEMORY; 2544 2545 pIoTask = vdIoTaskMetaAlloc(pIoStorage, pfnComplete, pvCompleteUser, pMetaXfer); 2546 if (!pIoTask) 2547 { 2548 RTMemFree(pMetaXfer); 2549 return VERR_NO_MEMORY; 2550 } 2551 2552 memcpy(pMetaXfer->abData, pvBuf, cbWrite); 2553 Seg.cbSeg = cbWrite; 2554 Seg.pvSeg = pMetaXfer->abData; 2555 2556 ASMAtomicIncU32(&pIoCtx->cMetaTransfersPending); 2557 2558 VDMETAXFER_TXDIR_SET(pMetaXfer->fFlags, VDMETAXFER_TXDIR_WRITE); 2559 rc = pDisk->pInterfaceAsyncIOCallbacks->pfnWriteAsync(pDisk->pInterfaceAsyncIO->pvUser, 2560 pIoStorage->u.pStorage, 2561 uOffset, &Seg, 1, 2562 cbWrite, pIoTask, 2563 &pvTask); 2564 if (RT_SUCCESS(rc)) 2565 { 2566 VDMETAXFER_TXDIR_SET(pMetaXfer->fFlags, VDMETAXFER_TXDIR_NONE); 2567 ASMAtomicDecU32(&pIoCtx->cMetaTransfersPending); 2568 vdIoTaskFree(pDisk, pIoTask); 2569 RTMemFree(pMetaXfer); 2570 pMetaXfer = NULL; 2571 } 2572 else if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS) 2573 { 2574 PVDIOCTXDEFERRED pDeferred = (PVDIOCTXDEFERRED)RTMemAllocZ(sizeof(VDIOCTXDEFERRED)); 2575 AssertPtr(pDeferred); 2576 2577 RTListInit(&pDeferred->NodeDeferred); 2578 pDeferred->pIoCtx = pIoCtx; 2579 2580 bool fInserted = RTAvlrFileOffsetInsert(pIoStorage->pTreeMetaXfers, &pMetaXfer->Core); 2581 Assert(fInserted); 2582 2583 RTListAppend(&pMetaXfer->ListIoCtxWaiting, &pDeferred->NodeDeferred); 2584 } 2585 else 2586 { 2587 RTMemFree(pMetaXfer); 2588 pMetaXfer = NULL; 2589 } 2590 } 2591 2592 Assert(VALID_PTR(pMetaXfer) || RT_SUCCESS(rc) || rc != VERR_VD_ASYNC_IO_IN_PROGRESS); 2262 2593 2263 2594 return rc; 2264 2595 } 2265 2596 2597 static void vdIOMetaXferRelease(void *pvUser, PVDMETAXFER pMetaXfer) 2598 { 2599 PVDIMAGE pImage = (PVDIMAGE)pvUser; 2600 PVDIOSTORAGE pIoStorage = pMetaXfer->pIoStorage; 2601 2602 VD_THREAD_IS_CRITSECT_OWNER(pImage->pDisk); 2603 2604 Assert( VDMETAXFER_TXDIR_GET(pMetaXfer->fFlags) == VDMETAXFER_TXDIR_NONE 2605 || VDMETAXFER_TXDIR_GET(pMetaXfer->fFlags) == VDMETAXFER_TXDIR_WRITE); 2606 Assert(pMetaXfer->cRefs > 0); 2607 2608 pMetaXfer->cRefs--; 2609 if ( !pMetaXfer->cRefs 2610 && RTListIsEmpty(&pMetaXfer->ListIoCtxWaiting) 2611 && VDMETAXFER_TXDIR_GET(pMetaXfer->fFlags) == VDMETAXFER_TXDIR_NONE) 2612 { 2613 /* Free the meta data entry. */ 2614 bool fRemoved = RTAvlrFileOffsetRemove(pIoStorage->pTreeMetaXfers, pMetaXfer->Core.Key); 2615 AssertMsg(fRemoved, ("Metadata transfer wasn't removed\n")); 2616 2617 RTMemFree(pMetaXfer); 2618 } 2619 } 2620 2266 2621 static int vdIOFlushAsync(void *pvUser, PVDIOSTORAGE pIoStorage, 2267 PVDIOCTX pIoCtx) 2622 PVDIOCTX pIoCtx, 2623 PFNVDXFERCOMPLETED pfnComplete, 2624 void *pvCompleteUser) 2268 2625 { 2269 2626 PVDIMAGE pImage = (PVDIMAGE)pvUser; … … 2271 2628 int rc = VINF_SUCCESS; 2272 2629 PVDIOTASK pIoTask; 2630 PVDMETAXFER pMetaXfer = NULL; 2273 2631 void *pvTask = NULL; 2274 2632 2275 pIoTask = vdIoTaskMetaAlloc(pDisk, pIoCtx, VDIOCTXTXDIR_FLUSH, pImage, 2276 NULL, NULL); 2633 VD_THREAD_IS_CRITSECT_OWNER(pDisk); 2634 2635 LogFlowFunc(("pvUser=%#p pIoStorage=%#p pIoCtx=%#p\n", 2636 pvUser, pIoStorage, pIoCtx)); 2637 2638 /* Allocate a new meta transfer. */ 2639 pMetaXfer = vdMetaXferAlloc(pImage, pIoStorage, 0, 0); 2640 if (!pMetaXfer) 2641 return VERR_NO_MEMORY; 2642 2643 pIoTask = vdIoTaskMetaAlloc(pIoStorage, pfnComplete, pvUser, pMetaXfer); 2277 2644 if (!pIoTask) 2645 { 2646 RTMemFree(pMetaXfer); 2278 2647 return VERR_NO_MEMORY; 2648 } 2279 2649 2280 2650 ASMAtomicIncU32(&pIoCtx->cMetaTransfersPending); 2281 2651 2282 int rc2 = pDisk->pInterfaceAsyncIOCallbacks->pfnFlushAsync(pDisk->pInterfaceAsyncIO->pvUser, 2283 pIoStorage->u.pStorage, 2284 pIoTask, 2285 &pvTask); 2286 if (rc2 == VINF_SUCCESS) 2287 { 2652 PVDIOCTXDEFERRED pDeferred = (PVDIOCTXDEFERRED)RTMemAllocZ(sizeof(VDIOCTXDEFERRED)); 2653 AssertPtr(pDeferred); 2654 2655 RTListInit(&pDeferred->NodeDeferred); 2656 pDeferred->pIoCtx = pIoCtx; 2657 2658 RTListAppend(&pMetaXfer->ListIoCtxWaiting, &pDeferred->NodeDeferred); 2659 VDMETAXFER_TXDIR_SET(pMetaXfer->fFlags, VDMETAXFER_TXDIR_FLUSH); 2660 rc = pDisk->pInterfaceAsyncIOCallbacks->pfnFlushAsync(pDisk->pInterfaceAsyncIO->pvUser, 2661 pIoStorage->u.pStorage, 2662 pIoTask, 2663 &pvTask); 2664 if (RT_SUCCESS(rc)) 2665 { 2666 VDMETAXFER_TXDIR_SET(pMetaXfer->fFlags, VDMETAXFER_TXDIR_NONE); 2288 2667 ASMAtomicDecU32(&pIoCtx->cMetaTransfersPending); 2289 2668 vdIoTaskFree(pDisk, pIoTask); 2290 }2291 else if (rc2 == VERR_VD_ASYNC_IO_IN_PROGRESS)2292 rc = VINF_SUCCESS;2293 else if ( RT_FAILURE(rc2))2294 rc = rc2;2669 RTMemFree(pDeferred); 2670 RTMemFree(pMetaXfer); 2671 } 2672 else if (rc != VERR_VD_ASYNC_IO_IN_PROGRESS) 2673 RTMemFree(pMetaXfer); 2295 2674 2296 2675 return rc; … … 2300 2679 void *pvBuf, size_t cbBuf) 2301 2680 { 2681 PVDIMAGE pImage = (PVDIMAGE)pvUser; 2682 PVBOXHDD pDisk = pImage->pDisk; 2683 2684 VD_THREAD_IS_CRITSECT_OWNER(pDisk); 2685 2302 2686 return vdIoCtxCopyTo(pIoCtx, (uint8_t *)pvBuf, cbBuf); 2303 2687 } … … 2306 2690 void *pvBuf, size_t cbBuf) 2307 2691 { 2692 PVDIMAGE pImage = (PVDIMAGE)pvUser; 2693 PVBOXHDD pDisk = pImage->pDisk; 2694 2695 VD_THREAD_IS_CRITSECT_OWNER(pDisk); 2696 2308 2697 return vdIoCtxCopyFrom(pIoCtx, (uint8_t *)pvBuf, cbBuf); 2309 2698 } … … 2312 2701 int ch, size_t cb) 2313 2702 { 2703 PVDIMAGE pImage = (PVDIMAGE)pvUser; 2704 PVBOXHDD pDisk = pImage->pDisk; 2705 2706 VD_THREAD_IS_CRITSECT_OWNER(pDisk); 2707 2314 2708 return vdIoCtxSet(pIoCtx, ch, cb); 2315 2709 } … … 2636 3030 2637 3031 /* Create the I/O callback table. */ 2638 pDisk->VDIIOCallbacks.cbSize = sizeof(VDINTERFACEIO); 2639 pDisk->VDIIOCallbacks.enmInterface = VDINTERFACETYPE_IO; 2640 pDisk->VDIIOCallbacks.pfnOpen = vdIOOpen; 2641 pDisk->VDIIOCallbacks.pfnClose = vdIOClose; 2642 pDisk->VDIIOCallbacks.pfnGetSize = vdIOGetSize; 2643 pDisk->VDIIOCallbacks.pfnSetSize = vdIOSetSize; 2644 pDisk->VDIIOCallbacks.pfnReadSync = vdIOReadSync; 2645 pDisk->VDIIOCallbacks.pfnWriteSync = vdIOWriteSync; 2646 pDisk->VDIIOCallbacks.pfnFlushSync = vdIOFlushSync; 2647 pDisk->VDIIOCallbacks.pfnReadUserAsync = vdIOReadUserAsync; 2648 pDisk->VDIIOCallbacks.pfnWriteUserAsync = vdIOWriteUserAsync; 2649 pDisk->VDIIOCallbacks.pfnReadMetaAsync = vdIOReadMetaAsync; 2650 pDisk->VDIIOCallbacks.pfnWriteMetaAsync = vdIOWriteMetaAsync; 2651 pDisk->VDIIOCallbacks.pfnFlushAsync = vdIOFlushAsync; 2652 pDisk->VDIIOCallbacks.pfnIoCtxCopyFrom = vdIOIoCtxCopyFrom; 2653 pDisk->VDIIOCallbacks.pfnIoCtxCopyTo = vdIOIoCtxCopyTo; 2654 pDisk->VDIIOCallbacks.pfnIoCtxSet = vdIOIoCtxSet; 3032 pDisk->VDIIOCallbacks.cbSize = sizeof(VDINTERFACEIO); 3033 pDisk->VDIIOCallbacks.enmInterface = VDINTERFACETYPE_IO; 3034 pDisk->VDIIOCallbacks.pfnOpen = vdIOOpen; 3035 pDisk->VDIIOCallbacks.pfnClose = vdIOClose; 3036 pDisk->VDIIOCallbacks.pfnGetSize = vdIOGetSize; 3037 pDisk->VDIIOCallbacks.pfnSetSize = vdIOSetSize; 3038 pDisk->VDIIOCallbacks.pfnReadSync = vdIOReadSync; 3039 pDisk->VDIIOCallbacks.pfnWriteSync = vdIOWriteSync; 3040 pDisk->VDIIOCallbacks.pfnFlushSync = vdIOFlushSync; 3041 pDisk->VDIIOCallbacks.pfnReadUserAsync = vdIOReadUserAsync; 3042 pDisk->VDIIOCallbacks.pfnWriteUserAsync = vdIOWriteUserAsync; 3043 pDisk->VDIIOCallbacks.pfnReadMetaAsync = vdIOReadMetaAsync; 3044 pDisk->VDIIOCallbacks.pfnWriteMetaAsync = vdIOWriteMetaAsync; 3045 pDisk->VDIIOCallbacks.pfnMetaXferRelease = vdIOMetaXferRelease; 3046 pDisk->VDIIOCallbacks.pfnFlushAsync = vdIOFlushAsync; 3047 pDisk->VDIIOCallbacks.pfnIoCtxCopyFrom = vdIOIoCtxCopyFrom; 3048 pDisk->VDIIOCallbacks.pfnIoCtxCopyTo = vdIOIoCtxCopyTo; 3049 pDisk->VDIIOCallbacks.pfnIoCtxSet = vdIOIoCtxSet; 2655 3050 2656 3051 *ppDisk = pDisk; -
trunk/src/VBox/Devices/Storage/VDIHDDCore.cpp
r28800 r30555 206 206 207 207 static int vdiFileWriteMetaAsync(PVDIIMAGEDESC pImage, uint64_t off, void *pcvBuf, size_t cbWrite, 208 PVDIOCTX pIoCtx , PFNVDMETACOMPLETED pfnMetaComplete, void *pvMetaUser)208 PVDIOCTX pIoCtx) 209 209 { 210 210 return pImage->pInterfaceIOCallbacks->pfnWriteMetaAsync(pImage->pInterfaceIO->pvUser, 211 211 pImage->pStorage, 212 212 off, pcvBuf, cbWrite, pIoCtx, 213 pfnMetaComplete, pvMetaUser);213 NULL, NULL); 214 214 } 215 215 216 216 static int vdiFileReadMetaAsync(PVDIIMAGEDESC pImage, uint64_t off, void *pvBuf, size_t cbRead, 217 PVDIOCTX pIoCtx , PFNVDMETACOMPLETED pfnMetaComplete, void *pvMetaUser)217 PVDIOCTX pIoCtx) 218 218 { 219 219 return pImage->pInterfaceIOCallbacks->pfnReadMetaAsync(pImage->pInterfaceIO->pvUser, 220 220 pImage->pStorage, 221 221 off, pvBuf, cbRead, pIoCtx, 222 pfnMetaComplete, pvMetaUser);222 NULL); 223 223 } 224 224 … … 235 235 { 236 236 return pImage->pInterfaceIOCallbacks->pfnFlushAsync(pImage->pInterfaceIO->pvUser, 237 pImage->pStorage, pIoCtx); 237 pImage->pStorage, pIoCtx, 238 NULL, NULL); 238 239 } 239 240 … … 873 874 rc = vdiFileWriteMetaAsync(pImage, sizeof(VDIPREHEADER), 874 875 &pImage->Header.u.v0, sizeof(pImage->Header.u.v0), 875 pIoCtx , NULL, NULL);876 pIoCtx); 876 877 break; 877 878 case 1: … … 879 880 rc = vdiFileWriteMetaAsync(pImage, sizeof(VDIPREHEADER), 880 881 &pImage->Header.u.v1, sizeof(pImage->Header.u.v1), 881 pIoCtx , NULL, NULL);882 pIoCtx); 882 883 else 883 884 rc = vdiFileWriteMetaAsync(pImage, sizeof(VDIPREHEADER), 884 885 &pImage->Header.u.v1plus, sizeof(pImage->Header.u.v1plus), 885 pIoCtx , NULL, NULL);886 pIoCtx); 886 887 break; 887 888 default: … … 889 890 break; 890 891 } 891 AssertMsgRC(rc, ("vdiUpdateHeader failed, filename=\"%s\" rc=%Rrc\n", pImage->pszFilename, rc)); 892 AssertMsg(RT_SUCCESS(rc) || rc == VERR_VD_ASYNC_IO_IN_PROGRESS, 893 ("vdiUpdateHeader failed, filename=\"%s\" rc=%Rrc\n", pImage->pszFilename, rc)); 892 894 return rc; 893 895 } … … 922 924 /* Update image header. */ 923 925 int rc = vdiUpdateHeaderAsync(pImage, pIoCtx); 924 if (RT_SUCCESS(rc) )926 if (RT_SUCCESS(rc) || rc == VERR_VD_ASYNC_IO_IN_PROGRESS) 925 927 { 926 928 /* write only one block pointer. */ … … 929 931 &pImage->paBlocks[uBlock], 930 932 sizeof(VDIIMAGEBLOCKPOINTER), 931 pIoCtx ,932 NULL, NULL);933 AssertMsgRC(rc,("vdiUpdateBlockInfo failed to update block=%u, filename=\"%s\", rc=%Rrc\n",934 933 pIoCtx); 934 AssertMsg(RT_SUCCESS(rc) || rc == VERR_VD_ASYNC_IO_IN_PROGRESS, 935 ("vdiUpdateBlockInfo failed to update block=%u, filename=\"%s\", rc=%Rrc\n", 936 uBlock, pImage->pszFilename, rc)); 935 937 } 936 938 return rc; … … 955 957 * Internal: Flush the image file to disk - async version. 956 958 */ 957 static void vdiFlushImageAsync(PVDIIMAGEDESC pImage, PVDIOCTX pIoCtx) 958 { 959 static int vdiFlushImageAsync(PVDIIMAGEDESC pImage, PVDIOCTX pIoCtx) 960 { 961 int rc = VINF_SUCCESS; 962 959 963 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)) 960 964 { 961 965 /* Save header. */ 962 int rc = vdiUpdateHeaderAsync(pImage, pIoCtx); 963 AssertMsgRC(rc, ("vdiUpdateHeaderAsync() failed, filename=\"%s\", rc=%Rrc\n", 964 pImage->pszFilename, rc)); 966 rc = vdiUpdateHeaderAsync(pImage, pIoCtx); 967 AssertMsg(RT_SUCCESS(rc) || rc == VERR_VD_ASYNC_IO_IN_PROGRESS, 968 ("vdiUpdateHeaderAsync() failed, filename=\"%s\", rc=%Rrc\n", 969 pImage->pszFilename, rc)); 965 970 rc = vdiFileFlushAsync(pImage, pIoCtx); 966 AssertMsgRC(rc, ("Flushing data to disk failed rc=%Rrc\n", rc)); 967 } 971 AssertMsg(RT_SUCCESS(rc) || rc == VERR_VD_ASYNC_IO_IN_PROGRESS, 972 ("Flushing data to disk failed rc=%Rrc\n", rc)); 973 } 974 975 return rc; 968 976 } 969 977 … … 2207 2215 pImage->pStorage, 2208 2216 u64Offset, 2209 pIoCtx, cbToWrite); 2217 pIoCtx, cbToWrite, 2218 NULL, NULL); 2210 2219 if (RT_UNLIKELY(RT_FAILURE_NP(rc) && (rc != VERR_VD_ASYNC_IO_IN_PROGRESS))) 2211 2220 goto out; … … 2214 2223 2215 2224 rc = vdiUpdateBlockInfoAsync(pImage, uBlock, pIoCtx); 2216 if (RT_FAILURE(rc) )2225 if (RT_FAILURE(rc) && (rc != VERR_VD_ASYNC_IO_IN_PROGRESS)) 2217 2226 goto out; 2218 2227 … … 2237 2246 pImage->pStorage, 2238 2247 u64Offset, 2239 pIoCtx, cbToWrite); 2248 pIoCtx, cbToWrite, 2249 NULL, NULL); 2240 2250 } 2241 2251 } while (0); … … 2257 2267 Assert(pImage); 2258 2268 2259 vdiFlushImageAsync(pImage, pIoCtx);2269 rc = vdiFlushImageAsync(pImage, pIoCtx); 2260 2270 LogFlowFunc(("returns %Rrc\n", rc)); 2261 2271 return rc; -
trunk/src/VBox/Devices/Storage/VHDHDDCore.cpp
r29250 r30555 198 198 } VHDIMAGE, *PVHDIMAGE; 199 199 200 /** 201 * Structure tracking the expansion process of the image 202 * for async access. 203 */ 204 typedef struct VHDIMAGEEXPAND 205 { 206 /** Flag indicating the status of each step. */ 207 volatile uint32_t fFlags; 208 /** The index in the block allocation table which is written. */ 209 uint32_t idxBatAllocated; 210 /** Big endian representation of the block index 211 * which is written in the BAT. */ 212 uint32_t idxBlockBe; 213 /** Old end of the file - used for rollback in case of an error. */ 214 uint64_t cbEofOld; 215 /** Sector bitmap written to the new block - variable in size. */ 216 uint8_t au8Bitmap[1]; 217 } VHDIMAGEEXPAND, *PVHDIMAGEEXPAND; 218 219 /** 220 * Flag defines 221 */ 222 #define VHDIMAGEEXPAND_STEP_IN_PROGRESS (0x0) 223 #define VHDIMAGEEXPAND_STEP_FAILED (0x2) 224 #define VHDIMAGEEXPAND_STEP_SUCCESS (0x3) 225 /** All steps completed successfully. */ 226 #define VHDIMAGEEXPAND_ALL_SUCCESS (0xff) 227 /** All steps completed (no success indicator) */ 228 #define VHDIMAGEEXPAND_ALL_COMPLETE (0xaa) 229 230 /** Every status field has 2 bits so we can encode 4 steps in one byte. */ 231 #define VHDIMAGEEXPAND_STATUS_MASK 0x03 232 #define VHDIMAGEEXPAND_BLOCKBITMAP_STATUS_SHIFT 0x00 233 #define VHDIMAGEEXPAND_USERBLOCK_STATUS_SHIFT 0x02 234 #define VHDIMAGEEXPAND_FOOTER_STATUS_SHIFT 0x04 235 #define VHDIMAGEEXPAND_BAT_STATUS_SHIFT 0x06 236 237 /** 238 * Helper macros to get and set the status field. 239 */ 240 #define VHDIMAGEEXPAND_STATUS_GET(fFlags, cShift) \ 241 (((fFlags) >> (cShift)) & VHDIMAGEEXPAND_STATUS_MASK) 242 #define VHDIMAGEEXPAND_STATUS_SET(fFlags, cShift, uVal) \ 243 ASMAtomicOrU32(&(fFlags), ((uVal) & VHDIMAGEEXPAND_STATUS_MASK) << (cShift)) 244 200 245 /******************************************************************************* 201 246 * Static Variables * … … 563 608 } 564 609 610 /** 611 * Internal: called when the async expansion process completed (failure or success). 612 * Will do the necessary rollback if an error occurred. 613 */ 614 static int vhdAsyncExpansionComplete(PVHDIMAGE pImage, PVDIOCTX pIoCtx, PVHDIMAGEEXPAND pExpand) 615 { 616 int rc = VINF_SUCCESS; 617 uint32_t fFlags = ASMAtomicReadU32(&pExpand->fFlags); 618 bool fIoInProgress = false; 619 620 /* Quick path, check if everything succeeded. */ 621 if (fFlags == VHDIMAGEEXPAND_ALL_SUCCESS) 622 { 623 RTMemFree(pExpand); 624 } 625 else 626 { 627 uint32_t uStatus; 628 629 uStatus = VHDIMAGEEXPAND_STATUS_GET(pExpand->fFlags, VHDIMAGEEXPAND_BAT_STATUS_SHIFT); 630 if ( uStatus == VHDIMAGEEXPAND_STEP_FAILED 631 || uStatus == VHDIMAGEEXPAND_STEP_SUCCESS) 632 { 633 /* Undo and restore the old value. */ 634 pImage->pBlockAllocationTable[pExpand->idxBatAllocated] == ~0U; 635 636 /* Restore the old value on the disk. 637 * No need for a completion callback because we can't 638 * do anything if this fails. */ 639 if (uStatus == VHDIMAGEEXPAND_STEP_SUCCESS) 640 { 641 rc = pImage->pInterfaceIOCallbacks->pfnWriteMetaAsync(pImage->pInterfaceIO->pvUser, 642 pImage->pStorage, 643 pImage->uBlockAllocationTableOffset + pExpand->idxBatAllocated * sizeof(uint32_t), 644 &pImage->pBlockAllocationTable[pExpand->idxBatAllocated], sizeof(uint32_t), pIoCtx, 645 NULL, NULL); 646 fIoInProgress |= rc == VERR_VD_ASYNC_IO_IN_PROGRESS; 647 } 648 } 649 650 /* Restore old size (including the footer because another application might 651 * fill up the free space making it impossible to add the footer) 652 * and add the footer at the right place again. */ 653 rc = pImage->pInterfaceIOCallbacks->pfnSetSize(pImage->pInterfaceIO->pvUser, 654 pImage->pStorage, 655 pExpand->cbEofOld + sizeof(VHDFooter)); 656 AssertRC(rc); 657 658 pImage->uCurrentEndOfFile = pExpand->cbEofOld; 659 rc = pImage->pInterfaceIOCallbacks->pfnWriteMetaAsync(pImage->pInterfaceIO->pvUser, 660 pImage->pStorage, 661 pImage->uCurrentEndOfFile, 662 &pImage->vhdFooterCopy, sizeof(VHDFooter), pIoCtx, 663 NULL, NULL); 664 fIoInProgress |= rc == VERR_VD_ASYNC_IO_IN_PROGRESS; 665 } 666 667 return fIoInProgress ? VERR_VD_ASYNC_IO_IN_PROGRESS : rc; 668 } 669 670 static int vhdAsyncExpansionStepCompleted(void *pvBackendData, PVDIOCTX pIoCtx, void *pvUser, int rcReq, unsigned iStep) 671 { 672 PVHDIMAGE pImage = (PVHDIMAGE)pvBackendData; 673 PVHDIMAGEEXPAND pExpand = (PVHDIMAGEEXPAND)pvUser; 674 675 LogFlowFunc(("pvBackendData=%#p pIoCtx=%#p pvUser=%#p rcReq=%Rrc iStep=%u\n", 676 pvBackendData, pIoCtx, pvUser, rcReq, iStep)); 677 678 if (RT_SUCCESS(rcReq)) 679 VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, iStep, VHDIMAGEEXPAND_STEP_SUCCESS); 680 else 681 VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, iStep, VHDIMAGEEXPAND_STEP_FAILED); 682 683 if ((pExpand->fFlags & VHDIMAGEEXPAND_ALL_COMPLETE) == VHDIMAGEEXPAND_ALL_COMPLETE) 684 return vhdAsyncExpansionComplete(pImage, pIoCtx, pExpand); 685 686 return VERR_VD_ASYNC_IO_IN_PROGRESS; 687 } 688 689 static int vhdAsyncExpansionDataBlockBitmapComplete(void *pvBackendData, PVDIOCTX pIoCtx, void *pvUser, int rcReq) 690 { 691 return vhdAsyncExpansionStepCompleted(pvBackendData, pIoCtx, pvUser, rcReq, VHDIMAGEEXPAND_BLOCKBITMAP_STATUS_SHIFT); 692 } 693 694 static int vhdAsyncExpansionDataComplete(void *pvBackendData, PVDIOCTX pIoCtx, void *pvUser, int rcReq) 695 { 696 return vhdAsyncExpansionStepCompleted(pvBackendData, pIoCtx, pvUser, rcReq, VHDIMAGEEXPAND_USERBLOCK_STATUS_SHIFT); 697 } 698 699 static int vhdAsyncExpansionBatUpdateComplete(void *pvBackendData, PVDIOCTX pIoCtx, void *pvUser, int rcReq) 700 { 701 return vhdAsyncExpansionStepCompleted(pvBackendData, pIoCtx, pvUser, rcReq, VHDIMAGEEXPAND_BAT_STATUS_SHIFT); 702 } 703 704 static int vhdAsyncExpansionFooterUpdateComplete(void *pvBackendData, PVDIOCTX pIoCtx, void *pvUser, int rcReq) 705 { 706 return vhdAsyncExpansionStepCompleted(pvBackendData, pIoCtx, pvUser, rcReq, VHDIMAGEEXPAND_FOOTER_STATUS_SHIFT); 707 } 565 708 566 709 static int vhdOpenImage(PVHDIMAGE pImage, unsigned uOpenFlags) … … 568 711 uint64_t FileSize; 569 712 VHDFooter vhdFooter; 570 571 if (uOpenFlags & VD_OPEN_FLAGS_ASYNC_IO)572 return VERR_NOT_SUPPORTED;573 713 574 714 pImage->uOpenFlags = uOpenFlags; … … 1093 1233 * Internal: Sets the given sector in the sector bitmap. 1094 1234 */ 1095 DECLINLINE( void) vhdBlockBitmapSectorSet(PVHDIMAGE pImage, uint32_t cBlockBitmapEntry)1235 DECLINLINE(bool) vhdBlockBitmapSectorSet(PVHDIMAGE pImage, uint8_t *pu8Bitmap, uint32_t cBlockBitmapEntry) 1096 1236 { 1097 1237 uint32_t iBitmap = (cBlockBitmapEntry / 8); /* Byte in the block bitmap. */ … … 1099 1239 /* 1100 1240 * The index of the bit in the byte of the data block bitmap. 1101 * The most signif cant bit stands for a lower sector number.1241 * The most significant bit stands for a lower sector number. 1102 1242 */ 1103 1243 uint8_t iBitInByte = (8-1) - (cBlockBitmapEntry % 8); 1104 uint8_t *puBitmap = p Image->pu8Bitmap + iBitmap;1105 1106 AssertMsg(puBitmap < (p Image->pu8Bitmap + pImage->cbDataBlockBitmap),1244 uint8_t *puBitmap = pu8Bitmap + iBitmap; 1245 1246 AssertMsg(puBitmap < (pu8Bitmap + pImage->cbDataBlockBitmap), 1107 1247 ("VHD: Current bitmap position exceeds maximum size of the bitmap\n")); 1108 1248 1109 ASMBitSet(puBitmap, iBitInByte);1249 return !ASMBitTestAndSet(puBitmap, iBitInByte); 1110 1250 } 1111 1251 … … 1313 1453 if (RT_SUCCESS(rc)) 1314 1454 { 1455 bool fChanged = false; 1456 1315 1457 /* Set the bits for all sectors having been written. */ 1316 1458 for (uint32_t iSector = 0; iSector < (cbToWrite / VHD_SECTOR_SIZE); iSector++) 1317 1459 { 1318 vhdBlockBitmapSectorSet(pImage, cBATEntryIndex);1460 fChanged |= vhdBlockBitmapSectorSet(pImage, pImage->pu8Bitmap, cBATEntryIndex); 1319 1461 cBATEntryIndex++; 1320 1462 } 1321 1463 1322 /* Write the bitmap back. */ 1323 rc = vhdFileWriteSync(pImage, 1324 ((uint64_t)pImage->pBlockAllocationTable[cBlockAllocationTableEntry]) * VHD_SECTOR_SIZE, 1325 pImage->pu8Bitmap, pImage->cbDataBlockBitmap, NULL); 1464 if (fChanged) 1465 { 1466 /* Write the bitmap back. */ 1467 rc = vhdFileWriteSync(pImage, 1468 ((uint64_t)pImage->pBlockAllocationTable[cBlockAllocationTableEntry]) * VHD_SECTOR_SIZE, 1469 pImage->pu8Bitmap, pImage->cbDataBlockBitmap, NULL); 1470 } 1326 1471 } 1327 1472 } … … 2131 2276 static bool vhdIsAsyncIOSupported(void *pvBackendData) 2132 2277 { 2133 return false;2134 } 2135 2136 static int vhdAsyncRead(void *p vBackendData, uint64_t uOffset, size_t cbRead,2278 return true; 2279 } 2280 2281 static int vhdAsyncRead(void *pBackendData, uint64_t uOffset, size_t cbRead, 2137 2282 PVDIOCTX pIoCtx, size_t *pcbActuallyRead) 2138 2283 { 2139 int rc = VERR_NOT_IMPLEMENTED; 2140 LogFlowFunc(("returns %Rrc\n", rc)); 2141 return rc; 2142 } 2143 2144 static int vhdAsyncWrite(void *pvBackendData, uint64_t uOffset, size_t cbWrite, 2284 PVHDIMAGE pImage = (PVHDIMAGE)pBackendData; 2285 int rc = VINF_SUCCESS; 2286 2287 LogFlowFunc(("pBackendData=%p uOffset=%#llx pIoCtx=%#p cbRead=%u pcbActuallyRead=%p\n", pBackendData, uOffset, pIoCtx, cbRead, pcbActuallyRead)); 2288 2289 if (uOffset + cbRead > pImage->cbSize) 2290 return VERR_INVALID_PARAMETER; 2291 2292 /* 2293 * If we have a dynamic disk image, we need to find the data block and sector to read. 2294 */ 2295 if (pImage->pBlockAllocationTable) 2296 { 2297 /* 2298 * Get the data block first. 2299 */ 2300 uint32_t cBlockAllocationTableEntry = (uOffset / VHD_SECTOR_SIZE) / pImage->cSectorsPerDataBlock; 2301 uint32_t cBATEntryIndex = (uOffset / VHD_SECTOR_SIZE) % pImage->cSectorsPerDataBlock; 2302 uint64_t uVhdOffset; 2303 2304 LogFlowFunc(("cBlockAllocationTableEntry=%u cBatEntryIndex=%u\n", cBlockAllocationTableEntry, cBATEntryIndex)); 2305 LogFlowFunc(("BlockAllocationEntry=%u\n", pImage->pBlockAllocationTable[cBlockAllocationTableEntry])); 2306 2307 /* 2308 * If the block is not allocated the content of the entry is ~0 2309 */ 2310 if (pImage->pBlockAllocationTable[cBlockAllocationTableEntry] == ~0U) 2311 { 2312 /* Return block size as read. */ 2313 *pcbActuallyRead = RT_MIN(cbRead, pImage->cSectorsPerDataBlock * VHD_SECTOR_SIZE); 2314 return VERR_VD_BLOCK_FREE; 2315 } 2316 2317 uVhdOffset = ((uint64_t)pImage->pBlockAllocationTable[cBlockAllocationTableEntry] + pImage->cDataBlockBitmapSectors + cBATEntryIndex) * VHD_SECTOR_SIZE; 2318 LogFlowFunc(("uVhdOffset=%llu cbRead=%u\n", uVhdOffset, cbRead)); 2319 2320 /* 2321 * Clip read range to remain in this data block. 2322 */ 2323 cbRead = RT_MIN(cbRead, (pImage->cbDataBlock - (cBATEntryIndex * VHD_SECTOR_SIZE))); 2324 2325 /* Read in the block's bitmap. */ 2326 PVDMETAXFER pMetaXfer; 2327 rc = pImage->pInterfaceIOCallbacks->pfnReadMetaAsync(pImage->pInterfaceIO->pvUser, 2328 pImage->pStorage, 2329 ((uint64_t)pImage->pBlockAllocationTable[cBlockAllocationTableEntry]) * VHD_SECTOR_SIZE, 2330 pImage->pu8Bitmap, pImage->cbDataBlockBitmap, pIoCtx, &pMetaXfer); 2331 2332 if (RT_SUCCESS(rc)) 2333 { 2334 uint32_t cSectors = 0; 2335 2336 pImage->pInterfaceIOCallbacks->pfnMetaXferRelease(pImage->pInterfaceIO->pvUser, pMetaXfer); 2337 if (vhdBlockBitmapSectorContainsData(pImage, cBATEntryIndex)) 2338 { 2339 cBATEntryIndex++; 2340 cSectors = 1; 2341 2342 /* 2343 * The first sector being read is marked dirty, read as much as we 2344 * can from child. Note that only sectors that are marked dirty 2345 * must be read from child. 2346 */ 2347 while ( (cSectors < (cbRead / VHD_SECTOR_SIZE)) 2348 && vhdBlockBitmapSectorContainsData(pImage, cBATEntryIndex)) 2349 { 2350 cBATEntryIndex++; 2351 cSectors++; 2352 } 2353 2354 cbRead = cSectors * VHD_SECTOR_SIZE; 2355 2356 LogFlowFunc(("uVhdOffset=%llu cbRead=%u\n", uVhdOffset, cbRead)); 2357 rc = pImage->pInterfaceIOCallbacks->pfnReadUserAsync(pImage->pInterfaceIO->pvUser, 2358 pImage->pStorage, 2359 uVhdOffset, pIoCtx, cbRead); 2360 } 2361 else 2362 { 2363 /* 2364 * The first sector being read is marked clean, so we should read from 2365 * our parent instead, but only as much as there are the following 2366 * clean sectors, because the block may still contain dirty sectors 2367 * further on. We just need to compute the number of clean sectors 2368 * and pass it to our caller along with the notification that they 2369 * should be read from the parent. 2370 */ 2371 cBATEntryIndex++; 2372 cSectors = 1; 2373 2374 while ( (cSectors < (cbRead / VHD_SECTOR_SIZE)) 2375 && !vhdBlockBitmapSectorContainsData(pImage, cBATEntryIndex)) 2376 { 2377 cBATEntryIndex++; 2378 cSectors++; 2379 } 2380 2381 cbRead = cSectors * VHD_SECTOR_SIZE; 2382 Log(("%s: Sectors free: uVhdOffset=%llu cbRead=%u\n", __FUNCTION__, uVhdOffset, cbRead)); 2383 rc = VERR_VD_BLOCK_FREE; 2384 } 2385 } 2386 else 2387 AssertMsg(rc == VERR_VD_NOT_ENOUGH_METADATA, ("Reading block bitmap failed rc=%Rrc\n", rc)); 2388 } 2389 else 2390 { 2391 rc = pImage->pInterfaceIOCallbacks->pfnReadUserAsync(pImage->pInterfaceIO->pvUser, 2392 pImage->pStorage, 2393 uOffset, pIoCtx, cbRead); 2394 } 2395 2396 if (pcbActuallyRead) 2397 *pcbActuallyRead = cbRead; 2398 2399 LogFlowFunc(("returns rc=%Rrc\n", rc)); 2400 return rc; 2401 } 2402 2403 static int vhdAsyncWrite(void *pBackendData, uint64_t uOffset, size_t cbWrite, 2145 2404 PVDIOCTX pIoCtx, 2146 2405 size_t *pcbWriteProcess, size_t *pcbPreRead, 2147 2406 size_t *pcbPostRead, unsigned fWrite) 2148 2407 { 2149 int rc = VERR_NOT_IMPLEMENTED; 2150 LogFlowFunc(("returns %Rrc\n", rc)); 2408 PVHDIMAGE pImage = (PVHDIMAGE)pBackendData; 2409 int rc = VINF_SUCCESS; 2410 2411 LogFlowFunc(("pBackendData=%p uOffset=%llu pIoCtx=%#p cbWrite=%u pcbWriteProcess=%p pcbPreRead=%p pcbPostRead=%p fWrite=%u\n", 2412 pBackendData, uOffset, pIoCtx, cbWrite, pcbWriteProcess, pcbPreRead, pcbPostRead, fWrite)); 2413 2414 AssertPtr(pImage); 2415 Assert(uOffset % VHD_SECTOR_SIZE == 0); 2416 Assert(cbWrite % VHD_SECTOR_SIZE == 0); 2417 2418 if (pImage->pBlockAllocationTable) 2419 { 2420 /* 2421 * Get the data block first. 2422 */ 2423 uint32_t cSector = uOffset / VHD_SECTOR_SIZE; 2424 uint32_t cBlockAllocationTableEntry = cSector / pImage->cSectorsPerDataBlock; 2425 uint32_t cBATEntryIndex = cSector % pImage->cSectorsPerDataBlock; 2426 uint64_t uVhdOffset; 2427 2428 /* 2429 * Clip write range. 2430 */ 2431 cbWrite = RT_MIN(cbWrite, (pImage->cbDataBlock - (cBATEntryIndex * VHD_SECTOR_SIZE))); 2432 2433 /* 2434 * If the block is not allocated the content of the entry is ~0 2435 * and we need to allocate a new block. Note that while blocks are 2436 * allocated with a relatively big granularity, each sector has its 2437 * own bitmap entry, indicating whether it has been written or not. 2438 * So that means for the purposes of the higher level that the 2439 * granularity is invisible. This means there's no need to return 2440 * VERR_VD_BLOCK_FREE unless the block hasn't been allocated yet. 2441 */ 2442 if (pImage->pBlockAllocationTable[cBlockAllocationTableEntry] == ~0U) 2443 { 2444 /* Check if the block allocation should be suppressed. */ 2445 if (fWrite & VD_WRITE_NO_ALLOC) 2446 { 2447 *pcbPreRead = cBATEntryIndex * VHD_SECTOR_SIZE; 2448 *pcbPostRead = pImage->cSectorsPerDataBlock * VHD_SECTOR_SIZE - cbWrite - *pcbPreRead; 2449 2450 if (pcbWriteProcess) 2451 *pcbWriteProcess = cbWrite; 2452 return VERR_VD_BLOCK_FREE; 2453 } 2454 2455 PVHDIMAGEEXPAND pExpand = (PVHDIMAGEEXPAND)RTMemAllocZ(RT_OFFSETOF(VHDIMAGEEXPAND, au8Bitmap[pImage->cDataBlockBitmapSectors * VHD_SECTOR_SIZE])); 2456 bool fIoInProgress = false; 2457 2458 if (!pExpand) 2459 return VERR_NO_MEMORY; 2460 2461 pExpand->cbEofOld = pImage->uCurrentEndOfFile; 2462 pExpand->idxBatAllocated = cBlockAllocationTableEntry; 2463 pExpand->idxBlockBe = RT_H2BE_U32(pImage->uCurrentEndOfFile / VHD_SECTOR_SIZE); 2464 2465 /* Set the bits for all sectors having been written. */ 2466 for (uint32_t iSector = 0; iSector < (cbWrite / VHD_SECTOR_SIZE); iSector++) 2467 { 2468 /* No need to check for a changed value because this is an initial write. */ 2469 vhdBlockBitmapSectorSet(pImage, pExpand->au8Bitmap, cBATEntryIndex); 2470 cBATEntryIndex++; 2471 } 2472 2473 do 2474 { 2475 /* 2476 * Start with the sector bitmap. 2477 */ 2478 rc = pImage->pInterfaceIOCallbacks->pfnWriteMetaAsync(pImage->pInterfaceIO->pvUser, 2479 pImage->pStorage, 2480 pImage->uCurrentEndOfFile, 2481 pExpand->au8Bitmap, pImage->cbDataBlockBitmap, pIoCtx, 2482 vhdAsyncExpansionDataBlockBitmapComplete, pExpand); 2483 if (RT_SUCCESS(rc)) 2484 VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_BLOCKBITMAP_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_SUCCESS); 2485 else if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS) 2486 fIoInProgress = true; 2487 else 2488 { 2489 VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_BLOCKBITMAP_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_FAILED); 2490 VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_USERBLOCK_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_FAILED); 2491 VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_BAT_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_FAILED); 2492 VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_FOOTER_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_FAILED); 2493 break; 2494 } 2495 2496 2497 /* 2498 * Write the new block at the current end of the file. 2499 */ 2500 rc = pImage->pInterfaceIOCallbacks->pfnWriteUserAsync(pImage->pInterfaceIO->pvUser, 2501 pImage->pStorage, 2502 pImage->uCurrentEndOfFile + pImage->cbDataBlockBitmap, 2503 pIoCtx, cbWrite, 2504 vhdAsyncExpansionDataComplete, pExpand); 2505 if (RT_SUCCESS(rc)) 2506 VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_USERBLOCK_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_SUCCESS); 2507 else if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS) 2508 fIoInProgress = true; 2509 else 2510 { 2511 VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_USERBLOCK_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_FAILED); 2512 VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_BAT_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_FAILED); 2513 VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_FOOTER_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_FAILED); 2514 break; 2515 } 2516 2517 /* 2518 * Write entry in the BAT. 2519 */ 2520 rc = pImage->pInterfaceIOCallbacks->pfnWriteMetaAsync(pImage->pInterfaceIO->pvUser, 2521 pImage->pStorage, 2522 pImage->uBlockAllocationTableOffset + cBlockAllocationTableEntry * sizeof(uint32_t), 2523 &pExpand->idxBlockBe, sizeof(uint32_t), pIoCtx, 2524 vhdAsyncExpansionBatUpdateComplete, pExpand); 2525 if (RT_SUCCESS(rc)) 2526 VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_BAT_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_SUCCESS); 2527 else if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS) 2528 fIoInProgress = true; 2529 else 2530 { 2531 VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_BAT_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_FAILED); 2532 VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_FOOTER_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_FAILED); 2533 break; 2534 } 2535 2536 /* 2537 * Set the new end of the file and link the new block into the BAT. 2538 */ 2539 pImage->pBlockAllocationTable[cBlockAllocationTableEntry] = pImage->uCurrentEndOfFile / VHD_SECTOR_SIZE; 2540 pImage->uCurrentEndOfFile += pImage->cbDataBlockBitmap + pImage->cbDataBlock; 2541 2542 /* Update the footer. */ 2543 rc = pImage->pInterfaceIOCallbacks->pfnWriteMetaAsync(pImage->pInterfaceIO->pvUser, 2544 pImage->pStorage, 2545 pImage->uCurrentEndOfFile, 2546 &pImage->vhdFooterCopy, sizeof(VHDFooter), pIoCtx, 2547 vhdAsyncExpansionFooterUpdateComplete, pExpand); 2548 if (RT_SUCCESS(rc)) 2549 VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_FOOTER_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_SUCCESS); 2550 else if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS) 2551 fIoInProgress = true; 2552 else 2553 { 2554 VHDIMAGEEXPAND_STATUS_SET(pExpand->fFlags, VHDIMAGEEXPAND_FOOTER_STATUS_SHIFT, VHDIMAGEEXPAND_STEP_FAILED); 2555 break; 2556 } 2557 2558 } while (0); 2559 2560 if (!fIoInProgress) 2561 vhdAsyncExpansionComplete(pImage, pIoCtx, pExpand); 2562 else 2563 rc = VERR_VD_ASYNC_IO_IN_PROGRESS; 2564 } 2565 else 2566 { 2567 /* 2568 * Calculate the real offset in the file. 2569 */ 2570 uVhdOffset = ((uint64_t)pImage->pBlockAllocationTable[cBlockAllocationTableEntry] + pImage->cDataBlockBitmapSectors + cBATEntryIndex) * VHD_SECTOR_SIZE; 2571 2572 /* Read in the block's bitmap. */ 2573 PVDMETAXFER pMetaXfer; 2574 rc = pImage->pInterfaceIOCallbacks->pfnReadMetaAsync(pImage->pInterfaceIO->pvUser, 2575 pImage->pStorage, 2576 ((uint64_t)pImage->pBlockAllocationTable[cBlockAllocationTableEntry]) * VHD_SECTOR_SIZE, 2577 pImage->pu8Bitmap, pImage->cbDataBlockBitmap, pIoCtx, &pMetaXfer); 2578 if (RT_SUCCESS(rc)) 2579 { 2580 pImage->pInterfaceIOCallbacks->pfnMetaXferRelease(pImage->pInterfaceIO->pvUser, pMetaXfer); 2581 2582 /* Write data. */ 2583 rc = pImage->pInterfaceIOCallbacks->pfnWriteUserAsync(pImage->pInterfaceIO->pvUser, 2584 pImage->pStorage, 2585 uVhdOffset, pIoCtx, cbWrite, 2586 NULL, NULL); 2587 if (RT_SUCCESS(rc) || rc == VERR_VD_ASYNC_IO_IN_PROGRESS) 2588 { 2589 bool fChanged = false; 2590 2591 /* Set the bits for all sectors having been written. */ 2592 for (uint32_t iSector = 0; iSector < (cbWrite / VHD_SECTOR_SIZE); iSector++) 2593 { 2594 fChanged |= vhdBlockBitmapSectorSet(pImage, pImage->pu8Bitmap, cBATEntryIndex); 2595 cBATEntryIndex++; 2596 } 2597 2598 /* Only write the bitmap if it was changed. */ 2599 if (fChanged) 2600 { 2601 /* 2602 * Write the bitmap back. 2603 * 2604 * @note We don't have a completion callback here because we 2605 * can't do anything if the write fails for some reason. 2606 * The error will propagated to the device/guest 2607 * by the generic VD layer already and we don't need 2608 * to rollback anything here. 2609 */ 2610 rc = pImage->pInterfaceIOCallbacks->pfnWriteMetaAsync(pImage->pInterfaceIO->pvUser, 2611 pImage->pStorage, 2612 ((uint64_t)pImage->pBlockAllocationTable[cBlockAllocationTableEntry]) * VHD_SECTOR_SIZE, 2613 pImage->pu8Bitmap, pImage->cbDataBlockBitmap, pIoCtx, 2614 NULL, NULL); 2615 } 2616 } 2617 } 2618 } 2619 } 2620 else 2621 { 2622 rc = pImage->pInterfaceIOCallbacks->pfnWriteUserAsync(pImage->pInterfaceIO->pvUser, 2623 pImage->pStorage, 2624 uOffset, pIoCtx, cbWrite, 2625 NULL, NULL); 2626 } 2627 2628 if (pcbWriteProcess) 2629 *pcbWriteProcess = cbWrite; 2630 2631 /* Stay on the safe side. Do not run the risk of confusing the higher 2632 * level, as that can be pretty lethal to image consistency. */ 2633 *pcbPreRead = 0; 2634 *pcbPostRead = 0; 2635 2151 2636 return rc; 2152 2637 } … … 2154 2639 static int vhdAsyncFlush(void *pvBackendData, PVDIOCTX pIoCtx) 2155 2640 { 2156 int rc = VERR_NOT_IMPLEMENTED; 2157 LogFlowFunc(("returns %Rrc\n", rc)); 2158 return rc; 2641 PVHDIMAGE pImage = (PVHDIMAGE)pvBackendData; 2642 2643 /* No need to write anything here. Data is always updated on a write. */ 2644 return pImage->pInterfaceIOCallbacks->pfnFlushAsync(pImage->pInterfaceIO->pvUser, 2645 pImage->pStorage, pIoCtx, 2646 NULL, NULL); 2159 2647 } 2160 2648 … … 2167 2655 /* uBackendCaps */ 2168 2656 VD_CAP_UUID | VD_CAP_DIFF | VD_CAP_FILE | 2169 VD_CAP_CREATE_FIXED | VD_CAP_CREATE_DYNAMIC, 2657 VD_CAP_CREATE_FIXED | VD_CAP_CREATE_DYNAMIC | 2658 VD_CAP_ASYNC, 2170 2659 /* papszFileExtensions */ 2171 2660 s_apszVhdFileExtensions, -
trunk/src/VBox/Devices/Storage/VmdkHDDCore.cpp
r29649 r30555 799 799 800 800 return pImage->pInterfaceIOCallbacks->pfnFlushAsync(pImage->pInterfaceIO->pvUser, 801 pVmdkFile->pStorage, pIoCtx); 801 pVmdkFile->pStorage, pIoCtx, 802 NULL, NULL); 802 803 } 803 804 … … 3117 3118 if (RT_LE2H_U32(u32Magic) == VMDK_SPARSE_MAGICNUMBER) 3118 3119 { 3119 /* Async I/IO is not supported with these files yet. So fail if opened in async I/O mode. */3120 if (uOpenFlags & VD_OPEN_FLAGS_ASYNC_IO)3121 {3122 rc = VERR_NOT_SUPPORTED;3123 goto out;3124 }3125 3126 3120 /* It's a hosted single-extent image. */ 3127 3121 rc = vmdkCreateExtents(pImage, 1); … … 4363 4357 if (RT_FAILURE(rc)) 4364 4358 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot read grain table entry in '%s'"), pExtent->pszFullname); 4359 pGTCacheEntry->uExtent = pExtent->uExtent; 4360 pGTCacheEntry->uGTBlock = uGTBlock; 4361 for (unsigned i = 0; i < VMDK_GT_CACHELINE_SIZE; i++) 4362 pGTCacheEntry->aGTData[i] = RT_LE2H_U32(aGTDataTmp[i]); 4363 } 4364 uGTBlockIndex = (uSector / pExtent->cSectorsPerGrain) % VMDK_GT_CACHELINE_SIZE; 4365 uint32_t uGrainSector = pGTCacheEntry->aGTData[uGTBlockIndex]; 4366 if (uGrainSector) 4367 *puExtentSector = uGrainSector + uSector % pExtent->cSectorsPerGrain; 4368 else 4369 *puExtentSector = 0; 4370 return VINF_SUCCESS; 4371 } 4372 4373 /** 4374 * Internal. Get sector number in the extent file from the relative sector 4375 * number in the extent - version for async access. 4376 */ 4377 static int vmdkGetSectorAsync(PVMDKIMAGE pImage, PVDIOCTX pIoCtx, 4378 PVMDKGTCACHE pCache, PVMDKEXTENT pExtent, 4379 uint64_t uSector, uint64_t *puExtentSector) 4380 { 4381 uint64_t uGDIndex, uGTSector, uGTBlock; 4382 uint32_t uGTHash, uGTBlockIndex; 4383 PVMDKGTCACHEENTRY pGTCacheEntry; 4384 uint32_t aGTDataTmp[VMDK_GT_CACHELINE_SIZE]; 4385 int rc; 4386 4387 uGDIndex = uSector / pExtent->cSectorsPerGDE; 4388 if (uGDIndex >= pExtent->cGDEntries) 4389 return VERR_OUT_OF_RANGE; 4390 uGTSector = pExtent->pGD[uGDIndex]; 4391 if (!uGTSector) 4392 { 4393 /* There is no grain table referenced by this grain directory 4394 * entry. So there is absolutely no data in this area. */ 4395 *puExtentSector = 0; 4396 return VINF_SUCCESS; 4397 } 4398 4399 uGTBlock = uSector / (pExtent->cSectorsPerGrain * VMDK_GT_CACHELINE_SIZE); 4400 uGTHash = vmdkGTCacheHash(pCache, uGTBlock, pExtent->uExtent); 4401 pGTCacheEntry = &pCache->aGTCache[uGTHash]; 4402 if ( pGTCacheEntry->uExtent != pExtent->uExtent 4403 || pGTCacheEntry->uGTBlock != uGTBlock) 4404 { 4405 /* Cache miss, fetch data from disk. */ 4406 PVDMETAXFER pMetaXfer; 4407 rc = pImage->pInterfaceIOCallbacks->pfnReadMetaAsync(pImage->pInterfaceIO->pvUser, 4408 pExtent->pFile->pStorage, 4409 VMDK_SECTOR2BYTE(uGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp), 4410 aGTDataTmp, sizeof(aGTDataTmp), pIoCtx, &pMetaXfer); 4411 if (RT_FAILURE(rc)) 4412 return rc; 4413 /* We can release the metadata transfer immediately. */ 4414 pImage->pInterfaceIOCallbacks->pfnMetaXferRelease(pImage->pInterfaceIO->pvUser, pMetaXfer); 4365 4415 pGTCacheEntry->uExtent = pExtent->uExtent; 4366 4416 pGTCacheEntry->uGTBlock = uGTBlock; … … 6016 6066 { 6017 6067 PVMDKIMAGE pImage = (PVMDKIMAGE)pvBackendData; 6068 6069 #if 1 6018 6070 bool fAsyncIOSupported = false; 6019 6071 … … 6033 6085 6034 6086 return fAsyncIOSupported; 6087 #else 6088 /* We do not support async I/O for stream optimized VMDK images. */ 6089 return (pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED) == 0; 6090 #endif 6035 6091 } 6036 6092 … … 6079 6135 case VMDKETYPE_ESX_SPARSE: 6080 6136 #endif /* VBOX_WITH_VMDK_ESX */ 6081 AssertMsgFailed(("Not supported\n")); 6137 rc = vmdkGetSectorAsync(pImage, pIoCtx, pImage->pGTCache, pExtent, 6138 uSectorExtentRel, &uSectorExtentAbs); 6139 if (RT_FAILURE(rc)) 6140 goto out; 6141 /* Clip read range to at most the rest of the grain. */ 6142 cbRead = RT_MIN(cbRead, VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain - uSectorExtentRel % pExtent->cSectorsPerGrain)); 6143 Assert(!(cbRead % 512)); 6144 if (uSectorExtentAbs == 0) 6145 rc = VERR_VD_BLOCK_FREE; 6146 else 6147 { 6148 AssertMsg(!(pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED), ("Async I/O is not supported for stream optimized VMDK's\n")); 6149 rc = pImage->pInterfaceIOCallbacks->pfnReadUserAsync(pImage->pInterfaceIO->pvUser, 6150 pExtent->pFile->pStorage, 6151 VMDK_SECTOR2BYTE(uSectorExtentAbs), 6152 pIoCtx, cbRead); 6153 } 6082 6154 break; 6083 6155 case VMDKETYPE_VMFS: … … 6161 6233 case VMDKETYPE_ESX_SPARSE: 6162 6234 #endif /* VBOX_WITH_VMDK_ESX */ 6163 AssertMsgFailed(("Not supported\n")); 6235 rc = vmdkGetSectorAsync(pImage, pIoCtx, pImage->pGTCache, pExtent, uSectorExtentRel, 6236 &uSectorExtentAbs); 6237 if (RT_FAILURE(rc)) 6238 goto out; 6239 /* Clip write range to at most the rest of the grain. */ 6240 cbWrite = RT_MIN(cbWrite, VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain - uSectorExtentRel % pExtent->cSectorsPerGrain)); 6241 if ( pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED 6242 && uSectorExtentRel < (uint64_t)pExtent->uLastGrainWritten * pExtent->cSectorsPerGrain) 6243 { 6244 rc = VERR_VD_VMDK_INVALID_WRITE; 6245 goto out; 6246 } 6247 if (uSectorExtentAbs == 0) 6248 { 6249 if (cbWrite == VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain)) 6250 { 6251 /* Full block write to a previously unallocated block. 6252 * Check if the caller wants to avoid the automatic alloc. */ 6253 if (!(fWrite & VD_WRITE_NO_ALLOC)) 6254 { 6255 AssertMsgFailed(("Implement\n")); 6256 #if 0 6257 /* Allocate GT and find out where to store the grain. */ 6258 rc = vmdkAllocGrain(pImage->pGTCache, pExtent, 6259 uSectorExtentRel, pvBuf, cbWrite); 6260 #endif 6261 } 6262 else 6263 rc = VERR_VD_BLOCK_FREE; 6264 *pcbPreRead = 0; 6265 *pcbPostRead = 0; 6266 } 6267 else 6268 { 6269 /* Clip write range to remain in this extent. */ 6270 cbWrite = RT_MIN(cbWrite, VMDK_SECTOR2BYTE(pExtent->uSectorOffset + pExtent->cNominalSectors - uSectorExtentRel)); 6271 *pcbPreRead = VMDK_SECTOR2BYTE(uSectorExtentRel % pExtent->cSectorsPerGrain); 6272 *pcbPostRead = VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain) - cbWrite - *pcbPreRead; 6273 rc = VERR_VD_BLOCK_FREE; 6274 } 6275 } 6276 else 6277 { 6278 Assert(!(pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED)); 6279 rc = pImage->pInterfaceIOCallbacks->pfnWriteUserAsync(pImage->pInterfaceIO->pvUser, 6280 pExtent->pFile->pStorage, 6281 VMDK_SECTOR2BYTE(uSectorExtentAbs), 6282 pIoCtx, cbWrite, 6283 NULL, NULL); 6284 } 6164 6285 break; 6165 6286 case VMDKETYPE_VMFS: … … 6170 6291 pExtent->pFile->pStorage, 6171 6292 VMDK_SECTOR2BYTE(uSectorExtentRel), 6172 pIoCtx, cbWrite );6293 pIoCtx, cbWrite, NULL, NULL); 6173 6294 break; 6174 6295 case VMDKETYPE_ZERO: … … 6202 6323 case VMDKETYPE_ESX_SPARSE: 6203 6324 #endif /* VBOX_WITH_VMDK_ESX */ 6204 /** Not supported atm.*/6205 AssertMsgFailed(("Async I/O not supported for sparse images\n"));6325 /** @todo: Fake success for now */ 6326 rc = VINF_SUCCESS; 6206 6327 break; 6207 6328 case VMDKETYPE_VMFS:
Note:
See TracChangeset
for help on using the changeset viewer.