Changeset 28620 in vbox
- Timestamp:
- Apr 22, 2010 10:43:37 PM (15 years ago)
- svn:sync-xref-src-repo-rev:
- 60469
- Location:
- trunk
- Files:
-
- 10 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/VBox/VBoxHDD.h
r28383 r28620 1338 1338 } VDBACKENDINFO, *PVDBACKENDINFO; 1339 1339 1340 /**1341 * Completion callback for metadata reads or writes.1342 *1343 * @return nothing.1344 * @param pvBackendData The opaque backend data.1345 * @param pvMetaUser Opaque user data passed during a metadata read/write request.1346 */1347 typedef DECLCALLBACK(void) FNVDMETACOMPLETED(void *pvBackendData, void *pvMetaUser);1348 /** Pointer to FNVDCOMPLETED() */1349 typedef FNVDMETACOMPLETED *PFNVDMETACOMPLETED;1350 1340 1351 1341 /** Forward declaration. Only visible in the VBoxHDD module. */ … … 1356 1346 /** Pointer to a storage backend handle. */ 1357 1347 typedef PVDIOSTORAGE *PPVDIOSTORAGE; 1348 1349 /** 1350 * Completion callback for metadata reads or writes. 1351 * 1352 * @return nothing. 1353 * @param pvBackendData The opaque backend data. 1354 * @param pIoCtx I/O context associated with this request. 1355 * @param pvMetaUser Opaque user data passed during a metadata read/write request. 1356 */ 1357 typedef DECLCALLBACK(void) FNVDMETACOMPLETED(void *pvBackendData, PVDIOCTX pIoCtx, void *pvMetaUser); 1358 /** Pointer to FNVDCOMPLETED() */ 1359 typedef FNVDMETACOMPLETED *PFNVDMETACOMPLETED; 1358 1360 1359 1361 /** -
trunk/src/VBox/Devices/Storage/DevAHCI.cpp
r28524 r28620 4855 4855 { 4856 4856 /* Free system resources occupied by the scatter gather list. */ 4857 ahciScatterGatherListDestroy(pAhciPort, pAhciPortTaskState); 4857 if (pAhciPortTaskState->enmTxDir != AHCITXDIR_FLUSH) 4858 ahciScatterGatherListDestroy(pAhciPort, pAhciPortTaskState); 4858 4859 4859 4860 pAhciPortTaskState->cmdHdr.u32PRDBC = pAhciPortTaskState->cbTransfer; … … 5290 5291 if (enmTxDir != AHCITXDIR_NONE) 5291 5292 { 5293 pAhciPortTaskState->enmTxDir = enmTxDir; 5294 5292 5295 if (pAhciPortTaskState->fQueued) 5293 5296 { -
trunk/src/VBox/Devices/Storage/DrvVD.cpp
r28383 r28620 1352 1352 break; 1353 1353 } 1354 rc = CFGMR3QueryBoolDef(pCurNode, "UseNewIo", &fUseNewIo, false);1354 rc = CFGMR3QueryBoolDef(pCurNode, "UseNewIo", &fUseNewIo, true); 1355 1355 if (RT_FAILURE(rc)) 1356 1356 { -
trunk/src/VBox/Devices/Storage/ParallelsHDDCore.cpp
r27808 r28620 65 65 { 66 66 /** Pointer to the per-disk VD interface list. */ 67 PVDINTERFACE pVDIfsDisk; 67 PVDINTERFACE pVDIfsDisk; 68 /** Pointer to the per-image VD interface list. */ 69 PVDINTERFACE pVDIfsImage; 68 70 /** Error interface. */ 69 71 PVDINTERFACE pInterfaceError; … … 284 286 #ifdef VBOX_WITH_NEW_IO_CODE 285 287 /* Try to get async I/O interface. */ 286 pImage->pInterfaceIO = VDInterfaceGet(pImage->pVDIfs Disk, VDINTERFACETYPE_IO);288 pImage->pInterfaceIO = VDInterfaceGet(pImage->pVDIfsImage, VDINTERFACETYPE_IO); 287 289 AssertPtr(pImage->pInterfaceIO); 288 290 pImage->pInterfaceIOCallbacks = VDGetInterfaceIO(pImage->pInterfaceIO); … … 499 501 pImage->pszFilename = pszFilename; 500 502 pImage->pVDIfsDisk = pVDIfsDisk; 503 pImage->pVDIfsImage = pVDIfsImage; 501 504 502 505 rc = parallelsOpenImage(pImage, uOpenFlags); -
trunk/src/VBox/Devices/Storage/RawHDDCore.cpp
r28154 r28620 58 58 /** Pointer to the per-disk VD interface list. */ 59 59 PVDINTERFACE pVDIfsDisk; 60 /** Pointer to the per-image VD interface list. */ 61 PVDINTERFACE pVDIfsImage; 60 62 61 63 /** Error callback. */ … … 269 271 #ifdef VBOX_WITH_NEW_IO_CODE 270 272 /* Try to get I/O interface. */ 271 pImage->pInterfaceIO = VDInterfaceGet(pImage->pVDIfs Disk, VDINTERFACETYPE_IO);273 pImage->pInterfaceIO = VDInterfaceGet(pImage->pVDIfsImage, VDINTERFACETYPE_IO); 272 274 AssertPtr(pImage->pInterfaceIO); 273 275 pImage->pInterfaceIOCallbacks = VDGetInterfaceIO(pImage->pInterfaceIO); … … 335 337 #ifdef VBOX_WITH_NEW_IO_CODE 336 338 /* Try to get async I/O interface. */ 337 pImage->pInterfaceIO = VDInterfaceGet(pImage->pVDIfs Disk, VDINTERFACETYPE_IO);339 pImage->pInterfaceIO = VDInterfaceGet(pImage->pVDIfsImage, VDINTERFACETYPE_IO); 338 340 AssertPtr(pImage->pInterfaceIO); 339 341 pImage->pInterfaceIOCallbacks = VDGetInterfaceIO(pImage->pInterfaceIO); … … 511 513 #endif 512 514 pImage->pVDIfsDisk = pVDIfsDisk; 515 pImage->pVDIfsImage = pVDIfsImage; 513 516 514 517 rc = rawOpenImage(pImage, uOpenFlags); … … 580 583 #endif 581 584 pImage->pVDIfsDisk = pVDIfsDisk; 585 pImage->pVDIfsImage = pVDIfsImage; 582 586 583 587 rc = rawCreateImage(pImage, cbSize, uImageFlags, pszComment, -
trunk/src/VBox/Devices/Storage/VBoxHDD.cpp
r28383 r28620 41 41 #include <iprt/memcache.h> 42 42 #include <iprt/sg.h> 43 #include <iprt/critsect.h> 44 #include <iprt/list.h> 43 45 44 46 #include <VBox/VBoxHDD-Plugin.h> … … 87 89 /** Function pointers for the various backend methods. */ 88 90 PCVBOXHDDBACKEND Backend; 91 /** Per image I/O interface. */ 92 VDINTERFACE VDIIO; 89 93 /** Pointer to list of VD interfaces, per-image. */ 90 94 PVDINTERFACE pVDIfsImage; 95 /** Disk this image is part of */ 96 PVBOXHDD pDisk; 91 97 } VDIMAGE, *PVDIMAGE; 92 98 … … 158 164 /** Memory cache for I/O tasks. */ 159 165 RTMEMCACHE hMemCacheIoTask; 166 /** Critical section protecting the disk against concurrent access. */ 167 RTCRITSECT CritSect; 168 /** Flag whether the last image is currently written to and needs to grow. 169 * Other write requests which will grow the image too need to be deferred to 170 * prevent data corruption. - Protected by the critical section. 171 */ 172 bool fGrowing; 173 /** List of waiting requests. - Protected by the critical section. */ 174 RTLISTNODE ListWriteGrowing; 160 175 }; 161 176 … … 187 202 } VDIOCTXTXDIR, *PVDIOCTXTXDIR; 188 203 204 /** Transfer function */ 205 typedef DECLCALLBACK(int) FNVDIOCTXTRANSFER (PVDIOCTX pIoCtx); 206 /** Pointer to a transfer function. */ 207 typedef FNVDIOCTXTRANSFER *PFNVDIOCTXTRANSFER; 208 189 209 /** 190 210 * I/O context … … 192 212 typedef struct VDIOCTX 193 213 { 214 /** Node in the list of deferred requests. */ 215 RTLISTNODE NodeWriteGrowing; 194 216 /** Disk this is request is for. */ 195 217 PVBOXHDD pDisk; … … 202 224 /** Current offset */ 203 225 volatile uint64_t uOffset; 226 /** Number of bytes to transfer */ 227 volatile size_t cbTransfer; 228 /** Current image in the chain. */ 229 PVDIMAGE pImage; 204 230 /** S/G buffer */ 205 231 RTSGBUF SgBuf; … … 211 237 * when the context completes. */ 212 238 void *pvAllocation; 239 /** Transfer function. */ 240 PFNVDIOCTXTRANSFER pfnIoCtxTransfer; 241 /** Next transfer part after the current one completed. */ 242 PFNVDIOCTXTRANSFER pfnIoCtxTransferNext; 213 243 /** Parent I/O context if any. Sets the type of the context (root/child) */ 214 244 PVDIOCTX pIoCtxParent; … … 235 265 /** Number of bytes transfered from the parent if this context completes. */ 236 266 size_t cbTransferParent; 267 /** Number of bytes to pre read */ 268 size_t cbPreRead; 269 /** Number of bytes to post read. */ 270 size_t cbPostRead; 271 /** Write type dependent data. */ 272 union 273 { 274 /** Optimized */ 275 struct 276 { 277 /** Bytes to fill to satisfy the block size. Not part of the virtual disk. */ 278 size_t cbFill; 279 /** Bytes to copy instead of reading from the parent */ 280 size_t cbWriteCopy; 281 /** Bytes to read from the image. */ 282 size_t cbReadImage; 283 /** Number of bytes to wite left. */ 284 size_t cbWrite; 285 } Optimized; 286 } Write; 237 287 } Child; 238 288 } Type; … … 266 316 /** User data */ 267 317 void *pvMetaUser; 318 /** Image the task was created for. */ 319 PVDIMAGE pImage; 268 320 } Meta; 269 321 } Type; … … 275 327 typedef struct VDIOSTORAGE 276 328 { 329 /** Image this storage handle belongs to. */ 330 PVDIMAGE pImage; 277 331 union 278 332 { 279 333 /** Storage handle */ 280 void 334 void *pStorage; 281 335 /** File handle for the limited I/O version. */ 282 RTFILE 336 RTFILE hFile; 283 337 } u; 284 338 } VDIOSTORAGE; … … 531 585 uint64_t uOffset, size_t cbTransfer, 532 586 PCRTSGSEG pcaSeg, unsigned cSeg, 533 void *pvAllocation) 587 void *pvAllocation, 588 PFNVDIOCTXTRANSFER pfnIoCtxTransfer) 534 589 { 535 590 PVDIOCTX pIoCtx = NULL; … … 542 597 pIoCtx->cbTransferLeft = cbTransfer; 543 598 pIoCtx->uOffset = uOffset; 599 pIoCtx->cbTransfer = cbTransfer; 544 600 pIoCtx->cMetaTransfersPending = 0; 545 601 pIoCtx->fComplete = false; 546 602 pIoCtx->pvAllocation = pvAllocation; 603 pIoCtx->pfnIoCtxTransfer = pfnIoCtxTransfer; 604 pIoCtx->pfnIoCtxTransferNext = NULL; 547 605 548 606 RTSgBufInit(&pIoCtx->SgBuf, pcaSeg, cSeg); … … 552 610 } 553 611 554 static PVDIOCTX vdIoCtxRootAlloc(PVBOXHDD pDisk, VDIOCTXTXDIR enmTxDir, 555 uint64_t uOffset, size_t cbTransfer, 556 PCRTSGSEG paSeg, unsigned cSeg, 557 PFNVDASYNCTRANSFERCOMPLETE pfnComplete, 558 void *pvUser1, void *pvUser2, 559 void *pvAllocation) 612 DECLINLINE(PVDIOCTX) vdIoCtxRootAlloc(PVBOXHDD pDisk, VDIOCTXTXDIR enmTxDir, 613 uint64_t uOffset, size_t cbTransfer, 614 PCRTSGSEG paSeg, unsigned cSeg, 615 PFNVDASYNCTRANSFERCOMPLETE pfnComplete, 616 void *pvUser1, void *pvUser2, 617 void *pvAllocation, 618 PFNVDIOCTXTRANSFER pfnIoCtxTransfer) 560 619 { 561 620 PVDIOCTX pIoCtx = vdIoCtxAlloc(pDisk, enmTxDir, uOffset, cbTransfer, 562 paSeg, cSeg, pvAllocation );621 paSeg, cSeg, pvAllocation, pfnIoCtxTransfer); 563 622 564 623 if (RT_LIKELY(pIoCtx)) … … 573 632 } 574 633 575 static PVDIOCTX vdIoCtxChildAlloc(PVBOXHDD pDisk, VDIOCTXTXDIR enmTxDir, 576 uint64_t uOffset, size_t cbTransfer, 577 PCRTSGSEG paSeg, unsigned cSeg, 578 PVDIOCTX pIoCtxParent, size_t cbTransferParent, 579 void *pvAllocation) 634 DECLINLINE(PVDIOCTX) vdIoCtxChildAlloc(PVBOXHDD pDisk, VDIOCTXTXDIR enmTxDir, 635 uint64_t uOffset, size_t cbTransfer, 636 PCRTSGSEG paSeg, unsigned cSeg, 637 PVDIOCTX pIoCtxParent, size_t cbTransferParent, 638 void *pvAllocation, 639 PFNVDIOCTXTRANSFER pfnIoCtxTransfer) 580 640 { 581 641 PVDIOCTX pIoCtx = vdIoCtxAlloc(pDisk, enmTxDir, uOffset, cbTransfer, 582 paSeg, cSeg, pvAllocation );642 paSeg, cSeg, pvAllocation, pfnIoCtxTransfer); 583 643 584 644 if (RT_LIKELY(pIoCtx)) … … 593 653 } 594 654 595 static PVDIOTASKvdIoTaskUserAlloc(PVBOXHDD pDisk, PVDIOCTX pIoCtx, uint32_t cbTransfer)655 DECLINLINE(PVDIOTASK) vdIoTaskUserAlloc(PVBOXHDD pDisk, PVDIOCTX pIoCtx, uint32_t cbTransfer) 596 656 { 597 657 PVDIOTASK pIoTask = NULL; … … 608 668 } 609 669 610 static PVDIOTASK vdIoTaskMetaAlloc(PVBOXHDD pDisk, PVDIOCTX pIoCtx, VDIOCTXTXDIR enmTxDir, 611 PFNVDMETACOMPLETED pfnMetaComplete, void *pvMetaUser) 670 DECLINLINE(PVDIOTASK) vdIoTaskMetaAlloc(PVBOXHDD pDisk, PVDIOCTX pIoCtx, VDIOCTXTXDIR enmTxDir, 671 PVDIMAGE pImage, 672 PFNVDMETACOMPLETED pfnMetaComplete, void *pvMetaUser) 612 673 { 613 674 PVDIOTASK pIoTask = NULL; … … 621 682 pIoTask->Type.Meta.pfnMetaComplete = pfnMetaComplete; 622 683 pIoTask->Type.Meta.pvMetaUser = pvMetaUser; 684 pIoTask->Type.Meta.pImage = pImage; 623 685 } 624 686 … … 626 688 } 627 689 628 static voidvdIoCtxFree(PVBOXHDD pDisk, PVDIOCTX pIoCtx)690 DECLINLINE(void) vdIoCtxFree(PVBOXHDD pDisk, PVDIOCTX pIoCtx) 629 691 { 630 692 if (pIoCtx->pvAllocation) … … 633 695 } 634 696 635 static voidvdIoTaskFree(PVBOXHDD pDisk, PVDIOTASK pIoTask)697 DECLINLINE(void) vdIoTaskFree(PVBOXHDD pDisk, PVDIOTASK pIoTask) 636 698 { 637 699 pIoTask->pIoCtx = NULL; … … 639 701 } 640 702 641 static voidvdIoCtxChildReset(PVDIOCTX pIoCtx)703 DECLINLINE(void) vdIoCtxChildReset(PVDIOCTX pIoCtx) 642 704 { 643 705 AssertPtr(pIoCtx->pIoCtxParent); … … 674 736 } 675 737 738 static int vdIoCtxProcess(PVDIOCTX pIoCtx) 739 { 740 int rc = VINF_SUCCESS; 741 PVBOXHDD pDisk = pIoCtx->pDisk; 742 743 if ( !pIoCtx->cbTransferLeft 744 && !pIoCtx->cMetaTransfersPending) 745 return VINF_VD_ASYNC_IO_FINISHED; 746 747 if (pIoCtx->pfnIoCtxTransfer) 748 { 749 /* Call the transfer function advancing to the next while there is no error. */ 750 RTCritSectEnter(&pDisk->CritSect); 751 while ( pIoCtx->pfnIoCtxTransfer 752 && RT_SUCCESS(rc)) 753 { 754 rc = pIoCtx->pfnIoCtxTransfer(pIoCtx); 755 756 /* Advance to the next part of the transfer if the current one succeeded. */ 757 if (RT_SUCCESS(rc)) 758 { 759 pIoCtx->pfnIoCtxTransfer = pIoCtx->pfnIoCtxTransferNext; 760 pIoCtx->pfnIoCtxTransferNext = NULL; 761 } 762 } 763 RTCritSectLeave(&pDisk->CritSect); 764 } 765 766 if ( RT_SUCCESS(rc) 767 && !pIoCtx->cbTransferLeft 768 && !pIoCtx->cMetaTransfersPending) 769 rc = VINF_VD_ASYNC_IO_FINISHED; 770 else if (RT_SUCCESS(rc)) 771 rc = VERR_VD_ASYNC_IO_IN_PROGRESS; 772 773 LogFlowFunc(("pIoCtx=%#p rc=%Rrc cbTransferLeft=%u cMetaTransfersPending=%u fComplete=%RTbool\n", 774 pIoCtx, rc, pIoCtx->cbTransferLeft, pIoCtx->cMetaTransfersPending, 775 pIoCtx->fComplete)); 776 777 return rc; 778 } 779 676 780 /** 677 781 * internal: read the specified amount of data in whatever blocks the backend 678 782 * will give us - async version. 679 783 */ 680 static int vdReadHelperAsync(PVBOXHDD pDisk, PVDIMAGE pImage, PVDIMAGE pImageParentOverride, 681 PVDIOCTX pIoCtx, uint64_t uOffset, size_t cbRead) 784 static int vdReadHelperAsync(PVDIOCTX pIoCtx) 682 785 { 683 786 int rc; 787 size_t cbToRead = pIoCtx->cbTransfer; 788 uint64_t uOffset = pIoCtx->uOffset; 789 PVDIMAGE pCurrImage = NULL; 684 790 size_t cbThisRead; 685 791 … … 687 793 do 688 794 { 795 pCurrImage = pIoCtx->pImage; 796 689 797 /* Search for image with allocated block. Do not attempt to read more 690 798 * than the previous reads marked as valid. Otherwise this would return 691 799 * stale data when different block sizes are used for the images. */ 692 cbThisRead = cb Read;800 cbThisRead = cbToRead; 693 801 694 802 /* … … 696 804 * If the block is not allocated read from override chain if present. 697 805 */ 698 rc = p Image->Backend->pfnAsyncRead(pImage->pvBackendData,699 uOffset, cbThisRead,700 pIoCtx, &cbThisRead);806 rc = pCurrImage->Backend->pfnAsyncRead(pCurrImage->pvBackendData, 807 uOffset, cbThisRead, 808 pIoCtx, &cbThisRead); 701 809 702 810 if (rc == VERR_VD_BLOCK_FREE) 703 811 { 704 for ( PVDIMAGE pCurrImage = pImageParentOverride ? pImageParentOverride : pImage->pPrev;812 for (pCurrImage = pCurrImage->pPrev; 705 813 pCurrImage != NULL && rc == VERR_VD_BLOCK_FREE; 706 814 pCurrImage = pCurrImage->pPrev) … … 723 831 break; 724 832 725 cb Read-= cbThisRead;726 uOffset += cbThisRead;727 } while (cb Read != 0 && RT_SUCCESS(rc));833 cbToRead -= cbThisRead; 834 uOffset += cbThisRead; 835 } while (cbToRead != 0 && RT_SUCCESS(rc)); 728 836 729 837 if (rc == VERR_VD_NOT_ENOUGH_METADATA) 730 838 { 731 pIoCtx->uOffset = uOffset; 839 /* Save the current state. */ 840 pIoCtx->uOffset = uOffset; 841 pIoCtx->cbTransfer = cbToRead; 842 pIoCtx->pImage = pCurrImage; 843 rc = VERR_VD_ASYNC_IO_IN_PROGRESS; 732 844 } 733 845 … … 1014 1126 * images that are really needed) - async version. 1015 1127 */ 1016 static int vdWriteHelperStandardAsync(PVBOXHDD pDisk, PVDIMAGE pImage, 1017 PVDIMAGE pImageParentOverride, 1018 uint64_t uOffset, size_t cbWrite, 1019 size_t cbThisWrite, size_t cbPreRead, 1020 size_t cbPostRead, PVDIOCTX pIoCtxSrc, 1021 PVDIOCTX pIoCtxDst) 1128 static int vdWriteHelperStandardAsync(PVDIOCTX pIoCtx) 1022 1129 { 1023 1130 int rc = VINF_SUCCESS; 1131 1132 #if 0 1024 1133 1025 1134 /* Read the data that goes before the write to fill the block. */ 1026 1135 if (cbPreRead) 1027 1136 { 1028 rc = vdReadHelperAsync(pDisk, pImage, pImageParentOverride, pIoCtxDst, 1029 uOffset - cbPreRead, cbPreRead); 1137 rc = vdReadHelperAsync(pIoCtxDst); 1030 1138 if (RT_FAILURE(rc)) 1031 1139 return rc; … … 1102 1210 1103 1211 return rc; 1212 #endif 1213 return VERR_NOT_IMPLEMENTED; 1214 } 1215 1216 static int vdWriteHelperOptimizedCmpAndWriteAsync(PVDIOCTX pIoCtx) 1217 { 1218 int rc = VINF_SUCCESS; 1219 PVDIMAGE pImage = pIoCtx->pImage; 1220 size_t cbThisWrite = 0; 1221 size_t cbPreRead = pIoCtx->Type.Child.cbPreRead; 1222 size_t cbPostRead = pIoCtx->Type.Child.cbPostRead; 1223 size_t cbWriteCopy = pIoCtx->Type.Child.Write.Optimized.cbWriteCopy; 1224 size_t cbFill = pIoCtx->Type.Child.Write.Optimized.cbFill; 1225 size_t cbReadImage = pIoCtx->Type.Child.Write.Optimized.cbReadImage; 1226 PVDIOCTX pIoCtxParent = pIoCtx->pIoCtxParent; 1227 1228 AssertPtr(pIoCtxParent); 1229 Assert(!pIoCtx->cbTransferLeft && !pIoCtx->cMetaTransfersPending); 1230 1231 vdIoCtxChildReset(pIoCtx); 1232 cbThisWrite = pIoCtx->Type.Child.cbTransferParent; 1233 RTSgBufAdvance(&pIoCtx->SgBuf, cbPreRead); 1234 1235 /* Check if the write would modify anything in this block. */ 1236 if (!RTSgBufCmp(&pIoCtx->SgBuf, &pIoCtxParent->SgBuf, cbThisWrite)) 1237 { 1238 RTSGBUF SgBufSrcTmp; 1239 1240 RTSgBufClone(&SgBufSrcTmp, &pIoCtxParent->SgBuf); 1241 RTSgBufAdvance(&SgBufSrcTmp, cbThisWrite); 1242 RTSgBufAdvance(&pIoCtx->SgBuf, cbThisWrite); 1243 1244 if (!cbWriteCopy || !RTSgBufCmp(&pIoCtx->SgBuf, &SgBufSrcTmp, cbWriteCopy)) 1245 { 1246 /* Block is completely unchanged, so no need to write anything. */ 1247 LogFlowFunc(("Block didn't changed\n")); 1248 ASMAtomicWriteU32(&pIoCtx->cbTransferLeft, 0); 1249 return VINF_VD_ASYNC_IO_FINISHED; 1250 } 1251 } 1252 1253 /* Copy the data to the right place in the buffer. */ 1254 RTSgBufReset(&pIoCtx->SgBuf); 1255 RTSgBufAdvance(&pIoCtx->SgBuf, cbPreRead); 1256 vdIoCtxCopy(pIoCtx, pIoCtxParent, cbThisWrite); 1257 1258 /* Handle the data that goes after the write to fill the block. */ 1259 if (cbPostRead) 1260 { 1261 /* Now assemble the remaining data. */ 1262 if (cbWriteCopy) 1263 vdIoCtxCopy(pIoCtx, pIoCtxParent, cbWriteCopy); 1264 /* Zero out the remainder of this block. Will never be visible, as this 1265 * is beyond the limit of the image. */ 1266 if (cbFill) 1267 { 1268 RTSgBufAdvance(&pIoCtx->SgBuf, cbReadImage); 1269 vdIoCtxSet(pIoCtx, '\0', cbFill); 1270 } 1271 } 1272 1273 /* Write the full block to the virtual disk. */ 1274 RTSgBufReset(&pIoCtx->SgBuf); 1275 rc = pImage->Backend->pfnAsyncWrite(pImage->pvBackendData, 1276 pIoCtx->uOffset - cbPreRead, 1277 cbPreRead + pIoCtx->cbTransferLeft + cbPostRead, 1278 pIoCtx, NULL, &cbPreRead, &cbPostRead, 0); 1279 Assert(rc != VERR_VD_BLOCK_FREE); 1280 Assert(cbPreRead == 0); 1281 Assert(cbPostRead == 0); 1282 1283 return rc; 1284 } 1285 1286 static int vdWriteHelperOptimizedPreReadAsync(PVDIOCTX pIoCtx) 1287 { 1288 pIoCtx->pfnIoCtxTransferNext = vdWriteHelperOptimizedCmpAndWriteAsync; 1289 return vdReadHelperAsync(pIoCtx); 1104 1290 } 1105 1291 … … 1110 1296 * All backends which support differential/growing images support this - async version. 1111 1297 */ 1112 static int vdWriteHelperOptimizedAsync(PVBOXHDD pDisk, PVDIMAGE pImage, 1113 PVDIMAGE pImageParentOverride, 1114 uint64_t uOffset, size_t cbWrite, 1115 size_t cbThisWrite, size_t cbPreRead, 1116 size_t cbPostRead, PVDIOCTX pIoCtxSrc, 1117 PVDIOCTX pIoCtxDst) 1118 { 1298 static int vdWriteHelperOptimizedAsync(PVDIOCTX pIoCtx) 1299 { 1300 PVBOXHDD pDisk = pIoCtx->pDisk; 1301 uint64_t uOffset = pIoCtx->Type.Child.uOffsetSaved; 1302 size_t cbThisWrite = pIoCtx->Type.Child.cbTransferParent; 1303 size_t cbPreRead = pIoCtx->Type.Child.cbPreRead; 1304 size_t cbPostRead = pIoCtx->Type.Child.cbPostRead; 1305 size_t cbWrite = pIoCtx->Type.Child.Write.Optimized.cbWrite; 1119 1306 size_t cbFill = 0; 1120 1307 size_t cbWriteCopy = 0; 1121 1308 size_t cbReadImage = 0; 1122 1309 int rc; 1310 1311 AssertPtr(pIoCtx->pIoCtxParent); 1123 1312 1124 1313 if (cbPostRead) … … 1139 1328 } 1140 1329 1330 pIoCtx->Type.Child.Write.Optimized.cbFill = cbFill; 1331 pIoCtx->Type.Child.Write.Optimized.cbWriteCopy = cbWriteCopy; 1332 pIoCtx->Type.Child.Write.Optimized.cbReadImage = cbReadImage; 1333 1141 1334 /* Read the entire data of the block so that we can compare whether it will 1142 1335 * be modified by the write or not. */ 1143 rc = vdReadHelperAsync(pDisk, pImage, pImageParentOverride, pIoCtxDst, 1144 uOffset - cbPreRead, 1145 cbPreRead + cbThisWrite + cbPostRead - cbFill); 1146 if (RT_FAILURE(rc)) 1147 return rc; 1148 1149 /** @todo Snapshots */ 1150 Assert(!pIoCtxDst->cbTransferLeft && !pIoCtxDst->cMetaTransfersPending); 1151 1152 vdIoCtxChildReset(pIoCtxDst); 1153 RTSgBufAdvance(&pIoCtxDst->SgBuf, cbPreRead); 1154 1155 /* Check if the write would modify anything in this block. */ 1156 if (!RTSgBufCmp(&pIoCtxDst->SgBuf, &pIoCtxSrc->SgBuf, cbThisWrite)) 1157 { 1158 RTSGBUF SgBufSrcTmp; 1159 1160 RTSgBufClone(&SgBufSrcTmp, &pIoCtxSrc->SgBuf); 1161 RTSgBufAdvance(&SgBufSrcTmp, cbThisWrite); 1162 RTSgBufAdvance(&pIoCtxDst->SgBuf, cbThisWrite); 1163 1164 if (!cbWriteCopy || !RTSgBufCmp(&pIoCtxDst->SgBuf, &SgBufSrcTmp, cbWriteCopy)) 1165 { 1166 /* Block is completely unchanged, so no need to write anything. */ 1167 LogFlowFunc(("Block didn't changed\n")); 1168 ASMAtomicWriteU32(&pIoCtxDst->cbTransferLeft, 0); 1169 return VINF_SUCCESS; 1170 } 1171 } 1172 1173 /* Copy the data to the right place in the buffer. */ 1174 RTSgBufReset(&pIoCtxDst->SgBuf); 1175 RTSgBufAdvance(&pIoCtxDst->SgBuf, cbPreRead); 1176 vdIoCtxCopy(pIoCtxDst, pIoCtxSrc, cbThisWrite); 1177 1178 /* Handle the data that goes after the write to fill the block. */ 1179 if (cbPostRead) 1180 { 1181 /* Now assemble the remaining data. */ 1182 if (cbWriteCopy) 1183 vdIoCtxCopy(pIoCtxDst, pIoCtxSrc, cbWriteCopy); 1184 /* Zero out the remainder of this block. Will never be visible, as this 1185 * is beyond the limit of the image. */ 1186 if (cbFill) 1187 { 1188 RTSgBufAdvance(&pIoCtxDst->SgBuf, cbReadImage); 1189 vdIoCtxSet(pIoCtxDst, '\0', cbFill); 1190 } 1191 } 1192 1193 /* Write the full block to the virtual disk. */ 1194 RTSgBufReset(&pIoCtxDst->SgBuf); 1195 rc = pImage->Backend->pfnAsyncWrite(pImage->pvBackendData, 1196 uOffset - cbPreRead, 1197 cbPreRead + cbThisWrite + cbPostRead, 1198 pIoCtxDst, NULL, &cbPreRead, &cbPostRead, 0); 1199 Assert(rc != VERR_VD_BLOCK_FREE); 1200 Assert(cbPreRead == 0); 1201 Assert(cbPostRead == 0); 1202 1203 return rc; 1336 pIoCtx->cbTransferLeft = cbPreRead + cbThisWrite + cbPostRead - cbFill; 1337 pIoCtx->cbTransfer = pIoCtx->cbTransferLeft; 1338 pIoCtx->uOffset -= cbPreRead; 1339 1340 /* Next step */ 1341 pIoCtx->pfnIoCtxTransferNext = vdWriteHelperOptimizedPreReadAsync; 1342 return VINF_SUCCESS; 1204 1343 } 1205 1344 … … 1208 1347 * write optimizations - async version. 1209 1348 */ 1210 static int vdWriteHelperAsync(PVBOXHDD pDisk, PVDIMAGE pImage, PVDIMAGE pImageParentOverride, 1211 PVDIOCTX pIoCtx, uint64_t uOffset, size_t cbWrite) 1349 static int vdWriteHelperAsync(PVDIOCTX pIoCtx) 1212 1350 { 1213 1351 int rc; 1352 size_t cbWrite = pIoCtx->cbTransfer; 1353 uint64_t uOffset = pIoCtx->uOffset; 1354 PVDIMAGE pImage = pIoCtx->pImage; 1355 PVBOXHDD pDisk = pIoCtx->pDisk; 1214 1356 unsigned fWrite; 1215 1357 size_t cbThisWrite; … … 1235 1377 { 1236 1378 /* 1237 * Allocate segment and buffer in one go.1238 * A bit hackish but avoids the need to allocate memory twice.1379 * If there is a growing request already put this one onto the waiting list. 1380 * It will be restarted if the current request completes. 1239 1381 */ 1240 PRTSGSEG pTmp = (PRTSGSEG)RTMemAlloc(cbPreRead + cbThisWrite + cbPostRead + sizeof(RTSGSEG)); 1241 AssertBreakStmt(VALID_PTR(pTmp), rc = VERR_NO_MEMORY); 1242 1243 pTmp->pvSeg = pTmp + 1; 1244 pTmp->cbSeg = cbPreRead + cbThisWrite + cbPostRead; 1245 1246 PVDIOCTX pIoCtxWrite = vdIoCtxChildAlloc(pDisk, VDIOCTXTXDIR_WRITE, 1247 uOffset - cbPreRead, pTmp->cbSeg, 1248 pTmp, 1, 1249 pIoCtx, cbThisWrite, 1250 pTmp); 1251 if (!VALID_PTR(pIoCtxWrite)) 1382 if (pDisk->fGrowing) 1252 1383 { 1253 RTMemTmpFree(pTmp); 1254 rc = VERR_NO_MEMORY; 1384 LogFlowFunc(("Deferring write pIoCtx=%#p\n", pIoCtx)); 1385 RTListAppend(&pDisk->ListWriteGrowing, &pIoCtx->NodeWriteGrowing); 1386 Assert(pIoCtx->NodeWriteGrowing.pNext == &pDisk->ListWriteGrowing); 1387 rc = VERR_VD_ASYNC_IO_IN_PROGRESS; 1255 1388 break; 1256 }1257 1258 if (!(pImage->uOpenFlags & VD_OPEN_FLAGS_HONOR_SAME))1259 {1260 /* Optimized write, suppress writing to a so far unallocated1261 * block if the data is in fact not changed. */1262 rc = vdWriteHelperOptimizedAsync(pDisk, pImage, pImageParentOverride,1263 uOffset, cbWrite,1264 cbThisWrite, cbPreRead, cbPostRead,1265 pIoCtx, pIoCtxWrite);1266 1389 } 1267 1390 else 1268 1391 { 1269 /* Normal write, not optimized in any way. The block will 1270 * be written no matter what. This will usually (unless the 1271 * backend has some further optimization enabled) cause the 1272 * block to be allocated. */ 1273 rc = vdWriteHelperStandardAsync(pDisk, pImage, pImageParentOverride, 1274 uOffset, cbWrite, 1275 cbThisWrite, cbPreRead, cbPostRead, 1276 pIoCtx, pIoCtxWrite); 1392 /* 1393 * Allocate segment and buffer in one go. 1394 * A bit hackish but avoids the need to allocate memory twice. 1395 */ 1396 PRTSGSEG pTmp = (PRTSGSEG)RTMemAlloc(cbPreRead + cbThisWrite + cbPostRead + sizeof(RTSGSEG)); 1397 AssertBreakStmt(VALID_PTR(pTmp), rc = VERR_NO_MEMORY); 1398 1399 pTmp->pvSeg = pTmp + 1; 1400 pTmp->cbSeg = cbPreRead + cbThisWrite + cbPostRead; 1401 1402 PVDIOCTX pIoCtxWrite = vdIoCtxChildAlloc(pDisk, VDIOCTXTXDIR_WRITE, 1403 uOffset, pTmp->cbSeg, 1404 pTmp, 1, 1405 pIoCtx, cbThisWrite, 1406 pTmp, 1407 (pImage->uOpenFlags & VD_OPEN_FLAGS_HONOR_SAME) 1408 ? vdWriteHelperStandardAsync 1409 : vdWriteHelperOptimizedAsync); 1410 if (!VALID_PTR(pIoCtxWrite)) 1411 { 1412 RTMemTmpFree(pTmp); 1413 rc = VERR_NO_MEMORY; 1414 break; 1415 } 1416 1417 /* Set the state to growing. */ 1418 LogFlowFunc(("Disk is growing because of pIoCtx=%#p pIoCtxWrite=%#p\n", 1419 pIoCtx, pIoCtxWrite)); 1420 pDisk->fGrowing = true; 1421 1422 pIoCtxWrite->pImage = pImage; 1423 pIoCtxWrite->Type.Child.cbPreRead = cbPreRead; 1424 pIoCtxWrite->Type.Child.cbPostRead = cbPostRead; 1425 1426 /* Process the write request */ 1427 rc = vdIoCtxProcess(pIoCtxWrite); 1428 1429 if (RT_FAILURE(rc) && (rc != VERR_VD_ASYNC_IO_IN_PROGRESS)) 1430 { 1431 vdIoCtxFree(pDisk, pIoCtxWrite); 1432 break; 1433 } 1434 else if ( rc == VINF_VD_ASYNC_IO_FINISHED 1435 && ASMAtomicCmpXchgBool(&pIoCtxWrite->fComplete, true, false)) 1436 { 1437 LogFlow(("Child write request completed\n")); 1438 Assert(pIoCtx->cbTransferLeft >= cbThisWrite); 1439 ASMAtomicSubU32(&pIoCtx->cbTransferLeft, cbThisWrite); 1440 pDisk->fGrowing = false; 1441 vdIoCtxFree(pDisk, pIoCtxWrite); 1442 1443 Assert(RTListIsEmpty(&pDisk->ListWriteGrowing)); 1444 rc = VINF_SUCCESS; 1445 } 1446 else 1447 LogFlow(("Child write pending\n")); 1277 1448 } 1278 1279 if (RT_FAILURE(rc)) 1280 { 1281 vdIoCtxFree(pDisk, pIoCtxWrite); 1282 break; 1283 } 1284 1285 if ( !(pIoCtxWrite->cbTransferLeft || pIoCtxWrite->cMetaTransfersPending) 1286 && ASMAtomicCmpXchgBool(&pIoCtxWrite->fComplete, true, false)) 1287 { 1288 LogFlow(("Child write request completed\n")); 1289 ASMAtomicSubU32(&pIoCtx->cbTransferLeft, cbThisWrite); 1290 vdIoCtxFree(pDisk, pIoCtxWrite); 1291 } 1292 else 1293 LogFlow(("Child write pending\n")); 1294 } 1295 1296 if (RT_FAILURE(rc)) 1297 break; 1449 } 1298 1450 1299 1451 cbWrite -= cbThisWrite; 1300 1452 uOffset += cbThisWrite; 1301 1453 } while (cbWrite != 0 && RT_SUCCESS(rc)); 1454 1455 if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS) 1456 { 1457 /* 1458 * Tell the caller that we don't need to go back here because all 1459 * writes are initiated. 1460 */ 1461 if (!cbWrite) 1462 rc = VINF_SUCCESS; 1463 1464 pIoCtx->uOffset = uOffset; 1465 pIoCtx->cbTransfer = cbWrite; 1466 } 1467 1468 return rc; 1469 } 1470 1471 /** 1472 * Flush helper async version. 1473 */ 1474 static int vdFlushHelperAsync(PVDIOCTX pIoCtx) 1475 { 1476 int rc = VINF_SUCCESS; 1477 PVBOXHDD pDisk = pIoCtx->pDisk; 1478 PVDIMAGE pImage = pIoCtx->pImage; 1479 1480 vdResetModifiedFlag(pDisk); 1481 rc = pImage->Backend->pfnAsyncFlush(pImage->pvBackendData, pIoCtx); 1302 1482 1303 1483 return rc; … … 1556 1736 static int vdIOReqCompleted(void *pvUser) 1557 1737 { 1738 int rc = VINF_SUCCESS; 1558 1739 PVDIOTASK pIoTask = (PVDIOTASK)pvUser; 1559 1740 PVDIOCTX pIoCtx = pIoTask->pIoCtx; … … 1567 1748 else 1568 1749 { 1569 Assert(pIoTask->Type.Meta.enmTxDir == VDIOCTXTXDIR_WRITE);1570 1750 if (pIoTask->Type.Meta.pfnMetaComplete) 1571 pIoTask->Type.Meta.pfnMetaComplete(NULL, pIoTask->Type.Meta.pvMetaUser); 1751 pIoTask->Type.Meta.pfnMetaComplete(pIoTask->Type.Meta.pImage->pvBackendData, 1752 pIoCtx, 1753 pIoTask->Type.Meta.pvMetaUser); 1572 1754 ASMAtomicDecU32(&pIoCtx->cMetaTransfersPending); 1573 1755 } … … 1575 1757 vdIoTaskFree(pDisk, pIoTask); 1576 1758 1577 if ( !pIoCtx->cbTransferLeft 1578 && !pIoCtx->cMetaTransfersPending 1759 /* Continue the transfer */ 1760 rc = vdIoCtxProcess(pIoCtx); 1761 1762 if ( rc == VINF_VD_ASYNC_IO_FINISHED 1579 1763 && ASMAtomicCmpXchgBool(&pIoCtx->fComplete, true, false)) 1580 1764 { 1581 LogFlowFunc(("I/O context completed \n"));1765 LogFlowFunc(("I/O context completed pIoCtx=%#p\n", pIoCtx)); 1582 1766 if (pIoCtx->pIoCtxParent) 1583 1767 { 1584 1768 PVDIOCTX pIoCtxParent = pIoCtx->pIoCtxParent; 1769 1770 LogFlowFunc(("I/O context transfered %u bytes for the parent pIoCtxParent=%p\n", 1771 pIoCtx->Type.Child.cbTransferParent, pIoCtxParent)); 1585 1772 1586 1773 /* Update the parent state. */ … … 1589 1776 ASMAtomicSubU32(&pIoCtxParent->cbTransferLeft, pIoCtx->Type.Child.cbTransferParent); 1590 1777 1591 if ( !pIoCtxParent->cbTransferLeft 1592 && !pIoCtxParent->cMetaTransfersPending 1778 rc = vdIoCtxProcess(pIoCtxParent); 1779 1780 if ( rc == VINF_VD_ASYNC_IO_FINISHED 1593 1781 && ASMAtomicCmpXchgBool(&pIoCtxParent->fComplete, true, false)) 1594 1782 { 1783 LogFlowFunc(("Parent I/O context completed pIoCtxParent=%#p\n", pIoCtx)); 1595 1784 pIoCtxParent->Type.Root.pfnComplete(pIoCtxParent->Type.Root.pvUser1, pIoCtxParent->Type.Root.pvUser2); 1596 1785 vdIoCtxFree(pDisk, pIoCtxParent); 1786 1787 /* 1788 * A completed parent means that we finsihed growing the image. 1789 * We have to process any pending writes now. 1790 */ 1791 Assert(pDisk->fGrowing); 1792 1793 RTCritSectEnter(&pDisk->CritSect); 1794 1795 pDisk->fGrowing = false; 1796 1797 if (!RTListIsEmpty(&pDisk->ListWriteGrowing)) 1798 { 1799 RTLISTNODE ListTmp; 1800 PVDIOCTX pIoCtxWait; 1801 1802 RTListMove(&ListTmp, &pDisk->ListWriteGrowing); 1803 1804 RTCritSectLeave(&pDisk->CritSect); 1805 1806 /* Process the list. */ 1807 RTListForEach(&ListTmp, pIoCtxWait, VDIOCTX, NodeWriteGrowing) 1808 { 1809 Assert(!pIoCtxWait->pIoCtxParent); 1810 1811 LogFlowFunc(("Processing waiting I/O context pIoCtxWait=%#p\n", pIoCtxWait)); 1812 1813 rc = vdIoCtxProcess(pIoCtxWait); 1814 if ( rc == VINF_VD_ASYNC_IO_FINISHED 1815 && ASMAtomicCmpXchgBool(&pIoCtxWait->fComplete, true, false)) 1816 { 1817 LogFlowFunc(("Waiting I/O context completed pIoCtxWait=%#p\n", pIoCtxWait)); 1818 pIoCtxWait->Type.Root.pfnComplete(pIoCtxWait->Type.Root.pvUser1, 1819 pIoCtxWait->Type.Root.pvUser2); 1820 vdIoCtxFree(pDisk, pIoCtxWait); 1821 } 1822 } 1823 } 1824 else 1825 RTCritSectLeave(&pDisk->CritSect); 1597 1826 } 1598 1827 } … … 1613 1842 { 1614 1843 int rc = VINF_SUCCESS; 1615 PVBOXHDD pDisk = (PVBOXHDD)pvUser; 1844 PVDIMAGE pImage = (PVDIMAGE)pvUser; 1845 PVBOXHDD pDisk = pImage->pDisk; 1616 1846 PVDIOSTORAGE pIoStorage = (PVDIOSTORAGE)RTMemAllocZ(sizeof(VDIOSTORAGE)); 1617 1847 … … 1634 1864 static int vdIOClose(void *pvUser, PVDIOSTORAGE pIoStorage) 1635 1865 { 1636 PVBOXHDD pDisk = (PVBOXHDD)pvUser; 1866 PVDIMAGE pImage = (PVDIMAGE)pvUser; 1867 PVBOXHDD pDisk = pImage->pDisk; 1637 1868 1638 1869 int rc = pDisk->pInterfaceAsyncIOCallbacks->pfnClose(pDisk->pInterfaceAsyncIO->pvUser, … … 1647 1878 uint64_t *pcbSize) 1648 1879 { 1649 PVBOXHDD pDisk = (PVBOXHDD)pvUser; 1880 PVDIMAGE pImage = (PVDIMAGE)pvUser; 1881 PVBOXHDD pDisk = pImage->pDisk; 1650 1882 1651 1883 return pDisk->pInterfaceAsyncIOCallbacks->pfnGetSize(pDisk->pInterfaceAsyncIO->pvUser, … … 1657 1889 uint64_t cbSize) 1658 1890 { 1659 PVBOXHDD pDisk = (PVBOXHDD)pvUser; 1891 PVDIMAGE pImage = (PVDIMAGE)pvUser; 1892 PVBOXHDD pDisk = pImage->pDisk; 1660 1893 1661 1894 return pDisk->pInterfaceAsyncIOCallbacks->pfnSetSize(pDisk->pInterfaceAsyncIO->pvUser, … … 1667 1900 size_t cbWrite, const void *pvBuf, size_t *pcbWritten) 1668 1901 { 1669 PVBOXHDD pDisk = (PVBOXHDD)pvUser; 1902 PVDIMAGE pImage = (PVDIMAGE)pvUser; 1903 PVBOXHDD pDisk = pImage->pDisk; 1670 1904 1671 1905 return pDisk->pInterfaceAsyncIOCallbacks->pfnWriteSync(pDisk->pInterfaceAsyncIO->pvUser, … … 1678 1912 size_t cbRead, void *pvBuf, size_t *pcbRead) 1679 1913 { 1680 PVBOXHDD pDisk = (PVBOXHDD)pvUser; 1914 PVDIMAGE pImage = (PVDIMAGE)pvUser; 1915 PVBOXHDD pDisk = pImage->pDisk; 1681 1916 1682 1917 return pDisk->pInterfaceAsyncIOCallbacks->pfnReadSync(pDisk->pInterfaceAsyncIO->pvUser, … … 1688 1923 static int vdIOFlushSync(void *pvUser, PVDIOSTORAGE pIoStorage) 1689 1924 { 1690 PVBOXHDD pDisk = (PVBOXHDD)pvUser; 1925 PVDIMAGE pImage = (PVDIMAGE)pvUser; 1926 PVBOXHDD pDisk = pImage->pDisk; 1691 1927 1692 1928 return pDisk->pInterfaceAsyncIOCallbacks->pfnFlushSync(pDisk->pInterfaceAsyncIO->pvUser, … … 1699 1935 { 1700 1936 int rc = VINF_SUCCESS; 1701 PVBOXHDD pDisk = (PVBOXHDD)pvUser; 1937 PVDIMAGE pImage = (PVDIMAGE)pvUser; 1938 PVBOXHDD pDisk = pImage->pDisk; 1939 1940 LogFlowFunc(("pvUser=%#p pIoStorage=%#p uOffset=%llu pIoCtx=%#p cbRead=%u\n", 1941 pvUser, pIoStorage, uOffset, pIoCtx, cbRead)); 1702 1942 1703 1943 /* Build the S/G array and spawn a new I/O task */ … … 1709 1949 1710 1950 cbTaskRead = RTSgBufSegArrayCreate(&pIoCtx->SgBuf, aSeg, &cSegments, cbRead); 1951 1952 AssertMsg(cbTaskRead <= cbRead, ("Invalid number of bytes to read\n")); 1953 1954 LogFlow(("Reading %u bytes into %u segments\n", cbTaskRead, cSegments)); 1955 1956 #ifdef DEBUG 1957 for (unsigned i = 0; i < cSegments; i++) 1958 AssertMsg(aSeg[i].pvSeg && !(aSeg[i].cbSeg % 512), 1959 ("Segment %u is invalid\n", i)); 1960 #endif 1711 1961 1712 1962 PVDIOTASK pIoTask = vdIoTaskUserAlloc(pDisk, pIoCtx, cbTaskRead); … … 1747 1997 { 1748 1998 int rc = VINF_SUCCESS; 1749 PVBOXHDD pDisk = (PVBOXHDD)pvUser; 1999 PVDIMAGE pImage = (PVDIMAGE)pvUser; 2000 PVBOXHDD pDisk = pImage->pDisk; 2001 2002 LogFlowFunc(("pvUser=%#p pIoStorage=%#p uOffset=%llu pIoCtx=%#p cbWrite=%u\n", 2003 pvUser, pIoStorage, uOffset, pIoCtx, cbWrite)); 1750 2004 1751 2005 /* Build the S/G array and spawn a new I/O task */ … … 1757 2011 1758 2012 cbTaskWrite = RTSgBufSegArrayCreate(&pIoCtx->SgBuf, aSeg, &cSegments, cbWrite); 2013 2014 AssertMsg(cbTaskWrite <= cbWrite, ("Invalid number of bytes to write\n")); 2015 2016 LogFlow(("Writing %u bytes from %u segments\n", cbTaskWrite, cSegments)); 2017 2018 #ifdef DEBUG 2019 for (unsigned i = 0; i < cSegments; i++) 2020 AssertMsg(aSeg[i].pvSeg && !(aSeg[i].cbSeg % 512), 2021 ("Segment %u is invalid\n", i)); 2022 #endif 1759 2023 1760 2024 PVDIOTASK pIoTask = vdIoTaskUserAlloc(pDisk, pIoCtx, cbTaskWrite); … … 1796 2060 void *pvMetaUser) 1797 2061 { 1798 PVBOXHDD pDisk = (PVBOXHDD)pvUser; 2062 PVDIMAGE pImage = (PVDIMAGE)pvUser; 2063 PVBOXHDD pDisk = pImage->pDisk; 1799 2064 int rc = VINF_SUCCESS; 1800 2065 RTSGSEG Seg; … … 1802 2067 void *pvTask = NULL; 1803 2068 1804 pIoTask = vdIoTaskMetaAlloc(pDisk, pIoCtx, VDIOCTXTXDIR_READ, 2069 pIoTask = vdIoTaskMetaAlloc(pDisk, pIoCtx, VDIOCTXTXDIR_READ, pImage, 1805 2070 pfnMetaComplete, pvMetaUser); 1806 2071 if (!pIoTask) … … 1836 2101 void *pvMetaUser) 1837 2102 { 1838 PVBOXHDD pDisk = (PVBOXHDD)pvUser; 2103 PVDIMAGE pImage = (PVDIMAGE)pvUser; 2104 PVBOXHDD pDisk = pImage->pDisk; 1839 2105 int rc = VINF_SUCCESS; 1840 2106 RTSGSEG Seg; … … 1842 2108 void *pvTask = NULL; 1843 2109 1844 pIoTask = vdIoTaskMetaAlloc(pDisk, pIoCtx, VDIOCTXTXDIR_WRITE, 2110 pIoTask = vdIoTaskMetaAlloc(pDisk, pIoCtx, VDIOCTXTXDIR_WRITE, pImage, 1845 2111 pfnMetaComplete, pvMetaUser); 1846 2112 if (!pIoTask) … … 1873 2139 PVDIOCTX pIoCtx) 1874 2140 { 1875 PVBOXHDD pDisk = (PVBOXHDD)pvUser; 2141 PVDIMAGE pImage = (PVDIMAGE)pvUser; 2142 PVBOXHDD pDisk = pImage->pDisk; 1876 2143 int rc = VINF_SUCCESS; 1877 2144 PVDIOTASK pIoTask; 1878 2145 void *pvTask = NULL; 1879 2146 1880 pIoTask = vdIoTaskMetaAlloc(pDisk, pIoCtx, VDIOCTXTXDIR_FLUSH, 2147 pIoTask = vdIoTaskMetaAlloc(pDisk, pIoCtx, VDIOCTXTXDIR_FLUSH, pImage, 1881 2148 NULL, NULL); 1882 2149 if (!pIoTask) … … 2172 2439 pDisk->pInterfaceThreadSync = NULL; 2173 2440 pDisk->pInterfaceThreadSyncCallbacks = NULL; 2441 pDisk->fGrowing = false; 2442 RTListInit(&pDisk->ListWriteGrowing); 2174 2443 2175 2444 /* Create the I/O ctx cache */ … … 2192 2461 } 2193 2462 2463 /* Create critical section. */ 2464 rc = RTCritSectInit(&pDisk->CritSect); 2465 if (RT_FAILURE(rc)) 2466 { 2467 RTMemCacheDestroy(pDisk->hMemCacheIoCtx); 2468 RTMemCacheDestroy(pDisk->hMemCacheIoTask); 2469 RTMemFree(pDisk); 2470 break; 2471 } 2194 2472 2195 2473 pDisk->pInterfaceError = VDInterfaceGet(pVDIfsDisk, VDINTERFACETYPE_ERROR); … … 2247 2525 pDisk->VDIIOCallbacks.pfnIoCtxCopyTo = vdIOIoCtxCopyTo; 2248 2526 pDisk->VDIIOCallbacks.pfnIoCtxSet = vdIOIoCtxSet; 2249 2250 /* Set up the I/O interface. */2251 rc = VDInterfaceAdd(&pDisk->VDIIO, "VD_IO", VDINTERFACETYPE_IO,2252 &pDisk->VDIIOCallbacks, pDisk, &pDisk->pVDIfsDisk);2253 AssertRC(rc);2254 2527 2255 2528 *ppDisk = pDisk; … … 2436 2709 } 2437 2710 2711 pImage->pDisk = pDisk; 2438 2712 pImage->pVDIfsImage = pVDIfsImage; 2439 2713 … … 2447 2721 break; 2448 2722 } 2723 2724 /* Set up the I/O interface. */ 2725 rc = VDInterfaceAdd(&pImage->VDIIO, "VD_IO", VDINTERFACETYPE_IO, 2726 &pDisk->VDIIOCallbacks, pImage, &pImage->pVDIfsImage); 2727 AssertRC(rc); 2449 2728 2450 2729 pImage->uOpenFlags = uOpenFlags & VD_OPEN_FLAGS_HONOR_SAME; … … 2718 2997 break; 2719 2998 } 2999 pImage->pDisk = pDisk; 2720 3000 pImage->pVDIfsImage = pVDIfsImage; 3001 3002 /* Set up the I/O interface. */ 3003 rc = VDInterfaceAdd(&pImage->VDIIO, "VD_IO", VDINTERFACETYPE_IO, 3004 &pDisk->VDIIOCallbacks, pImage, &pImage->pVDIfsImage); 3005 AssertRC(rc); 2721 3006 2722 3007 rc = vdFindBackend(pszBackend, &pImage->Backend); … … 2961 3246 break; 2962 3247 } 3248 3249 pImage->pDisk = pDisk; 3250 pImage->pVDIfsImage = pVDIfsImage; 3251 3252 /* Set up the I/O interface. */ 3253 rc = VDInterfaceAdd(&pImage->VDIIO, "VD_IO", VDINTERFACETYPE_IO, 3254 &pDisk->VDIIOCallbacks, pImage, &pImage->pVDIfsImage); 3255 AssertRC(rc); 2963 3256 2964 3257 /* Create UUID if the caller didn't specify one. */ … … 5608 5901 cbRead, paSeg, cSeg, 5609 5902 pfnComplete, pvUser1, pvUser2, 5610 NULL );5903 NULL, vdReadHelperAsync); 5611 5904 if (!pIoCtx) 5612 5905 { … … 5615 5908 } 5616 5909 5617 PVDIMAGE pImage = pDisk->pLast; 5618 AssertPtrBreakStmt(pImage, rc = VERR_VD_NOT_OPENED); 5619 5620 rc = vdReadHelperAsync(pDisk, pImage, NULL, pIoCtx, uOffset, cbRead); 5910 pIoCtx->pImage = pDisk->pLast; 5911 AssertPtrBreakStmt(pIoCtx->pImage, rc = VERR_VD_NOT_OPENED); 5912 5913 rc = vdIoCtxProcess(pIoCtx); 5914 if (rc == VINF_VD_ASYNC_IO_FINISHED) 5915 { 5916 if (ASMAtomicCmpXchgBool(&pIoCtx->fComplete, true, false)) 5917 vdIoCtxFree(pDisk, pIoCtx); 5918 else 5919 rc = VERR_VD_ASYNC_IO_IN_PROGRESS; /* Let the other handler complete the request. */ 5920 } 5921 else if (rc != VERR_VD_ASYNC_IO_IN_PROGRESS) /* Another error */ 5922 vdIoCtxFree(pDisk, pIoCtx); 5923 5621 5924 } while (0); 5622 5925 5623 if (RT_UNLIKELY(fLockRead) )5926 if (RT_UNLIKELY(fLockRead) && (rc != VINF_VD_ASYNC_IO_FINISHED)) 5624 5927 { 5625 5928 rc2 = vdThreadFinishRead(pDisk); 5626 5929 AssertRC(rc2); 5627 }5628 5629 if (RT_SUCCESS(rc))5630 {5631 if ( !pIoCtx->cbTransferLeft5632 && !pIoCtx->cMetaTransfersPending5633 && ASMAtomicCmpXchgBool(&pIoCtx->fComplete, true, false))5634 {5635 vdIoCtxFree(pDisk, pIoCtx);5636 rc = VINF_VD_ASYNC_IO_FINISHED;5637 }5638 else5639 {5640 LogFlow(("cbTransferLeft=%u cMetaTransfersPending=%u fComplete=%RTbool\n",5641 pIoCtx->cbTransferLeft, pIoCtx->cMetaTransfersPending,5642 pIoCtx->fComplete));5643 rc = VERR_VD_ASYNC_IO_IN_PROGRESS;5644 }5645 5930 } 5646 5931 … … 5691 5976 cbWrite, paSeg, cSeg, 5692 5977 pfnComplete, pvUser1, pvUser2, 5693 NULL );5978 NULL, vdWriteHelperAsync); 5694 5979 if (!pIoCtx) 5695 5980 { … … 5700 5985 PVDIMAGE pImage = pDisk->pLast; 5701 5986 AssertPtrBreakStmt(pImage, rc = VERR_VD_NOT_OPENED); 5702 5703 rc = vdWriteHelperAsync(pDisk, pImage, NULL, pIoCtx, uOffset, cbWrite); 5704 5987 pIoCtx->pImage = pImage; 5988 5989 rc = vdIoCtxProcess(pIoCtx); 5990 if (rc == VINF_VD_ASYNC_IO_FINISHED) 5991 { 5992 if (ASMAtomicCmpXchgBool(&pIoCtx->fComplete, true, false)) 5993 vdIoCtxFree(pDisk, pIoCtx); 5994 else 5995 rc = VERR_VD_ASYNC_IO_IN_PROGRESS; /* Let the other handler complete the request. */ 5996 } 5997 else if (rc != VERR_VD_ASYNC_IO_IN_PROGRESS) /* Another error */ 5998 vdIoCtxFree(pDisk, pIoCtx); 5999 } while (0); 6000 6001 if (RT_UNLIKELY(fLockWrite) && RT_FAILURE(rc)) 6002 { 6003 rc2 = vdThreadFinishWrite(pDisk); 6004 AssertRC(rc2); 6005 } 6006 6007 LogFlowFunc(("returns %Rrc\n", rc)); 6008 return rc; 6009 } 6010 6011 6012 VBOXDDU_DECL(int) VDAsyncFlush(PVBOXHDD pDisk, PFNVDASYNCTRANSFERCOMPLETE pfnComplete, 6013 void *pvUser1, void *pvUser2) 6014 { 6015 int rc; 6016 int rc2; 6017 bool fLockWrite = false; 6018 PVDIOCTX pIoCtx = NULL; 6019 6020 LogFlowFunc(("pDisk=%#p\n", pDisk)); 6021 6022 do 6023 { 6024 /* sanity check */ 6025 AssertPtrBreakStmt(pDisk, rc = VERR_INVALID_PARAMETER); 6026 AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature)); 6027 6028 rc2 = vdThreadStartWrite(pDisk); 6029 AssertRC(rc2); 6030 fLockWrite = true; 6031 6032 pIoCtx = vdIoCtxRootAlloc(pDisk, VDIOCTXTXDIR_FLUSH, 0, 6033 0, NULL, 0, 6034 pfnComplete, pvUser1, pvUser2, 6035 NULL, vdFlushHelperAsync); 6036 if (!pIoCtx) 6037 { 6038 rc = VERR_NO_MEMORY; 6039 break; 6040 } 6041 6042 PVDIMAGE pImage = pDisk->pLast; 6043 AssertPtrBreakStmt(pImage, rc = VERR_VD_NOT_OPENED); 6044 pIoCtx->pImage = pImage; 6045 6046 rc = vdIoCtxProcess(pIoCtx); 5705 6047 } while (0); 5706 6048 … … 5733 6075 } 5734 6076 5735 5736 VBOXDDU_DECL(int) VDAsyncFlush(PVBOXHDD pDisk, PFNVDASYNCTRANSFERCOMPLETE pfnComplete,5737 void *pvUser1, void *pvUser2)5738 {5739 int rc;5740 int rc2;5741 bool fLockWrite = false;5742 PVDIOCTX pIoCtx = NULL;5743 5744 LogFlowFunc(("pDisk=%#p\n", pDisk));5745 5746 do5747 {5748 /* sanity check */5749 AssertPtrBreakStmt(pDisk, rc = VERR_INVALID_PARAMETER);5750 AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));5751 5752 rc2 = vdThreadStartWrite(pDisk);5753 AssertRC(rc2);5754 fLockWrite = true;5755 5756 pIoCtx = vdIoCtxRootAlloc(pDisk, VDIOCTXTXDIR_FLUSH, 0,5757 0, NULL, 0,5758 pfnComplete, pvUser1, pvUser2,5759 NULL);5760 if (!pIoCtx)5761 {5762 rc = VERR_NO_MEMORY;5763 break;5764 }5765 5766 PVDIMAGE pImage = pDisk->pLast;5767 AssertPtrBreakStmt(pImage, rc = VERR_VD_NOT_OPENED);5768 5769 vdResetModifiedFlag(pDisk);5770 rc = pImage->Backend->pfnAsyncFlush(pImage->pvBackendData, pIoCtx);5771 } while (0);5772 5773 if (RT_UNLIKELY(fLockWrite) && RT_FAILURE(rc))5774 {5775 rc2 = vdThreadFinishWrite(pDisk);5776 AssertRC(rc2);5777 }5778 5779 if (RT_SUCCESS(rc))5780 {5781 if ( !pIoCtx->cbTransferLeft5782 && !pIoCtx->cMetaTransfersPending5783 && ASMAtomicCmpXchgBool(&pIoCtx->fComplete, true, false))5784 {5785 vdIoCtxFree(pDisk, pIoCtx);5786 rc = VINF_VD_ASYNC_IO_FINISHED;5787 }5788 else5789 {5790 LogFlow(("cbTransferLeft=%u cMetaTransfersPending=%u fComplete=%RTbool\n",5791 pIoCtx->cbTransferLeft, pIoCtx->cMetaTransfersPending,5792 pIoCtx->fComplete));5793 rc = VERR_VD_ASYNC_IO_IN_PROGRESS;5794 }5795 }5796 5797 LogFlowFunc(("returns %Rrc\n", rc));5798 return rc;5799 }5800 5801 6077 #if 0 5802 6078 /** @copydoc VBOXHDDBACKEND::pfnComposeLocation */ -
trunk/src/VBox/Devices/Storage/VDICore.h
r27808 r28620 586 586 /** Pointer to the per-disk VD interface list. */ 587 587 PVDINTERFACE pVDIfsDisk; 588 /** Pointer to the per-image VD interface list. */ 589 PVDINTERFACE pVDIfsImage; 588 590 /** Error interface. */ 589 591 PVDINTERFACE pInterfaceError; -
trunk/src/VBox/Devices/Storage/VDIHDDCore.cpp
r28383 r28620 541 541 #ifdef VBOX_WITH_NEW_IO_CODE 542 542 /* Try to get I/O interface. */ 543 pImage->pInterfaceIO = VDInterfaceGet(pImage->pVDIfs Disk, VDINTERFACETYPE_IO);543 pImage->pInterfaceIO = VDInterfaceGet(pImage->pVDIfsImage, VDINTERFACETYPE_IO); 544 544 AssertPtr(pImage->pInterfaceIO); 545 545 pImage->pInterfaceIOCallbacks = VDGetInterfaceIO(pImage->pInterfaceIO); … … 727 727 #ifdef VBOX_WITH_NEW_IO_CODE 728 728 /* Try to get I/O interface. */ 729 pImage->pInterfaceIO = VDInterfaceGet(pImage->pVDIfs Disk, VDINTERFACETYPE_IO);729 pImage->pInterfaceIO = VDInterfaceGet(pImage->pVDIfsImage, VDINTERFACETYPE_IO); 730 730 AssertPtr(pImage->pInterfaceIO); 731 731 pImage->pInterfaceIOCallbacks = VDGetInterfaceIO(pImage->pInterfaceIO); … … 1071 1071 pImage->paBlocks = NULL; 1072 1072 pImage->pVDIfsDisk = pVDIfsDisk; 1073 pImage->pVDIfsImage = pVDIfsImage; 1073 1074 1074 1075 rc = vdiOpenImage(pImage, uOpenFlags); … … 1149 1150 pImage->paBlocks = NULL; 1150 1151 pImage->pVDIfsDisk = pVDIfsDisk; 1152 pImage->pVDIfsImage = pVDIfsImage; 1151 1153 1152 1154 rc = vdiCreateImage(pImage, cbSize, uImageFlags, pszComment, -
trunk/src/VBox/Devices/Storage/VHDHDDCore.cpp
r27808 r28620 144 144 /** Pointer to the per-disk VD interface list. */ 145 145 PVDINTERFACE pVDIfsDisk; 146 /** Pointer to the per-image VD interface list. */ 147 PVDINTERFACE pVDIfsImage; 146 148 /** Error interface. */ 147 149 PVDINTERFACE pInterfaceError; … … 581 583 #ifdef VBOX_WITH_NEW_IO_CODE 582 584 /* Try to get async I/O interface. */ 583 pImage->pInterfaceIO = VDInterfaceGet(pImage->pVDIfs Disk, VDINTERFACETYPE_IO);585 pImage->pInterfaceIO = VDInterfaceGet(pImage->pVDIfsImage, VDINTERFACETYPE_IO); 584 586 AssertPtr(pImage->pInterfaceIO); 585 587 pImage->pInterfaceIOCallbacks = VDGetInterfaceIO(pImage->pInterfaceIO); … … 684 686 #endif 685 687 pImage->pVDIfsDisk = pVDIfsDisk; 688 pImage->pVDIfsImage = pVDIfsImage; 686 689 687 690 rc = vhdOpenImage(pImage, uOpenFlags); … … 1972 1975 #endif 1973 1976 pImage->pVDIfsDisk = pVDIfsDisk; 1977 pImage->pVDIfsImage = pVDIfsImage; 1974 1978 1975 1979 #ifdef VBOX_WITH_NEW_IO_CODE -
trunk/src/VBox/Devices/Storage/VmdkHDDCore.cpp
r27977 r28620 423 423 /** Pointer to the per-disk VD interface list. */ 424 424 PVDINTERFACE pVDIfsDisk; 425 /** Pointer to the per-image VD interface list. */ 426 PVDINTERFACE pVDIfsImage; 425 427 426 428 /** Error interface. */ … … 786 788 if (pVmdkFile->fAsyncIO) 787 789 return pImage->pInterfaceIOCallbacks->pfnFlushSync(pImage->pInterfaceIO->pvUser, 788 790 pVmdkFile->pStorage); 789 791 else 790 792 return RTFileFlush(pVmdkFile->File); 791 793 #else 792 794 return pImage->pInterfaceIOCallbacks->pfnFlushSync(pImage->pInterfaceIO->pvUser, 793 795 pVmdkFile->pStorage); 794 796 #endif 797 } 798 799 800 DECLINLINE(int) vmdkFileFlushAsync(PVMDKFILE pVmdkFile, PVDIOCTX pIoCtx) 801 { 802 PVMDKIMAGE pImage = pVmdkFile->pImage; 803 804 return pImage->pInterfaceIOCallbacks->pfnFlushAsync(pImage->pInterfaceIO->pvUser, 805 pVmdkFile->pStorage, pIoCtx); 795 806 } 796 807 … … 2536 2547 2537 2548 /** 2549 * Internal: write/update the descriptor part of the image - async version. 2550 */ 2551 static int vmdkWriteDescriptorAsync(PVMDKIMAGE pImage, PVDIOCTX pIoCtx) 2552 { 2553 int rc = VINF_SUCCESS; 2554 uint64_t cbLimit; 2555 uint64_t uOffset; 2556 PVMDKFILE pDescFile; 2557 2558 if (pImage->pDescData) 2559 { 2560 /* Separate descriptor file. */ 2561 uOffset = 0; 2562 cbLimit = 0; 2563 pDescFile = pImage->pFile; 2564 } 2565 else 2566 { 2567 /* Embedded descriptor file. */ 2568 uOffset = VMDK_SECTOR2BYTE(pImage->pExtents[0].uDescriptorSector); 2569 cbLimit = VMDK_SECTOR2BYTE(pImage->pExtents[0].cDescriptorSectors); 2570 pDescFile = pImage->pExtents[0].pFile; 2571 } 2572 /* Bail out if there is no file to write to. */ 2573 if (pDescFile == NULL) 2574 return VERR_INVALID_PARAMETER; 2575 2576 /* 2577 * Allocate temporary descriptor buffer. 2578 * In case there is no limit allocate a default 2579 * and increase if required. 2580 */ 2581 size_t cbDescriptor = cbLimit ? cbLimit : 4 * _1K; 2582 char *pszDescriptor = (char *)RTMemAllocZ(cbDescriptor); 2583 unsigned offDescriptor = 0; 2584 2585 if (!pszDescriptor) 2586 return VERR_NO_MEMORY; 2587 2588 for (unsigned i = 0; i < pImage->Descriptor.cLines; i++) 2589 { 2590 const char *psz = pImage->Descriptor.aLines[i]; 2591 size_t cb = strlen(psz); 2592 2593 /* 2594 * Increase the descriptor if there is no limit and 2595 * there is not enough room left for this line. 2596 */ 2597 if (offDescriptor + cb + 1 > cbDescriptor) 2598 { 2599 if (cbLimit) 2600 { 2601 rc = vmdkError(pImage, VERR_BUFFER_OVERFLOW, RT_SRC_POS, N_("VMDK: descriptor too long in '%s'"), pImage->pszFilename); 2602 break; 2603 } 2604 else 2605 { 2606 char *pszDescriptorNew = NULL; 2607 LogFlow(("Increasing descriptor cache\n")); 2608 2609 pszDescriptorNew = (char *)RTMemRealloc(pszDescriptor, cbDescriptor + cb + 4 * _1K); 2610 if (!pszDescriptorNew) 2611 { 2612 rc = VERR_NO_MEMORY; 2613 break; 2614 } 2615 pszDescriptorNew = pszDescriptor; 2616 cbDescriptor += cb + 4 * _1K; 2617 } 2618 } 2619 2620 if (cb > 0) 2621 { 2622 memcpy(pszDescriptor + offDescriptor, psz, cb); 2623 offDescriptor += cb; 2624 } 2625 2626 memcpy(pszDescriptor + offDescriptor, "\n", 1); 2627 offDescriptor++; 2628 } 2629 2630 if (RT_SUCCESS(rc)) 2631 { 2632 rc = vmdkFileWriteAt(pDescFile, uOffset, pszDescriptor, cbLimit ? cbLimit : offDescriptor, NULL); 2633 if (RT_FAILURE(rc)) 2634 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error writing descriptor in '%s'"), pImage->pszFilename); 2635 } 2636 2637 if (RT_SUCCESS(rc) && !cbLimit) 2638 { 2639 rc = vmdkFileSetSize(pDescFile, offDescriptor); 2640 if (RT_FAILURE(rc)) 2641 rc = vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error truncating descriptor in '%s'"), pImage->pszFilename); 2642 } 2643 2644 if (RT_SUCCESS(rc)) 2645 pImage->Descriptor.fDirty = false; 2646 2647 RTMemFree(pszDescriptor); 2648 return rc; 2649 } 2650 2651 /** 2538 2652 * Internal: validate the consistency check values in a binary header. 2539 2653 */ … … 2974 3088 2975 3089 /* Try to get async I/O interface. */ 2976 pImage->pInterfaceIO = VDInterfaceGet(pImage->pVDIfs Disk, VDINTERFACETYPE_IO);3090 pImage->pInterfaceIO = VDInterfaceGet(pImage->pVDIfsImage, VDINTERFACETYPE_IO); 2977 3091 if (pImage->pInterfaceIO) 2978 3092 pImage->pInterfaceIOCallbacks = VDGetInterfaceIO(pImage->pInterfaceIO); … … 3843 3957 3844 3958 /* Try to get async I/O interface. */ 3845 pImage->pInterfaceIO = VDInterfaceGet(pImage->pVDIfs Disk, VDINTERFACETYPE_IO);3959 pImage->pInterfaceIO = VDInterfaceGet(pImage->pVDIfsImage, VDINTERFACETYPE_IO); 3846 3960 if (pImage->pInterfaceIO) 3847 3961 pImage->pInterfaceIOCallbacks = VDGetInterfaceIO(pImage->pInterfaceIO); … … 4117 4231 && !(pExtent->pszBasename[0] == RTPATH_SLASH)) 4118 4232 rc = vmdkFileFlush(pExtent->pFile); 4233 break; 4234 case VMDKETYPE_ZERO: 4235 /* No need to do anything for this extent. */ 4236 break; 4237 default: 4238 AssertMsgFailed(("unknown extent type %d\n", pExtent->enmType)); 4239 break; 4240 } 4241 } 4242 4243 out: 4244 return rc; 4245 } 4246 4247 /** 4248 * Internal. Flush image data (and metadata) to disk - async version. 4249 */ 4250 static int vmdkFlushImageAsync(PVMDKIMAGE pImage, PVDIOCTX pIoCtx) 4251 { 4252 PVMDKEXTENT pExtent; 4253 int rc = VINF_SUCCESS; 4254 4255 /* Update descriptor if changed. */ 4256 if (pImage->Descriptor.fDirty) 4257 { 4258 rc = vmdkWriteDescriptor(pImage); 4259 if (RT_FAILURE(rc)) 4260 goto out; 4261 } 4262 4263 for (unsigned i = 0; i < pImage->cExtents; i++) 4264 { 4265 pExtent = &pImage->pExtents[i]; 4266 if (pExtent->pFile != NULL && pExtent->fMetaDirty) 4267 { 4268 switch (pExtent->enmType) 4269 { 4270 case VMDKETYPE_HOSTED_SPARSE: 4271 AssertMsgFailed(("Async I/O not supported for sparse images\n")); 4272 break; 4273 #ifdef VBOX_WITH_VMDK_ESX 4274 case VMDKETYPE_ESX_SPARSE: 4275 /** @todo update the header. */ 4276 break; 4277 #endif /* VBOX_WITH_VMDK_ESX */ 4278 case VMDKETYPE_VMFS: 4279 case VMDKETYPE_FLAT: 4280 /* Nothing to do. */ 4281 break; 4282 case VMDKETYPE_ZERO: 4283 default: 4284 AssertMsgFailed(("extent with type %d marked as dirty\n", 4285 pExtent->enmType)); 4286 break; 4287 } 4288 } 4289 switch (pExtent->enmType) 4290 { 4291 case VMDKETYPE_HOSTED_SPARSE: 4292 #ifdef VBOX_WITH_VMDK_ESX 4293 case VMDKETYPE_ESX_SPARSE: 4294 #endif /* VBOX_WITH_VMDK_ESX */ 4295 case VMDKETYPE_VMFS: 4296 case VMDKETYPE_FLAT: 4297 /** @todo implement proper path absolute check. */ 4298 if ( pExtent->pFile != NULL 4299 && !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY) 4300 && !(pExtent->pszBasename[0] == RTPATH_SLASH)) 4301 rc = vmdkFileFlushAsync(pExtent->pFile, pIoCtx); 4119 4302 break; 4120 4303 case VMDKETYPE_ZERO: … … 4522 4705 pImage->pDescData = NULL; 4523 4706 pImage->pVDIfsDisk = pVDIfsDisk; 4707 pImage->pVDIfsImage = pVDIfsDisk; 4524 4708 /** @todo speed up this test open (VD_OPEN_FLAGS_INFO) by skipping as 4525 4709 * much as possible in vmdkOpenImage. */ … … 4572 4756 pImage->pDescData = NULL; 4573 4757 pImage->pVDIfsDisk = pVDIfsDisk; 4758 pImage->pVDIfsImage = pVDIfsImage; 4574 4759 4575 4760 rc = vmdkOpenImage(pImage, uOpenFlags);
Note:
See TracChangeset
for help on using the changeset viewer.