Changeset 10715 in vbox for trunk/src/VBox/Devices/Storage
- Timestamp:
- Jul 16, 2008 10:38:23 PM (17 years ago)
- svn:sync-xref-src-repo-rev:
- 33435
- Location:
- trunk/src/VBox/Devices/Storage
- Files:
-
- 9 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Storage/DrvBlock.cpp
r8529 r10715 260 260 261 261 /** @copydoc PDMIBLOCKASYNC::pfnRead */ 262 static DECLCALLBACK(int) drvblockAsyncReadStart(PPDMIBLOCKASYNC pInterface, uint64_t off, PPDM IDATATRANSPORTSEG pSeg, unsigned cSeg, size_t cbRead, void *pvUser)262 static DECLCALLBACK(int) drvblockAsyncReadStart(PPDMIBLOCKASYNC pInterface, uint64_t off, PPDMDATASEG pSeg, unsigned cSeg, size_t cbRead, void *pvUser) 263 263 { 264 264 PDRVBLOCK pData = PDMIBLOCKASYNC_2_DRVBLOCK(pInterface); … … 279 279 280 280 /** @copydoc PDMIBLOCKASYNC::pfnWrite */ 281 static DECLCALLBACK(int) drvblockAsyncWriteStart(PPDMIBLOCKASYNC pInterface, uint64_t off, PPDM IDATATRANSPORTSEG pSeg, unsigned cSeg, size_t cbWrite, void *pvUser)281 static DECLCALLBACK(int) drvblockAsyncWriteStart(PPDMIBLOCKASYNC pInterface, uint64_t off, PPDMDATASEG pSeg, unsigned cSeg, size_t cbWrite, void *pvUser) 282 282 { 283 283 PDRVBLOCK pData = PDMIBLOCKASYNC_2_DRVBLOCK(pInterface); … … 302 302 #define PDMIMEDIAASYNCPORT_2_DRVBLOCK(pInterface) ( (PDRVBLOCK((uintptr_t)pInterface - RT_OFFSETOF(DRVBLOCK, IMediaAsyncPort))) ) 303 303 304 305 static DECLCALLBACK(int) drvblockAsyncReadCompleteNotify(PPDMIMEDIAASYNCPORT pInterface, uint64_t uOffset, PPDMIDATATRANSPORTSEG pSeg, unsigned cSeg, size_t cbRead, void *pvUser) 304 static DECLCALLBACK(int) drvblockAsyncTransferCompleteNotify(PPDMIMEDIAASYNCPORT pInterface, void *pvUser) 306 305 { 307 306 PDRVBLOCK pData = PDMIMEDIAASYNCPORT_2_DRVBLOCK(pInterface); 308 307 309 return pData->pDrvBlockAsyncPort->pfnReadCompleteNotify(pData->pDrvBlockAsyncPort, uOffset, pSeg, cSeg, cbRead, pvUser); 310 } 311 312 static DECLCALLBACK(int) drvblockAsyncWriteCompleteNotify(PPDMIMEDIAASYNCPORT pInterface, uint64_t uOffset, PPDMIDATATRANSPORTSEG pSeg, unsigned cSeg, size_t cbWritten, void *pvUser) 313 { 314 PDRVBLOCK pData = PDMIMEDIAASYNCPORT_2_DRVBLOCK(pInterface); 315 316 #ifdef VBOX_PERIODIC_FLUSH 317 if (pData->cbFlushInterval) 318 { 319 pData->cbDataWritten += cbWritten; 320 if (pData->cbDataWritten > pData->cbFlushInterval) 321 { 322 pData->cbDataWritten = 0; 323 pData->pDrvMedia->pfnFlush(pData->pDrvMedia); 324 } 325 } 326 #endif /* VBOX_PERIODIC_FLUSH */ 327 328 return pData->pDrvBlockAsyncPort->pfnWriteCompleteNotify(pData->pDrvBlockAsyncPort, uOffset, pSeg, cSeg, cbWritten, pvUser); 308 return pData->pDrvBlockAsyncPort->pfnTransferCompleteNotify(pData->pDrvBlockAsyncPort, pvUser); 329 309 } 330 310 … … 678 658 return pData->pDrvMediaAsync ? &pData->IBlockAsync : NULL; 679 659 case PDMINTERFACE_MEDIA_ASYNC_PORT: 680 return &pData->IMediaAsyncPort;660 return pData->pDrvBlockAsyncPort ? &pData->IMediaAsyncPort : NULL; 681 661 default: 682 662 return NULL; … … 771 751 772 752 /* IMediaAsyncPort. */ 773 pData->IMediaAsyncPort.pfnReadCompleteNotify = drvblockAsyncReadCompleteNotify; 774 pData->IMediaAsyncPort.pfnWriteCompleteNotify = drvblockAsyncWriteCompleteNotify; 753 pData->IMediaAsyncPort.pfnTransferCompleteNotify = drvblockAsyncTransferCompleteNotify; 775 754 776 755 /* -
trunk/src/VBox/Devices/Storage/DrvVD.cpp
r8155 r10715 34 34 #include <iprt/file.h> 35 35 #include <iprt/string.h> 36 #include <iprt/cache.h> 36 37 37 38 #include "Builtins.h" … … 54 55 ( PDMINS2DATA(PDMIBASE_2_DRVINS(pInterface), PVBOXDISK) ) 55 56 57 /** Converts a pointer to VBOXDISK::IMediaAsync to a PVBOXDISK. */ 58 #define PDMIMEDIAASYNC_2_VBOXDISK(pInterface) \ 59 ( (PVBOXDISK)((uintptr_t)pInterface - RT_OFFSETOF(VBOXDISK, IMediaAsync)) ) 60 61 /** Converts a pointer to VBOXDISK::ITransportAsyncPort to a PVBOXDISK. */ 62 #define PDMITRANSPORTASYNCPORT_2_VBOXDISK(pInterface) \ 63 ( (PVBOXDISK)((uintptr_t)pInterface - RT_OFFSETOF(VBOXDISK, ITransportAsyncPort)) ) 64 65 /** 66 * Structure for an async I/O task. 67 */ 68 typedef struct DRVVDASYNCTASK 69 { 70 /** Callback which is called on completion. */ 71 PFNVDCOMPLETED pfnCompleted; 72 /** Opqaue user data which is passed on completion. */ 73 void *pvUser; 74 /** Opaque user data the caller passed on transfer initiation. */ 75 void *pvUserCaller; 76 } DRVVDASYNCTASK, *PDRVVDASYNCTASK; 56 77 57 78 /** … … 61 82 { 62 83 /** The VBox disk container. */ 63 PVBOXHDD pDisk;84 PVBOXHDD pDisk; 64 85 /** The media interface. */ 65 PDMIMEDIA IMedia;86 PDMIMEDIA IMedia; 66 87 /** Pointer to the driver instance. */ 67 PPDMDRVINS pDrvIns;88 PPDMDRVINS pDrvIns; 68 89 /** Flag whether suspend has changed image open mode to read only. */ 69 bool fTempReadOnly; 90 bool fTempReadOnly; 91 /** Common structure for the supported error interface. */ 92 VDINTERFACE VDIError; 93 /** Callback table for error interface. */ 94 VDINTERFACEERROR VDIErrorCallbacks; 95 /** Common structure for the supported async I/O interface. */ 96 VDINTERFACE VDIAsyncIO; 97 /** Callback table for async I/O interface. */ 98 VDINTERFACEASYNCIO VDIAsyncIOCallbacks; 99 /** Flag whether opened disk suppports async I/O operations. */ 100 bool fAsyncIOSupported; 101 /** The async media interface. */ 102 PDMIMEDIAASYNC IMediaAsync; 103 /** The async media port interface above. */ 104 PPDMIMEDIAASYNCPORT pDrvMediaAsyncPort; 105 /** Pointer to the asynchronous media driver below. */ 106 PPDMITRANSPORTASYNC pDrvTransportAsync; 107 /** Async transport port interface. */ 108 PDMITRANSPORTASYNCPORT ITransportAsyncPort; 109 /** Our cache to reduce allocation overhead. */ 110 PRTOBJCACHE pCache; 70 111 } VBOXDISK, *PVBOXDISK; 71 112 … … 79 120 PPDMDRVINS pDrvIns = (PPDMDRVINS)pvUser; 80 121 pDrvIns->pDrvHlp->pfnVMSetErrorV(pDrvIns, rc, RT_SRC_POS_ARGS, pszFormat, va); 122 } 123 124 /******************************************************************************* 125 * VD Async I/O interface implementation * 126 *******************************************************************************/ 127 128 static DECLCALLBACK(int) drvvdAsyncIOOpen(void *pvUser, const char *pszLocation, bool fReadonly, void **ppStorage) 129 { 130 PVBOXDISK pDrvVD = (PVBOXDISK)pvUser; 131 132 return pDrvVD->pDrvTransportAsync->pfnOpen(pDrvVD->pDrvTransportAsync, pszLocation, fReadonly, ppStorage); 133 } 134 135 static DECLCALLBACK(int) drvvdAsyncIOClose(void *pvUser, void *pStorage) 136 { 137 PVBOXDISK pDrvVD = (PVBOXDISK)pvUser; 138 139 AssertMsg(pDrvVD->pDrvTransportAsync, ("Asynchronous function called but no async transport interface below\n")); 140 141 return pDrvVD->pDrvTransportAsync->pfnClose(pDrvVD->pDrvTransportAsync, pStorage); 142 } 143 144 static DECLCALLBACK(int) drvvdAsyncIORead(void *pvUser, void *pStorage, uint64_t uOffset, 145 size_t cbRead, void *pvBuf, size_t *pcbRead) 146 { 147 PVBOXDISK pDrvVD = (PVBOXDISK)pvUser; 148 149 AssertMsg(pDrvVD->pDrvTransportAsync, ("Asynchronous function called but no async transport interface below\n")); 150 151 return pDrvVD->pDrvTransportAsync->pfnReadSynchronous(pDrvVD->pDrvTransportAsync, 152 pStorage, 153 uOffset, pvBuf, cbRead, pcbRead); 154 } 155 156 static DECLCALLBACK(int) drvvdAsyncIOWrite(void *pvUser, void *pStorage, uint64_t uOffset, 157 size_t cbWrite, const void *pvBuf, size_t *pcbWritten) 158 { 159 PVBOXDISK pDrvVD = (PVBOXDISK)pvUser; 160 161 AssertMsg(pDrvVD->pDrvTransportAsync, ("Asynchronous function called but no async transport interface below\n")); 162 163 return pDrvVD->pDrvTransportAsync->pfnWriteSynchronous(pDrvVD->pDrvTransportAsync, 164 pStorage, 165 uOffset, pvBuf, cbWrite, pcbWritten); 166 } 167 168 static DECLCALLBACK(int) drvvdAsyncIOFlush(void *pvUser, void *pStorage) 169 { 170 PVBOXDISK pDrvVD = (PVBOXDISK)pvUser; 171 172 AssertMsg(pDrvVD->pDrvTransportAsync, ("Asynchronous function called but no async transport interface below\n")); 173 174 return pDrvVD->pDrvTransportAsync->pfnFlushSynchronous(pDrvVD->pDrvTransportAsync, pStorage); 175 } 176 177 static DECLCALLBACK(int) drvvdAsyncIOPrepareRead(void *pvUser, void *pStorage, uint64_t uOffset, void *pvBuf, size_t cbRead, void **ppTask) 178 { 179 PVBOXDISK pDrvVD = (PVBOXDISK)pvUser; 180 181 AssertMsg(pDrvVD->pDrvTransportAsync, ("Asynchronous function called but no async transport interface below\n")); 182 183 return pDrvVD->pDrvTransportAsync->pfnPrepareRead(pDrvVD->pDrvTransportAsync, pStorage, uOffset, pvBuf, cbRead, ppTask); 184 } 185 186 static DECLCALLBACK(int) drvvdAsyncIOPrepareWrite(void *pvUser, void *pStorage, uint64_t uOffset, void *pvBuf, size_t cbWrite, void **ppTask) 187 { 188 PVBOXDISK pDrvVD = (PVBOXDISK)pvUser; 189 190 AssertMsg(pDrvVD->pDrvTransportAsync, ("Asynchronous function called but no async transport interface below\n")); 191 192 return pDrvVD->pDrvTransportAsync->pfnPrepareWrite(pDrvVD->pDrvTransportAsync, pStorage, uOffset, pvBuf, cbWrite, ppTask); 193 } 194 195 static DECLCALLBACK(int) drvvdAsyncIOTasksSubmit(void *pvUser, void *apTasks[], unsigned cTasks, void *pvUser2, 196 void *pvUserCaller, PFNVDCOMPLETED pfnTasksCompleted) 197 { 198 PVBOXDISK pDrvVD = (PVBOXDISK)pvUser; 199 PDRVVDASYNCTASK pDrvVDAsyncTask; 200 int rc; 201 202 AssertMsg(pDrvVD->pDrvTransportAsync, ("Asynchronous function called but no async transport interface below\n")); 203 204 rc = RTCacheRequest(pDrvVD->pCache, (void **)&pDrvVDAsyncTask); 205 206 if (RT_FAILURE(rc)) 207 return rc; 208 209 pDrvVDAsyncTask->pfnCompleted = pfnTasksCompleted; 210 pDrvVDAsyncTask->pvUser = pvUser2; 211 pDrvVDAsyncTask->pvUserCaller = pvUserCaller; 212 213 return pDrvVD->pDrvTransportAsync->pfnTasksSubmit(pDrvVD->pDrvTransportAsync, apTasks, cTasks, pDrvVDAsyncTask); 81 214 } 82 215 … … 213 346 } 214 347 348 /******************************************************************************* 349 * Async Media interface methods * 350 *******************************************************************************/ 351 352 static DECLCALLBACK(int) drvvdStartRead(PPDMIMEDIAASYNC pInterface, uint64_t uOffset, 353 PPDMDATASEG paSeg, unsigned cSeg, 354 size_t cbRead, void *pvUser) 355 { 356 LogFlow(("%s: uOffset=%#llx paSeg=%#p cSeg=%u cbRead=%d\n pvUser=%#p", __FUNCTION__, 357 uOffset, paSeg, cSeg, cbRead, pvUser)); 358 PVBOXDISK pData = PDMIMEDIAASYNC_2_VBOXDISK(pInterface); 359 int rc = VDAsyncRead(pData->pDisk, uOffset, cbRead, paSeg, cSeg, pvUser); 360 LogFlow(("%s: returns %Vrc\n", __FUNCTION__, rc)); 361 return rc; 362 } 363 364 static DECLCALLBACK(int) drvvdStartWrite(PPDMIMEDIAASYNC pInterface, uint64_t uOffset, 365 PPDMDATASEG paSeg, unsigned cSeg, 366 size_t cbWrite, void *pvUser) 367 { 368 LogFlow(("%s: uOffset=%#llx paSeg=%#p cSeg=%u cbWrite=%d\n pvUser=%#p", __FUNCTION__, 369 uOffset, paSeg, cSeg, cbWrite, pvUser)); 370 PVBOXDISK pData = PDMIMEDIAASYNC_2_VBOXDISK(pInterface); 371 int rc = VDAsyncWrite(pData->pDisk, uOffset, cbWrite, paSeg, cSeg, pvUser); 372 LogFlow(("%s: returns %Vrc\n", __FUNCTION__, rc)); 373 return rc; 374 } 375 376 /******************************************************************************* 377 * Async transport port interface methods * 378 *******************************************************************************/ 379 380 static DECLCALLBACK(int) drvvdTasksCompleteNotify(PPDMITRANSPORTASYNCPORT pInterface, void *pvUser) 381 { 382 PVBOXDISK pData = PDMITRANSPORTASYNCPORT_2_VBOXDISK(pInterface); 383 PDRVVDASYNCTASK pDrvVDAsyncTask = (PDRVVDASYNCTASK)pvUser; 384 int rc = VINF_VDI_ASYNC_IO_FINISHED; 385 386 /* Having a completion callback for a task is not mandatory. */ 387 if (pDrvVDAsyncTask->pfnCompleted) 388 rc = pDrvVDAsyncTask->pfnCompleted(pDrvVDAsyncTask->pvUser); 389 390 /* Check if the request is finished. */ 391 if (rc == VINF_VDI_ASYNC_IO_FINISHED) 392 { 393 rc = pData->pDrvMediaAsyncPort->pfnTransferCompleteNotify(pData->pDrvMediaAsyncPort, pDrvVDAsyncTask->pvUserCaller); 394 } 395 else if (rc == VERR_VDI_ASYNC_IO_IN_PROGRESS) 396 rc = VINF_SUCCESS; 397 398 rc = RTCacheInsert(pData->pCache, pDrvVDAsyncTask); 399 AssertRC(rc); 400 401 return rc; 402 } 403 215 404 216 405 /******************************************************************************* … … 230 419 case PDMINTERFACE_MEDIA: 231 420 return &pData->IMedia; 421 case PDMINTERFACE_MEDIA_ASYNC: 422 return pData->fAsyncIOSupported ? &pData->IMediaAsync : NULL; 423 case PDMINTERFACE_TRANSPORT_ASYNC_PORT: 424 return &pData->ITransportAsyncPort; 232 425 default: 233 426 return NULL; … … 282 475 pData->IMedia.pfnGetUuid = drvvdGetUuid; 283 476 477 /* IMediaAsync */ 478 pData->IMediaAsync.pfnStartRead = drvvdStartRead; 479 pData->IMediaAsync.pfnStartWrite = drvvdStartWrite; 480 481 /* ITransportAsyncPort */ 482 pData->ITransportAsyncPort.pfnTaskCompleteNotify = drvvdTasksCompleteNotify; 483 484 /* Initialize supported VD interfaces. */ 485 pData->VDIErrorCallbacks.cbSize = sizeof(VDINTERFACEERROR); 486 pData->VDIErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR; 487 pData->VDIErrorCallbacks.pfnError = drvvdErrorCallback; 488 489 rc = VDInterfaceCreate(&pData->VDIError, "DrvVD_VDIError", VDINTERFACETYPE_ERROR, 490 &pData->VDIErrorCallbacks, pData, NULL); 491 AssertRC(rc); 492 493 pData->VDIAsyncIOCallbacks.cbSize = sizeof(VDINTERFACEASYNCIO); 494 pData->VDIAsyncIOCallbacks.enmInterface = VDINTERFACETYPE_ASYNCIO; 495 pData->VDIAsyncIOCallbacks.pfnOpen = drvvdAsyncIOOpen; 496 pData->VDIAsyncIOCallbacks.pfnClose = drvvdAsyncIOClose; 497 pData->VDIAsyncIOCallbacks.pfnRead = drvvdAsyncIORead; 498 pData->VDIAsyncIOCallbacks.pfnWrite = drvvdAsyncIOWrite; 499 pData->VDIAsyncIOCallbacks.pfnFlush = drvvdAsyncIOFlush; 500 pData->VDIAsyncIOCallbacks.pfnPrepareRead = drvvdAsyncIOPrepareRead; 501 pData->VDIAsyncIOCallbacks.pfnPrepareWrite = drvvdAsyncIOPrepareWrite; 502 pData->VDIAsyncIOCallbacks.pfnTasksSubmit = drvvdAsyncIOTasksSubmit; 503 504 rc = VDInterfaceCreate(&pData->VDIAsyncIO, "DrvVD_AsyncIO", VDINTERFACETYPE_ASYNCIO, 505 &pData->VDIAsyncIOCallbacks, pData, &pData->VDIError); 506 AssertRC(rc); 507 508 /* Try to attach async media port interface above.*/ 509 pData->pDrvMediaAsyncPort = (PPDMIMEDIAASYNCPORT)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMINTERFACE_MEDIA_ASYNC_PORT); 510 511 /* 512 * Attach the async transport driver below of the device above us implements the 513 * async interface. 514 */ 515 if (pData->pDrvMediaAsyncPort) 516 { 517 /* Try to attach the driver. */ 518 PPDMIBASE pBase; 519 520 rc = pDrvIns->pDrvHlp->pfnAttach(pDrvIns, &pBase); 521 if (rc == VERR_PDM_NO_ATTACHED_DRIVER) 522 { 523 /* 524 * Though the device supports async I/O the backend seems to not support it. 525 * Revert to non async I/O. 526 */ 527 pData->pDrvMediaAsyncPort = NULL; 528 } 529 else if (VBOX_FAILURE(rc)) 530 { 531 AssertMsgFailed(("Failed to attach async transport driver below rc=%Vrc\n", rc)); 532 } 533 else 534 { 535 /* Success query the async transport interface. */ 536 pData->pDrvTransportAsync = (PPDMITRANSPORTASYNC)pBase->pfnQueryInterface(pBase, PDMINTERFACE_TRANSPORT_ASYNC); 537 if (!pData->pDrvTransportAsync) 538 { 539 /* Whoops. */ 540 AssertMsgFailed(("Configuration error: No async transport interface below!\n")); 541 return VERR_PDM_MISSING_INTERFACE_ABOVE; 542 543 } 544 } 545 } 546 284 547 /* 285 548 * Validate configuration and find all parent images. … … 325 588 if (VBOX_SUCCESS(rc)) 326 589 { 327 rc = VDCreate( drvvdErrorCallback, pDrvIns, &pData->pDisk);590 rc = VDCreate(&pData->VDIAsyncIO, &pData->pDisk); 328 591 /* Error message is already set correctly. */ 329 592 } … … 388 651 if (fHonorZeroWrites) 389 652 uOpenFlags |= VD_OPEN_FLAGS_HONOR_ZEROES; 653 if (pData->pDrvMediaAsyncPort) 654 uOpenFlags |= VD_OPEN_FLAGS_ASYNC_IO; 655 656 /** Try to open backend in asyc I/O mode first. */ 390 657 rc = VDOpen(pData->pDisk, pszFormat, pszName, uOpenFlags); 658 if (rc == VERR_NOT_SUPPORTED) 659 { 660 /* Seems asxnc I/O is not supported by the backend, open in normal mode. */ 661 uOpenFlags &= ~VD_OPEN_FLAGS_ASYNC_IO; 662 rc = VDOpen(pData->pDisk, pszFormat, pszName, uOpenFlags); 663 } 664 391 665 if (VBOX_SUCCESS(rc)) 392 666 Log(("%s: %d - Opened '%s' in %s mode\n", __FUNCTION__, … … 395 669 else 396 670 { 397 AssertMsgFailed(("Failed to open image '%s' rc=%Vrc\n", pszName, rc)); 398 break; 399 } 671 AssertMsgFailed(("Failed to open image '%s' rc=%Vrc\n", pszName, rc)); 672 break; 673 } 674 675 400 676 MMR3HeapFree(pszName); 401 677 pszName = NULL; … … 419 695 if (VALID_PTR(pszFormat)) 420 696 MMR3HeapFree(pszFormat); 697 } 698 699 /* 700 * Check for async I/O support. Every opened image has to support 701 * it. 702 */ 703 pData->fAsyncIOSupported = true; 704 for (unsigned i = 0; i < VDGetCount(pData->pDisk); i++) 705 { 706 VDBACKENDINFO vdBackendInfo; 707 708 rc = VDBackendInfoSingle(pData->pDisk, i, &vdBackendInfo); 709 AssertRC(rc); 710 711 if (vdBackendInfo.uBackendCaps & VD_CAP_ASYNC) 712 { 713 /* 714 * Backend indicates support for at least some files. 715 * Check if current file is supported with async I/O) 716 */ 717 rc = VDImageIsAsyncIOSupported(pData->pDisk, i, &pData->fAsyncIOSupported); 718 AssertRC(rc); 719 720 /* 721 * Check if current image is supported. 722 * If not we can stop checking because 723 * at least one does not support it. 724 */ 725 if (!pData->fAsyncIOSupported) 726 break; 727 } 728 else 729 { 730 pData->fAsyncIOSupported = false; 731 break; 732 } 733 } 734 735 /* Create cache if async I/O is supported. */ 736 if (pData->fAsyncIOSupported) 737 { 738 rc = RTCacheCreate(&pData->pCache, 0, sizeof(DRVVDASYNCTASK), RTOBJCACHE_PROTECT_INSERT); 739 AssertMsg(RT_SUCCESS(rc), ("Failed to create cache rc=%Vrc\n", rc)); 421 740 } 422 741 … … 435 754 static DECLCALLBACK(void) drvvdDestruct(PPDMDRVINS pDrvIns) 436 755 { 437 LogFlow(("%s:\n", __FUNCTION__));756 int rc; 438 757 PVBOXDISK pData = PDMINS2DATA(pDrvIns, PVBOXDISK); 439 int rc = VDCloseAll(pData->pDisk); 758 LogFlow(("%s:\n", __FUNCTION__)); 759 rc = RTCacheDestroy(pData->pCache); 440 760 AssertRC(rc); 441 761 } … … 487 807 } 488 808 489 809 static DECLCALLBACK(void) drvvdPowerOff(PPDMDRVINS pDrvIns) 810 { 811 LogFlow(("%s:\n", __FUNCTION__)); 812 PVBOXDISK pData = PDMINS2DATA(pDrvIns, PVBOXDISK); 813 814 /* 815 * We must close the disk here to ensure that 816 * the backend closes all files before the 817 * async transport driver is destructed. 818 */ 819 int rc = VDCloseAll(pData->pDisk); 820 AssertRC(rc); 821 } 490 822 491 823 /** … … 523 855 drvvdResume, 524 856 /* pfnDetach */ 525 NULL 857 NULL, 858 /* pfnPowerOff */ 859 drvvdPowerOff 526 860 }; -
trunk/src/VBox/Devices/Storage/RawHDDCore.cpp
r10467 r10715 48 48 49 49 /** Error callback. */ 50 P FNVDERROR pfnError;50 PVDINTERFACE pInterfaceError; 51 51 /** Opaque data for error callback. */ 52 void *pvErrorUser;52 PVDINTERFACEERROR pInterfaceErrorCallbacks; 53 53 54 54 /** Open flags passed by VBoxHD layer. */ … … 84 84 va_list va; 85 85 va_start(va, pszFormat); 86 if (pImage->p fnError)87 pImage->p fnError(pImage->pvErrorUser, rc, RT_SRC_POS_ARGS,88 pszFormat, va);86 if (pImage->pInterfaceError) 87 pImage->pInterfaceErrorCallbacks->pfnError(pImage->pInterfaceError->pvUser, rc, RT_SRC_POS_ARGS, 88 pszFormat, va); 89 89 va_end(va); 90 90 return rc; … … 98 98 int rc; 99 99 RTFILE File; 100 101 if (uOpenFlags & VD_OPEN_FLAGS_ASYNC_IO) 102 return VERR_NOT_SUPPORTED; 100 103 101 104 pImage->uOpenFlags = uOpenFlags; … … 305 308 /** @copydoc VBOXHDDBACKEND::pfnOpen */ 306 309 static int rawOpen(const char *pszFilename, unsigned uOpenFlags, 307 PFNVDERROR pfnError, void *pvErrorUser, 308 void **ppBackendData) 310 PVDINTERFACE pInterfaces, void **ppBackendData) 309 311 { 310 312 LogFlowFunc(("pszFilename=\"%s\" uOpenFlags=%#x ppBackendData=%#p\n", pszFilename, uOpenFlags, ppBackendData)); … … 336 338 pImage->pszFilename = pszFilename; 337 339 pImage->File = NIL_RTFILE; 338 pImage->pfnError = pfnError; 339 pImage->pvErrorUser = pvErrorUser; 340 pImage->pInterfaceError = NULL; 341 pImage->pInterfaceErrorCallbacks = NULL; 342 343 pImage->pInterfaceError = VDGetInterfaceFromList(pInterfaces, VDINTERFACETYPE_ERROR); 344 if (pImage->pInterfaceError) 345 pImage->pInterfaceErrorCallbacks = VDGetInterfaceError(pImage->pInterfaceError->pCallbacks); 340 346 341 347 rc = rawOpenImage(pImage, uOpenFlags); … … 356 362 unsigned uOpenFlags, PFNVMPROGRESS pfnProgress, 357 363 void *pvUser, unsigned uPercentStart, 358 unsigned uPercentSpan, P FNVDERROR pfnError,359 void * pvErrorUser, void **ppBackendData)360 { 361 LogFlowFunc(("pszFilename=\"%s\" enmType=%d cbSize=%llu uImageFlags=%#x pszComment=\"%s\" pPCHSGeometry=%#p pLCHSGeometry=%#p uOpenFlags=%#x pfnProgress=%#p pvUser=%#p uPercentStart=%u uPercentSpan=%u p fnError=%#p pvErrorUser=%#p ppBackendData=%#p", pszFilename, enmType, cbSize, uImageFlags, pszComment, pPCHSGeometry, pLCHSGeometry, uOpenFlags, pfnProgress, pvUser, uPercentStart, uPercentSpan, pfnError, pvErrorUser, ppBackendData));364 unsigned uPercentSpan, PVDINTERFACE pInterfaces, 365 void **ppBackendData) 366 { 367 LogFlowFunc(("pszFilename=\"%s\" enmType=%d cbSize=%llu uImageFlags=%#x pszComment=\"%s\" pPCHSGeometry=%#p pLCHSGeometry=%#p uOpenFlags=%#x pfnProgress=%#p pvUser=%#p uPercentStart=%u uPercentSpan=%u pInterfaces=%#p ppBackendData=%#p", pszFilename, enmType, cbSize, uImageFlags, pszComment, pPCHSGeometry, pLCHSGeometry, uOpenFlags, pfnProgress, pvUser, uPercentStart, uPercentSpan, pInterfaces, ppBackendData)); 362 368 int rc; 363 369 PRAWIMAGE pImage; … … 389 395 pImage->pszFilename = pszFilename; 390 396 pImage->File = NIL_RTFILE; 391 pImage->pfnError = pfnError; 392 pImage->pvErrorUser = pvErrorUser; 397 398 pImage->pInterfaceError = VDGetInterfaceFromList(pInterfaces, VDINTERFACETYPE_ERROR); 399 if (pImage->pInterfaceError) 400 pImage->pInterfaceErrorCallbacks = VDGetInterfaceError(pImage->pInterfaceError); 401 393 402 394 403 rc = rawCreateImage(pImage, enmType, cbSize, uImageFlags, pszComment, … … 987 996 } 988 997 998 static int rawGetTimeStamp(void *pvBackendData, PRTTIMESPEC pTimeStamp) 999 { 1000 int rc = VERR_NOT_IMPLEMENTED; 1001 LogFlow(("%s: returned %Vrc\n", __FUNCTION__, rc)); 1002 return rc; 1003 } 1004 1005 static int rawGetParentTimeStamp(void *pvBackendData, PRTTIMESPEC pTimeStamp) 1006 { 1007 int rc = VERR_NOT_IMPLEMENTED; 1008 LogFlow(("%s: returned %Vrc\n", __FUNCTION__, rc)); 1009 return rc; 1010 } 1011 1012 static int rawSetParentTimeStamp(void *pvBackendData, PCRTTIMESPEC pTimeStamp) 1013 { 1014 int rc = VERR_NOT_IMPLEMENTED; 1015 LogFlow(("%s: returned %Vrc\n", __FUNCTION__, rc)); 1016 return rc; 1017 } 1018 1019 static int rawGetParentFilename(void *pvBackendData, char **ppszParentFilename) 1020 { 1021 int rc = VERR_NOT_IMPLEMENTED; 1022 LogFlow(("%s: returned %Vrc\n", __FUNCTION__, rc)); 1023 return rc; 1024 } 1025 1026 static int rawSetParentFilename(void *pvBackendData, const char *pszParentFilename) 1027 { 1028 int rc = VERR_NOT_IMPLEMENTED; 1029 LogFlow(("%s: returned %Vrc\n", __FUNCTION__, rc)); 1030 return rc; 1031 } 1032 1033 static bool rawIsAsyncIOSupported(void *pvBackendData) 1034 { 1035 return false; 1036 } 1037 1038 static int rawAsyncRead(void *pvBackendData, uint64_t uOffset, size_t cbRead, 1039 PPDMDATASEG paSeg, unsigned cSeg, void *pvUser) 1040 { 1041 int rc = VERR_NOT_IMPLEMENTED; 1042 LogFlowFunc(("returns %Vrc\n", rc)); 1043 return rc; 1044 } 1045 1046 static int rawAsyncWrite(void *pvBackendData, uint64_t uOffset, size_t cbWrite, 1047 PPDMDATASEG paSeg, unsigned cSeg, void *pvUser) 1048 { 1049 int rc = VERR_NOT_IMPLEMENTED; 1050 LogFlowFunc(("returns %Vrc\n", rc)); 1051 return rc; 1052 } 989 1053 990 1054 VBOXHDDBACKEND g_RawBackend = … … 1055 1119 rawSetParentModificationUuid, 1056 1120 /* pfnDump */ 1057 rawDump 1121 rawDump, 1122 /* pfnGetTimeStamp */ 1123 rawGetTimeStamp, 1124 /* pfnGetParentTimeStamp */ 1125 rawGetParentTimeStamp, 1126 /* pfnSetParentTimeStamp */ 1127 rawSetParentTimeStamp, 1128 /* pfnGetParentFilename */ 1129 rawGetParentFilename, 1130 /* pfnSetParentFilename */ 1131 rawSetParentFilename, 1132 /* pfnIsAsyncIOSupported */ 1133 rawIsAsyncIOSupported, 1134 /* pfnAsyncRead */ 1135 rawAsyncRead, 1136 /* pfnAsyncWrite */ 1137 rawAsyncWrite 1058 1138 }; 1139 -
trunk/src/VBox/Devices/Storage/VBoxHDD-new.cpp
r10540 r10715 108 108 PDMMEDIAGEOMETRY LCHSGeometry; 109 109 110 /** Error message processing callback. */ 111 PFNVDERROR pfnError; 112 /** Opaque data for error callback. */ 113 void *pvErrorUser; 110 /** List of interfaces the caller supports. */ 111 PVDINTERFACE pInterfaces; 112 /** Pointer to the common interface structure for error reporting. */ 113 PVDINTERFACE pInterfaceError; 114 /** Pointer to the error interface we use if available. */ 115 PVDINTERFACEERROR pInterfaceErrorCallbacks; 114 116 }; 115 117 … … 148 150 va_list va; 149 151 va_start(va, pszFormat); 150 if (pDisk->p fnError)151 pDisk->p fnError(pDisk->pvErrorUser, rc, RT_SRC_POS_ARGS, pszFormat, va);152 if (pDisk->pInterfaceErrorCallbacks) 153 pDisk->pInterfaceErrorCallbacks->pfnError(pDisk->pInterfaceError->pvUser, rc, RT_SRC_POS_ARGS, pszFormat, va); 152 154 va_end(va); 153 155 return rc; … … 761 763 } 762 764 765 /** 766 * Lists the capablities of a backend indentified by its name. 767 * Free all returned names with RTStrFree() when you no longer need them. 768 * 769 * @returns VBox status code. 770 * @param pszBackend The backend name. 771 * @param pEntries Pointer to an entry. 772 */ 773 VBOXDDU_DECL(int) VDBackendInfoOne(const char *pszBackend, PVDBACKENDINFO pEntry) 774 { 775 return VERR_NOT_IMPLEMENTED; 776 } 763 777 764 778 /** … … 767 781 * 768 782 * @returns VBox status code. 769 * @param pfnError Callback for setting extended error information. 770 * @param pvErrorUser Opaque parameter for pfnError. 783 * @param pInterfaces Pointer to the first supported interface. 771 784 * @param ppDisk Where to store the reference to HDD container. 772 785 */ 773 VBOXDDU_DECL(int) VDCreate(PFNVDERROR pfnError, void *pvErrorUser, 774 PVBOXHDD *ppDisk) 786 VBOXDDU_DECL(int) VDCreate(PVDINTERFACE pInterfaces, PVBOXHDD *ppDisk) 775 787 { 776 788 int rc = VINF_SUCCESS; 777 789 PVBOXHDD pDisk = NULL; 778 790 779 LogFlowFunc(("p fnError=%#p pvErrorUser=%#p\n", pfnError, pvErrorUser));791 LogFlowFunc(("pInterfaces=%#p\n", pInterfaces)); 780 792 do 781 793 { 782 794 /* Check arguments. */ 783 AssertMsgBreakStmt(VALID_PTR(pfnError),784 ("pfnError=%#p\n", pfnError),785 rc = VERR_INVALID_PARAMETER);786 795 AssertMsgBreakStmt(VALID_PTR(ppDisk), 787 796 ("ppDisk=%#p\n", ppDisk), … … 802 811 pDisk->LCHSGeometry.cHeads = 0; 803 812 pDisk->LCHSGeometry.cSectors = 0; 804 pDisk->pfnError = pfnError; 805 pDisk->pvErrorUser = pvErrorUser; 813 pDisk->pInterfaces = pInterfaces; 814 pDisk->pInterfaceError = NULL; 815 pDisk->pInterfaceErrorCallbacks = NULL; 816 817 pDisk->pInterfaceError = VDGetInterfaceFromList(pInterfaces, VDINTERFACETYPE_ERROR); 818 if (pDisk->pInterfaceError) 819 pDisk->pInterfaceErrorCallbacks = VDGetInterfaceError(pDisk->pInterfaceError->pCallbacks); 806 820 *ppDisk = pDisk; 807 821 } … … 1078 1092 rc = pImage->Backend->pfnOpen(pImage->pszFilename, 1079 1093 uOpenFlags & ~VD_OPEN_FLAGS_HONOR_SAME, 1080 pDisk->p fnError, pDisk->pvErrorUser,1094 pDisk->pInterfaces, 1081 1095 &pImage->pvBackendData); 1082 1096 /* If the open in read-write mode failed, retry in read-only mode. */ … … 1092 1106 (uOpenFlags & ~VD_OPEN_FLAGS_HONOR_SAME) 1093 1107 | VD_OPEN_FLAGS_READONLY, 1094 pDisk->p fnError, pDisk->pvErrorUser,1108 pDisk->pInterfaces, 1095 1109 &pImage->pvBackendData); 1096 1110 if (VBOX_FAILURE(rc)) … … 1342 1356 uOpenFlags & ~VD_OPEN_FLAGS_HONOR_SAME, 1343 1357 pfnProgress, pvUser, 0, 99, 1344 pDisk->p fnError, pDisk->pvErrorUser,1358 pDisk->pInterfaces, 1345 1359 &pImage->pvBackendData); 1346 1360 … … 1515 1529 uOpenFlags & ~VD_OPEN_FLAGS_HONOR_SAME, 1516 1530 pfnProgress, pvUser, 0, 99, 1517 pDisk->p fnError, pDisk->pvErrorUser,1531 pDisk->pInterfaces, 1518 1532 &pImage->pvBackendData); 1519 1533 … … 2471 2485 } while (0); 2472 2486 2473 LogFlowFunc(("%s: %Vrc (PCHS=%u/%u/%u)\n", rc,2487 LogFlowFunc(("%s: %Vrc (PCHS=%u/%u/%u)\n", __FUNCTION__, rc, 2474 2488 pDisk->PCHSGeometry.cCylinders, pDisk->PCHSGeometry.cHeads, 2475 2489 pDisk->PCHSGeometry.cSectors)); … … 2617 2631 } while (0); 2618 2632 2619 LogFlowFunc((" %s: %Vrc (LCHS=%u/%u/%u)\n", rc,2633 LogFlowFunc((": %Vrc (LCHS=%u/%u/%u)\n", rc, 2620 2634 pDisk->LCHSGeometry.cCylinders, pDisk->LCHSGeometry.cHeads, 2621 2635 pDisk->LCHSGeometry.cSectors)); … … 2800 2814 } 2801 2815 2816 2817 /** 2818 * List the capabilities of image backend in HDD container. 2819 * 2820 * @returns VBox status code. 2821 * @returns VERR_VDI_IMAGE_NOT_FOUND if image with specified number was not opened. 2822 * @param pDisk Pointer to the HDD container. 2823 * @param nImage Image number, counts from 0. 0 is always base image of container. 2824 * @param pbackendInfo Where to store the backend information. 2825 */ 2826 VBOXDDU_DECL(int) VDBackendInfoSingle(PVBOXHDD pDisk, unsigned nImage, 2827 PVDBACKENDINFO pBackendInfo) 2828 { 2829 int rc = VINF_SUCCESS; 2830 2831 LogFlowFunc(("pDisk=%#p nImage=%u penmType=%#p\n", 2832 pDisk, nImage, pBackendInfo)); 2833 do 2834 { 2835 /* sanity check */ 2836 AssertPtrBreakStmt(pDisk, rc = VERR_INVALID_PARAMETER); 2837 AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature)); 2838 2839 /* Check arguments. */ 2840 AssertMsgBreakStmt(VALID_PTR(pBackendInfo), 2841 ("pBackendInfo=%#p\n", pBackendInfo), 2842 rc = VERR_INVALID_PARAMETER); 2843 2844 PVDIMAGE pImage = vdGetImageByNumber(pDisk, nImage); 2845 AssertPtrBreakStmt(pImage, rc = VERR_VDI_IMAGE_NOT_FOUND); 2846 2847 if ( pImage->enmImageType >= VD_IMAGE_TYPE_FIRST 2848 && pImage->enmImageType <= VD_IMAGE_TYPE_DIFF) 2849 { 2850 pBackendInfo->pszBackend = RTStrDup(pImage->Backend->pszBackendName); 2851 pBackendInfo->uBackendCaps = pImage->Backend->uBackendCaps; 2852 rc = VINF_SUCCESS; 2853 } 2854 else 2855 rc = VERR_VDI_INVALID_TYPE; 2856 } while (0); 2857 2858 LogFlowFunc(("returns %Vrc\n", rc)); 2859 return rc; 2860 } 2861 2802 2862 /** 2803 2863 * Get flags of image in HDD container. … … 3306 3366 } 3307 3367 3368 /** 3369 * Query if asynchronous operations are supported for this disk. 3370 * 3371 * @returns VBox status code. 3372 * @returns VERR_VDI_IMAGE_NOT_FOUND if image with specified number was not opened. 3373 * @param pDisk Pointer to the HDD container. 3374 * @param nImage Image number, counts from 0. 0 is always base image of container. 3375 * @param pfAIOSupported Where to store if async IO is supported. 3376 */ 3377 VBOXDDU_DECL(int) VDImageIsAsyncIOSupported(PVBOXHDD pDisk, unsigned nImage, bool *pfAIOSupported) 3378 { 3379 int rc = VINF_SUCCESS; 3380 3381 LogFlowFunc(("pDisk=%#p nImage=%u pfAIOSupported=%#p\n", pDisk, nImage, pfAIOSupported)); 3382 do 3383 { 3384 /* sanity check */ 3385 AssertPtrBreakStmt(pDisk, rc = VERR_INVALID_PARAMETER); 3386 AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature)); 3387 3388 /* Check arguments. */ 3389 AssertMsgBreakStmt(VALID_PTR(pfAIOSupported), 3390 ("pfAIOSupported=%#p\n", pfAIOSupported), 3391 rc = VERR_INVALID_PARAMETER); 3392 3393 PVDIMAGE pImage = vdGetImageByNumber(pDisk, nImage); 3394 AssertPtrBreakStmt(pImage, rc = VERR_VDI_IMAGE_NOT_FOUND); 3395 3396 if (pImage->Backend->uBackendCaps & VD_CAP_ASYNC) 3397 *pfAIOSupported = pImage->Backend->pfnIsAsyncIOSupported(pImage->pvBackendData); 3398 else 3399 *pfAIOSupported = false; 3400 } while (0); 3401 3402 LogFlowFunc(("returns %Vrc, fAIOSupported=%u\n", rc, *pfAIOSupported)); 3403 return rc; 3404 } 3405 3406 /** 3407 * Start a asynchronous read request. 3408 * 3409 * @returns VBox status code. 3410 * @param pDisk Pointer to the HDD container. 3411 * @param uOffset The offset of the virtual disk to read from. 3412 * @param cbRead How many bytes to read. 3413 * @param paSeg Pointer to an array of segments. 3414 * @param cSeg Number of segments in the array. 3415 * @param pvUser User data which is passed on completion 3416 */ 3417 VBOXDDU_DECL(int) VDAsyncRead(PVBOXHDD pDisk, uint64_t uOffset, size_t cbRead, 3418 PPDMDATASEG paSeg, unsigned cSeg, 3419 void *pvUser) 3420 { 3421 int rc = VERR_VDI_BLOCK_FREE; 3422 3423 LogFlowFunc(("pDisk=%#p uOffset=%llu paSeg=%p cSeg=%u cbRead=%zu\n", 3424 pDisk, uOffset, paSeg, cSeg, cbRead)); 3425 do 3426 { 3427 /* sanity check */ 3428 AssertPtrBreakStmt(pDisk, rc = VERR_INVALID_PARAMETER); 3429 AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature)); 3430 3431 /* Check arguments. */ 3432 AssertMsgBreakStmt(cbRead, 3433 ("cbRead=%zu\n", cbRead), 3434 rc = VERR_INVALID_PARAMETER); 3435 AssertMsgBreakStmt(uOffset + cbRead <= pDisk->cbSize, 3436 ("uOffset=%llu cbRead=%zu pDisk->cbSize=%llu\n", 3437 uOffset, cbRead, pDisk->cbSize), 3438 rc = VERR_INVALID_PARAMETER); 3439 AssertMsgBreakStmt(VALID_PTR(paSeg), 3440 ("paSeg=%#p\n", paSeg), 3441 rc = VERR_INVALID_PARAMETER); 3442 AssertMsgBreakStmt(cSeg, 3443 ("cSeg=%zu\n", cSeg), 3444 rc = VERR_INVALID_PARAMETER); 3445 3446 3447 PVDIMAGE pImage = pDisk->pLast; 3448 AssertPtrBreakStmt(pImage, rc = VERR_VDI_NOT_OPENED); 3449 3450 /* @todo: This does not work for images which do not have all meta data in memory. */ 3451 for (PVDIMAGE pCurrImage = pImage; 3452 pCurrImage != NULL && rc == VERR_VDI_BLOCK_FREE; 3453 pCurrImage = pCurrImage->pPrev) 3454 { 3455 rc = pCurrImage->Backend->pfnAsyncRead(pCurrImage->pvBackendData, 3456 uOffset, cbRead, paSeg, cSeg, 3457 pvUser); 3458 } 3459 3460 /* No image in the chain contains the data for the block. */ 3461 if (rc == VERR_VDI_BLOCK_FREE) 3462 { 3463 for (unsigned i = 0; i < cSeg && (cbRead > 0); i++) 3464 { 3465 memset(paSeg[i].pvSeg, '\0', paSeg[i].cbSeg); 3466 cbRead -= paSeg[i].cbSeg; 3467 } 3468 /* Request finished without the need to enqueue a async I/O request. Tell caller. */ 3469 rc = VINF_VDI_ASYNC_IO_FINISHED; 3470 } 3471 3472 } while (0); 3473 3474 LogFlowFunc(("returns %Vrc\n", rc)); 3475 return rc; 3476 } 3477 3478 3479 /** 3480 * Start a asynchronous write request. 3481 * 3482 * @returns VBox status code. 3483 * @param pDisk Pointer to the HDD container. 3484 * @param uOffset The offset of the virtual disk to write to. 3485 * @param cbWrtie How many bytes to write. 3486 * @param paSeg Pointer to an array of segments. 3487 * @param cSeg Number of segments in the array. 3488 * @param pvUser User data which is passed on completion. 3489 */ 3490 VBOXDDU_DECL(int) VDAsyncWrite(PVBOXHDD pDisk, uint64_t uOffset, size_t cbWrite, 3491 PPDMDATASEG paSeg, unsigned cSeg, 3492 void *pvUser) 3493 { 3494 int rc; 3495 3496 LogFlowFunc(("pDisk=%#p uOffset=%llu paSeg=%p cSeg=%u cbWrite=%zu\n", 3497 pDisk, uOffset, paSeg, cSeg, cbWrite)); 3498 do 3499 { 3500 /* sanity check */ 3501 AssertPtrBreakStmt(pDisk, rc = VERR_INVALID_PARAMETER); 3502 AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature)); 3503 3504 /* Check arguments. */ 3505 AssertMsgBreakStmt(cbWrite, 3506 ("cbWrite=%zu\n", cbWrite), 3507 rc = VERR_INVALID_PARAMETER); 3508 AssertMsgBreakStmt(uOffset + cbWrite <= pDisk->cbSize, 3509 ("uOffset=%llu cbWrite=%zu pDisk->cbSize=%llu\n", 3510 uOffset, cbWrite, pDisk->cbSize), 3511 rc = VERR_INVALID_PARAMETER); 3512 AssertMsgBreakStmt(VALID_PTR(paSeg), 3513 ("paSeg=%#p\n", paSeg), 3514 rc = VERR_INVALID_PARAMETER); 3515 AssertMsgBreakStmt(cSeg, 3516 ("cSeg=%zu\n", cSeg), 3517 rc = VERR_INVALID_PARAMETER); 3518 3519 3520 PVDIMAGE pImage = pDisk->pLast; 3521 AssertPtrBreakStmt(pImage, rc = VERR_VDI_NOT_OPENED); 3522 3523 vdSetModifiedFlag(pDisk); 3524 rc = pImage->Backend->pfnAsyncWrite(pImage->pvBackendData, 3525 uOffset, cbWrite, 3526 paSeg, cSeg, pvUser); 3527 } while (0); 3528 3529 LogFlowFunc(("returns %Vrc\n", rc)); 3530 return rc; 3531 3532 } 3533 -
trunk/src/VBox/Devices/Storage/VBoxHDD-newInternal.h
r9734 r10715 71 71 * unchanged during the lifetime of this image. 72 72 * @param uOpenFlags Image file open mode, see VD_OPEN_FLAGS_* constants. 73 * @param pfnError Callback for setting extended error information. 74 * @param pvErrorUser Opaque parameter for pfnError. 73 * @param pInterfaces Pointer to the first element of supported interfaces of the caller. 75 74 * @param ppvBackendData Opaque state data for this image. 76 75 */ 77 DECLR3CALLBACKMEMBER(int, pfnOpen, (const char *pszFilename, unsigned uOpenFlags, PFNVDERROR pfnError, void *pvErrorUser, void **ppvBackendData)); 76 DECLR3CALLBACKMEMBER(int, pfnOpen, (const char *pszFilename, unsigned uOpenFlags, 77 PVDINTERFACE pInterfaces, void **ppvBackendData)); 78 78 79 79 /** … … 94 94 * @param uPercentStart Starting value for progress percentage. 95 95 * @param uPercentSpan Span for varying progress percentage. 96 * @param pfnError Callback for setting extended error information. 97 * @param pvErrorUser Opaque parameter for pfnError. 96 * @param pInterfaces Pointer to the supported interfaces of the caller. 98 97 * @param ppvBackendData Opaque state data for this image. 99 98 */ 100 DECLR3CALLBACKMEMBER(int, pfnCreate, (const char *pszFilename, VDIMAGETYPE enmType, uint64_t cbSize, unsigned uImageFlags, const char *pszComment, PCPDMMEDIAGEOMETRY pPCHSGeometry, PCPDMMEDIAGEOMETRY pLCHSGeometry, unsigned uOpenFlags, PFNVMPROGRESS pfnProgress, void *pvUser, unsigned uPercentStart, unsigned uPercentSpan, P FNVDERROR pfnError, void *pvErrorUser, void **ppvBackendData));99 DECLR3CALLBACKMEMBER(int, pfnCreate, (const char *pszFilename, VDIMAGETYPE enmType, uint64_t cbSize, unsigned uImageFlags, const char *pszComment, PCPDMMEDIAGEOMETRY pPCHSGeometry, PCPDMMEDIAGEOMETRY pLCHSGeometry, unsigned uOpenFlags, PFNVMPROGRESS pfnProgress, void *pvUser, unsigned uPercentStart, unsigned uPercentSpan, PVDINTERFACE pInterfaces, void **ppvBackendData)); 101 100 102 101 /** … … 421 420 DECLR3CALLBACKMEMBER(int, pfnSetParentFilename, (void *pvBackendData, const char *pszParentFilename)); 422 421 422 /** 423 * Return whether asynchronous I/O operations are supported for this image. 424 * 425 * @returns true if asynchronous I/O is supported 426 * false otherwise. 427 * @param pvBackendData Opaque state data for this image. 428 */ 429 DECLR3CALLBACKMEMBER(bool, pfnIsAsyncIOSupported, (void *pvBackendData)); 430 431 /** 432 * Start an asynchronous read request. 433 * 434 * @returns VBox status code. 435 * @param pvBackendData Opaque state data for this image. 436 * @param uOffset The offset of the virtual disk to read from. 437 * @param cbRead How many bytes to read. 438 * @param paSeg Pointer to the segment array. 439 * @param cSeg Number of segments. 440 * @param pvUser Opaque user data. 441 */ 442 DECLR3CALLBACKMEMBER(int, pfnAsyncRead, (void *pvBackendData, uint64_t uOffset, size_t cbRead, 443 PPDMDATASEG paSeg, unsigned cSeg, void *pvUser)); 444 445 /** 446 * Start an asynchronous write request. 447 * 448 * @returns VBox status code. 449 * @param pvBackendData Opaque state data for this image. 450 * @param uOffset The offset of the virtual disk to write to. 451 * @param cbWrite How many bytes to write. 452 * @param paSeg Pointer to the segment array. 453 * @param cSeg Number of segments. 454 * @param pvUser Oaque user data- 455 */ 456 DECLR3CALLBACKMEMBER(int, pfnAsyncWrite, (void *pvBackendData, uint64_t uOffset, size_t cbWrite, 457 PPDMDATASEG paSeg, unsigned cSeg, void *pvUser)); 458 423 459 } VBOXHDDBACKEND; 424 460 -
trunk/src/VBox/Devices/Storage/VDICore.h
r8170 r10715 562 562 /** Physical geometry of this image (never actually stored). */ 563 563 PDMMEDIAGEOMETRY PCHSGeometry; 564 /** Error callback. */565 P FNVDERROR pfnError;566 /** Opaque data for error callback. */567 void *pvErrorUser;564 /** Error interface. */ 565 PVDINTERFACE pInterfaceError; 566 /** Error interface callback table. */ 567 PVDINTERFACEERROR pInterfaceErrorCallbacks; 568 568 #endif /* VBOX_VDICORE_VD */ 569 569 } VDIIMAGEDESC, *PVDIIMAGEDESC; -
trunk/src/VBox/Devices/Storage/VDIHDDCore.cpp
r10539 r10715 63 63 va_list va; 64 64 va_start(va, pszFormat); 65 if (pImage->pfnError) 66 pImage->pfnError(pImage->pvErrorUser, rc, RT_SRC_POS_ARGS, 67 pszFormat, va); 65 if (pImage->pInterfaceError && pImage->pInterfaceErrorCallbacks) 66 pImage->pInterfaceErrorCallbacks->pfnError(pImage->pInterfaceError->pvUser, 67 rc, RT_SRC_POS_ARGS, 68 pszFormat, va); 68 69 va_end(va); 69 70 return rc; … … 508 509 int rc; 509 510 RTFILE File; 511 512 if (uOpenFlags & VD_OPEN_FLAGS_ASYNC_IO) 513 return VERR_NOT_SUPPORTED; 510 514 511 515 pImage->uOpenFlags = uOpenFlags; … … 731 735 pImage->File = NIL_RTFILE; 732 736 pImage->paBlocks = NULL; 733 pImage->p fnError = NULL;734 pImage->p vErrorUser= NULL;737 pImage->pInterfaceError = NULL; 738 pImage->pInterfaceErrorCallbacks = NULL; 735 739 736 740 rc = vdiOpenImage(pImage, VD_OPEN_FLAGS_INFO | VD_OPEN_FLAGS_READONLY); … … 744 748 /** @copydoc VBOXHDDBACKEND::pfnOpen */ 745 749 static int vdiOpen(const char *pszFilename, unsigned uOpenFlags, 746 P FNVDERROR pfnError, void *pvErrorUser,750 PVDINTERFACE pInterfaces, 747 751 void **ppBackendData) 748 752 { … … 775 779 pImage->File = NIL_RTFILE; 776 780 pImage->paBlocks = NULL; 777 pImage->pfnError = pfnError; 778 pImage->pvErrorUser = pvErrorUser; 781 pImage->pInterfaceError = NULL; 782 pImage->pInterfaceErrorCallbacks = NULL; 783 784 pImage->pInterfaceError = VDGetInterfaceFromList(pInterfaces, VDINTERFACETYPE_ERROR); 785 if (pImage->pInterfaceError) 786 pImage->pInterfaceErrorCallbacks = VDGetInterfaceError(pImage->pInterfaceError->pCallbacks); 779 787 780 788 rc = vdiOpenImage(pImage, uOpenFlags); … … 795 803 unsigned uOpenFlags, PFNVMPROGRESS pfnProgress, 796 804 void *pvUser, unsigned uPercentStart, 797 unsigned uPercentSpan, P FNVDERROR pfnError,798 void * pvErrorUser, void **ppBackendData)799 { 800 LogFlowFunc(("pszFilename=\"%s\" enmType=%d cbSize=%llu uImageFlags=%#x pszComment=\"%s\" pPCHSGeometry=%#p pLCHSGeometry=%#p uOpenFlags=%#x pfnProgress=%#p pvUser=%#p uPercentStart=%u uPercentSpan=%u p fnError=%#p pvErrorUser=%#p ppBackendData=%#p", pszFilename, enmType, cbSize, uImageFlags, pszComment, pPCHSGeometry, pLCHSGeometry, uOpenFlags, pfnProgress, pvUser, uPercentStart, uPercentSpan, pfnError, pvErrorUser, ppBackendData));805 unsigned uPercentSpan, PVDINTERFACE pInterfaces, 806 void **ppBackendData) 807 { 808 LogFlowFunc(("pszFilename=\"%s\" enmType=%d cbSize=%llu uImageFlags=%#x pszComment=\"%s\" pPCHSGeometry=%#p pLCHSGeometry=%#p uOpenFlags=%#x pfnProgress=%#p pvUser=%#p uPercentStart=%u uPercentSpan=%u pInterfaces=%#p ppBackendData=%#p", pszFilename, enmType, cbSize, uImageFlags, pszComment, pPCHSGeometry, pLCHSGeometry, uOpenFlags, pfnProgress, pvUser, uPercentStart, uPercentSpan, pInterfaces, ppBackendData)); 801 809 int rc; 802 810 PVDIIMAGEDESC pImage; … … 831 839 pImage->File = NIL_RTFILE; 832 840 pImage->paBlocks = NULL; 833 pImage->p fnError = pfnError;834 pImage->p vErrorUser = pvErrorUser;841 pImage->pInterfaceError = NULL; 842 pImage->pInterfaceErrorCallbacks = NULL; 835 843 836 844 rc = vdiCreateImage(pImage, enmType, cbSize, uImageFlags, pszComment, … … 1753 1761 return rc; 1754 1762 } 1763 1764 static bool vdiIsAsyncIOSupported(void *pvBackendData) 1765 { 1766 return false; 1767 } 1768 1769 static int vdiAsyncRead(void *pvBackendData, uint64_t uOffset, size_t cbRead, 1770 PPDMDATASEG paSeg, unsigned cSeg, void *pvUser) 1771 { 1772 int rc = VERR_NOT_IMPLEMENTED; 1773 LogFlowFunc(("returns %Vrc\n", rc)); 1774 return rc; 1775 } 1776 1777 static int vdiAsyncWrite(void *pvBackendData, uint64_t uOffset, size_t cbWrite, 1778 PPDMDATASEG paSeg, unsigned cSeg, void *pvUser) 1779 { 1780 int rc = VERR_NOT_IMPLEMENTED; 1781 LogFlowFunc(("returns %Vrc\n", rc)); 1782 return rc; 1783 } 1784 1755 1785 1756 1786 VBOXHDDBACKEND g_VDIBackend = … … 1832 1862 vdiGetParentFilename, 1833 1863 /* pfnSetParentFilename */ 1834 vdiSetParentFilename 1864 vdiSetParentFilename, 1865 /* pfnIsAsyncIOSupported */ 1866 vdiIsAsyncIOSupported, 1867 /* pfnAsyncRead */ 1868 vdiAsyncRead, 1869 /* pfnAsyncWrite */ 1870 vdiAsyncWrite 1835 1871 }; 1836 1872 -
trunk/src/VBox/Devices/Storage/VmdkHDDCore.cpp
r10539 r10715 179 179 } VMDKACCESS, *PVMDKACCESS; 180 180 181 /** Forward declaration for PVMDKIMAGE. */ 182 typedef struct VMDKIMAGE *PVMDKIMAGE; 183 184 /** 185 * Extents files entry. Used for opening a particular file only once. 186 */ 187 typedef struct VMDKFILE 188 { 189 /** Pointer to filename. Local copy. */ 190 const char *pszFilename; 191 /** File open flags for consistency checking. */ 192 unsigned fOpen; 193 /** File handle. */ 194 RTFILE File; 195 /** Handle for asnychronous access if requested.*/ 196 void *pStorage; 197 /** Flag whether to use File or pStorage. */ 198 bool fAsyncIO; 199 /** Reference counter. */ 200 unsigned uReferences; 201 /** Flag whether the file should be deleted on last close. */ 202 bool fDelete; 203 /** Pointer to the image we belong to. */ 204 PVMDKIMAGE pImage; 205 /** Pointer to next file descriptor. */ 206 struct VMDKFILE *pNext; 207 /** Pointer to the previous file descriptor. */ 208 struct VMDKFILE *pPrev; 209 } VMDKFILE, *PVMDKFILE; 210 181 211 /** 182 212 * VMDK extent data structure. … … 185 215 { 186 216 /** File handle. */ 187 RTFILEFile;217 PVMDKFILE pFile; 188 218 /** Base name of the image extent. */ 189 219 const char *pszBasename; … … 239 269 240 270 /** 241 * Extents files entry. Used for opening a particular file only once.242 */243 typedef struct VMDKFILE244 {245 /** Pointer to filename. Local copy. */246 const char *pszFilename;247 /** File open flags for consistency checking. */248 unsigned fOpen;249 /** File handle. */250 RTFILE File;251 /** Reference counter. */252 unsigned uReferences;253 /** Flag whether the file should be deleted on last close. */254 bool fDelete;255 /** Pointer to next file descriptor. Singly linked list is fast enough. */256 struct VMDKFILE *pNext;257 } VMDKFILE, *PVMDKFILE;258 259 /**260 271 * Grain table cache size. Allocated per image. 261 272 */ … … 346 357 const char *pszFilename; 347 358 /** Descriptor file if applicable. */ 348 RTFILE File; 349 350 /** Error callback. */ 351 PFNVDERROR pfnError; 352 /** Opaque data for error callback. */ 353 void *pvErrorUser; 359 PVMDKFILE pFile; 360 361 /** Error interface. */ 362 PVDINTERFACE pInterfaceError; 363 /** Error interface callbacks. */ 364 PVDINTERFACEERROR pInterfaceErrorCallbacks; 365 366 /** Async I/O interface. */ 367 PVDINTERFACE pInterfaceAsyncIO; 368 /** Async I/O interface callbacks. */ 369 PVDINTERFACEASYNCIO pInterfaceAsyncIOCallbacks; 370 /** 371 * Pointer to an array of task handles for task submission. 372 * This is an optimization because the task number to submit is not known 373 * and allocating/freeing an array in the read/write functions every time 374 * is too expensive. 375 */ 376 void **apTask; 377 /** Entries available in the task handle array. */ 378 unsigned cTask; 354 379 355 380 /** Open flags passed by VBoxHD layer. */ … … 382 407 /** Parsed descriptor file content. */ 383 408 VMDKDESCRIPTOR Descriptor; 384 } VMDKIMAGE , *PVMDKIMAGE;409 } VMDKIMAGE; 385 410 386 411 … … 408 433 va_list va; 409 434 va_start(va, pszFormat); 410 if (pImage->p fnError)411 pImage->p fnError(pImage->pvErrorUser, rc, RT_SRC_POS_ARGS,412 pszFormat, va);435 if (pImage->pInterfaceError && pImage->pInterfaceErrorCallbacks) 436 pImage->pInterfaceErrorCallbacks->pfnError(pImage->pInterfaceError->pvUser, rc, RT_SRC_POS_ARGS, 437 pszFormat, va); 413 438 va_end(va); 414 439 return rc; … … 419 444 * is only opened once - anything else can cause locking problems). 420 445 */ 421 static int vmdkFileOpen(PVMDKIMAGE pImage, P RTFILE pFile,422 const char *pszFilename, unsigned fOpen )446 static int vmdkFileOpen(PVMDKIMAGE pImage, PVMDKFILE *ppVmdkFile, 447 const char *pszFilename, unsigned fOpen, bool fAsyncIO) 423 448 { 424 449 int rc = VINF_SUCCESS; … … 433 458 Assert(fOpen == pVmdkFile->fOpen); 434 459 pVmdkFile->uReferences++; 435 *pFile = pVmdkFile->File; 460 461 *ppVmdkFile = pVmdkFile; 462 436 463 return rc; 437 464 } … … 442 469 if (!VALID_PTR(pVmdkFile)) 443 470 { 444 *p File = NIL_RTFILE;471 *ppVmdkFile = NULL; 445 472 return VERR_NO_MEMORY; 446 473 } … … 450 477 { 451 478 RTMemFree(pVmdkFile); 452 *p File = NIL_RTFILE;479 *ppVmdkFile = NULL; 453 480 return VERR_NO_MEMORY; 454 481 } 455 482 pVmdkFile->fOpen = fOpen; 456 rc = RTFileOpen(&pVmdkFile->File, pszFilename, fOpen); 483 if ((pImage->uOpenFlags & VD_OPEN_FLAGS_ASYNC_IO) && (fAsyncIO)) 484 { 485 rc = pImage->pInterfaceAsyncIOCallbacks->pfnOpen(pImage->pInterfaceAsyncIO->pvUser, 486 pszFilename, 487 pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY 488 ? true 489 : false, 490 &pVmdkFile->pStorage); 491 pVmdkFile->fAsyncIO = true; 492 } 493 else 494 { 495 rc = RTFileOpen(&pVmdkFile->File, pszFilename, fOpen); 496 pVmdkFile->fAsyncIO = false; 497 } 457 498 if (VBOX_SUCCESS(rc)) 458 499 { 459 500 pVmdkFile->uReferences = 1; 501 pVmdkFile->pImage = pImage; 460 502 pVmdkFile->pNext = pImage->pFiles; 503 if (pImage->pFiles) 504 pImage->pFiles->pPrev = pVmdkFile; 461 505 pImage->pFiles = pVmdkFile; 462 *p File = pVmdkFile->File;506 *ppVmdkFile = pVmdkFile; 463 507 } 464 508 else … … 466 510 RTStrFree((char *)(void *)pVmdkFile->pszFilename); 467 511 RTMemFree(pVmdkFile); 468 *p File = NIL_RTFILE;512 *ppVmdkFile = NULL; 469 513 } 470 514 … … 475 519 * Internal: close a file, updating the file descriptor cache. 476 520 */ 477 static int vmdkFileClose(PVMDKIMAGE pImage, P RTFILE pFile, bool fDelete)521 static int vmdkFileClose(PVMDKIMAGE pImage, PVMDKFILE *ppVmdkFile, bool fDelete) 478 522 { 479 523 int rc = VINF_SUCCESS; 480 RTFILE File; 481 PVMDKFILE pVmdkFile, pPrev; 482 483 Assert(VALID_PTR(pFile) && *pFile != NIL_RTFILE); 484 File = *pFile; 485 486 pPrev = NULL; 487 for (pVmdkFile = pImage->pFiles; 488 pVmdkFile != NULL; 489 pVmdkFile = pVmdkFile->pNext) 490 { 491 if (File == pVmdkFile->File) 492 { 493 pVmdkFile->fDelete |= fDelete; 494 Assert(pVmdkFile->uReferences); 495 pVmdkFile->uReferences--; 496 if (pVmdkFile->uReferences == 0) 497 { 498 /* Unchain the element from the list. */ 499 if (pPrev == NULL) 500 pImage->pFiles = pVmdkFile->pNext; 501 else 502 pPrev->pNext = pVmdkFile->pNext; 503 rc = RTFileClose(File); 504 *pFile = NIL_RTFILE; 505 if (VBOX_SUCCESS(rc) && pVmdkFile->fDelete) 506 rc = RTFileDelete(pVmdkFile->pszFilename); 507 RTStrFree((char *)(void *)pVmdkFile->pszFilename); 508 RTMemFree(pVmdkFile); 509 } 510 return rc; 511 } 512 pPrev = pVmdkFile; 513 } 514 515 AssertMsgFailed(("trying to close unknown file %#p", File)); 516 return VERR_INVALID_PARAMETER; 524 PVMDKFILE pVmdkFile = *ppVmdkFile; 525 526 Assert(VALID_PTR(pVmdkFile)); 527 528 pVmdkFile->fDelete |= fDelete; 529 Assert(pVmdkFile->uReferences); 530 pVmdkFile->uReferences--; 531 if (pVmdkFile->uReferences == 0) 532 { 533 PVMDKFILE pPrev; 534 PVMDKFILE pNext; 535 536 /* Unchain the element from the list. */ 537 pPrev = pVmdkFile->pPrev; 538 pNext = pVmdkFile->pNext; 539 540 if (pNext) 541 pNext->pPrev = pPrev; 542 if (pPrev) 543 pPrev->pNext = pNext; 544 else 545 pImage->pFiles = pNext; 546 547 if (pVmdkFile->fAsyncIO) 548 { 549 rc = pImage->pInterfaceAsyncIOCallbacks->pfnClose(pImage->pInterfaceAsyncIO->pvUser, 550 pVmdkFile->pStorage); 551 } 552 else 553 { 554 rc = RTFileClose(pVmdkFile->File); 555 } 556 if (VBOX_SUCCESS(rc) && pVmdkFile->fDelete) 557 rc = RTFileDelete(pVmdkFile->pszFilename); 558 RTStrFree((char *)(void *)pVmdkFile->pszFilename); 559 RTMemFree(pVmdkFile); 560 } 561 562 *ppVmdkFile = NULL; 563 return rc; 564 } 565 566 /** 567 * Internal: read from a file distinguishing between async and normal operation 568 */ 569 DECLINLINE(int) vmdkFileReadAt(PVMDKFILE pVmdkFile, 570 uint64_t uOffset, void *pvBuf, 571 size_t cbToRead, size_t *pcbRead) 572 { 573 PVMDKIMAGE pImage = pVmdkFile->pImage; 574 575 if (pVmdkFile->fAsyncIO) 576 return pImage->pInterfaceAsyncIOCallbacks->pfnRead(pImage->pInterfaceAsyncIO->pvUser, 577 pVmdkFile->pStorage, uOffset, 578 cbToRead, pvBuf, pcbRead); 579 else 580 return RTFileReadAt(pVmdkFile->File, uOffset, pvBuf, cbToRead, pcbRead); 581 } 582 583 /** 584 * Internal: write to a file distinguishing between async and normal operation 585 */ 586 DECLINLINE(int) vmdkFileWriteAt(PVMDKFILE pVmdkFile, 587 uint64_t uOffset, const void *pvBuf, 588 size_t cbToWrite, size_t *pcbWritten) 589 { 590 PVMDKIMAGE pImage = pVmdkFile->pImage; 591 592 if (pVmdkFile->fAsyncIO) 593 return pImage->pInterfaceAsyncIOCallbacks->pfnWrite(pImage->pInterfaceAsyncIO->pvUser, 594 pVmdkFile->pStorage, uOffset, 595 cbToWrite, pvBuf, pcbWritten); 596 else 597 return RTFileWriteAt(pVmdkFile->File, uOffset, pvBuf, cbToWrite, pcbWritten); 598 } 599 600 /** 601 * Internal: get the size of a file distinguishing beween async and normal operation 602 */ 603 DECLINLINE(int) vmdkFileGetSize(PVMDKFILE pVmdkFile, uint64_t *pcbSize) 604 { 605 if (pVmdkFile->fAsyncIO) 606 { 607 AssertMsgFailed(("TODO\n")); 608 return 0; 609 } 610 else 611 return RTFileGetSize(pVmdkFile->File, pcbSize); 612 } 613 614 /** 615 * Internal: set the size of a file distinguishing beween async and normal operation 616 */ 617 DECLINLINE(int) vmdkFileSetSize(PVMDKFILE pVmdkFile, uint64_t cbSize) 618 { 619 if (pVmdkFile->fAsyncIO) 620 { 621 AssertMsgFailed(("TODO\n")); 622 return VERR_NOT_SUPPORTED; 623 } 624 else 625 return RTFileSetSize(pVmdkFile->File, cbSize); 626 } 627 628 /** 629 * Internal: flush a file distinguishing between async and normal operation 630 */ 631 DECLINLINE(int) vmdkFileFlush(PVMDKFILE pVmdkFile) 632 { 633 PVMDKIMAGE pImage = pVmdkFile->pImage; 634 635 if (pVmdkFile->fAsyncIO) 636 return pImage->pInterfaceAsyncIOCallbacks->pfnFlush(pImage->pInterfaceAsyncIO->pvUser, 637 pVmdkFile->pStorage); 638 else 639 return RTFileFlush(pVmdkFile->File); 517 640 } 518 641 … … 533 656 pVmdkFile->pszFilename)); 534 657 pImage->pFiles = pVmdkFile->pNext; 535 rc2 = RTFileClose(pVmdkFile->File); 658 659 if (pImage->uOpenFlags & VD_OPEN_FLAGS_ASYNC_IO) 660 rc2 = pImage->pInterfaceAsyncIOCallbacks->pfnClose(pImage->pInterfaceAsyncIO->pvUser, 661 pVmdkFile->pStorage); 662 else 663 rc2 = RTFileClose(pVmdkFile->File); 664 536 665 if (VBOX_SUCCESS(rc) && pVmdkFile->fDelete) 537 666 rc2 = RTFileDelete(pVmdkFile->pszFilename); … … 649 778 } 650 779 pExtent->pGD = pGD; 651 rc = RTFileReadAt(pExtent->File, VMDK_SECTOR2BYTE(pExtent->uSectorGD),652 pGD, cbGD, NULL);780 rc = vmdkFileReadAt(pExtent->pFile, VMDK_SECTOR2BYTE(pExtent->uSectorGD), 781 pGD, cbGD, NULL); 653 782 AssertRC(rc); 654 783 if (VBOX_FAILURE(rc)) … … 669 798 } 670 799 pExtent->pRGD = pRGD; 671 rc = RTFileReadAt(pExtent->File, VMDK_SECTOR2BYTE(pExtent->uSectorRGD),672 pRGD, cbGD, NULL);800 rc = vmdkFileReadAt(pExtent->pFile, VMDK_SECTOR2BYTE(pExtent->uSectorRGD), 801 pRGD, cbGD, NULL); 673 802 AssertRC(rc); 674 803 if (VBOX_FAILURE(rc)) … … 714 843 goto out; 715 844 } 716 rc = RTFileReadAt(pExtent->File, VMDK_SECTOR2BYTE(*pGDTmp),717 pTmpGT1, cbGT, NULL);845 rc = vmdkFileReadAt(pExtent->pFile, VMDK_SECTOR2BYTE(*pGDTmp), 846 pTmpGT1, cbGT, NULL); 718 847 if (VBOX_FAILURE(rc)) 719 848 { … … 723 852 goto out; 724 853 } 725 rc = RTFileReadAt(pExtent->File, VMDK_SECTOR2BYTE(*pRGDTmp),726 pTmpGT2, cbGT, NULL);854 rc = vmdkFileReadAt(pExtent->pFile, VMDK_SECTOR2BYTE(*pRGDTmp), 855 pTmpGT2, cbGT, NULL); 727 856 if (VBOX_FAILURE(rc)) 728 857 { … … 782 911 783 912 cbOverhead = RT_ALIGN_64(VMDK_SECTOR2BYTE(uStartSector) + 2 * (cbGDRounded + cbGTRounded), VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain)); 784 rc = RTFileSetSize(pExtent->File, cbOverhead);913 rc = vmdkFileSetSize(pExtent->pFile, cbOverhead); 785 914 if (VBOX_FAILURE(rc)) 786 915 goto out; … … 799 928 uGTSectorLE = RT_H2LE_U64(uOffsetSectors); 800 929 /* Write the redundant grain directory entry to disk. */ 801 rc = RTFileWriteAt(pExtent->File,802 VMDK_SECTOR2BYTE(pExtent->uSectorRGD) + i * sizeof(uGTSectorLE),803 &uGTSectorLE, sizeof(uGTSectorLE), NULL);930 rc = vmdkFileWriteAt(pExtent->pFile, 931 VMDK_SECTOR2BYTE(pExtent->uSectorRGD) + i * sizeof(uGTSectorLE), 932 &uGTSectorLE, sizeof(uGTSectorLE), NULL); 804 933 if (VBOX_FAILURE(rc)) 805 934 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write new redundant grain directory entry in '%s'"), pExtent->pszFullname); … … 813 942 uGTSectorLE = RT_H2LE_U64(uOffsetSectors); 814 943 /* Write the grain directory entry to disk. */ 815 rc = RTFileWriteAt(pExtent->File,816 VMDK_SECTOR2BYTE(pExtent->uSectorGD) + i * sizeof(uGTSectorLE),817 &uGTSectorLE, sizeof(uGTSectorLE), NULL);944 rc = vmdkFileWriteAt(pExtent->pFile, 945 VMDK_SECTOR2BYTE(pExtent->uSectorGD) + i * sizeof(uGTSectorLE), 946 &uGTSectorLE, sizeof(uGTSectorLE), NULL); 818 947 if (VBOX_FAILURE(rc)) 819 948 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write new grain directory entry in '%s'"), pExtent->pszFullname); … … 1819 1948 uint64_t cbLimit; 1820 1949 uint64_t uOffset; 1821 RTFILEDescFile;1950 PVMDKFILE pDescFile; 1822 1951 1823 1952 if (pImage->pDescData) … … 1826 1955 uOffset = 0; 1827 1956 cbLimit = 0; 1828 DescFile = pImage->File;1957 pDescFile = pImage->pFile; 1829 1958 } 1830 1959 else … … 1834 1963 cbLimit = VMDK_SECTOR2BYTE(pImage->pExtents[0].cDescriptorSectors); 1835 1964 cbLimit += uOffset; 1836 DescFile = pImage->pExtents[0].File;1965 pDescFile = pImage->pExtents[0].pFile; 1837 1966 } 1838 1967 for (unsigned i = 0; i < pImage->Descriptor.cLines; i++) … … 1843 1972 if (cbLimit && uOffset + cb + 1 > cbLimit) 1844 1973 return vmdkError(pImage, VERR_BUFFER_OVERFLOW, RT_SRC_POS, N_("VMDK: descriptor too long in '%s'"), pImage->pszFilename); 1845 rc = RTFileWriteAt(DescFile, uOffset, psz, cb, NULL);1974 rc = vmdkFileWriteAt(pDescFile, uOffset, psz, cb, NULL); 1846 1975 if (VBOX_FAILURE(rc)) 1847 1976 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error writing descriptor in '%s'"), pImage->pszFilename); 1848 1977 uOffset += cb; 1849 rc = RTFileWriteAt(DescFile, uOffset, "\n", 1, NULL);1978 rc = vmdkFileWriteAt(pDescFile, uOffset, "\n", 1, NULL); 1850 1979 if (VBOX_FAILURE(rc)) 1851 1980 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error writing descriptor in '%s'"), pImage->pszFilename); … … 1857 1986 while (uOffset < cbLimit) 1858 1987 { 1859 rc = RTFileWriteAt(DescFile, uOffset, "", 1, NULL);1988 rc = vmdkFileWriteAt(pDescFile, uOffset, "", 1, NULL); 1860 1989 if (VBOX_FAILURE(rc)) 1861 1990 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error writing descriptor in '%s'"), pImage->pszFilename); … … 1865 1994 else 1866 1995 { 1867 rc = RTFileSetSize(DescFile, uOffset);1996 rc = vmdkFileSetSize(pDescFile, uOffset); 1868 1997 if (VBOX_FAILURE(rc)) 1869 1998 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error truncating descriptor in '%s'"), pImage->pszFilename); … … 1881 2010 uint64_t cbExtentSize, cSectorsPerGDE; 1882 2011 1883 int rc = RTFileReadAt(pExtent->File, 0, &Header, sizeof(Header), NULL);2012 int rc = vmdkFileReadAt(pExtent->pFile, 0, &Header, sizeof(Header), NULL); 1884 2013 AssertRC(rc); 1885 2014 if (VBOX_FAILURE(rc)) … … 1896 2025 /* The image must be a multiple of a sector in size. If not, it means the 1897 2026 * image is at least truncated, or even seriously garbled. */ 1898 rc = RTFileGetSize(pExtent->File, &cbExtentSize);2027 rc = vmdkFileGetSize(pExtent->pFile, &cbExtentSize); 1899 2028 if (VBOX_FAILURE(rc)) 1900 2029 { … … 2005 2134 Header.doubleEndLineChar2 = '\n'; 2006 2135 2007 int rc = RTFileWriteAt(pExtent->File, 0, &Header, sizeof(Header), NULL);2136 int rc = vmdkFileWriteAt(pExtent->pFile, 0, &Header, sizeof(Header), NULL); 2008 2137 AssertRC(rc); 2009 2138 if (VBOX_FAILURE(rc)) … … 2023 2152 uint64_t cSectorsPerGDE; 2024 2153 2025 int rc = RTFileReadAt(pExtent->File, 0, &Header, sizeof(Header), NULL);2154 int rc = vmdkFileReadAt(pExtent->pFile, 0, &Header, sizeof(Header), NULL); 2026 2155 AssertRC(rc); 2027 2156 if (VBOX_FAILURE(rc)) … … 2093 2222 pExtent->pDescData = NULL; 2094 2223 } 2095 if (pExtent-> File != NIL_RTFILE)2096 { 2097 vmdkFileClose(pImage, &pExtent-> File,2224 if (pExtent->pFile != NULL) 2225 { 2226 vmdkFileClose(pImage, &pExtent->pFile, 2098 2227 fDelete 2099 2228 && pExtent->pszFullname … … 2157 2286 for (unsigned i = 0; i < cExtents; i++) 2158 2287 { 2159 pExtents[i]. File = NIL_RTFILE;2288 pExtents[i].pFile = NULL; 2160 2289 pExtents[i].pszBasename = NULL; 2161 2290 pExtents[i].pszFullname = NULL; … … 2182 2311 int rc; 2183 2312 uint32_t u32Magic; 2184 RTFILEFile;2313 PVMDKFILE pFile; 2185 2314 PVMDKEXTENT pExtent; 2186 2315 … … 2189 2318 /* 2190 2319 * Open the image. 2320 * We don't have to check for asynchronous access because 2321 * we only support raw access and the opened file is a description 2322 * file were no data is stored. 2191 2323 */ 2192 rc = vmdkFileOpen(pImage, & File, pImage->pszFilename,2324 rc = vmdkFileOpen(pImage, &pFile, pImage->pszFilename, 2193 2325 uOpenFlags & VD_OPEN_FLAGS_READONLY 2194 2326 ? RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE 2195 : RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE );2327 : RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE, false); 2196 2328 if (VBOX_FAILURE(rc)) 2197 2329 { … … 2200 2332 goto out; 2201 2333 } 2202 pImage-> File =File;2334 pImage->pFile = pFile; 2203 2335 2204 2336 /* Read magic (if present). */ 2205 rc = RTFileReadAt(File, 0, &u32Magic, sizeof(u32Magic), NULL);2337 rc = vmdkFileReadAt(pFile, 0, &u32Magic, sizeof(u32Magic), NULL); 2206 2338 if (VBOX_FAILURE(rc)) 2207 2339 { … … 2220 2352 * file, so no need to keep anything open for the image. */ 2221 2353 pExtent = &pImage->pExtents[0]; 2222 pExtent-> File =File;2223 pImage-> File = NIL_RTFILE;2354 pExtent->pFile = pFile; 2355 pImage->pFile = NULL; 2224 2356 pExtent->pszFullname = RTStrDup(pImage->pszFilename); 2225 2357 if (!pExtent->pszFullname) … … 2245 2377 goto out; 2246 2378 } 2247 rc = RTFileReadAt(pExtent->File,2248 VMDK_SECTOR2BYTE(pExtent->uDescriptorSector),2249 pExtent->pDescData,2250 VMDK_SECTOR2BYTE(pExtent->cDescriptorSectors), NULL);2379 rc = vmdkFileReadAt(pExtent->pFile, 2380 VMDK_SECTOR2BYTE(pExtent->uDescriptorSector), 2381 pExtent->pDescData, 2382 VMDK_SECTOR2BYTE(pExtent->cDescriptorSectors), NULL); 2251 2383 AssertRC(rc); 2252 2384 if (VBOX_FAILURE(rc)) … … 2279 2411 2280 2412 size_t cbRead; 2281 rc = RTFileReadAt(pImage->File, 0, pImage->pDescData,2282 pImage->cbDescAlloc, &cbRead);2413 rc = vmdkFileReadAt(pImage->pFile, 0, pImage->pDescData, 2414 pImage->cbDescAlloc, &cbRead); 2283 2415 if (VBOX_FAILURE(rc)) 2284 2416 { … … 2298 2430 if (VBOX_FAILURE(rc)) 2299 2431 goto out; 2432 2433 /* 2434 * We have to check for the asynchronous open flag. The 2435 * extents are parsed and the type of all are known now. 2436 * Check if every extent is either FLAT or ZERO. 2437 */ 2438 if (uOpenFlags & VD_OPEN_FLAGS_ASYNC_IO) 2439 { 2440 for (unsigned i = 0; i < pImage->cExtents; i++) 2441 { 2442 PVMDKEXTENT pExtent = &pImage->pExtents[i]; 2443 2444 if ( (pExtent->enmType != VMDKETYPE_FLAT) 2445 && (pExtent->enmType != VMDKETYPE_ZERO)) 2446 { 2447 /* 2448 * Opened image contains at least one none flat or zero extent. 2449 * Return error but don't set error message as the caller 2450 * has the chance to open in non async I/O mode. 2451 */ 2452 rc = VERR_NOT_SUPPORTED; 2453 goto out; 2454 } 2455 } 2456 } 2300 2457 2301 2458 for (unsigned i = 0; i < pImage->cExtents; i++) … … 2344 2501 { 2345 2502 case VMDKETYPE_HOSTED_SPARSE: 2346 rc = vmdkFileOpen(pImage, &pExtent-> File, pExtent->pszFullname,2503 rc = vmdkFileOpen(pImage, &pExtent->pFile, pExtent->pszFullname, 2347 2504 uOpenFlags & VD_OPEN_FLAGS_READONLY 2348 2505 ? RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE 2349 : RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE );2506 : RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE, false); 2350 2507 if (VBOX_FAILURE(rc)) 2351 2508 { … … 2367 2524 break; 2368 2525 case VMDKETYPE_FLAT: 2369 rc = vmdkFileOpen(pImage, &pExtent-> File, pExtent->pszFullname,2526 rc = vmdkFileOpen(pImage, &pExtent->pFile, pExtent->pszFullname, 2370 2527 uOpenFlags & VD_OPEN_FLAGS_READONLY 2371 2528 ? RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE 2372 : RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE );2529 : RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE, true); 2373 2530 if (VBOX_FAILURE(rc)) 2374 2531 { … … 2469 2626 pExtent = &pImage->pExtents[0]; 2470 2627 /* Create raw disk descriptor file. */ 2471 rc = vmdkFileOpen(pImage, &pImage->File, pImage->pszFilename, 2472 RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE | RTFILE_O_NOT_CONTENT_INDEXED); 2628 rc = vmdkFileOpen(pImage, &pImage->pFile, pImage->pszFilename, 2629 RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE | RTFILE_O_NOT_CONTENT_INDEXED, 2630 false); 2473 2631 if (VBOX_FAILURE(rc)) 2474 2632 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pImage->pszFilename); … … 2492 2650 2493 2651 /* Open flat image, the raw disk. */ 2494 rc = vmdkFileOpen(pImage, &pExtent-> File, pExtent->pszFullname,2495 RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE );2652 rc = vmdkFileOpen(pImage, &pExtent->pFile, pExtent->pszFullname, 2653 RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE, false); 2496 2654 if (VBOX_FAILURE(rc)) 2497 2655 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not open raw disk file '%s'"), pExtent->pszFullname); … … 2541 2699 2542 2700 /* Create raw partition descriptor file. */ 2543 rc = vmdkFileOpen(pImage, &pImage->File, pImage->pszFilename, 2544 RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE | RTFILE_O_NOT_CONTENT_INDEXED); 2701 rc = vmdkFileOpen(pImage, &pImage->pFile, pImage->pszFilename, 2702 RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE | RTFILE_O_NOT_CONTENT_INDEXED, 2703 false); 2545 2704 if (VBOX_FAILURE(rc)) 2546 2705 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pImage->pszFilename); … … 2612 2771 2613 2772 /* Create partition table flat image. */ 2614 rc = vmdkFileOpen(pImage, &pExtent->File, pExtent->pszFullname, 2615 RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE | RTFILE_O_NOT_CONTENT_INDEXED); 2773 rc = vmdkFileOpen(pImage, &pExtent->pFile, pExtent->pszFullname, 2774 RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE | RTFILE_O_NOT_CONTENT_INDEXED, 2775 false); 2616 2776 if (VBOX_FAILURE(rc)) 2617 2777 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new partition data file '%s'"), pExtent->pszFullname); 2618 rc = RTFileWriteAt(pExtent->File,2619 VMDK_SECTOR2BYTE(uPartOffset),2620 pPart->pvPartitionData,2621 pPart->cbPartitionData, NULL);2778 rc = vmdkFileWriteAt(pExtent->pFile, 2779 VMDK_SECTOR2BYTE(uPartOffset), 2780 pPart->pvPartitionData, 2781 pPart->cbPartitionData, NULL); 2622 2782 if (VBOX_FAILURE(rc)) 2623 2783 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not write partition data to '%s'"), pExtent->pszFullname); … … 2659 2819 2660 2820 /* Open flat image, the raw partition. */ 2661 rc = vmdkFileOpen(pImage, &pExtent->File, pExtent->pszFullname, 2662 RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE); 2821 rc = vmdkFileOpen(pImage, &pExtent->pFile, pExtent->pszFullname, 2822 RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE, 2823 false); 2663 2824 if (VBOX_FAILURE(rc)) 2664 2825 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not open raw partition file '%s'"), pExtent->pszFullname); … … 2731 2892 if (cExtents != 1 || enmType == VD_IMAGE_TYPE_FIXED) 2732 2893 { 2733 rc = vmdkFileOpen(pImage, &pImage->File, pImage->pszFilename, 2734 RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE | RTFILE_O_NOT_CONTENT_INDEXED); 2894 rc = vmdkFileOpen(pImage, &pImage->pFile, pImage->pszFilename, 2895 RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE | RTFILE_O_NOT_CONTENT_INDEXED, 2896 false); 2735 2897 if (VBOX_FAILURE(rc)) 2736 2898 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new sparse descriptor file '%s'"), pImage->pszFilename); … … 2738 2900 } 2739 2901 else 2740 pImage-> File = NIL_RTFILE;2902 pImage->pFile = NULL; 2741 2903 2742 2904 /* Set up all extents. */ … … 2801 2963 2802 2964 /* Create file for extent. */ 2803 rc = vmdkFileOpen(pImage, &pExtent->File, pExtent->pszFullname, 2804 RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE | RTFILE_O_NOT_CONTENT_INDEXED); 2965 rc = vmdkFileOpen(pImage, &pExtent->pFile, pExtent->pszFullname, 2966 RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE | RTFILE_O_NOT_CONTENT_INDEXED, 2967 false); 2805 2968 if (VBOX_FAILURE(rc)) 2806 2969 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pExtent->pszFullname); 2807 2970 if (enmType == VD_IMAGE_TYPE_FIXED) 2808 2971 { 2809 rc = RTFileSetSize(pExtent->File, cbExtent);2972 rc = vmdkFileSetSize(pExtent->pFile, cbExtent); 2810 2973 if (VBOX_FAILURE(rc)) 2811 2974 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not set size of new file '%s'"), pExtent->pszFullname); … … 2830 2993 unsigned cbChunk = (unsigned)RT_MIN(cbExtent, cbBuf); 2831 2994 2832 rc = RTFileWriteAt(pExtent->File, uOff, pvBuf, cbChunk, NULL);2995 rc = vmdkFileWriteAt(pExtent->pFile, uOff, pvBuf, cbChunk, NULL); 2833 2996 if (VBOX_FAILURE(rc)) 2834 2997 { … … 3140 3303 pImage->pExtents = NULL; 3141 3304 } 3142 if (pImage-> File != NIL_RTFILE)3143 vmdkFileClose(pImage, &pImage-> File, fDelete);3305 if (pImage->pFile != NULL) 3306 vmdkFileClose(pImage, &pImage->pFile, fDelete); 3144 3307 vmdkFileCheckAllClose(pImage); 3145 3308 } … … 3164 3327 { 3165 3328 pExtent = &pImage->pExtents[i]; 3166 if (pExtent-> File != NIL_RTFILE&& pExtent->fMetaDirty)3329 if (pExtent->pFile != NULL && pExtent->fMetaDirty) 3167 3330 { 3168 3331 switch (pExtent->enmType) … … 3196 3359 case VMDKETYPE_FLAT: 3197 3360 /** @todo implement proper path absolute check. */ 3198 if ( pExtent-> File != NIL_RTFILE3361 if ( pExtent->pFile != NULL 3199 3362 && !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY) 3200 3363 && !(pExtent->pszBasename[0] == RTPATH_SLASH)) 3201 rc = RTFileFlush(pExtent->File);3364 rc = vmdkFileFlush(pExtent->pFile); 3202 3365 break; 3203 3366 case VMDKETYPE_ZERO: … … 3285 3448 { 3286 3449 /* Cache miss, fetch data from disk. */ 3287 rc = RTFileReadAt(pExtent->File,3288 VMDK_SECTOR2BYTE(uGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp),3289 aGTDataTmp, sizeof(aGTDataTmp), NULL);3450 rc = vmdkFileReadAt(pExtent->pFile, 3451 VMDK_SECTOR2BYTE(uGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp), 3452 aGTDataTmp, sizeof(aGTDataTmp), NULL); 3290 3453 if (VBOX_FAILURE(rc)) 3291 3454 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot read grain table entry in '%s'"), pExtent->pszFullname); … … 3334 3497 * entry. So there is absolutely no data in this area. Allocate 3335 3498 * a new grain table and put the reference to it in the GDs. */ 3336 rc = RTFileGetSize(pExtent->File, &cbExtentSize);3499 rc = vmdkFileGetSize(pExtent->pFile, &cbExtentSize); 3337 3500 if (VBOX_FAILURE(rc)) 3338 3501 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: error getting size in '%s'"), pExtent->pszFullname); … … 3353 3516 i++) 3354 3517 { 3355 rc = RTFileWriteAt(pExtent->File,3356 VMDK_SECTOR2BYTE(uGTSector) + i * sizeof(aGTDataTmp),3357 aGTDataTmp, sizeof(aGTDataTmp), NULL);3518 rc = vmdkFileWriteAt(pExtent->pFile, 3519 VMDK_SECTOR2BYTE(uGTSector) + i * sizeof(aGTDataTmp), 3520 aGTDataTmp, sizeof(aGTDataTmp), NULL); 3358 3521 if (VBOX_FAILURE(rc)) 3359 3522 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write grain table allocation in '%s'"), pExtent->pszFullname); … … 3362 3525 { 3363 3526 AssertReturn(!uRGTSector, VERR_VDI_INVALID_HEADER); 3364 rc = RTFileGetSize(pExtent->File, &cbExtentSize);3527 rc = vmdkFileGetSize(pExtent->pFile, &cbExtentSize); 3365 3528 if (VBOX_FAILURE(rc)) 3366 3529 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: error getting size in '%s'"), pExtent->pszFullname); … … 3380 3543 i++) 3381 3544 { 3382 rc = RTFileWriteAt(pExtent->File,3383 VMDK_SECTOR2BYTE(uRGTSector) + i * sizeof(aGTDataTmp),3384 aGTDataTmp, sizeof(aGTDataTmp), NULL);3545 rc = vmdkFileWriteAt(pExtent->pFile, 3546 VMDK_SECTOR2BYTE(uRGTSector) + i * sizeof(aGTDataTmp), 3547 aGTDataTmp, sizeof(aGTDataTmp), NULL); 3385 3548 if (VBOX_FAILURE(rc)) 3386 3549 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write backup grain table allocation in '%s'"), pExtent->pszFullname); … … 3393 3556 * some unused sectors in the extent. */ 3394 3557 uint32_t uGTSectorLE = RT_H2LE_U64(uGTSector); 3395 rc = RTFileWriteAt(pExtent->File,3396 VMDK_SECTOR2BYTE(pExtent->uSectorGD) + uGDIndex * sizeof(uGTSectorLE),3397 &uGTSectorLE, sizeof(uGTSectorLE), NULL);3558 rc = vmdkFileWriteAt(pExtent->pFile, 3559 VMDK_SECTOR2BYTE(pExtent->uSectorGD) + uGDIndex * sizeof(uGTSectorLE), 3560 &uGTSectorLE, sizeof(uGTSectorLE), NULL); 3398 3561 if (VBOX_FAILURE(rc)) 3399 3562 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write grain directory entry in '%s'"), pExtent->pszFullname); … … 3401 3564 { 3402 3565 uint32_t uRGTSectorLE = RT_H2LE_U64(uRGTSector); 3403 rc = RTFileWriteAt(pExtent->File,3404 VMDK_SECTOR2BYTE(pExtent->uSectorRGD) + uGDIndex * sizeof(uRGTSectorLE),3405 &uRGTSectorLE, sizeof(uRGTSectorLE), NULL);3566 rc = vmdkFileWriteAt(pExtent->pFile, 3567 VMDK_SECTOR2BYTE(pExtent->uSectorRGD) + uGDIndex * sizeof(uRGTSectorLE), 3568 &uRGTSectorLE, sizeof(uRGTSectorLE), NULL); 3406 3569 if (VBOX_FAILURE(rc)) 3407 3570 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write backup grain directory entry in '%s'"), pExtent->pszFullname); … … 3414 3577 } 3415 3578 3416 rc = RTFileGetSize(pExtent->File, &cbExtentSize);3579 rc = vmdkFileGetSize(pExtent->pFile, &cbExtentSize); 3417 3580 if (VBOX_FAILURE(rc)) 3418 3581 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: error getting size in '%s'"), pExtent->pszFullname); … … 3420 3583 3421 3584 /* Write the data. */ 3422 rc = RTFileWriteAt(pExtent->File, cbExtentSize, pvBuf, cbWrite, NULL);3585 rc = vmdkFileWriteAt(pExtent->pFile, cbExtentSize, pvBuf, cbWrite, NULL); 3423 3586 if (VBOX_FAILURE(rc)) 3424 3587 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write allocated data block in '%s'"), pExtent->pszFullname); … … 3432 3595 { 3433 3596 /* Cache miss, fetch data from disk. */ 3434 rc = RTFileReadAt(pExtent->File,3435 VMDK_SECTOR2BYTE(uGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp),3436 aGTDataTmp, sizeof(aGTDataTmp), NULL);3597 rc = vmdkFileReadAt(pExtent->pFile, 3598 VMDK_SECTOR2BYTE(uGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp), 3599 aGTDataTmp, sizeof(aGTDataTmp), NULL); 3437 3600 if (VBOX_FAILURE(rc)) 3438 3601 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot read allocated grain table entry in '%s'"), pExtent->pszFullname); … … 3453 3616 pGTCacheEntry->aGTData[uGTBlockIndex] = VMDK_BYTE2SECTOR(cbExtentSize); 3454 3617 /* Update grain table on disk. */ 3455 rc = RTFileWriteAt(pExtent->File,3456 VMDK_SECTOR2BYTE(uGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp),3457 aGTDataTmp, sizeof(aGTDataTmp), NULL);3618 rc = vmdkFileWriteAt(pExtent->pFile, 3619 VMDK_SECTOR2BYTE(uGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp), 3620 aGTDataTmp, sizeof(aGTDataTmp), NULL); 3458 3621 if (VBOX_FAILURE(rc)) 3459 3622 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write updated grain table in '%s'"), pExtent->pszFullname); … … 3461 3624 { 3462 3625 /* Update backup grain table on disk. */ 3463 rc = RTFileWriteAt(pExtent->File,3464 VMDK_SECTOR2BYTE(uRGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp),3465 aGTDataTmp, sizeof(aGTDataTmp), NULL);3626 rc = vmdkFileWriteAt(pExtent->pFile, 3627 VMDK_SECTOR2BYTE(uRGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp), 3628 aGTDataTmp, sizeof(aGTDataTmp), NULL); 3466 3629 if (VBOX_FAILURE(rc)) 3467 3630 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write updated backup grain table in '%s'"), pExtent->pszFullname); … … 3500 3663 } 3501 3664 pImage->pszFilename = pszFilename; 3502 pImage-> File = NIL_RTFILE;3665 pImage->pFile = NULL; 3503 3666 pImage->pExtents = NULL; 3504 3667 pImage->pFiles = NULL; 3505 3668 pImage->pGTCache = NULL; 3506 3669 pImage->pDescData = NULL; 3507 pImage->p fnError = NULL;3508 pImage->p vErrorUser= NULL;3670 pImage->pInterfaceError = NULL; 3671 pImage->pInterfaceErrorCallbacks = NULL; 3509 3672 /** @todo speed up this test open (VD_OPEN_FLAGS_INFO) by skipping as 3510 3673 * much as possible in vmdkOpenImage. */ … … 3519 3682 /** @copydoc VBOXHDDBACKEND::pfnOpen */ 3520 3683 static int vmdkOpen(const char *pszFilename, unsigned uOpenFlags, 3521 P FNVDERROR pfnError, void *pvErrorUser,3684 PVDINTERFACE pInterfaces, 3522 3685 void **ppBackendData) 3523 3686 { … … 3550 3713 } 3551 3714 pImage->pszFilename = pszFilename; 3552 pImage-> File = NIL_RTFILE;3715 pImage->pFile = NULL; 3553 3716 pImage->pExtents = NULL; 3554 3717 pImage->pFiles = NULL; 3555 3718 pImage->pGTCache = NULL; 3556 3719 pImage->pDescData = NULL; 3557 pImage->pfnError = pfnError; 3558 pImage->pvErrorUser = pvErrorUser; 3720 pImage->pInterfaceError = NULL; 3721 pImage->pInterfaceErrorCallbacks = NULL; 3722 3723 /* Try to get error interface. */ 3724 pImage->pInterfaceError = VDGetInterfaceFromList(pInterfaces, VDINTERFACETYPE_ERROR); 3725 if (pImage->pInterfaceError) 3726 pImage->pInterfaceErrorCallbacks = VDGetInterfaceError(pImage->pInterfaceError->pCallbacks); 3727 3728 /* Try to get async I/O interfaec. */ 3729 pImage->pInterfaceAsyncIO = VDGetInterfaceFromList(pInterfaces, VDINTERFACETYPE_ASYNCIO); 3730 if (pImage->pInterfaceAsyncIO) 3731 pImage->pInterfaceAsyncIOCallbacks = VDGetInterfaceAsyncIO(pImage->pInterfaceAsyncIO->pCallbacks); 3732 3559 3733 3560 3734 rc = vmdkOpenImage(pImage, uOpenFlags); … … 3575 3749 unsigned uOpenFlags, PFNVMPROGRESS pfnProgress, 3576 3750 void *pvUser, unsigned uPercentStart, 3577 unsigned uPercentSpan, P FNVDERROR pfnError,3578 void * pvErrorUser, void **ppBackendData)3579 { 3580 LogFlowFunc(("pszFilename=\"%s\" enmType=%d cbSize=%llu uImageFlags=%#x pszComment=\"%s\" pPCHSGeometry=%#p pLCHSGeometry=%#p uOpenFlags=%#x pfnProgress=%#p pvUser=%#p uPercentStart=%u uPercentSpan=%u p fnError=%#p pvErrorUser=%#p ppBackendData=%#p", pszFilename, enmType, cbSize, uImageFlags, pszComment, pPCHSGeometry, pLCHSGeometry, uOpenFlags, pfnProgress, pvUser, uPercentStart, uPercentSpan, pfnError, pvErrorUser, ppBackendData));3751 unsigned uPercentSpan, PVDINTERFACE pInterfaces, 3752 void **ppBackendData) 3753 { 3754 LogFlowFunc(("pszFilename=\"%s\" enmType=%d cbSize=%llu uImageFlags=%#x pszComment=\"%s\" pPCHSGeometry=%#p pLCHSGeometry=%#p uOpenFlags=%#x pfnProgress=%#p pvUser=%#p uPercentStart=%u uPercentSpan=%u pInterfaces=%#p ppBackendData=%#p", pszFilename, enmType, cbSize, uImageFlags, pszComment, pPCHSGeometry, pLCHSGeometry, uOpenFlags, pfnProgress, pvUser, uPercentStart, uPercentSpan, pInterfaces, ppBackendData)); 3581 3755 int rc; 3582 3756 PVMDKIMAGE pImage; … … 3612 3786 } 3613 3787 pImage->pszFilename = pszFilename; 3614 pImage-> File = NIL_RTFILE;3788 pImage->pFile = NULL; 3615 3789 pImage->pExtents = NULL; 3616 3790 pImage->pFiles = NULL; 3617 3791 pImage->pGTCache = NULL; 3618 3792 pImage->pDescData = NULL; 3619 pImage->p fnError = pfnError;3620 pImage->p vErrorUser = pvErrorUser;3793 pImage->pInterfaceError = NULL; 3794 pImage->pInterfaceErrorCallbacks = NULL; 3621 3795 pImage->cbDescAlloc = VMDK_SECTOR2BYTE(20); 3622 3796 pImage->pDescData = (char *)RTMemAllocZ(pImage->cbDescAlloc); … … 3626 3800 goto out; 3627 3801 } 3802 3803 /* Get error interface. */ 3804 pImage->pInterfaceError = VDGetInterfaceFromList(pInterfaces, VDINTERFACETYPE_ERROR); 3805 if (pImage->pInterfaceError) 3806 pImage->pInterfaceErrorCallbacks = VDGetInterfaceError(pImage->pInterfaceError); 3628 3807 3629 3808 rc = vmdkCreateImage(pImage, enmType, cbSize, uImageFlags, pszComment, … … 3780 3959 goto rollback; 3781 3960 /* Close the extent file. */ 3782 vmdkFileClose(pImage, &pExtent-> File, false);3961 vmdkFileClose(pImage, &pExtent->pFile, false); 3783 3962 /* Rename the extent file. */ 3784 3963 rc = RTFileMove(pExtent->pszFullname, apszNewName[i], 0); … … 3846 4025 } 3847 4026 /* Restore the old descriptor. */ 3848 RTFILEFile;3849 rrc = RTFileOpen(&File, pszOldDescName,3850 RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE );4027 PVMDKFILE pFile; 4028 rrc = vmdkFileOpen(pImage, &pFile, pszOldDescName, 4029 RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE, false); 3851 4030 AssertRC(rrc); 3852 4031 if (fEmbeddedDesc) 3853 4032 { 3854 ExtentCopy. File =File;4033 ExtentCopy.pFile = pFile; 3855 4034 pImage->pExtents = &ExtentCopy; 3856 4035 } 3857 4036 else 3858 pImage-> File =File;4037 pImage->pFile = pFile; 3859 4038 pImage->Descriptor = DescriptorCopy; 3860 4039 vmdkWriteDescriptor(pImage); 3861 RTFileClose(File);4040 vmdkFileClose(pImage, &pFile, false); 3862 4041 RTStrFree(pszOldDescName); 3863 4042 /* Re-open the image back. */ … … 3950 4129 rc = VERR_VDI_BLOCK_FREE; 3951 4130 else 3952 rc = RTFileReadAt(pExtent->File,3953 VMDK_SECTOR2BYTE(uSectorExtentAbs),3954 pvBuf, cbToRead, NULL);4131 rc = vmdkFileReadAt(pExtent->pFile, 4132 VMDK_SECTOR2BYTE(uSectorExtentAbs), 4133 pvBuf, cbToRead, NULL); 3955 4134 break; 3956 4135 case VMDKETYPE_FLAT: 3957 rc = RTFileReadAt(pExtent->File,3958 VMDK_SECTOR2BYTE(uSectorExtentRel),3959 pvBuf, cbToRead, NULL);4136 rc = vmdkFileReadAt(pExtent->pFile, 4137 VMDK_SECTOR2BYTE(uSectorExtentRel), 4138 pvBuf, cbToRead, NULL); 3960 4139 break; 3961 4140 case VMDKETYPE_ZERO: … … 4057 4236 } 4058 4237 else 4059 rc = RTFileWriteAt(pExtent->File,4060 VMDK_SECTOR2BYTE(uSectorExtentAbs),4061 pvBuf, cbToWrite, NULL);4238 rc = vmdkFileWriteAt(pExtent->pFile, 4239 VMDK_SECTOR2BYTE(uSectorExtentAbs), 4240 pvBuf, cbToWrite, NULL); 4062 4241 break; 4063 4242 case VMDKETYPE_FLAT: 4064 4243 /* Clip write range to remain in this extent. */ 4065 4244 cbToWrite = RT_MIN(cbToWrite, VMDK_SECTOR2BYTE(pExtent->uSectorOffset + pExtent->cNominalSectors - uSectorExtentRel)); 4066 rc = RTFileWriteAt(pExtent->File,4067 VMDK_SECTOR2BYTE(uSectorExtentRel),4068 pvBuf, cbToWrite, NULL);4245 rc = vmdkFileWriteAt(pExtent->pFile, 4246 VMDK_SECTOR2BYTE(uSectorExtentRel), 4247 pvBuf, cbToWrite, NULL); 4069 4248 break; 4070 4249 case VMDKETYPE_ZERO: … … 4154 4333 { 4155 4334 uint64_t cbFile; 4156 if (pImage-> File != NIL_RTFILE)4157 { 4158 int rc = RTFileGetSize(pImage->File, &cbFile);4335 if (pImage->pFile != NULL) 4336 { 4337 int rc = vmdkFileGetSize(pImage->pFile, &cbFile); 4159 4338 if (VBOX_SUCCESS(rc)) 4160 4339 cb += cbFile; 4161 4340 for (unsigned i = 0; i <= pImage->cExtents; i++) 4162 4341 { 4163 rc = RTFileGetSize(pImage->File, &cbFile);4342 rc = vmdkFileGetSize(pImage->pFile, &cbFile); 4164 4343 if (VBOX_SUCCESS(rc)) 4165 4344 cb += cbFile; … … 4336 4515 /* Image must be opened and the new flags must be valid. Just readonly flag 4337 4516 * is supported. */ 4338 if (!pImage || uOpenFlags & ~ VD_OPEN_FLAGS_READONLY)4517 if (!pImage || uOpenFlags & ~(VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_ASYNC_IO)) 4339 4518 { 4340 4519 rc = VERR_INVALID_PARAMETER; … … 4672 4851 } 4673 4852 4853 static bool vmdkIsAsyncIOSupported(void *pvBackendData) 4854 { 4855 PVMDKIMAGE pImage = (PVMDKIMAGE)pvBackendData; 4856 bool fAsyncIOSupported = false; 4857 4858 if (pImage) 4859 { 4860 /* We only support async I/O support if the image only consists of FLAT or ZERO extents. */ 4861 fAsyncIOSupported = true; 4862 for (unsigned i = 0; i < pImage->cExtents; i++) 4863 { 4864 if ( (pImage->pExtents[i].enmType != VMDKETYPE_FLAT) 4865 && (pImage->pExtents[i].enmType != VMDKETYPE_ZERO)) 4866 { 4867 fAsyncIOSupported = false; 4868 break; /* Stop search */ 4869 } 4870 } 4871 } 4872 4873 return fAsyncIOSupported; 4874 } 4875 4876 static int vmdkAsyncRead(void *pvBackendData, uint64_t uOffset, size_t cbRead, 4877 PPDMDATASEG paSeg, unsigned cSeg, void *pvUser) 4878 { 4879 PVMDKIMAGE pImage = (PVMDKIMAGE)pvBackendData; 4880 PVMDKEXTENT pExtent; 4881 int rc = VINF_SUCCESS; 4882 unsigned cTasksToSubmit = 0; 4883 PPDMDATASEG paSegCurrent = paSeg; 4884 unsigned cbLeftInCurrentSegment = paSegCurrent->cbSeg; 4885 unsigned uOffsetInCurrentSegment = 0; 4886 4887 Assert(pImage); 4888 Assert(uOffset % 512 == 0); 4889 Assert(cbRead % 512 == 0); 4890 4891 if ( uOffset + cbRead > pImage->cbSize 4892 || cbRead == 0) 4893 { 4894 rc = VERR_INVALID_PARAMETER; 4895 goto out; 4896 } 4897 4898 while (cbRead && cSeg) 4899 { 4900 unsigned cbToRead; 4901 uint64_t uSectorExtentRel; 4902 4903 rc = vmdkFindExtent(pImage, VMDK_BYTE2SECTOR(uOffset), 4904 &pExtent, &uSectorExtentRel); 4905 if (VBOX_FAILURE(rc)) 4906 goto out; 4907 4908 /* Check access permissions as defined in the extent descriptor. */ 4909 if (pExtent->enmAccess == VMDKACCESS_NOACCESS) 4910 { 4911 rc = VERR_VDI_INVALID_STATE; 4912 goto out; 4913 } 4914 4915 /* Clip read range to remain in this extent. */ 4916 cbToRead = RT_MIN(cbRead, VMDK_SECTOR2BYTE(pExtent->uSectorOffset + pExtent->cNominalSectors - uSectorExtentRel)); 4917 /* Clip read range to remain into current data segment. */ 4918 cbToRead = RT_MIN(cbToRead, cbLeftInCurrentSegment); 4919 4920 switch (pExtent->enmType) 4921 { 4922 case VMDKETYPE_FLAT: 4923 { 4924 /* Setup new task. */ 4925 void *pTask; 4926 rc = pImage->pInterfaceAsyncIOCallbacks->pfnPrepareRead(pImage->pInterfaceAsyncIO->pvUser, pExtent->pFile->pStorage, 4927 VMDK_SECTOR2BYTE(uSectorExtentRel), 4928 (uint8_t *)paSegCurrent->pvSeg + uOffsetInCurrentSegment, 4929 cbToRead, &pTask); 4930 if (VBOX_FAILURE(rc)) 4931 { 4932 AssertMsgFailed(("Preparing read failed rc=%Vrc\n", rc)); 4933 goto out; 4934 } 4935 4936 /* Check for enough room first. */ 4937 if (cTasksToSubmit >= pImage->cTask) 4938 { 4939 /* We reached maximum, resize array. Try to realloc memory first. */ 4940 void **apTaskNew = (void **)RTMemRealloc(pImage->apTask, (cTasksToSubmit + 10)*sizeof(void *)); 4941 4942 if (!apTaskNew) 4943 { 4944 /* We failed. Allocate completely new. */ 4945 apTaskNew = (void **)RTMemAllocZ((cTasksToSubmit + 10)* sizeof(void *)); 4946 if (!apTaskNew) 4947 { 4948 /* Damn, we are out of memory. */ 4949 rc = VERR_NO_MEMORY; 4950 goto out; 4951 } 4952 4953 /* Copy task handles over. */ 4954 for (unsigned i = 0; i < cTasksToSubmit; i++) 4955 apTaskNew[i] = pImage->apTask[i]; 4956 4957 /* Free old memory. */ 4958 RTMemFree(pImage->apTask); 4959 } 4960 4961 pImage->cTask = cTasksToSubmit + 10; 4962 pImage->apTask = apTaskNew; 4963 } 4964 4965 pImage->apTask[cTasksToSubmit] = pTask; 4966 cTasksToSubmit++; 4967 break; 4968 } 4969 case VMDKETYPE_ZERO: 4970 memset((uint8_t *)paSegCurrent->pvSeg + uOffsetInCurrentSegment, 0, cbToRead); 4971 break; 4972 default: 4973 AssertMsgFailed(("Unsupported extent type %u\n", pExtent->enmType)); 4974 } 4975 4976 cbRead -= cbToRead; 4977 uOffset += cbToRead; 4978 cbLeftInCurrentSegment -= cbToRead; 4979 uOffsetInCurrentSegment += cbToRead; 4980 /* Go to next extent if there is no space left in current one. */ 4981 if (!cbLeftInCurrentSegment) 4982 { 4983 uOffsetInCurrentSegment = 0; 4984 paSegCurrent++; 4985 cSeg--; 4986 cbLeftInCurrentSegment = paSegCurrent->cbSeg; 4987 } 4988 } 4989 4990 AssertMsg((cSeg >= 0) && (cbRead == 0), ("No segment left but there is still data to read\n")); 4991 4992 if (cTasksToSubmit == 0) 4993 { 4994 /* The request was completely in a ZERO extent nothing to do. */ 4995 rc = VINF_VDI_ASYNC_IO_FINISHED; 4996 } 4997 else 4998 { 4999 /* Submit tasks. */ 5000 rc = pImage->pInterfaceAsyncIOCallbacks->pfnTasksSubmit(pImage->pInterfaceAsyncIO->pvUser, 5001 pImage->apTask, cTasksToSubmit, 5002 NULL, pvUser, 5003 NULL /* Nothing required after read. */); 5004 AssertMsg(VBOX_SUCCESS(rc), ("Failed to enqueue tasks rc=%Vrc\n", rc)); 5005 } 5006 5007 out: 5008 LogFlowFunc(("returns %Vrc\n", rc)); 5009 return rc; 5010 } 5011 5012 static int vmdkAsyncWrite(void *pvBackendData, uint64_t uOffset, size_t cbWrite, 5013 PPDMDATASEG paSeg, unsigned cSeg, void *pvUser) 5014 { 5015 PVMDKIMAGE pImage = (PVMDKIMAGE)pvBackendData; 5016 PVMDKEXTENT pExtent; 5017 int rc = VINF_SUCCESS; 5018 unsigned cTasksToSubmit = 0; 5019 PPDMDATASEG paSegCurrent = paSeg; 5020 unsigned cbLeftInCurrentSegment = paSegCurrent->cbSeg; 5021 unsigned uOffsetInCurrentSegment = 0; 5022 5023 Assert(pImage); 5024 Assert(uOffset % 512 == 0); 5025 Assert(cbWrite % 512 == 0); 5026 5027 if ( uOffset + cbWrite > pImage->cbSize 5028 || cbWrite == 0) 5029 { 5030 rc = VERR_INVALID_PARAMETER; 5031 goto out; 5032 } 5033 5034 while (cbWrite && cSeg) 5035 { 5036 unsigned cbToWrite; 5037 uint64_t uSectorExtentRel; 5038 5039 rc = vmdkFindExtent(pImage, VMDK_BYTE2SECTOR(uOffset), 5040 &pExtent, &uSectorExtentRel); 5041 if (VBOX_FAILURE(rc)) 5042 goto out; 5043 5044 /* Check access permissions as defined in the extent descriptor. */ 5045 if (pExtent->enmAccess == VMDKACCESS_NOACCESS) 5046 { 5047 rc = VERR_VDI_INVALID_STATE; 5048 goto out; 5049 } 5050 5051 /* Clip write range to remain in this extent. */ 5052 cbToWrite = RT_MIN(cbWrite, VMDK_SECTOR2BYTE(pExtent->uSectorOffset + pExtent->cNominalSectors - uSectorExtentRel)); 5053 /* Clip write range to remain into current data segment. */ 5054 cbToWrite = RT_MIN(cbToWrite, cbLeftInCurrentSegment); 5055 5056 switch (pExtent->enmType) 5057 { 5058 case VMDKETYPE_FLAT: 5059 { 5060 /* Setup new task. */ 5061 void *pTask; 5062 rc = pImage->pInterfaceAsyncIOCallbacks->pfnPrepareWrite(pImage->pInterfaceAsyncIO->pvUser, pExtent->pFile->pStorage, 5063 VMDK_SECTOR2BYTE(uSectorExtentRel), 5064 (uint8_t *)paSegCurrent->pvSeg + uOffsetInCurrentSegment, 5065 cbToWrite, &pTask); 5066 if (VBOX_FAILURE(rc)) 5067 { 5068 AssertMsgFailed(("Preparing read failed rc=%Vrc\n", rc)); 5069 goto out; 5070 } 5071 5072 /* Check for enough room first. */ 5073 if (cTasksToSubmit >= pImage->cTask) 5074 { 5075 /* We reached maximum, resize array. Try to realloc memory first. */ 5076 void **apTaskNew = (void **)RTMemRealloc(pImage->apTask, (cTasksToSubmit + 10)*sizeof(void *)); 5077 5078 if (!apTaskNew) 5079 { 5080 /* We failed. Allocate completely new. */ 5081 apTaskNew = (void **)RTMemAllocZ((cTasksToSubmit + 10)* sizeof(void *)); 5082 if (!apTaskNew) 5083 { 5084 /* Damn, we are out of memory. */ 5085 rc = VERR_NO_MEMORY; 5086 goto out; 5087 } 5088 5089 /* Copy task handles over. */ 5090 for (unsigned i = 0; i < cTasksToSubmit; i++) 5091 apTaskNew[i] = pImage->apTask[i]; 5092 5093 /* Free old memory. */ 5094 RTMemFree(pImage->apTask); 5095 } 5096 5097 pImage->cTask = cTasksToSubmit + 10; 5098 pImage->apTask = apTaskNew; 5099 } 5100 5101 pImage->apTask[cTasksToSubmit] = pTask; 5102 cTasksToSubmit++; 5103 break; 5104 } 5105 case VMDKETYPE_ZERO: 5106 /* Nothing left to do. */ 5107 break; 5108 default: 5109 AssertMsgFailed(("Unsupported extent type %u\n", pExtent->enmType)); 5110 } 5111 5112 cbWrite -= cbToWrite; 5113 uOffset += cbToWrite; 5114 cbLeftInCurrentSegment -= cbToWrite; 5115 uOffsetInCurrentSegment += cbToWrite; 5116 /* Go to next extent if there is no space left in current one. */ 5117 if (!cbLeftInCurrentSegment) 5118 { 5119 uOffsetInCurrentSegment = 0; 5120 paSegCurrent++; 5121 cSeg--; 5122 cbLeftInCurrentSegment = paSegCurrent->cbSeg; 5123 } 5124 } 5125 5126 AssertMsg((cSeg >= 0) && (cbWrite == 0), ("No segment left but there is still data to read\n")); 5127 5128 if (cTasksToSubmit == 0) 5129 { 5130 /* The request was completely in a ZERO extent nothing to do. */ 5131 rc = VINF_VDI_ASYNC_IO_FINISHED; 5132 } 5133 else 5134 { 5135 /* Submit tasks. */ 5136 rc = pImage->pInterfaceAsyncIOCallbacks->pfnTasksSubmit(pImage->pInterfaceAsyncIO->pvUser, 5137 pImage->apTask, cTasksToSubmit, 5138 NULL, pvUser, 5139 NULL /* Nothing required after read. */); 5140 AssertMsg(VBOX_SUCCESS(rc), ("Failed to enqueue tasks rc=%Vrc\n", rc)); 5141 } 5142 5143 out: 5144 LogFlowFunc(("returns %Vrc\n", rc)); 5145 return rc; 5146 5147 } 5148 5149 4674 5150 VBOXHDDBACKEND g_VmdkBackend = 4675 5151 { … … 4680 5156 /* uBackendCaps */ 4681 5157 VD_CAP_UUID | VD_CAP_CREATE_FIXED | VD_CAP_CREATE_DYNAMIC 4682 | VD_CAP_CREATE_SPLIT_2G | VD_CAP_DIFF | VD_CAP_FILE ,5158 | VD_CAP_CREATE_SPLIT_2G | VD_CAP_DIFF | VD_CAP_FILE |VD_CAP_ASYNC, 4683 5159 /* pfnCheckIfValid */ 4684 5160 vmdkCheckIfValid, … … 4750 5226 vmdkGetParentFilename, 4751 5227 /* pfnSetParentFilename */ 4752 vmdkSetParentFilename 5228 vmdkSetParentFilename, 5229 /* pfnIsAsyncIOSupported */ 5230 vmdkIsAsyncIOSupported, 5231 /* pfnAsyncRead */ 5232 vmdkAsyncRead, 5233 /* pfnAsyncWrite */ 5234 vmdkAsyncWrite 4753 5235 }; -
trunk/src/VBox/Devices/Storage/testcase/tstVD.cpp
r9734 r10715 56 56 PDMMEDIAGEOMETRY PCHS = { 0, 0, 0 }; 57 57 PDMMEDIAGEOMETRY LCHS = { 0, 0, 0 }; 58 VDINTERFACE VDIError; 59 VDINTERFACEERROR VDIErrorCallbacks; 58 60 59 61 #define CHECK(str) \ … … 68 70 } while (0) 69 71 70 rc = VDCreate(tstVDError, NULL, &pVD); 72 /* Create error interface. */ 73 VDIErrorCallbacks.cbSize = sizeof(VDINTERFACEERROR); 74 VDIErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR; 75 VDIErrorCallbacks.pfnError = tstVDError; 76 77 rc = VDInterfaceCreate(&VDIError, "tstVD_Error", VDINTERFACETYPE_ERROR, &VDIErrorCallbacks, 78 NULL, NULL); 79 AssertRC(rc); 80 81 rc = VDCreate(&VDIError, &pVD); 71 82 CHECK("VDCreate()"); 72 83 … … 420 431 uint64_t u64DiskSize = 1000 * _1M; 421 432 uint32_t u32SectorSize = 512; 433 VDINTERFACE VDIError; 434 VDINTERFACEERROR VDIErrorCallbacks; 422 435 423 436 #define CHECK(str) \ … … 432 445 } while (0) 433 446 434 rc = VDCreate(tstVDError, NULL, &pVD); 447 /* Create error interface. */ 448 VDIErrorCallbacks.cbSize = sizeof(VDINTERFACEERROR); 449 VDIErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR; 450 VDIErrorCallbacks.pfnError = tstVDError; 451 452 rc = VDInterfaceCreate(&VDIError, "tstVD_Error", VDINTERFACETYPE_ERROR, &VDIErrorCallbacks, 453 NULL, NULL); 454 AssertRC(rc); 455 456 457 rc = VDCreate(&VDIError, &pVD); 435 458 CHECK("VDCreate()"); 436 459 … … 526 549 uint64_t u64DiskSize = 1000 * _1M; 527 550 uint32_t u32SectorSize = 512; 551 VDINTERFACE VDIError; 552 VDINTERFACEERROR VDIErrorCallbacks; 528 553 529 554 #define CHECK(str) \ … … 538 563 } while (0) 539 564 540 rc = VDCreate(tstVDError, NULL, &pVD); 565 /* Create error interface. */ 566 VDIErrorCallbacks.cbSize = sizeof(VDINTERFACEERROR); 567 VDIErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR; 568 VDIErrorCallbacks.pfnError = tstVDError; 569 570 rc = VDInterfaceCreate(&VDIError, "tstVD_Error", VDINTERFACETYPE_ERROR, &VDIErrorCallbacks, 571 NULL, NULL); 572 AssertRC(rc); 573 574 575 rc = VDCreate(&VDIError, &pVD); 541 576 CHECK("VDCreate()"); 542 577
Note:
See TracChangeset
for help on using the changeset viewer.