Changeset 20167 in vbox for trunk/src/VBox/Devices/Storage
- Timestamp:
- Jun 1, 2009 8:25:54 PM (16 years ago)
- Location:
- trunk/src/VBox/Devices/Storage
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Storage/DrvVD.cpp
r18778 r20167 27 27 #include <VBox/VBoxHDD.h> 28 28 #include <VBox/pdmdrv.h> 29 #include <VBox/pdmasynccompletion.h> 29 30 #include <iprt/alloc.h> 30 31 #include <iprt/assert.h> … … 34 35 #include <iprt/cache.h> 35 36 #include <iprt/tcp.h> 37 #include <iprt/semaphore.h> 36 38 37 39 #ifdef VBOX_WITH_INIP … … 72 74 ( (PVBOXDISK)((uintptr_t)pInterface - RT_OFFSETOF(VBOXDISK, IMediaAsync)) ) 73 75 74 /** Converts a pointer to VBOXDISK::ITransportAsyncPort to a PVBOXDISK. */75 #define PDMITRANSPORTASYNCPORT_2_VBOXDISK(pInterface) \76 ( (PVBOXDISK)((uintptr_t)pInterface - RT_OFFSETOF(VBOXDISK, ITransportAsyncPort)) )77 78 /**79 * Structure for an async I/O task.80 */81 typedef struct DRVVDASYNCTASK82 {83 /** Callback which is called on completion. */84 PFNVDCOMPLETED pfnCompleted;85 /** Opqaue user data which is passed on completion. */86 void *pvUser;87 /** Opaque user data the caller passed on transfer initiation. */88 void *pvUserCaller;89 } DRVVDASYNCTASK, *PDRVVDASYNCTASK;90 91 76 /** 92 77 * VBox disk container, image information, private part. … … 102 87 VDINTERFACE VDIConfig; 103 88 } VBOXIMAGE, *PVBOXIMAGE; 89 90 /** 91 * Storage backend data. 92 */ 93 typedef struct DRVVDSTORAGEBACKEND 94 { 95 /** PDM async completion end point. */ 96 PPDMASYNCCOMPLETIONENDPOINT pEndpoint; 97 /** The template. */ 98 PPDMASYNCCOMPLETIONTEMPLATE pTemplate; 99 /** Event semaphore for synchronous operations. */ 100 RTSEMEVENT EventSem; 101 /** Flag whether a synchronous operation is currently pending. */ 102 volatile bool fSyncIoPending; 103 /** Callback routine */ 104 PFNVDCOMPLETED pfnCompleted; 105 } DRVVDSTORAGEBACKEND, *PDRVVDSTORAGEBACKEND; 104 106 105 107 /** … … 140 142 /** The async media port interface above. */ 141 143 PPDMIMEDIAASYNCPORT pDrvMediaAsyncPort; 142 /** Pointer to the asynchronous media driver below. */143 PPDMITRANSPORTASYNC pDrvTransportAsync;144 /** Async transport port interface. */145 PDMITRANSPORTASYNCPORT ITransportAsyncPort;146 /** Our cache to reduce allocation overhead. */147 PRTOBJCACHE pCache;148 144 /** Pointer to the list of data we need to keep per image. */ 149 145 PVBOXIMAGE pImages; … … 207 203 *******************************************************************************/ 208 204 209 static DECLCALLBACK(int) drvvdAsyncIOOpen(void *pvUser, const char *pszLocation, bool fReadonly, void **ppStorage) 205 static DECLCALLBACK(void) drvvdAsyncTaskCompleted(PPDMDRVINS pDrvIns, void *pvTemplateUser, void *pvUser) 206 { 207 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK); 208 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pvTemplateUser; 209 int rc = VINF_VD_ASYNC_IO_FINISHED; 210 void *pvCallerUser = NULL; 211 212 if (pStorageBackend->fSyncIoPending) 213 { 214 pStorageBackend->fSyncIoPending; 215 RTSemEventSignal(pStorageBackend->EventSem); 216 } 217 else if (pStorageBackend->pfnCompleted) 218 rc = pStorageBackend->pfnCompleted(pvUser, &pvCallerUser); 219 else 220 pvCallerUser = pvUser; 221 222 if (rc == VINF_VD_ASYNC_IO_FINISHED) 223 { 224 rc = pThis->pDrvMediaAsyncPort->pfnTransferCompleteNotify(pThis->pDrvMediaAsyncPort, pvCallerUser); 225 AssertRC(rc); 226 } 227 else 228 AssertMsg(rc == VERR_VD_ASYNC_IO_IN_PROGRESS, ("Invalid return code from disk backend rc=%Rrc\n", rc)); 229 } 230 231 static DECLCALLBACK(int) drvvdAsyncIOOpen(void *pvUser, const char *pszLocation, bool fReadonly, 232 PFNVDCOMPLETED pfnCompleted, void **ppStorage) 210 233 { 211 234 PVBOXDISK pDrvVD = (PVBOXDISK)pvUser; 212 213 return pDrvVD->pDrvTransportAsync->pfnOpen(pDrvVD->pDrvTransportAsync, pszLocation, fReadonly, ppStorage); 235 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)RTMemAllocZ(sizeof(DRVVDSTORAGEBACKEND)); 236 int rc = VINF_SUCCESS; 237 238 if (pStorageBackend) 239 { 240 pStorageBackend->fSyncIoPending = false; 241 pStorageBackend->pfnCompleted = pfnCompleted; 242 243 int rc = RTSemEventCreate(&pStorageBackend->EventSem); 244 if (RT_SUCCESS(rc)) 245 { 246 rc = PDMDrvHlpPDMAsyncCompletionTemplateCreate(pDrvVD->pDrvIns, &pStorageBackend->pTemplate, 247 drvvdAsyncTaskCompleted, pStorageBackend, "AsyncTaskCompleted"); 248 if (RT_SUCCESS(rc)) 249 { 250 rc = PDMR3AsyncCompletionEpCreateForFile(&pStorageBackend->pEndpoint, pszLocation, 251 fReadonly 252 ? PDMACEP_FILE_FLAGS_READ_ONLY | PDMACEP_FILE_FLAGS_CACHING 253 : PDMACEP_FILE_FLAGS_CACHING, 254 pStorageBackend->pTemplate); 255 if (RT_SUCCESS(rc)) 256 { 257 *ppStorage = pStorageBackend; 258 return VINF_SUCCESS; 259 } 260 261 PDMR3AsyncCompletionTemplateDestroy(pStorageBackend->pTemplate); 262 } 263 RTSemEventDestroy(pStorageBackend->EventSem); 264 } 265 RTMemFree(pStorageBackend); 266 } 267 else 268 rc = VERR_NO_MEMORY; 269 270 return rc; 214 271 } 215 272 … … 217 274 { 218 275 PVBOXDISK pDrvVD = (PVBOXDISK)pvUser; 219 220 AssertMsg(pDrvVD->pDrvTransportAsync, ("Asynchronous function called but no async transport interface below\n")); 221 222 return pDrvVD->pDrvTransportAsync->pfnClose(pDrvVD->pDrvTransportAsync, pStorage); 223 } 224 225 static DECLCALLBACK(int) drvvdAsyncIORead(void *pvUser, void *pStorage, uint64_t uOffset, 226 size_t cbRead, void *pvBuf, size_t *pcbRead) 276 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage; 277 278 PDMR3AsyncCompletionEpClose(pStorageBackend->pEndpoint); 279 PDMR3AsyncCompletionTemplateDestroy(pStorageBackend->pTemplate); 280 RTSemEventDestroy(pStorageBackend->EventSem); 281 RTMemFree(pStorageBackend); 282 283 return VINF_SUCCESS;; 284 } 285 286 static DECLCALLBACK(int) drvvdAsyncIOGetSize(void *pvUser, void *pStorage, uint64_t *pcbSize) 227 287 { 228 288 PVBOXDISK pDrvVD = (PVBOXDISK)pvUser; 229 230 AssertMsg(pDrvVD->pDrvTransportAsync, ("Asynchronous function called but no async transport interface below\n")); 231 232 return pDrvVD->pDrvTransportAsync->pfnReadSynchronous(pDrvVD->pDrvTransportAsync, 233 pStorage, 234 uOffset, pvBuf, cbRead, pcbRead); 235 } 236 237 static DECLCALLBACK(int) drvvdAsyncIOWrite(void *pvUser, void *pStorage, uint64_t uOffset, 238 size_t cbWrite, const void *pvBuf, size_t *pcbWritten) 289 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage; 290 291 return PDMR3AsyncCompletionEpGetSize(pStorageBackend->pEndpoint, pcbSize); 292 } 293 294 static DECLCALLBACK(int) drvvdAsyncIOReadSync(void *pvUser, void *pStorage, uint64_t uOffset, 295 size_t cbRead, void *pvBuf, size_t *pcbRead) 239 296 { 240 297 PVBOXDISK pDrvVD = (PVBOXDISK)pvUser; 241 242 AssertMsg(pDrvVD->pDrvTransportAsync, ("Asynchronous function called but no async transport interface below\n")); 243 244 return pDrvVD->pDrvTransportAsync->pfnWriteSynchronous(pDrvVD->pDrvTransportAsync, 245 pStorage, 246 uOffset, pvBuf, cbWrite, pcbWritten); 247 } 248 249 static DECLCALLBACK(int) drvvdAsyncIOFlush(void *pvUser, void *pStorage) 250 { 251 PVBOXDISK pDrvVD = (PVBOXDISK)pvUser; 252 253 AssertMsg(pDrvVD->pDrvTransportAsync, ("Asynchronous function called but no async transport interface below\n")); 254 255 return pDrvVD->pDrvTransportAsync->pfnFlushSynchronous(pDrvVD->pDrvTransportAsync, pStorage); 256 } 257 258 static DECLCALLBACK(int) drvvdAsyncIOPrepareRead(void *pvUser, void *pStorage, uint64_t uOffset, void *pvBuf, size_t cbRead, void **ppTask) 259 { 260 PVBOXDISK pDrvVD = (PVBOXDISK)pvUser; 261 262 AssertMsg(pDrvVD->pDrvTransportAsync, ("Asynchronous function called but no async transport interface below\n")); 263 264 return pDrvVD->pDrvTransportAsync->pfnPrepareRead(pDrvVD->pDrvTransportAsync, pStorage, uOffset, pvBuf, cbRead, ppTask); 265 } 266 267 static DECLCALLBACK(int) drvvdAsyncIOPrepareWrite(void *pvUser, void *pStorage, uint64_t uOffset, void *pvBuf, size_t cbWrite, void **ppTask) 268 { 269 PVBOXDISK pDrvVD = (PVBOXDISK)pvUser; 270 271 AssertMsg(pDrvVD->pDrvTransportAsync, ("Asynchronous function called but no async transport interface below\n")); 272 273 return pDrvVD->pDrvTransportAsync->pfnPrepareWrite(pDrvVD->pDrvTransportAsync, pStorage, uOffset, pvBuf, cbWrite, ppTask); 274 } 275 276 static DECLCALLBACK(int) drvvdAsyncIOTasksSubmit(void *pvUser, void *apTasks[], unsigned cTasks, void *pvUser2, 277 void *pvUserCaller, PFNVDCOMPLETED pfnTasksCompleted) 278 { 279 PVBOXDISK pDrvVD = (PVBOXDISK)pvUser; 280 PDRVVDASYNCTASK pDrvVDAsyncTask; 281 int rc; 282 283 AssertMsg(pDrvVD->pDrvTransportAsync, ("Asynchronous function called but no async transport interface below\n")); 284 285 rc = RTCacheRequest(pDrvVD->pCache, (void **)&pDrvVDAsyncTask); 286 298 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage; 299 PDMDATASEG DataSeg; 300 PPDMASYNCCOMPLETIONTASK pTask; 301 302 Assert(!pStorageBackend->fSyncIoPending); 303 pStorageBackend->fSyncIoPending = true; 304 DataSeg.cbSeg = cbRead; 305 DataSeg.pvSeg = pvBuf; 306 307 int rc = PDMR3AsyncCompletionEpRead(pStorageBackend->pEndpoint, uOffset, &DataSeg, 1, cbRead, NULL, &pTask); 287 308 if (RT_FAILURE(rc)) 288 309 return rc; 289 310 290 pDrvVDAsyncTask->pfnCompleted = pfnTasksCompleted; 291 pDrvVDAsyncTask->pvUser = pvUser2; 292 pDrvVDAsyncTask->pvUserCaller = pvUserCaller; 293 294 return pDrvVD->pDrvTransportAsync->pfnTasksSubmit(pDrvVD->pDrvTransportAsync, apTasks, cTasks, pDrvVDAsyncTask); 295 } 311 /* Wait */ 312 rc = RTSemEventWait(pStorageBackend->EventSem, RT_INDEFINITE_WAIT); 313 AssertRC(rc); 314 315 if (pcbRead) 316 *pcbRead = cbRead; 317 318 return VINF_SUCCESS; 319 } 320 321 static DECLCALLBACK(int) drvvdAsyncIOWriteSync(void *pvUser, void *pStorage, uint64_t uOffset, 322 size_t cbWrite, const void *pvBuf, size_t *pcbWritten) 323 { 324 PVBOXDISK pDrvVD = (PVBOXDISK)pvUser; 325 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage; 326 PDMDATASEG DataSeg; 327 PPDMASYNCCOMPLETIONTASK pTask; 328 329 Assert(!pStorageBackend->fSyncIoPending); 330 pStorageBackend->fSyncIoPending = true; 331 DataSeg.cbSeg = cbWrite; 332 DataSeg.pvSeg = (void *)pvBuf; 333 334 int rc = PDMR3AsyncCompletionEpWrite(pStorageBackend->pEndpoint, uOffset, &DataSeg, 1, cbWrite, NULL, &pTask); 335 if (RT_FAILURE(rc)) 336 return rc; 337 338 /* Wait */ 339 rc = RTSemEventWait(pStorageBackend->EventSem, RT_INDEFINITE_WAIT); 340 AssertRC(rc); 341 342 if (pcbWritten) 343 *pcbWritten = cbWrite; 344 345 return VINF_SUCCESS; 346 } 347 348 static DECLCALLBACK(int) drvvdAsyncIOFlushSync(void *pvUser, void *pStorage) 349 { 350 PVBOXDISK pDrvVD = (PVBOXDISK)pvUser; 351 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage; 352 PPDMASYNCCOMPLETIONTASK pTask; 353 354 Assert(!pStorageBackend->fSyncIoPending); 355 pStorageBackend->fSyncIoPending = true; 356 357 int rc = PDMR3AsyncCompletionEpFlush(pStorageBackend->pEndpoint, NULL, &pTask); 358 if (RT_FAILURE(rc)) 359 return rc; 360 361 /* Wait */ 362 rc = RTSemEventWait(pStorageBackend->EventSem, RT_INDEFINITE_WAIT); 363 AssertRC(rc); 364 365 return VINF_SUCCESS; 366 } 367 368 static DECLCALLBACK(int) drvvdAsyncIOReadAsync(void *pvUser, void *pStorage, uint64_t uOffset, 369 PCPDMDATASEG paSegments, size_t cSegments, 370 size_t cbRead, void *pvCompletion, 371 void **ppTask) 372 { 373 PVBOXDISK pDrvVD = (PVBOXDISK)pvUser; 374 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage; 375 376 return PDMR3AsyncCompletionEpRead(pStorageBackend->pEndpoint, uOffset, paSegments, cSegments, cbRead, 377 pvCompletion, (PPPDMASYNCCOMPLETIONTASK)ppTask); 378 } 379 380 static DECLCALLBACK(int) drvvdAsyncIOWriteAsync(void *pvUser, void *pStorage, uint64_t uOffset, 381 PCPDMDATASEG paSegments, size_t cSegments, 382 size_t cbWrite, void *pvCompletion, 383 void **ppTask) 384 { 385 PVBOXDISK pDrvVD = (PVBOXDISK)pvUser; 386 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage; 387 388 return PDMR3AsyncCompletionEpWrite(pStorageBackend->pEndpoint, uOffset, paSegments, cSegments, cbWrite, 389 pvCompletion, (PPPDMASYNCCOMPLETIONTASK)ppTask); 390 } 391 392 static DECLCALLBACK(int) drvvdAsyncIOFlushAsync(void *pvUser, void *pStorage, 393 void *pvCompletion, void **ppTask) 394 { 395 PVBOXDISK pDrvVD = (PVBOXDISK)pvUser; 396 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage; 397 398 return PDMR3AsyncCompletionEpFlush(pStorageBackend->pEndpoint, pvCompletion, 399 (PPPDMASYNCCOMPLETIONTASK)ppTask); 400 } 401 296 402 297 403 /******************************************************************************* … … 641 747 *******************************************************************************/ 642 748 643 static DECLCALLBACK(int) drvvdTasksCompleteNotify(PPDMITRANSPORTASYNCPORT pInterface, void *pvUser) 644 { 645 PVBOXDISK pThis = PDMITRANSPORTASYNCPORT_2_VBOXDISK(pInterface); 646 PDRVVDASYNCTASK pDrvVDAsyncTask = (PDRVVDASYNCTASK)pvUser; 647 int rc = VINF_VD_ASYNC_IO_FINISHED; 648 649 /* Having a completion callback for a task is not mandatory. */ 650 if (pDrvVDAsyncTask->pfnCompleted) 651 rc = pDrvVDAsyncTask->pfnCompleted(pDrvVDAsyncTask->pvUser); 652 653 /* Check if the request is finished. */ 654 if (rc == VINF_VD_ASYNC_IO_FINISHED) 655 { 656 rc = pThis->pDrvMediaAsyncPort->pfnTransferCompleteNotify(pThis->pDrvMediaAsyncPort, pDrvVDAsyncTask->pvUserCaller); 657 } 658 else if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS) 659 rc = VINF_SUCCESS; 660 661 rc = RTCacheInsert(pThis->pCache, pDrvVDAsyncTask); 662 AssertRC(rc); 663 664 return rc; 749 static DECLCALLBACK(int) drvvdTasksCompleteNotify(PPDMDRVINS pDrvIns, void *pvUser) 750 { 751 return VERR_NOT_IMPLEMENTED; 665 752 } 666 753 … … 684 771 case PDMINTERFACE_MEDIA_ASYNC: 685 772 return pThis->fAsyncIOSupported ? &pThis->IMediaAsync : NULL; 686 case PDMINTERFACE_TRANSPORT_ASYNC_PORT:687 return &pThis->ITransportAsyncPort;688 773 default: 689 774 return NULL; … … 743 828 pThis->IMediaAsync.pfnStartWrite = drvvdStartWrite; 744 829 745 /* ITransportAsyncPort */746 pThis->ITransportAsyncPort.pfnTaskCompleteNotify = drvvdTasksCompleteNotify;747 748 830 /* Initialize supported VD interfaces. */ 749 831 pThis->pVDIfsDisk = NULL; … … 761 843 pThis->VDIAsyncIOCallbacks.pfnOpen = drvvdAsyncIOOpen; 762 844 pThis->VDIAsyncIOCallbacks.pfnClose = drvvdAsyncIOClose; 763 pThis->VDIAsyncIOCallbacks.pfnRead = drvvdAsyncIORead; 764 pThis->VDIAsyncIOCallbacks.pfnWrite = drvvdAsyncIOWrite; 765 pThis->VDIAsyncIOCallbacks.pfnFlush = drvvdAsyncIOFlush; 766 pThis->VDIAsyncIOCallbacks.pfnPrepareRead = drvvdAsyncIOPrepareRead; 767 pThis->VDIAsyncIOCallbacks.pfnPrepareWrite = drvvdAsyncIOPrepareWrite; 768 pThis->VDIAsyncIOCallbacks.pfnTasksSubmit = drvvdAsyncIOTasksSubmit; 845 pThis->VDIAsyncIOCallbacks.pfnGetSize = drvvdAsyncIOGetSize; 846 pThis->VDIAsyncIOCallbacks.pfnReadSync = drvvdAsyncIOReadSync; 847 pThis->VDIAsyncIOCallbacks.pfnWriteSync = drvvdAsyncIOWriteSync; 848 pThis->VDIAsyncIOCallbacks.pfnFlushSync = drvvdAsyncIOFlushSync; 849 pThis->VDIAsyncIOCallbacks.pfnReadAsync = drvvdAsyncIOReadAsync; 850 pThis->VDIAsyncIOCallbacks.pfnWriteAsync = drvvdAsyncIOWriteAsync; 851 pThis->VDIAsyncIOCallbacks.pfnFlushAsync = drvvdAsyncIOFlushAsync; 769 852 770 853 rc = VDInterfaceAdd(&pThis->VDIAsyncIO, "DrvVD_AsyncIO", VDINTERFACETYPE_ASYNCIO, … … 820 903 pThis->fAsyncIOSupported = true; 821 904 822 /* Success query the async transport interface. */ 823 pThis->pDrvTransportAsync = (PPDMITRANSPORTASYNC)pBase->pfnQueryInterface(pBase, PDMINTERFACE_TRANSPORT_ASYNC); 824 if (!pThis->pDrvTransportAsync) 825 { 826 /* An attached driver without an async transport interface - impossible. */ 827 AssertMsgFailed(("Configuration error: No async transport interface below!\n")); 828 return VERR_PDM_MISSING_INTERFACE_ABOVE; 829 } 905 /** @todo: Use PDM async completion manager */ 830 906 } 831 907 } … … 1108 1184 } 1109 1185 1110 /*1111 * We know definitly if async I/O is supported now.1112 * Create cache if it is supported.1113 */1114 if (pThis->fAsyncIOSupported)1115 {1116 rc = RTCacheCreate(&pThis->pCache, 0, sizeof(DRVVDASYNCTASK), RTOBJCACHE_PROTECT_INSERT);1117 AssertMsgRC(rc, ("Failed to create cache rc=%Rrc\n", rc));1118 }1119 1120 1186 /* Switch to runtime error facility. */ 1121 1187 pThis->fErrorUseRuntime = true; … … 1141 1207 1142 1208 drvvdFreeImages(pThis); 1143 if (pThis->pCache)1144 {1145 rc = RTCacheDestroy(pThis->pCache);1146 AssertRC(rc);1147 }1148 1209 } 1149 1210 -
trunk/src/VBox/Devices/Storage/VmdkHDDCore.cpp
r19921 r20167 432 432 PVDINTERFACEASYNCIO pInterfaceAsyncIOCallbacks; 433 433 /** 434 * Pointer to an array of task handles for task submission.434 * Pointer to an array of segment entries for async I/O. 435 435 * This is an optimization because the task number to submit is not known 436 436 * and allocating/freeing an array in the read/write functions every time 437 437 * is too expensive. 438 438 */ 439 void **apTask;440 /** Entries available in the task handlearray. */441 unsigned c Task;439 PPDMDATASEG paSegments; 440 /** Entries available in the segments array. */ 441 unsigned cSegments; 442 442 443 443 /** Open flags passed by VBoxHD layer. */ … … 584 584 ? true 585 585 : false, 586 NULL, 586 587 &pVmdkFile->pStorage); 587 588 pVmdkFile->fAsyncIO = true; … … 670 671 671 672 if (pVmdkFile->fAsyncIO) 672 return pImage->pInterfaceAsyncIOCallbacks->pfnRead (pImage->pInterfaceAsyncIO->pvUser,673 pVmdkFile->pStorage, uOffset,674 cbToRead, pvBuf, pcbRead);673 return pImage->pInterfaceAsyncIOCallbacks->pfnReadSync(pImage->pInterfaceAsyncIO->pvUser, 674 pVmdkFile->pStorage, uOffset, 675 cbToRead, pvBuf, pcbRead); 675 676 else 676 677 return RTFileReadAt(pVmdkFile->File, uOffset, pvBuf, cbToRead, pcbRead); … … 687 688 688 689 if (pVmdkFile->fAsyncIO) 689 return pImage->pInterfaceAsyncIOCallbacks->pfnWrite (pImage->pInterfaceAsyncIO->pvUser,690 pVmdkFile->pStorage, uOffset,691 cbToWrite, pvBuf, pcbWritten);690 return pImage->pInterfaceAsyncIOCallbacks->pfnWriteSync(pImage->pInterfaceAsyncIO->pvUser, 691 pVmdkFile->pStorage, uOffset, 692 cbToWrite, pvBuf, pcbWritten); 692 693 else 693 694 return RTFileWriteAt(pVmdkFile->File, uOffset, pvBuf, cbToWrite, pcbWritten); … … 730 731 731 732 if (pVmdkFile->fAsyncIO) 732 return pImage->pInterfaceAsyncIOCallbacks->pfnFlush (pImage->pInterfaceAsyncIO->pvUser,733 pVmdkFile->pStorage);733 return pImage->pInterfaceAsyncIOCallbacks->pfnFlushSync(pImage->pInterfaceAsyncIO->pvUser, 734 pVmdkFile->pStorage); 734 735 else 735 736 return RTFileFlush(pVmdkFile->File); … … 5740 5741 PVMDKEXTENT pExtent; 5741 5742 int rc = VINF_SUCCESS; 5742 unsigned c TasksToSubmit= 0;5743 unsigned cSegments = 0; 5743 5744 PPDMDATASEG paSegCurrent = paSeg; 5744 5745 size_t cbLeftInCurrentSegment = paSegCurrent->cbSeg; … … 5773 5774 } 5774 5775 5775 /* Clip readrange to remain in this extent. */5776 /* Clip write range to remain in this extent. */ 5776 5777 cbToRead = RT_MIN(cbRead, VMDK_SECTOR2BYTE(pExtent->uSectorOffset + pExtent->cNominalSectors - uSectorExtentRel)); 5777 /* Clip readrange to remain into current data segment. */5778 /* Clip write range to remain into current data segment. */ 5778 5779 cbToRead = RT_MIN(cbToRead, cbLeftInCurrentSegment); 5779 5780 … … 5783 5784 case VMDKETYPE_FLAT: 5784 5785 { 5785 /* Setup new task. */5786 void *pTask;5787 rc = pImage->pInterfaceAsyncIOCallbacks->pfnPrepareRead(pImage->pInterfaceAsyncIO->pvUser, pExtent->pFile->pStorage,5788 VMDK_SECTOR2BYTE(uSectorExtentRel),5789 (uint8_t *)paSegCurrent->pvSeg + uOffsetInCurrentSegment,5790 cbToRead, &pTask);5791 if (RT_FAILURE(rc))5792 {5793 AssertMsgFailed(("Preparing read failed rc=%Rrc\n", rc));5794 goto out;5795 }5796 5797 5786 /* Check for enough room first. */ 5798 if ( cTasksToSubmit >= pImage->cTask)5787 if (RT_LIKELY(cSegments >= pImage->cSegments)) 5799 5788 { 5800 5789 /* We reached maximum, resize array. Try to realloc memory first. */ 5801 void **apTaskNew = (void **)RTMemRealloc(pImage->apTask, (cTasksToSubmit + 10)*sizeof(void *));5802 5803 if (! apTaskNew)5790 PPDMDATASEG paSegmentsNew = (PPDMDATASEG)RTMemRealloc(pImage->paSegments, (cSegments + 10)*sizeof(PDMDATASEG)); 5791 5792 if (!paSegmentsNew) 5804 5793 { 5805 5794 /* We failed. Allocate completely new. */ 5806 apTaskNew = (void **)RTMemAllocZ((cTasksToSubmit + 10)* sizeof(void *));5807 if (! apTaskNew)5795 paSegmentsNew = (PPDMDATASEG)RTMemAllocZ((cSegments + 10)* sizeof(PDMDATASEG)); 5796 if (!paSegmentsNew) 5808 5797 { 5809 5798 /* Damn, we are out of memory. */ … … 5813 5802 5814 5803 /* Copy task handles over. */ 5815 for (unsigned i = 0; i < c TasksToSubmit; i++)5816 apTaskNew[i] = pImage->apTask[i];5804 for (unsigned i = 0; i < cSegments; i++) 5805 paSegmentsNew[i] = pImage->paSegments[i]; 5817 5806 5818 5807 /* Free old memory. */ 5819 RTMemFree(pImage-> apTask);5808 RTMemFree(pImage->paSegments); 5820 5809 } 5821 5810 5822 pImage->c Task = cTasksToSubmit+ 10;5823 pImage-> apTask = apTaskNew;5811 pImage->cSegments = cSegments + 10; 5812 pImage->paSegments = paSegmentsNew; 5824 5813 } 5825 5814 5826 pImage->apTask[cTasksToSubmit] = pTask; 5827 cTasksToSubmit++; 5828 break; 5829 } 5830 case VMDKETYPE_ZERO: 5831 memset((uint8_t *)paSegCurrent->pvSeg + uOffsetInCurrentSegment, 0, cbToRead); 5832 break; 5833 default: 5834 AssertMsgFailed(("Unsupported extent type %u\n", pExtent->enmType)); 5835 } 5836 5837 cbRead -= cbToRead; 5838 uOffset += cbToRead; 5839 cbLeftInCurrentSegment -= cbToRead; 5840 uOffsetInCurrentSegment += cbToRead; 5841 /* Go to next extent if there is no space left in current one. */ 5842 if (!cbLeftInCurrentSegment) 5843 { 5844 uOffsetInCurrentSegment = 0; 5845 paSegCurrent++; 5846 cSeg--; 5847 cbLeftInCurrentSegment = paSegCurrent->cbSeg; 5848 } 5849 } 5850 5851 AssertMsg(cbRead == 0, ("No segment left but there is still data to read\n")); 5852 5853 if (cTasksToSubmit == 0) 5854 { 5855 /* The request was completely in a ZERO extent nothing to do. */ 5856 rc = VINF_VD_ASYNC_IO_FINISHED; 5857 } 5858 else 5859 { 5860 /* Submit tasks. */ 5861 rc = pImage->pInterfaceAsyncIOCallbacks->pfnTasksSubmit(pImage->pInterfaceAsyncIO->pvUser, 5862 pImage->apTask, cTasksToSubmit, 5863 NULL, pvUser, 5864 NULL /* Nothing required after read. */); 5865 AssertMsgRC(rc, ("Failed to enqueue tasks rc=%Rrc\n", rc)); 5866 } 5867 5868 out: 5869 LogFlowFunc(("returns %Rrc\n", rc)); 5870 return rc; 5871 } 5872 5873 static int vmdkAsyncWrite(void *pvBackendData, uint64_t uOffset, size_t cbWrite, 5874 PPDMDATASEG paSeg, unsigned cSeg, void *pvUser) 5875 { 5876 PVMDKIMAGE pImage = (PVMDKIMAGE)pvBackendData; 5877 PVMDKEXTENT pExtent; 5878 int rc = VINF_SUCCESS; 5879 unsigned cTasksToSubmit = 0; 5880 PPDMDATASEG paSegCurrent = paSeg; 5881 size_t cbLeftInCurrentSegment = paSegCurrent->cbSeg; 5882 size_t uOffsetInCurrentSegment = 0; 5883 5884 AssertPtr(pImage); 5885 Assert(uOffset % 512 == 0); 5886 Assert(cbWrite % 512 == 0); 5887 5888 if ( uOffset + cbWrite > pImage->cbSize 5889 || cbWrite == 0) 5890 { 5891 rc = VERR_INVALID_PARAMETER; 5892 goto out; 5893 } 5894 5895 while (cbWrite && cSeg) 5896 { 5897 size_t cbToWrite; 5898 uint64_t uSectorExtentRel; 5899 5900 rc = vmdkFindExtent(pImage, VMDK_BYTE2SECTOR(uOffset), 5901 &pExtent, &uSectorExtentRel); 5902 if (RT_FAILURE(rc)) 5903 goto out; 5904 5905 /* Check access permissions as defined in the extent descriptor. */ 5906 if (pExtent->enmAccess == VMDKACCESS_NOACCESS) 5907 { 5908 rc = VERR_VD_VMDK_INVALID_STATE; 5909 goto out; 5910 } 5911 5912 /* Clip write range to remain in this extent. */ 5913 cbToWrite = RT_MIN(cbWrite, VMDK_SECTOR2BYTE(pExtent->uSectorOffset + pExtent->cNominalSectors - uSectorExtentRel)); 5914 /* Clip write range to remain into current data segment. */ 5915 cbToWrite = RT_MIN(cbToWrite, cbLeftInCurrentSegment); 5916 5917 switch (pExtent->enmType) 5918 { 5919 case VMDKETYPE_VMFS: 5920 case VMDKETYPE_FLAT: 5921 { 5922 /* Setup new task. */ 5923 void *pTask; 5924 rc = pImage->pInterfaceAsyncIOCallbacks->pfnPrepareWrite(pImage->pInterfaceAsyncIO->pvUser, pExtent->pFile->pStorage, 5925 VMDK_SECTOR2BYTE(uSectorExtentRel), 5926 (uint8_t *)paSegCurrent->pvSeg + uOffsetInCurrentSegment, 5927 cbToWrite, &pTask); 5928 if (RT_FAILURE(rc)) 5929 { 5930 AssertMsgFailed(("Preparing read failed rc=%Rrc\n", rc)); 5931 goto out; 5932 } 5933 5934 /* Check for enough room first. */ 5935 if (cTasksToSubmit >= pImage->cTask) 5936 { 5937 /* We reached maximum, resize array. Try to realloc memory first. */ 5938 void **apTaskNew = (void **)RTMemRealloc(pImage->apTask, (cTasksToSubmit + 10)*sizeof(void *)); 5939 5940 if (!apTaskNew) 5941 { 5942 /* We failed. Allocate completely new. */ 5943 apTaskNew = (void **)RTMemAllocZ((cTasksToSubmit + 10)* sizeof(void *)); 5944 if (!apTaskNew) 5945 { 5946 /* Damn, we are out of memory. */ 5947 rc = VERR_NO_MEMORY; 5948 goto out; 5949 } 5950 5951 /* Copy task handles over. */ 5952 for (unsigned i = 0; i < cTasksToSubmit; i++) 5953 apTaskNew[i] = pImage->apTask[i]; 5954 5955 /* Free old memory. */ 5956 RTMemFree(pImage->apTask); 5957 } 5958 5959 pImage->cTask = cTasksToSubmit + 10; 5960 pImage->apTask = apTaskNew; 5961 } 5962 5963 pImage->apTask[cTasksToSubmit] = pTask; 5964 cTasksToSubmit++; 5815 pImage->paSegments[cSegments].cbSeg = cbToRead; 5816 pImage->paSegments[cSegments].pvSeg = (uint8_t *)paSegCurrent->pvSeg + uOffsetInCurrentSegment; 5817 cSegments++; 5965 5818 break; 5966 5819 } … … 5972 5825 } 5973 5826 5827 cbRead -= cbToRead; 5828 uOffset += cbToRead; 5829 cbLeftInCurrentSegment -= cbToRead; 5830 uOffsetInCurrentSegment += cbToRead; 5831 /* Go to next extent if there is no space left in current one. */ 5832 if (!cbLeftInCurrentSegment) 5833 { 5834 uOffsetInCurrentSegment = 0; 5835 paSegCurrent++; 5836 cSeg--; 5837 cbLeftInCurrentSegment = paSegCurrent->cbSeg; 5838 } 5839 } 5840 5841 AssertMsg(cbRead == 0, ("No segment left but there is still data to write\n")); 5842 5843 if (cSegments == 0) 5844 { 5845 /* The request was completely in a ZERO extent nothing to do. */ 5846 rc = VINF_VD_ASYNC_IO_FINISHED; 5847 } 5848 else 5849 { 5850 /* Start the write */ 5851 void *pTask; 5852 rc = pImage->pInterfaceAsyncIOCallbacks->pfnReadAsync(pImage->pInterfaceAsyncIO->pvUser, 5853 pExtent->pFile->pStorage, uOffset, 5854 pImage->paSegments, cSegments, cbRead, 5855 pvUser, &pTask); 5856 } 5857 5858 out: 5859 LogFlowFunc(("returns %Rrc\n", rc)); 5860 return rc; 5861 } 5862 5863 static int vmdkAsyncWrite(void *pvBackendData, uint64_t uOffset, size_t cbWrite, 5864 PPDMDATASEG paSeg, unsigned cSeg, void *pvUser) 5865 { 5866 PVMDKIMAGE pImage = (PVMDKIMAGE)pvBackendData; 5867 PVMDKEXTENT pExtent; 5868 int rc = VINF_SUCCESS; 5869 unsigned cSegments = 0; 5870 PPDMDATASEG paSegCurrent = paSeg; 5871 size_t cbLeftInCurrentSegment = paSegCurrent->cbSeg; 5872 size_t uOffsetInCurrentSegment = 0; 5873 5874 AssertPtr(pImage); 5875 Assert(uOffset % 512 == 0); 5876 Assert(cbWrite % 512 == 0); 5877 5878 if ( uOffset + cbWrite > pImage->cbSize 5879 || cbWrite == 0) 5880 { 5881 rc = VERR_INVALID_PARAMETER; 5882 goto out; 5883 } 5884 5885 while (cbWrite && cSeg) 5886 { 5887 size_t cbToWrite; 5888 uint64_t uSectorExtentRel; 5889 5890 rc = vmdkFindExtent(pImage, VMDK_BYTE2SECTOR(uOffset), 5891 &pExtent, &uSectorExtentRel); 5892 if (RT_FAILURE(rc)) 5893 goto out; 5894 5895 /* Check access permissions as defined in the extent descriptor. */ 5896 if (pExtent->enmAccess == VMDKACCESS_NOACCESS) 5897 { 5898 rc = VERR_VD_VMDK_INVALID_STATE; 5899 goto out; 5900 } 5901 5902 /* Clip write range to remain in this extent. */ 5903 cbToWrite = RT_MIN(cbWrite, VMDK_SECTOR2BYTE(pExtent->uSectorOffset + pExtent->cNominalSectors - uSectorExtentRel)); 5904 /* Clip write range to remain into current data segment. */ 5905 cbToWrite = RT_MIN(cbToWrite, cbLeftInCurrentSegment); 5906 5907 switch (pExtent->enmType) 5908 { 5909 case VMDKETYPE_VMFS: 5910 case VMDKETYPE_FLAT: 5911 { 5912 /* Check for enough room first. */ 5913 if (RT_LIKELY(cSegments >= pImage->cSegments)) 5914 { 5915 /* We reached maximum, resize array. Try to realloc memory first. */ 5916 PPDMDATASEG paSegmentsNew = (PPDMDATASEG)RTMemRealloc(pImage->paSegments, (cSegments + 10)*sizeof(PDMDATASEG)); 5917 5918 if (!paSegmentsNew) 5919 { 5920 /* We failed. Allocate completely new. */ 5921 paSegmentsNew = (PPDMDATASEG)RTMemAllocZ((cSegments + 10)* sizeof(PDMDATASEG)); 5922 if (!paSegmentsNew) 5923 { 5924 /* Damn, we are out of memory. */ 5925 rc = VERR_NO_MEMORY; 5926 goto out; 5927 } 5928 5929 /* Copy task handles over. */ 5930 for (unsigned i = 0; i < cSegments; i++) 5931 paSegmentsNew[i] = pImage->paSegments[i]; 5932 5933 /* Free old memory. */ 5934 RTMemFree(pImage->paSegments); 5935 } 5936 5937 pImage->cSegments = cSegments + 10; 5938 pImage->paSegments = paSegmentsNew; 5939 } 5940 5941 pImage->paSegments[cSegments].cbSeg = cbToWrite; 5942 pImage->paSegments[cSegments].pvSeg = (uint8_t *)paSegCurrent->pvSeg + uOffsetInCurrentSegment; 5943 cSegments++; 5944 break; 5945 } 5946 case VMDKETYPE_ZERO: 5947 /* Nothing left to do. */ 5948 break; 5949 default: 5950 AssertMsgFailed(("Unsupported extent type %u\n", pExtent->enmType)); 5951 } 5952 5974 5953 cbWrite -= cbToWrite; 5975 5954 uOffset += cbToWrite; … … 5986 5965 } 5987 5966 5988 AssertMsg(cbWrite == 0, ("No segment left but there is still data to read\n"));5989 5990 if (c TasksToSubmit== 0)5967 AssertMsg(cbWrite == 0, ("No segment left but there is still data to write\n")); 5968 5969 if (cSegments == 0) 5991 5970 { 5992 5971 /* The request was completely in a ZERO extent nothing to do. */ … … 5995 5974 else 5996 5975 { 5997 /* S ubmit tasks.*/5998 rc = pImage->pInterfaceAsyncIOCallbacks->pfnTasksSubmit(pImage->pInterfaceAsyncIO->pvUser,5999 pImage->apTask, cTasksToSubmit,6000 NULL, pvUser,6001 NULL /* Nothing required after read. */);6002 AssertMsgRC(rc, ("Failed to enqueue tasks rc=%Rrc\n", rc));5976 /* Start the write */ 5977 void *pTask; 5978 rc = pImage->pInterfaceAsyncIOCallbacks->pfnWriteAsync(pImage->pInterfaceAsyncIO->pvUser, 5979 pExtent->pFile->pStorage, uOffset, 5980 pImage->paSegments, cSegments, cbWrite, 5981 pvUser, &pTask); 6003 5982 } 6004 5983 … … 6006 5985 LogFlowFunc(("returns %Rrc\n", rc)); 6007 5986 return rc; 6008 6009 5987 } 6010 5988
Note:
See TracChangeset
for help on using the changeset viewer.