Changeset 30863 in vbox
- Timestamp:
- Jul 15, 2010 7:53:40 PM (15 years ago)
- Location:
- trunk
- Files:
-
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/VBox/VBoxHDD.h
r30788 r30863 1029 1029 * @param pszAddress The address to connect to. 1030 1030 * @param uPort The port to connect to. 1031 * @param pSock Where to store the handle to the established connect 1032 ion. 1031 * @param pSock Where to store the handle to the established connection. 1033 1032 */ 1034 1033 DECLR3CALLBACKMEMBER(int, pfnClientConnect, (const char *pszAddress, uint32_t uPort, PRTSOCKET pSock)); … … 1039 1038 * @return iprt status code. 1040 1039 * @param Sock Socket descriptor. 1041 ion.1042 1040 */ 1043 1041 DECLR3CALLBACKMEMBER(int, pfnClientClose, (RTSOCKET Sock)); … … 1543 1541 * 1544 1542 * @returns VBox status code. 1545 * @param pvUser The opaque user data passed on container creation. 1546 * @param pStorage The storage handle. 1547 * @param uOffset Offset to start reading from. 1548 * @param pvBuf Where to store the data. 1549 * @param cbRead How many bytes to read. 1550 * @param pIoCtx The I/O context which triggered the read. 1551 * @param ppMetaXfer Where to store the metadata transfer handle on success. 1543 * @param pvUser The opaque user data passed on container creation. 1544 * @param pStorage The storage handle. 1545 * @param uOffset Offset to start reading from. 1546 * @param pvBuf Where to store the data. 1547 * @param cbRead How many bytes to read. 1548 * @param pIoCtx The I/O context which triggered the read. 1549 * @param ppMetaXfer Where to store the metadata transfer handle on success. 1550 * @param pfnCompleted Completion callback. 1551 * @param pvCompleteUser Opaque user data passed in the completion callback. 1552 1552 */ 1553 1553 DECLR3CALLBACKMEMBER(int, pfnReadMetaAsync, (void *pvUser, PVDIOSTORAGE pStorage, 1554 1554 uint64_t uOffset, void *pvBuf, 1555 1555 size_t cbRead, PVDIOCTX pIoCtx, 1556 PPVDMETAXFER ppMetaXfer)); 1556 PPVDMETAXFER ppMetaXfer, 1557 PFNVDXFERCOMPLETED pfnComplete, 1558 void *pvCompleteUser)); 1557 1559 1558 1560 /** -
trunk/src/VBox/Devices/Storage/ParallelsHDDCore.cpp
r28800 r30863 567 567 else 568 568 { 569 /* *Calculate offset in the real file. */569 /* Calculate offset in the real file. */ 570 570 uSector = uOffset / 512; 571 /* *One chunk in the file is always one track big. */571 /* One chunk in the file is always one track big. */ 572 572 iIndexInAllocationTable = (uint32_t)(uSector / pImage->PCHSGeometry.cSectors); 573 573 uSector = uSector % pImage->PCHSGeometry.cSectors; -
trunk/src/VBox/Devices/Storage/VBoxHDD.cpp
r30555 r30863 711 711 } 712 712 713 LogFlow(("Allocated root I/O context %#p\n", pIoCtx)); 713 714 return pIoCtx; 714 715 } … … 736 737 } 737 738 739 LogFlow(("Allocated child I/O context %#p\n", pIoCtx)); 738 740 return pIoCtx; 739 741 } … … 776 778 DECLINLINE(void) vdIoCtxFree(PVBOXHDD pDisk, PVDIOCTX pIoCtx) 777 779 { 780 LogFlow(("Freeing I/O context %#p\n", pIoCtx)); 778 781 if (pIoCtx->pvAllocation) 779 782 RTMemFree(pIoCtx->pvAllocation); 783 #ifdef DEBUG 784 memset(pIoCtx, 0xff, sizeof(VDIOCTX)); 785 #endif 780 786 RTMemCacheFree(pDisk->hMemCacheIoCtx, pIoCtx); 781 787 } … … 845 851 LogFlowFunc(("pIoCtx=%#p\n", pIoCtx)); 846 852 853 RTCritSectEnter(&pDisk->CritSect); 854 847 855 if ( !pIoCtx->cbTransferLeft 848 856 && !pIoCtx->cMetaTransfersPending 849 857 && !pIoCtx->cDataTransfersPending 850 858 && !pIoCtx->pfnIoCtxTransfer) 851 return VINF_VD_ASYNC_IO_FINISHED; 859 { 860 rc = VINF_VD_ASYNC_IO_FINISHED; 861 goto out; 862 } 852 863 853 864 /* … … 858 869 && !pIoCtx->cMetaTransfersPending 859 870 && !pIoCtx->cDataTransfersPending) 860 return VINF_VD_ASYNC_IO_FINISHED; 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; 871 { 872 rc = VINF_VD_ASYNC_IO_FINISHED; 873 goto out; 874 } 875 876 /* Don't change anything if there is a metadata transfer pending or we are blocked. */ 877 if ( pIoCtx->cMetaTransfersPending 878 || pIoCtx->fBlocked) 879 { 880 rc = VERR_VD_ASYNC_IO_IN_PROGRESS; 881 goto out; 882 } 865 883 866 884 if (pIoCtx->pfnIoCtxTransfer) 867 885 { 868 886 /* Call the transfer function advancing to the next while there is no error. */ 869 RTCritSectEnter(&pDisk->CritSect);870 887 while ( pIoCtx->pfnIoCtxTransfer 871 888 && RT_SUCCESS(rc)) … … 881 898 } 882 899 } 883 RTCritSectLeave(&pDisk->CritSect);884 900 } 885 901 … … 904 920 rc = VERR_VD_ASYNC_IO_IN_PROGRESS; 905 921 } 922 923 out: 924 RTCritSectLeave(&pDisk->CritSect); 906 925 907 926 LogFlowFunc(("pIoCtx=%#p rc=%Rrc cbTransferLeft=%u cMetaTransfersPending=%u fComplete=%RTbool\n", … … 1554 1573 LogFlowFunc(("Deferring write pIoCtx=%#p\n", pIoCtx)); 1555 1574 1575 Assert(!pIoCtx->pIoCtxParent && !pIoCtx->fBlocked); 1576 1556 1577 RTListInit(&pDeferred->NodeDeferred); 1557 1578 pDeferred->pIoCtx = pIoCtx; … … 1618 1639 } 1619 1640 else 1641 { 1620 1642 LogFlow(("Child write pending\n")); 1643 pIoCtx->fBlocked = true; 1644 rc = VERR_VD_ASYNC_IO_IN_PROGRESS; 1645 cbWrite -= cbThisWrite; 1646 uOffset += cbThisWrite; 1647 break; 1648 } 1621 1649 } 1622 1650 } … … 1943 1971 Assert(!pIoCtxParent->pIoCtxParent); 1944 1972 Assert(pIoCtx->enmTxDir == VDIOCTXTXDIR_WRITE); 1973 Assert(pIoCtxParent->cbTransferLeft >= pIoCtx->Type.Child.cbTransferParent); 1945 1974 ASMAtomicSubU32(&pIoCtxParent->cbTransferLeft, pIoCtx->Type.Child.cbTransferParent); 1946 1975 … … 1949 1978 1950 1979 /* 1951 * A completed child write means that we fin sihed growing the image.1980 * A completed child write means that we finished growing the image. 1952 1981 * We have to process any pending writes now. 1953 1982 */ 1954 1983 Assert(pDisk->fGrowing); 1955 1984 ASMAtomicWriteBool(&pDisk->fGrowing, false); 1985 1986 /* Unblock the parent */ 1987 pIoCtxParent->fBlocked = false; 1956 1988 1957 1989 rc = vdIoCtxProcess(pIoCtxParent); … … 1968 2000 } 1969 2001 1970 /* Process any pending writes . */2002 /* Process any pending writes if the current request didn't caused another growing. */ 1971 2003 RTCritSectEnter(&pDisk->CritSect); 1972 2004 1973 if (!RTListIsEmpty(&pDisk->ListWriteGrowing) )2005 if (!RTListIsEmpty(&pDisk->ListWriteGrowing) && !pDisk->fGrowing) 1974 2006 { 1975 2007 RTLISTNODE ListTmp; … … 1996 2028 RTMemFree(pDeferred); 1997 2029 2030 Assert(!pIoCtxWait->pIoCtxParent); 2031 1998 2032 pIoCtxWait->fBlocked = false; 1999 2000 Assert(!pIoCtxWait->pIoCtxParent);2001 2002 2033 LogFlowFunc(("Processing waiting I/O context pIoCtxWait=%#p\n", pIoCtxWait)); 2003 2034 … … 2052 2083 pIoStorage, pIoCtx, pfnComplete, pvUser, cbTransfer, rcReq)); 2053 2084 2085 Assert(pIoCtx->cbTransferLeft >= cbTransfer); 2054 2086 ASMAtomicSubU32(&pIoCtx->cbTransferLeft, cbTransfer); 2055 2087 ASMAtomicDecU32(&pIoCtx->cDataTransfersPending); 2056 2088 2057 2089 if (pfnComplete) 2090 { 2091 RTCritSectEnter(&pDisk->CritSect); 2058 2092 rc = pfnComplete(pIoStorage->pImage->pvBackendData, pIoCtx, pvUser, rcReq); 2093 RTCritSectLeave(&pDisk->CritSect); 2094 } 2059 2095 2060 2096 if (RT_SUCCESS(rc)) … … 2074 2110 PVBOXHDD pDisk = pIoStorage->pImage->pDisk; 2075 2111 RTLISTNODE ListIoCtxWaiting; 2076 bool fFlush = VDMETAXFER_TXDIR_GET(pMetaXfer->fFlags) == VDMETAXFER_TXDIR_FLUSH;2112 bool fFlush; 2077 2113 2078 2114 LogFlowFunc(("pIoStorage=%#p pfnComplete=%#p pvUser=%#p pMetaXfer=%#p rcReq=%Rrc\n", 2079 2115 pIoStorage, pfnComplete, pvUser, pMetaXfer, rcReq)); 2080 2116 2117 RTCritSectEnter(&pDisk->CritSect); 2118 fFlush = VDMETAXFER_TXDIR_GET(pMetaXfer->fFlags) == VDMETAXFER_TXDIR_FLUSH; 2081 2119 VDMETAXFER_TXDIR_SET(pMetaXfer->fFlags, VDMETAXFER_TXDIR_NONE); 2082 2120 2083 2121 if (!fFlush) 2084 2122 { 2085 RTCritSectEnter(&pDisk->CritSect);2086 2087 2123 RTListMove(&ListIoCtxWaiting, &pMetaXfer->ListIoCtxWaiting); 2088 2124 … … 2090 2126 { 2091 2127 /* Remove from the AVL tree. */ 2128 LogFlow(("Removing meta xfer=%#p\n", pMetaXfer)); 2092 2129 bool fRemoved = RTAvlrFileOffsetRemove(pIoStorage->pTreeMetaXfers, pMetaXfer->Core.Key); 2093 2130 Assert(fRemoved); … … 2099 2136 pMetaXfer->cRefs++; 2100 2137 } 2101 2102 RTCritSectLeave(&pDisk->CritSect);2103 2138 } 2104 2139 else 2105 {2106 /*2107 * Flushes don't need the critical section because they are never accessed concurrently2108 * (they also have only one context attached).2109 */2110 2140 RTListMove(&ListIoCtxWaiting, &pMetaXfer->ListIoCtxWaiting); 2111 }2141 RTCritSectLeave(&pDisk->CritSect); 2112 2142 2113 2143 /* Go through the waiting list and continue the I/O contexts. */ … … 2124 2154 2125 2155 if (pfnComplete) 2156 { 2157 RTCritSectEnter(&pDisk->CritSect); 2126 2158 rc = pfnComplete(pIoStorage->pImage->pvBackendData, pIoCtx, pvUser, rcReq); 2159 RTCritSectLeave(&pDisk->CritSect); 2160 } 2127 2161 2128 2162 LogFlow(("Completion callback for I/O context %#p returned %Rrc\n", pIoCtx, rc)); … … 2142 2176 RTCritSectEnter(&pDisk->CritSect); 2143 2177 pMetaXfer->cRefs--; 2144 if (!pMetaXfer->cRefs )2178 if (!pMetaXfer->cRefs && RTListIsEmpty(&pMetaXfer->ListIoCtxWaiting)) 2145 2179 { 2146 2180 /* Remove from the AVL tree. */ 2181 LogFlow(("Removing meta xfer=%#p\n", pMetaXfer)); 2147 2182 bool fRemoved = RTAvlrFileOffsetRemove(pIoStorage->pTreeMetaXfers, pMetaXfer->Core.Key); 2148 2183 Assert(fRemoved); … … 2430 2465 uint64_t uOffset, void *pvBuf, 2431 2466 size_t cbRead, PVDIOCTX pIoCtx, 2432 PPVDMETAXFER ppMetaXfer) 2467 PPVDMETAXFER ppMetaXfer, 2468 PFNVDXFERCOMPLETED pfnComplete, 2469 void *pvCompleteUser) 2433 2470 { 2434 2471 PVDIMAGE pImage = (PVDIMAGE)pvUser; … … 2448 2485 if (!pMetaXfer) 2449 2486 { 2487 #ifdef RT_STRICT 2488 pMetaXfer = (PVDMETAXFER)RTAvlrFileOffsetGetBestFit(pIoStorage->pTreeMetaXfers, uOffset, false /* fAbove */); 2489 AssertMsg(!pMetaXfer || (pMetaXfer->Core.Key + pMetaXfer->cbMeta <= uOffset), 2490 ("Overlapping meta transfers!\n")); 2491 #endif 2492 2450 2493 /* Allocate a new meta transfer. */ 2451 2494 pMetaXfer = vdMetaXferAlloc(pImage, pIoStorage, uOffset, cbRead); … … 2453 2496 return VERR_NO_MEMORY; 2454 2497 2455 pIoTask = vdIoTaskMetaAlloc(pIoStorage, NULL, NULL, pMetaXfer);2498 pIoTask = vdIoTaskMetaAlloc(pIoStorage, pfnComplete, pvCompleteUser, pMetaXfer); 2456 2499 if (!pIoTask) 2457 2500 { … … 2469 2512 cbRead, pIoTask, 2470 2513 &pvTask); 2514 2515 if (RT_SUCCESS(rc) || rc == VERR_VD_ASYNC_IO_IN_PROGRESS) 2516 { 2517 bool fInserted = RTAvlrFileOffsetInsert(pIoStorage->pTreeMetaXfers, &pMetaXfer->Core); 2518 Assert(fInserted); 2519 } 2520 else 2521 RTMemFree(pMetaXfer); 2522 2471 2523 if (RT_SUCCESS(rc)) 2472 2524 { … … 2474 2526 vdIoTaskFree(pDisk, pIoTask); 2475 2527 } 2476 else if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS )2528 else if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS && !pfnComplete) 2477 2529 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 else2485 RTMemFree(pMetaXfer);2486 2530 } 2487 2531 2488 2532 Assert(VALID_PTR(pMetaXfer) || RT_FAILURE(rc)); 2489 2533 2490 if (RT_SUCCESS(rc) || rc == VERR_VD_NOT_ENOUGH_METADATA )2534 if (RT_SUCCESS(rc) || rc == VERR_VD_NOT_ENOUGH_METADATA || rc == VERR_VD_ASYNC_IO_IN_PROGRESS) 2491 2535 { 2492 2536 /* If it is pending add the request to the list. */ … … 2508 2552 pMetaXfer->cRefs++; 2509 2553 Assert(pMetaXfer->cbMeta >= cbRead); 2554 Assert(pMetaXfer->Core.Key == (RTFOFF)uOffset); 2510 2555 memcpy(pvBuf, pMetaXfer->abData, cbRead); 2511 2556 *ppMetaXfer = pMetaXfer; … … 2528 2573 PVDIOTASK pIoTask; 2529 2574 PVDMETAXFER pMetaXfer = NULL; 2575 bool fInTree = false; 2530 2576 void *pvTask = NULL; 2531 2577 … … 2542 2588 if (!pMetaXfer) 2543 2589 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); 2590 } 2591 else 2592 { 2593 Assert(pMetaXfer->cbMeta >= cbWrite); 2594 Assert(pMetaXfer->Core.Key == (RTFOFF)uOffset); 2595 fInTree = true; 2596 } 2597 2598 Assert(VDMETAXFER_TXDIR_GET(pMetaXfer->fFlags) == VDMETAXFER_TXDIR_NONE); 2599 2600 pIoTask = vdIoTaskMetaAlloc(pIoStorage, pfnComplete, pvCompleteUser, pMetaXfer); 2601 if (!pIoTask) 2602 { 2603 RTMemFree(pMetaXfer); 2604 return VERR_NO_MEMORY; 2605 } 2606 2607 memcpy(pMetaXfer->abData, pvBuf, cbWrite); 2608 Seg.cbSeg = cbWrite; 2609 Seg.pvSeg = pMetaXfer->abData; 2610 2611 ASMAtomicIncU32(&pIoCtx->cMetaTransfersPending); 2612 2613 VDMETAXFER_TXDIR_SET(pMetaXfer->fFlags, VDMETAXFER_TXDIR_WRITE); 2614 rc = pDisk->pInterfaceAsyncIOCallbacks->pfnWriteAsync(pDisk->pInterfaceAsyncIO->pvUser, 2615 pIoStorage->u.pStorage, 2616 uOffset, &Seg, 1, 2617 cbWrite, pIoTask, 2618 &pvTask); 2619 if (RT_SUCCESS(rc)) 2620 { 2621 VDMETAXFER_TXDIR_SET(pMetaXfer->fFlags, VDMETAXFER_TXDIR_NONE); 2622 ASMAtomicDecU32(&pIoCtx->cMetaTransfersPending); 2623 vdIoTaskFree(pDisk, pIoTask); 2624 if (fInTree && !pMetaXfer->cRefs) 2625 { 2626 LogFlow(("Removing meta xfer=%#p\n", pMetaXfer)); 2627 bool fRemoved = RTAvlrFileOffsetRemove(pIoStorage->pTreeMetaXfers, pMetaXfer->Core.Key); 2628 AssertMsg(fRemoved, ("Metadata transfer wasn't removed\n")); 2569 2629 RTMemFree(pMetaXfer); 2570 2630 pMetaXfer = NULL; 2571 2631 } 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 2632 } 2633 else if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS) 2634 { 2635 PVDIOCTXDEFERRED pDeferred = (PVDIOCTXDEFERRED)RTMemAllocZ(sizeof(VDIOCTXDEFERRED)); 2636 AssertPtr(pDeferred); 2637 2638 RTListInit(&pDeferred->NodeDeferred); 2639 pDeferred->pIoCtx = pIoCtx; 2640 2641 if (!fInTree) 2642 { 2580 2643 bool fInserted = RTAvlrFileOffsetInsert(pIoStorage->pTreeMetaXfers, &pMetaXfer->Core); 2581 2644 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); 2645 } 2646 2647 RTListAppend(&pMetaXfer->ListIoCtxWaiting, &pDeferred->NodeDeferred); 2648 } 2649 else 2650 { 2651 RTMemFree(pMetaXfer); 2652 pMetaXfer = NULL; 2653 } 2593 2654 2594 2655 return rc; … … 2612 2673 { 2613 2674 /* Free the meta data entry. */ 2675 LogFlow(("Removing meta xfer=%#p\n", pMetaXfer)); 2614 2676 bool fRemoved = RTAvlrFileOffsetRemove(pIoStorage->pTreeMetaXfers, pMetaXfer->Core.Key); 2615 2677 AssertMsg(fRemoved, ("Metadata transfer wasn't removed\n")); -
trunk/src/VBox/Devices/Storage/VDIHDDCore.cpp
r30555 r30863 220 220 pImage->pStorage, 221 221 off, pvBuf, cbRead, pIoCtx, 222 NULL );222 NULL, NULL, NULL); 223 223 } 224 224 -
trunk/src/VBox/Devices/Storage/VHDHDDCore.cpp
r30555 r30863 2328 2328 pImage->pStorage, 2329 2329 ((uint64_t)pImage->pBlockAllocationTable[cBlockAllocationTableEntry]) * VHD_SECTOR_SIZE, 2330 pImage->pu8Bitmap, pImage->cbDataBlockBitmap, pIoCtx, &pMetaXfer); 2330 pImage->pu8Bitmap, pImage->cbDataBlockBitmap, pIoCtx, &pMetaXfer, 2331 NULL, NULL); 2331 2332 2332 2333 if (RT_SUCCESS(rc)) … … 2575 2576 pImage->pStorage, 2576 2577 ((uint64_t)pImage->pBlockAllocationTable[cBlockAllocationTableEntry]) * VHD_SECTOR_SIZE, 2577 pImage->pu8Bitmap, pImage->cbDataBlockBitmap, pIoCtx, &pMetaXfer); 2578 pImage->pu8Bitmap, pImage->cbDataBlockBitmap, pIoCtx, &pMetaXfer, 2579 NULL, NULL); 2578 2580 if (RT_SUCCESS(rc)) 2579 2581 { -
trunk/src/VBox/Devices/Storage/VmdkHDDCore.cpp
r30555 r30863 495 495 } VMDKDEFLATESTATE; 496 496 497 /** Tracks async grain allocation. */ 498 typedef struct VMDKGRAINALLOCASYNC 499 { 500 /** Old size of the extent. Used for rollback after an error. */ 501 uint64_t cbExtentOld; 502 /** Flag whether the allocation failed. */ 503 bool fIoErr; 504 /** Current number of transfers pending. 505 * If reached 0 and there is an error the old state is restored. */ 506 unsigned cIoXfersPending; 507 /** Sector number */ 508 uint64_t uSector; 509 /** Flag whether the grain table needs to be updated. */ 510 bool fGTUpdateNeeded; 511 /** Extent the allocation happens. */ 512 PVMDKEXTENT pExtent; 513 /** New size of the extent, required for the grain table update. */ 514 uint64_t cbExtentSize; 515 /** Grain table sector. */ 516 uint64_t uGTSector; 517 /** Backup grain table sector. */ 518 uint64_t uRGTSector; 519 } VMDKGRAINALLOCASYNC, *PVMDKGRAINALLOCASYNC; 520 497 521 /******************************************************************************* 498 522 * Static Variables * … … 520 544 static void vmdkFreeImage(PVMDKIMAGE pImage, bool fDelete); 521 545 546 static int vmdkAllocGrainAsyncComplete(void *pvBackendData, PVDIOCTX pIoCtx, void *pvUser, int rcReq); 522 547 523 548 /** … … 2896 2921 } 2897 2922 2923 /** 2924 * Internal: write/update the metadata for a sparse extent - async version. 2925 */ 2926 static int vmdkWriteMetaSparseExtentAsync(PVMDKIMAGE pImage, PVMDKEXTENT pExtent, 2927 uint64_t uOffset, PVDIOCTX pIoCtx) 2928 { 2929 SparseExtentHeader Header; 2930 2931 memset(&Header, '\0', sizeof(Header)); 2932 Header.magicNumber = RT_H2LE_U32(VMDK_SPARSE_MAGICNUMBER); 2933 Header.version = RT_H2LE_U32(pExtent->uVersion); 2934 Header.flags = RT_H2LE_U32(RT_BIT(0)); 2935 if (pExtent->pRGD) 2936 Header.flags |= RT_H2LE_U32(RT_BIT(1)); 2937 if (pExtent->pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED) 2938 Header.flags |= RT_H2LE_U32(RT_BIT(16) | RT_BIT(17)); 2939 Header.capacity = RT_H2LE_U64(pExtent->cSectors); 2940 Header.grainSize = RT_H2LE_U64(pExtent->cSectorsPerGrain); 2941 Header.descriptorOffset = RT_H2LE_U64(pExtent->uDescriptorSector); 2942 Header.descriptorSize = RT_H2LE_U64(pExtent->cDescriptorSectors); 2943 Header.numGTEsPerGT = RT_H2LE_U32(pExtent->cGTEntries); 2944 if (pExtent->fFooter && uOffset == 0) 2945 { 2946 if (pExtent->pRGD) 2947 { 2948 Assert(pExtent->uSectorRGD); 2949 Header.rgdOffset = RT_H2LE_U64(VMDK_GD_AT_END); 2950 Header.gdOffset = RT_H2LE_U64(VMDK_GD_AT_END); 2951 } 2952 else 2953 { 2954 Header.gdOffset = RT_H2LE_U64(VMDK_GD_AT_END); 2955 } 2956 } 2957 else 2958 { 2959 if (pExtent->pRGD) 2960 { 2961 Assert(pExtent->uSectorRGD); 2962 Header.rgdOffset = RT_H2LE_U64(pExtent->uSectorRGD); 2963 Header.gdOffset = RT_H2LE_U64(pExtent->uSectorGD); 2964 } 2965 else 2966 { 2967 Header.gdOffset = RT_H2LE_U64(pExtent->uSectorGD); 2968 } 2969 } 2970 Header.overHead = RT_H2LE_U64(pExtent->cOverheadSectors); 2971 Header.uncleanShutdown = pExtent->fUncleanShutdown; 2972 Header.singleEndLineChar = '\n'; 2973 Header.nonEndLineChar = ' '; 2974 Header.doubleEndLineChar1 = '\r'; 2975 Header.doubleEndLineChar2 = '\n'; 2976 Header.compressAlgorithm = RT_H2LE_U16(pExtent->uCompression); 2977 2978 int rc = pImage->pInterfaceIOCallbacks->pfnWriteMetaAsync(pImage->pInterfaceIO->pvUser, 2979 pExtent->pFile->pStorage, 2980 uOffset, &Header, sizeof(Header), 2981 pIoCtx, NULL, NULL); 2982 if (RT_FAILURE(rc) && (rc != VERR_VD_ASYNC_IO_IN_PROGRESS)) 2983 rc = vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: error writing extent header in '%s'"), pExtent->pszFullname); 2984 return rc; 2985 } 2986 2898 2987 #ifdef VBOX_WITH_VMDK_ESX 2899 2988 /** … … 4397 4486 } 4398 4487 4488 LogFlowFunc(("uGTSector=%llu\n", uGTSector)); 4489 4399 4490 uGTBlock = uSector / (pExtent->cSectorsPerGrain * VMDK_GT_CACHELINE_SIZE); 4400 4491 uGTHash = vmdkGTCacheHash(pCache, uGTBlock, pExtent->uExtent); … … 4408 4499 pExtent->pFile->pStorage, 4409 4500 VMDK_SECTOR2BYTE(uGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp), 4410 aGTDataTmp, sizeof(aGTDataTmp), pIoCtx, &pMetaXfer );4501 aGTDataTmp, sizeof(aGTDataTmp), pIoCtx, &pMetaXfer, NULL, NULL); 4411 4502 if (RT_FAILURE(rc)) 4412 4503 return rc; … … 4696 4787 } 4697 4788 #endif /* VBOX_WITH_VMDK_ESX */ 4789 return rc; 4790 } 4791 4792 /** 4793 * Internal: Updates the grain table during a async grain allocation. 4794 */ 4795 static int vmdkAllocGrainAsyncGTUpdate(PVMDKIMAGE pImage, PVMDKEXTENT pExtent, 4796 PVMDKGTCACHE pCache, PVDIOCTX pIoCtx, 4797 PVMDKGRAINALLOCASYNC pGrainAlloc) 4798 { 4799 int rc = VINF_SUCCESS; 4800 uint32_t aGTDataTmp[VMDK_GT_CACHELINE_SIZE]; 4801 uint32_t uGTHash, uGTBlockIndex; 4802 uint64_t uGDIndex, uGTSector, uRGTSector, uGTBlock; 4803 uint64_t uSector = pGrainAlloc->uSector; 4804 PVMDKGTCACHEENTRY pGTCacheEntry; 4805 4806 LogFlowFunc(("pImage=%#p pExtent=%#p pCache=%#p pIoCtx=%#p pGrainAlloc=%#p\n", 4807 pImage, pExtent, pCache, pIoCtx, pGrainAlloc)); 4808 4809 uGTSector = pGrainAlloc->uGTSector; 4810 uRGTSector = pGrainAlloc->uRGTSector; 4811 LogFlow(("uGTSector=%llu uRGTSector=%llu\n", uGTSector, uRGTSector)); 4812 4813 /* Update the grain table (and the cache). */ 4814 uGTBlock = uSector / (pExtent->cSectorsPerGrain * VMDK_GT_CACHELINE_SIZE); 4815 uGTHash = vmdkGTCacheHash(pCache, uGTBlock, pExtent->uExtent); 4816 pGTCacheEntry = &pCache->aGTCache[uGTHash]; 4817 if ( pGTCacheEntry->uExtent != pExtent->uExtent 4818 || pGTCacheEntry->uGTBlock != uGTBlock) 4819 { 4820 /* Cache miss, fetch data from disk. */ 4821 LogFlow(("Cache miss, fetch data from disk\n")); 4822 PVDMETAXFER pMetaXfer = NULL; 4823 rc = pImage->pInterfaceIOCallbacks->pfnReadMetaAsync(pExtent->pImage->pInterfaceIO->pvUser, 4824 pExtent->pFile->pStorage, 4825 VMDK_SECTOR2BYTE(uGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp), 4826 aGTDataTmp, sizeof(aGTDataTmp), pIoCtx, 4827 &pMetaXfer, 4828 vmdkAllocGrainAsyncComplete, pGrainAlloc); 4829 if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS) 4830 { 4831 pGrainAlloc->cIoXfersPending++; 4832 pGrainAlloc->fGTUpdateNeeded = true; 4833 /* Leave early, we will be called again after the read completed. */ 4834 LogFlowFunc(("Metadata read in progress, leaving\n")); 4835 return rc; 4836 } 4837 else if (RT_FAILURE(rc)) 4838 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot read allocated grain table entry in '%s'"), pExtent->pszFullname); 4839 pImage->pInterfaceIOCallbacks->pfnMetaXferRelease(pExtent->pImage->pInterfaceIO->pvUser, pMetaXfer); 4840 pGTCacheEntry->uExtent = pExtent->uExtent; 4841 pGTCacheEntry->uGTBlock = uGTBlock; 4842 for (unsigned i = 0; i < VMDK_GT_CACHELINE_SIZE; i++) 4843 pGTCacheEntry->aGTData[i] = RT_LE2H_U32(aGTDataTmp[i]); 4844 } 4845 else 4846 { 4847 /* Cache hit. Convert grain table block back to disk format, otherwise 4848 * the code below will write garbage for all but the updated entry. */ 4849 for (unsigned i = 0; i < VMDK_GT_CACHELINE_SIZE; i++) 4850 aGTDataTmp[i] = RT_H2LE_U32(pGTCacheEntry->aGTData[i]); 4851 } 4852 pGrainAlloc->fGTUpdateNeeded = false; 4853 uGTBlockIndex = (uSector / pExtent->cSectorsPerGrain) % VMDK_GT_CACHELINE_SIZE; 4854 aGTDataTmp[uGTBlockIndex] = RT_H2LE_U32(VMDK_BYTE2SECTOR(pGrainAlloc->cbExtentSize)); 4855 pGTCacheEntry->aGTData[uGTBlockIndex] = VMDK_BYTE2SECTOR(pGrainAlloc->cbExtentSize); 4856 /* Update grain table on disk. */ 4857 rc = pImage->pInterfaceIOCallbacks->pfnWriteMetaAsync(pExtent->pImage->pInterfaceIO->pvUser, 4858 pExtent->pFile->pStorage, 4859 VMDK_SECTOR2BYTE(uGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp), 4860 aGTDataTmp, sizeof(aGTDataTmp), pIoCtx, 4861 vmdkAllocGrainAsyncComplete, pGrainAlloc); 4862 if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS) 4863 pGrainAlloc->cIoXfersPending++; 4864 else if (RT_FAILURE(rc)) 4865 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write updated grain table in '%s'"), pExtent->pszFullname); 4866 if (pExtent->pRGD) 4867 { 4868 /* Update backup grain table on disk. */ 4869 rc = pImage->pInterfaceIOCallbacks->pfnWriteMetaAsync(pExtent->pImage->pInterfaceIO->pvUser, 4870 pExtent->pFile->pStorage, 4871 VMDK_SECTOR2BYTE(uRGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp), 4872 aGTDataTmp, sizeof(aGTDataTmp), pIoCtx, 4873 vmdkAllocGrainAsyncComplete, pGrainAlloc); 4874 if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS) 4875 pGrainAlloc->cIoXfersPending++; 4876 else if (RT_FAILURE(rc)) 4877 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write updated backup grain table in '%s'"), pExtent->pszFullname); 4878 } 4879 #ifdef VBOX_WITH_VMDK_ESX 4880 if (RT_SUCCESS(rc) && pExtent->enmType == VMDKETYPE_ESX_SPARSE) 4881 { 4882 pExtent->uFreeSector = uGTSector + VMDK_BYTE2SECTOR(cbWrite); 4883 pExtent->fMetaDirty = true; 4884 } 4885 #endif /* VBOX_WITH_VMDK_ESX */ 4886 4887 LogFlowFunc(("leaving rc=%Rrc\n", rc)); 4888 4889 return rc; 4890 } 4891 4892 /** 4893 * Internal - complete the grain allocation by updating disk grain table if required. 4894 */ 4895 static int vmdkAllocGrainAsyncComplete(void *pvBackendData, PVDIOCTX pIoCtx, void *pvUser, int rcReq) 4896 { 4897 int rc = VINF_SUCCESS; 4898 PVMDKIMAGE pImage = (PVMDKIMAGE)pvBackendData; 4899 PVMDKGRAINALLOCASYNC pGrainAlloc = (PVMDKGRAINALLOCASYNC)pvUser; 4900 PVMDKEXTENT pExtent = pGrainAlloc->pExtent; 4901 4902 LogFlowFunc(("pvBackendData=%#p pIoCtx=%#p pvUser=%#p rcReq=%Rrc\n", 4903 pvBackendData, pIoCtx, pvUser, rcReq)); 4904 4905 pGrainAlloc->cIoXfersPending--; 4906 if (!pGrainAlloc->cIoXfersPending && pGrainAlloc->fGTUpdateNeeded) 4907 rc = vmdkAllocGrainAsyncGTUpdate(pImage, pGrainAlloc->pExtent, pImage->pGTCache, 4908 pIoCtx, pGrainAlloc); 4909 4910 if (!pGrainAlloc->cIoXfersPending) 4911 { 4912 /* Grain allocation completed. */ 4913 RTMemFree(pGrainAlloc); 4914 } 4915 4916 LogFlowFunc(("Leaving rc=%Rrc\n", rc)); 4917 return rc; 4918 } 4919 4920 /** 4921 * Internal. Allocates a new grain table (if necessary) - async version. 4922 */ 4923 static int vmdkAllocGrainAsync(PVMDKGTCACHE pCache, PVMDKEXTENT pExtent, 4924 PVDIOCTX pIoCtx, uint64_t uSector, 4925 uint64_t cbWrite) 4926 { 4927 uint64_t uGDIndex, uGTSector, uRGTSector, uGTBlock; 4928 uint64_t cbExtentSize; 4929 uint32_t aGTDataTmp[VMDK_GT_CACHELINE_SIZE]; 4930 PVMDKGRAINALLOCASYNC pGrainAlloc = NULL; 4931 PVMDKIMAGE pImage = pExtent->pImage; 4932 int rc; 4933 4934 LogFlowFunc(("pCache=%#p pExtent=%#p pIoCtx=%#p uSector=%llu cbWrite=%llu\n", 4935 pCache, pExtent, pIoCtx, uSector, cbWrite)); 4936 4937 AssertReturn(!(pExtent->pImage->uImageFlags & VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED), VERR_NOT_SUPPORTED); 4938 4939 pGrainAlloc = (PVMDKGRAINALLOCASYNC)RTMemAllocZ(sizeof(VMDKGRAINALLOCASYNC)); 4940 if (!pGrainAlloc) 4941 return VERR_NO_MEMORY; 4942 4943 pGrainAlloc->pExtent = pExtent; 4944 pGrainAlloc->uSector = uSector; 4945 4946 uGDIndex = uSector / pExtent->cSectorsPerGDE; 4947 if (uGDIndex >= pExtent->cGDEntries) 4948 return VERR_OUT_OF_RANGE; 4949 uGTSector = pExtent->pGD[uGDIndex]; 4950 if (pExtent->pRGD) 4951 uRGTSector = pExtent->pRGD[uGDIndex]; 4952 else 4953 uRGTSector = 0; /**< avoid compiler warning */ 4954 if (!uGTSector) 4955 { 4956 LogFlow(("Allocating new grain table\n")); 4957 4958 /* There is no grain table referenced by this grain directory 4959 * entry. So there is absolutely no data in this area. Allocate 4960 * a new grain table and put the reference to it in the GDs. */ 4961 rc = vmdkFileGetSize(pExtent->pFile, &cbExtentSize); 4962 if (RT_FAILURE(rc)) 4963 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: error getting size in '%s'"), pExtent->pszFullname); 4964 Assert(!(cbExtentSize % 512)); 4965 4966 pGrainAlloc->cbExtentOld = cbExtentSize; 4967 4968 cbExtentSize = RT_ALIGN_64(cbExtentSize, 512); 4969 uGTSector = VMDK_BYTE2SECTOR(cbExtentSize); 4970 4971 /* Normally the grain table is preallocated for hosted sparse extents 4972 * that support more than 32 bit sector numbers. So this shouldn't 4973 * ever happen on a valid extent. */ 4974 if (uGTSector > UINT32_MAX) 4975 return VERR_VD_VMDK_INVALID_HEADER; 4976 4977 /* Write grain table by writing the required number of grain table 4978 * cache chunks. Allocate memory dynamically here or we flood the 4979 * metadata cache with very small entries. 4980 */ 4981 size_t cbGTDataTmp = (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE) * VMDK_GT_CACHELINE_SIZE * sizeof(uint32_t); 4982 uint32_t *paGTDataTmp = (uint32_t *)RTMemTmpAllocZ(cbGTDataTmp); 4983 4984 if (!paGTDataTmp) 4985 return VERR_NO_MEMORY; 4986 4987 memset(paGTDataTmp, '\0', cbGTDataTmp); 4988 rc = pImage->pInterfaceIOCallbacks->pfnWriteMetaAsync(pExtent->pImage->pInterfaceIO->pvUser, 4989 pExtent->pFile->pStorage, 4990 VMDK_SECTOR2BYTE(uGTSector), 4991 paGTDataTmp, cbGTDataTmp, pIoCtx, 4992 vmdkAllocGrainAsyncComplete, pGrainAlloc); 4993 if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS) 4994 pGrainAlloc->cIoXfersPending++; 4995 else if (RT_FAILURE(rc)) 4996 { 4997 RTMemTmpFree(paGTDataTmp); 4998 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write grain table allocation in '%s'"), pExtent->pszFullname); 4999 } 5000 5001 if (pExtent->pRGD) 5002 { 5003 AssertReturn(!uRGTSector, VERR_VD_VMDK_INVALID_HEADER); 5004 rc = vmdkFileGetSize(pExtent->pFile, &cbExtentSize); 5005 if (RT_FAILURE(rc)) 5006 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: error getting size in '%s'"), pExtent->pszFullname); 5007 Assert(!(cbExtentSize % 512)); 5008 uRGTSector = VMDK_BYTE2SECTOR(cbExtentSize); 5009 5010 /* Normally the redundant grain table is preallocated for hosted 5011 * sparse extents that support more than 32 bit sector numbers. So 5012 * this shouldn't ever happen on a valid extent. */ 5013 if (uRGTSector > UINT32_MAX) 5014 { 5015 RTMemTmpFree(paGTDataTmp); 5016 return VERR_VD_VMDK_INVALID_HEADER; 5017 } 5018 /* Write backup grain table by writing the required number of grain 5019 * table cache chunks. */ 5020 rc = pImage->pInterfaceIOCallbacks->pfnWriteMetaAsync(pExtent->pImage->pInterfaceIO->pvUser, 5021 pExtent->pFile->pStorage, 5022 VMDK_SECTOR2BYTE(uRGTSector), 5023 paGTDataTmp, cbGTDataTmp, pIoCtx, 5024 vmdkAllocGrainAsyncComplete, pGrainAlloc); 5025 if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS) 5026 pGrainAlloc->cIoXfersPending++; 5027 else if (RT_FAILURE(rc)) 5028 { 5029 RTMemTmpFree(paGTDataTmp); 5030 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write backup grain table allocation in '%s'"), pExtent->pszFullname); 5031 } 5032 } 5033 5034 RTMemTmpFree(paGTDataTmp); 5035 5036 /* Update the grain directory on disk (doing it before writing the 5037 * grain table will result in a garbled extent if the operation is 5038 * aborted for some reason. Otherwise the worst that can happen is 5039 * some unused sectors in the extent. */ 5040 uint32_t uGTSectorLE = RT_H2LE_U64(uGTSector); 5041 rc = pImage->pInterfaceIOCallbacks->pfnWriteMetaAsync(pExtent->pImage->pInterfaceIO->pvUser, 5042 pExtent->pFile->pStorage, 5043 VMDK_SECTOR2BYTE(pExtent->uSectorGD) + uGDIndex * sizeof(uGTSectorLE), 5044 &uGTSectorLE, sizeof(uGTSectorLE), pIoCtx, 5045 vmdkAllocGrainAsyncComplete, pGrainAlloc); 5046 if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS) 5047 pGrainAlloc->cIoXfersPending++; 5048 else if (RT_FAILURE(rc)) 5049 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write grain directory entry in '%s'"), pExtent->pszFullname); 5050 if (pExtent->pRGD) 5051 { 5052 uint32_t uRGTSectorLE = RT_H2LE_U64(uRGTSector); 5053 rc = pImage->pInterfaceIOCallbacks->pfnWriteMetaAsync(pExtent->pImage->pInterfaceIO->pvUser, 5054 pExtent->pFile->pStorage, 5055 VMDK_SECTOR2BYTE(pExtent->uSectorRGD) + uGDIndex * sizeof(uGTSectorLE), 5056 &uRGTSectorLE, sizeof(uRGTSectorLE), pIoCtx, 5057 vmdkAllocGrainAsyncComplete, pGrainAlloc); 5058 if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS) 5059 pGrainAlloc->cIoXfersPending++; 5060 else if (RT_FAILURE(rc)) 5061 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write backup grain directory entry in '%s'"), pExtent->pszFullname); 5062 } 5063 5064 /* As the final step update the in-memory copy of the GDs. */ 5065 pExtent->pGD[uGDIndex] = uGTSector; 5066 if (pExtent->pRGD) 5067 pExtent->pRGD[uGDIndex] = uRGTSector; 5068 } 5069 5070 LogFlow(("uGTSector=%llu uRGTSector=%llu\n", uGTSector, uRGTSector)); 5071 pGrainAlloc->uGTSector = uGTSector; 5072 pGrainAlloc->uRGTSector = uRGTSector; 5073 5074 rc = vmdkFileGetSize(pExtent->pFile, &cbExtentSize); 5075 if (RT_FAILURE(rc)) 5076 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: error getting size in '%s'"), pExtent->pszFullname); 5077 Assert(!(cbExtentSize % 512)); 5078 5079 if (!pGrainAlloc->cbExtentOld) 5080 pGrainAlloc->cbExtentOld = cbExtentSize; 5081 5082 pGrainAlloc->cbExtentSize = cbExtentSize; 5083 5084 /* Write the data. Always a full grain, or we're in big trouble. */ 5085 rc = pImage->pInterfaceIOCallbacks->pfnWriteUserAsync(pImage->pInterfaceIO->pvUser, 5086 pExtent->pFile->pStorage, 5087 cbExtentSize, 5088 pIoCtx, cbWrite, 5089 vmdkAllocGrainAsyncComplete, pGrainAlloc); 5090 if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS) 5091 pGrainAlloc->cIoXfersPending++; 5092 else if (RT_FAILURE(rc)) 5093 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write allocated data block in '%s'"), pExtent->pszFullname); 5094 5095 rc = vmdkAllocGrainAsyncGTUpdate(pImage, pExtent, pCache, pIoCtx, pGrainAlloc); 5096 5097 if (!pGrainAlloc->cIoXfersPending) 5098 { 5099 /* Grain allocation completed. */ 5100 RTMemFree(pGrainAlloc); 5101 } 5102 5103 LogFlowFunc(("leaving rc=%Rrc\n", rc)); 5104 4698 5105 return rc; 4699 5106 } … … 6067 6474 PVMDKIMAGE pImage = (PVMDKIMAGE)pvBackendData; 6068 6475 6069 #if 1 6476 #if 1 /** @todo: Remove once the async support is tested throughly */ 6070 6477 bool fAsyncIOSupported = false; 6071 6478 … … 6253 6660 if (!(fWrite & VD_WRITE_NO_ALLOC)) 6254 6661 { 6255 AssertMsgFailed(("Implement\n"));6256 #if 06257 6662 /* Allocate GT and find out where to store the grain. */ 6258 rc = vmdkAllocGrain(pImage->pGTCache, pExtent, 6259 uSectorExtentRel, pvBuf, cbWrite); 6260 #endif 6663 rc = vmdkAllocGrainAsync(pImage->pGTCache, pExtent, pIoCtx, 6664 uSectorExtentRel, cbWrite); 6261 6665 } 6262 6666 else … … 6323 6727 case VMDKETYPE_ESX_SPARSE: 6324 6728 #endif /* VBOX_WITH_VMDK_ESX */ 6325 /** @todo: Fake success for now */ 6326 rc = VINF_SUCCESS; 6729 rc = vmdkWriteMetaSparseExtentAsync(pImage, pExtent, 0, pIoCtx); 6730 if (RT_FAILURE(rc) && (rc != VERR_VD_ASYNC_IO_IN_PROGRESS)) 6731 goto out; 6732 if (pExtent->fFooter) 6733 { 6734 uint64_t cbSize; 6735 rc = vmdkFileGetSize(pExtent->pFile, &cbSize); 6736 if (RT_FAILURE(rc)) 6737 goto out; 6738 cbSize = RT_ALIGN_64(cbSize, 512); 6739 rc = vmdkWriteMetaSparseExtent(pExtent, cbSize - 2*512); 6740 if (RT_FAILURE(rc) && (rc != VERR_VD_ASYNC_IO_IN_PROGRESS)) 6741 goto out; 6742 } 6327 6743 break; 6328 6744 case VMDKETYPE_VMFS:
Note:
See TracChangeset
for help on using the changeset viewer.