Changeset 10715 in vbox for trunk/src/VBox/Devices/Storage/DrvVD.cpp
- Timestamp:
- Jul 16, 2008 10:38:23 PM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
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 };
Note:
See TracChangeset
for help on using the changeset viewer.