Changeset 27806 in vbox
- Timestamp:
- Mar 29, 2010 8:18:50 PM (15 years ago)
- Location:
- trunk
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/VBox/pdmifs.h
r27754 r27806 58 58 * 'down' or 'up'. This refers to a model with the device on the top and the 59 59 * drivers stacked below it. Sometimes there is mention of 'main' or 'external' 60 * which normally means the same, i.e. the Main or VBoxBFE API. Pic kture the61 * orientation of 'main' as hori sontal.60 * which normally means the same, i.e. the Main or VBoxBFE API. Picture the 61 * orientation of 'main' as horizontal. 62 62 * 63 63 * @{ … … 806 806 /** Pointer to a block notify interface (dummy). */ 807 807 typedef PDMIBLOCKPORT *PPDMIBLOCKPORT; 808 809 810 /** 811 * Callback which provides progress information. 812 * 813 * @return VBox status code. 814 * @param pvUser Opaque user data. 815 * @param uPercent Completion percentage. 816 */ 817 typedef DECLCALLBACK(int) FNSIMPLEPROGRESS(void *pvUser, unsigned uPercentage); 818 /** Pointer to FNSIMPLEPROGRESS() */ 819 typedef FNSIMPLEPROGRESS *PFNSIMPLEPROGRESS; 808 820 809 821 … … 903 915 904 916 /** 917 * Merge medium contents during a live snapshot deletion. 918 * 919 * @returns VBox status code. 920 * @param pInterface Pointer to the interface structure containing the called function pointer. 921 * @param pfnProgress Function pointer for progress notification. 922 * @param pvUser Opaque user data for progress notification. 923 * @thread Any thread. 924 */ 925 DECLR3CALLBACKMEMBER(int, pfnMerge,(PPDMIBLOCK pInterface, PFNSIMPLEPROGRESS pfnProgress, void *pvUser)); 926 927 /** 905 928 * Check if the media is readonly or not. 906 929 * … … 1107 1130 */ 1108 1131 DECLR3CALLBACKMEMBER(int, pfnFlush,(PPDMIMEDIA pInterface)); 1132 1133 /** 1134 * Merge medium contents during a live snapshot deletion. All details 1135 * must have been configured through CFGM or this will fail. 1136 * This method is optional (i.e. the function pointer may be NULL). 1137 * 1138 * @returns VBox status code. 1139 * @param pInterface Pointer to the interface structure containing the called function pointer. 1140 * @param pfnProgress Function pointer for progress notification. 1141 * @param pvUser Opaque user data for progress notification. 1142 * @thread Any thread. 1143 */ 1144 DECLR3CALLBACKMEMBER(int, pfnMerge,(PPDMIMEDIA pInterface, PFNSIMPLEPROGRESS pfnProgress, void *pvUser)); 1109 1145 1110 1146 /** -
trunk/src/VBox/Devices/Storage/DrvBlock.cpp
r26173 r27806 205 205 206 206 207 /** @copydoc PDMIBLOCK::pfnMerge */ 208 static DECLCALLBACK(int) drvblockMerge(PPDMIBLOCK pInterface, 209 PFNSIMPLEPROGRESS pfnProgress, 210 void *pvUser) 211 { 212 PDRVBLOCK pThis = PDMIBLOCK_2_DRVBLOCK(pInterface); 213 214 /* 215 * Check the state. 216 */ 217 if (!pThis->pDrvMedia) 218 { 219 AssertMsgFailed(("Invalid state! Not mounted!\n")); 220 return VERR_PDM_MEDIA_NOT_MOUNTED; 221 } 222 223 if (!pThis->pDrvMedia->pfnMerge) 224 return VERR_NOT_SUPPORTED; 225 226 int rc = pThis->pDrvMedia->pfnMerge(pThis->pDrvMedia, pfnProgress, pvUser); 227 return rc; 228 } 229 230 207 231 /** @copydoc PDMIBLOCK::pfnIsReadOnly */ 208 232 static DECLCALLBACK(bool) drvblockIsReadOnly(PPDMIBLOCK pInterface) … … 725 749 pThis->IBlock.pfnWrite = drvblockWrite; 726 750 pThis->IBlock.pfnFlush = drvblockFlush; 751 pThis->IBlock.pfnMerge = drvblockMerge; 727 752 pThis->IBlock.pfnIsReadOnly = drvblockIsReadOnly; 728 753 pThis->IBlock.pfnGetSize = drvblockGetSize; -
trunk/src/VBox/Devices/Storage/DrvVD.cpp
r27739 r27806 28 28 #include <VBox/pdmdrv.h> 29 29 #include <VBox/pdmasynccompletion.h> 30 #include <iprt/asm.h> 30 31 #include <iprt/alloc.h> 31 32 #include <iprt/assert.h> … … 145 146 /** Callback table for async I/O interface. */ 146 147 VDINTERFACEASYNCIO VDIAsyncIOCallbacks; 148 /** Common structure for the supported thread synchronization interface. */ 149 VDINTERFACE VDIThreadSync; 150 /** Callback table for thread synchronization interface. */ 151 VDINTERFACETHREADSYNC VDIThreadSyncCallbacks; 147 152 /** Callback table for the configuration information interface. */ 148 153 VDINTERFACECONFIG VDIConfigCallbacks; … … 155 160 /** Pointer to the list of data we need to keep per image. */ 156 161 PVBOXIMAGE pImages; 162 /** Flag whether a merge operation has been set up. */ 163 bool fMergePending; 164 /** Synchronization to prevent destruction before merge finishes. */ 165 RTSEMFASTMUTEX MergeCompleteMutex; 166 /** Synchronization between merge and other image accesses. */ 167 RTSEMRW MergeLock; 168 /** Source image index for merging. */ 169 unsigned uMergeSource; 170 /** Target image index for merging. */ 171 unsigned uMergeTarget; 157 172 } VBOXDISK, *PVBOXDISK; 158 173 … … 193 208 RTMemFree(p); 194 209 } 210 } 211 212 213 /** 214 * Make the image temporarily read-only. 215 * 216 * @returns VBox status code. 217 * @param pThis The driver instance data. 218 */ 219 static int drvvdSetReadonly(PVBOXDISK pThis) 220 { 221 int rc = VINF_SUCCESS; 222 if (!VDIsReadOnly(pThis->pDisk)) 223 { 224 unsigned uOpenFlags; 225 rc = VDGetOpenFlags(pThis->pDisk, VD_LAST_IMAGE, &uOpenFlags); 226 AssertRC(rc); 227 uOpenFlags |= VD_OPEN_FLAGS_READONLY; 228 rc = VDSetOpenFlags(pThis->pDisk, VD_LAST_IMAGE, uOpenFlags); 229 AssertRC(rc); 230 pThis->fTempReadOnly = true; 231 } 232 return rc; 195 233 } 196 234 … … 293 331 void **ppStorage) 294 332 { 295 PVBOXDISK p DrvVD= (PVBOXDISK)pvUser;333 PVBOXDISK pThis = (PVBOXDISK)pvUser; 296 334 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)RTMemAllocZ(sizeof(DRVVDSTORAGEBACKEND)); 297 335 int rc = VINF_SUCCESS; … … 311 349 if (RT_SUCCESS(rc)) 312 350 { 313 rc = PDMDrvHlpPDMAsyncCompletionTemplateCreate(p DrvVD->pDrvIns, &pStorageBackend->pTemplate,351 rc = PDMDrvHlpPDMAsyncCompletionTemplateCreate(pThis->pDrvIns, &pStorageBackend->pTemplate, 314 352 drvvdAsyncTaskCompleted, pStorageBackend, "AsyncTaskCompleted"); 315 353 if (RT_SUCCESS(rc)) … … 340 378 static DECLCALLBACK(int) drvvdAsyncIOClose(void *pvUser, void *pStorage) 341 379 { 342 PVBOXDISK p DrvVD= (PVBOXDISK)pvUser;380 PVBOXDISK pThis = (PVBOXDISK)pvUser; 343 381 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage; 344 382 … … 354 392 size_t cbRead, void *pvBuf, size_t *pcbRead) 355 393 { 356 PVBOXDISK p DrvVD= (PVBOXDISK)pvUser;394 PVBOXDISK pThis = (PVBOXDISK)pvUser; 357 395 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage; 358 396 PDMDATASEG DataSeg; … … 386 424 size_t cbWrite, const void *pvBuf, size_t *pcbWritten) 387 425 { 388 PVBOXDISK p DrvVD= (PVBOXDISK)pvUser;426 PVBOXDISK pThis = (PVBOXDISK)pvUser; 389 427 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage; 390 428 PDMDATASEG DataSeg; … … 417 455 static DECLCALLBACK(int) drvvdAsyncIOFlushSync(void *pvUser, void *pStorage) 418 456 { 419 PVBOXDISK p DrvVD= (PVBOXDISK)pvUser;457 PVBOXDISK pThis = (PVBOXDISK)pvUser; 420 458 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage; 421 459 PPDMASYNCCOMPLETIONTASK pTask; … … 445 483 void **ppTask) 446 484 { 447 PVBOXDISK p DrvVD= (PVBOXDISK)pvUser;485 PVBOXDISK pThis = (PVBOXDISK)pvUser; 448 486 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage; 449 487 … … 457 495 void **ppTask) 458 496 { 459 PVBOXDISK p DrvVD= (PVBOXDISK)pvUser;497 PVBOXDISK pThis = (PVBOXDISK)pvUser; 460 498 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage; 461 499 … … 467 505 void *pvCompletion, void **ppTask) 468 506 { 469 PVBOXDISK p DrvVD= (PVBOXDISK)pvUser;507 PVBOXDISK pThis = (PVBOXDISK)pvUser; 470 508 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage; 471 509 … … 495 533 496 534 #endif /* VBOX_WITH_PDM_ASYNC_COMPLETION */ 535 536 537 /******************************************************************************* 538 * VD Thread Synchronization interface implementation * 539 *******************************************************************************/ 540 541 static DECLCALLBACK(int) drvvdThreadStartRead(void *pvUser) 542 { 543 PVBOXDISK pThis = (PVBOXDISK)pvUser; 544 545 return RTSemRWRequestRead(pThis->MergeLock, RT_INDEFINITE_WAIT); 546 } 547 548 static DECLCALLBACK(int) drvvdThreadFinishRead(void *pvUser) 549 { 550 PVBOXDISK pThis = (PVBOXDISK)pvUser; 551 552 return RTSemRWReleaseRead(pThis->MergeLock); 553 } 554 555 static DECLCALLBACK(int) drvvdThreadStartWrite(void *pvUser) 556 { 557 PVBOXDISK pThis = (PVBOXDISK)pvUser; 558 559 return RTSemRWRequestWrite(pThis->MergeLock, RT_INDEFINITE_WAIT); 560 } 561 562 static DECLCALLBACK(int) drvvdThreadFinishWrite(void *pvUser) 563 { 564 PVBOXDISK pThis = (PVBOXDISK)pvUser; 565 566 return RTSemRWReleaseWrite(pThis->MergeLock); 567 } 497 568 498 569 … … 775 846 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface); 776 847 int rc = VDFlush(pThis->pDisk); 848 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc)); 849 return rc; 850 } 851 852 /** @copydoc PDMIMEDIA::pfnMerge */ 853 static DECLCALLBACK(int) drvvdMerge(PPDMIMEDIA pInterface, 854 PFNSIMPLEPROGRESS pfnProgress, 855 void *pvUser) 856 { 857 LogFlow(("%s:\n", __FUNCTION__)); 858 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface); 859 int rc = VINF_SUCCESS; 860 861 /* Note: There is an unavoidable race between destruction and another 862 * thread invoking this function. This is handled safely and gracefully by 863 * atomically invalidating the lock handle in drvvdDestruct. */ 864 int rc2 = RTSemFastMutexRequest(pThis->MergeCompleteMutex); 865 AssertRC(rc2); 866 if (RT_SUCCESS(rc2) && pThis->fMergePending) 867 { 868 /* Take shortcut: PFNSIMPLEPROGRESS is exactly the same type as 869 * PFNVDPROGRESS, so there's no need for a conversion function. */ 870 /** @todo maybe introduce a conversion which limits update frequency. */ 871 PVDINTERFACE pVDIfsOperation = NULL; 872 VDINTERFACE VDIProgress; 873 VDINTERFACEPROGRESS VDIProgressCallbacks; 874 VDIProgressCallbacks.cbSize = sizeof(VDINTERFACEPROGRESS); 875 VDIProgressCallbacks.enmInterface = VDINTERFACETYPE_PROGRESS; 876 VDIProgressCallbacks.pfnProgress = pfnProgress; 877 rc2 = VDInterfaceAdd(&VDIProgress, "DrvVD_VDIProgress", VDINTERFACETYPE_PROGRESS, 878 &VDIProgressCallbacks, pvUser, &pVDIfsOperation); 879 AssertRC(rc2); 880 pThis->fMergePending = false; 881 rc = VDMerge(pThis->pDisk, pThis->uMergeSource, 882 pThis->uMergeTarget, pVDIfsOperation); 883 } 884 rc2 = RTSemFastMutexRelease(pThis->MergeCompleteMutex); 885 AssertRC(rc2); 777 886 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc)); 778 887 return rc; … … 1017 1126 LogFlow(("%s:\n", __FUNCTION__)); 1018 1127 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK); 1019 if (!VDIsReadOnly(pThis->pDisk)) 1020 { 1021 unsigned uOpenFlags; 1022 int rc = VDGetOpenFlags(pThis->pDisk, VD_LAST_IMAGE, &uOpenFlags); 1023 AssertRC(rc); 1024 uOpenFlags |= VD_OPEN_FLAGS_READONLY; 1025 rc = VDSetOpenFlags(pThis->pDisk, VD_LAST_IMAGE, uOpenFlags); 1026 AssertRC(rc); 1027 pThis->fTempReadOnly = true; 1028 } 1128 drvvdSetReadonly(pThis); 1029 1129 } 1030 1130 … … 1055 1155 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns); 1056 1156 1157 RTSEMFASTMUTEX mutex = (RTSEMFASTMUTEX)ASMAtomicXchgPtr((void **)&pThis->MergeCompleteMutex, 1158 (void *)NIL_RTSEMFASTMUTEX); 1159 if (mutex != NIL_RTSEMFASTMUTEX) 1160 { 1161 /* Request the semaphore to wait until a potentially running merge 1162 * operation has been finished. */ 1163 int rc = RTSemFastMutexRequest(mutex); 1164 AssertRC(rc); 1165 pThis->fMergePending = false; 1166 rc = RTSemFastMutexRelease(mutex); 1167 AssertRC(rc); 1168 rc = RTSemFastMutexDestroy(mutex); 1169 AssertRC(rc); 1170 } 1171 if (pThis->MergeLock != NIL_RTSEMRW) 1172 { 1173 int rc = RTSemRWDestroy(pThis->MergeLock); 1174 AssertRC(rc); 1175 pThis->MergeLock = NIL_RTSEMRW; 1176 } 1177 1057 1178 if (VALID_PTR(pThis->pDisk)) 1058 1179 { … … 1089 1210 pThis->pDisk = NULL; 1090 1211 pThis->fAsyncIOSupported = false; 1212 pThis->fMergePending = false; 1213 pThis->MergeCompleteMutex = NIL_RTSEMFASTMUTEX; 1214 pThis->uMergeSource = VD_LAST_IMAGE; 1215 pThis->uMergeTarget = VD_LAST_IMAGE; 1091 1216 1092 1217 /* IMedia */ … … 1094 1219 pThis->IMedia.pfnWrite = drvvdWrite; 1095 1220 pThis->IMedia.pfnFlush = drvvdFlush; 1221 pThis->IMedia.pfnMerge = drvvdMerge; 1096 1222 pThis->IMedia.pfnGetSize = drvvdGetSize; 1097 1223 pThis->IMedia.pfnIsReadOnly = drvvdIsReadOnly; … … 1152 1278 "Format\0Path\0" 1153 1279 "ReadOnly\0TempReadOnly\0HonorZeroWrites\0" 1154 "HostIPStack\0UseNewIo\0 ");1280 "HostIPStack\0UseNewIo\0SetupMerge\0"); 1155 1281 } 1156 1282 else … … 1158 1284 /* All other image configurations only contain image name and 1159 1285 * the format information. */ 1160 fValid = CFGMR3AreValuesValid(pCurNode, "Format\0Path\0"); 1286 fValid = CFGMR3AreValuesValid(pCurNode, "Format\0Path\0" 1287 "MergeSource\0MergeTarget\0"); 1161 1288 } 1162 1289 if (!fValid) … … 1202 1329 if (fReadOnly && pThis->fTempReadOnly) 1203 1330 { 1204 rc = PDMDRV_SET_ERROR(pDrvIns, rc,1331 rc = PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRIVER_INVALID_PROPERTIES, 1205 1332 N_("DrvVD: Configuration error: Both \"ReadOnly\" and \"TempReadOnly\" are set")); 1206 1333 break; … … 1213 1340 break; 1214 1341 } 1342 rc = CFGMR3QueryBoolDef(pCurNode, "SetupMerge", &pThis->fMergePending, false); 1343 if (RT_FAILURE(rc)) 1344 { 1345 rc = PDMDRV_SET_ERROR(pDrvIns, rc, 1346 N_("DrvVD: Configuration error: Querying \"SetupMerge\" as boolean failed")); 1347 break; 1348 } 1349 if (fReadOnly && pThis->fMergePending) 1350 { 1351 rc = PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRIVER_INVALID_PROPERTIES, 1352 N_("DrvVD: Configuration error: Both \"ReadOnly\" and \"MergePending\" are set")); 1353 break; 1354 } 1215 1355 } 1216 1356 … … 1223 1363 1224 1364 /* 1225 * Open the images.1365 * Create the image container and the necessary interfaces. 1226 1366 */ 1227 1367 if (RT_SUCCESS(rc)) … … 1293 1433 } 1294 1434 1295 /** @todo implement and set up the thread synchronization interface 1296 * if enabled by some CFGM key. If this is enabled then there also 1297 * needs to be a way for the console object to query the pDisk pointer 1298 * (so that it can perform the merge in parallel), or alternatively 1299 * some code needs to be added here which does the merge. The latter 1300 * might be preferred, as a running merge must block the destruction 1301 * of the disk, or things will go really wrong. */ 1435 if (RT_SUCCESS(rc) && pThis->fMergePending) 1436 { 1437 rc = RTSemFastMutexCreate(&pThis->MergeCompleteMutex); 1438 if (RT_SUCCESS(rc)) 1439 rc = RTSemRWCreate(&pThis->MergeLock); 1440 if (RT_SUCCESS(rc)) 1441 { 1442 pThis->VDIThreadSyncCallbacks.cbSize = sizeof(VDINTERFACETHREADSYNC); 1443 pThis->VDIThreadSyncCallbacks.enmInterface = VDINTERFACETYPE_THREADSYNC; 1444 pThis->VDIThreadSyncCallbacks.pfnStartRead = drvvdThreadStartRead; 1445 pThis->VDIThreadSyncCallbacks.pfnFinishRead = drvvdThreadFinishRead; 1446 pThis->VDIThreadSyncCallbacks.pfnStartWrite = drvvdThreadStartWrite; 1447 pThis->VDIThreadSyncCallbacks.pfnFinishWrite = drvvdThreadFinishWrite; 1448 1449 rc = VDInterfaceAdd(&pThis->VDIThreadSync, "DrvVD_ThreadSync", VDINTERFACETYPE_THREADSYNC, 1450 &pThis->VDIThreadSyncCallbacks, pThis, &pThis->pVDIfsDisk); 1451 } 1452 else 1453 { 1454 rc = PDMDRV_SET_ERROR(pDrvIns, rc, 1455 N_("DrvVD: Failed to create semaphores for \"MergePending\"")); 1456 } 1457 } 1302 1458 1303 1459 if (RT_SUCCESS(rc)) … … 1311 1467 pThis->fAsyncIOSupported = true; 1312 1468 1469 unsigned iImageIdx = 0; 1313 1470 while (pCurNode && RT_SUCCESS(rc)) 1314 1471 { … … 1338 1495 N_("DrvVD: Configuration error: Querying \"Format\" as string failed")); 1339 1496 break; 1497 } 1498 1499 bool fMergeSource; 1500 rc = CFGMR3QueryBoolDef(pCurNode, "MergeSource", &fMergeSource, false); 1501 if (RT_FAILURE(rc)) 1502 { 1503 rc = PDMDRV_SET_ERROR(pDrvIns, rc, 1504 N_("DrvVD: Configuration error: Querying \"MergeSource\" as boolean failed")); 1505 break; 1506 } 1507 if (fMergeSource) 1508 { 1509 if (pThis->uMergeSource == VD_LAST_IMAGE) 1510 pThis->uMergeSource = iImageIdx; 1511 else 1512 { 1513 rc = PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRIVER_INVALID_PROPERTIES, 1514 N_("DrvVD: Configuration error: Multiple \"MergeSource\" occurrences")); 1515 break; 1516 } 1517 } 1518 1519 bool fMergeTarget; 1520 rc = CFGMR3QueryBoolDef(pCurNode, "MergeTarget", &fMergeTarget, false); 1521 if (RT_FAILURE(rc)) 1522 { 1523 rc = PDMDRV_SET_ERROR(pDrvIns, rc, 1524 N_("DrvVD: Configuration error: Querying \"MergeTarget\" as boolean failed")); 1525 break; 1526 } 1527 if (fMergeTarget) 1528 { 1529 if (pThis->uMergeTarget == VD_LAST_IMAGE) 1530 pThis->uMergeTarget = iImageIdx; 1531 else 1532 { 1533 rc = PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRIVER_INVALID_PROPERTIES, 1534 N_("DrvVD: Configuration error: Multiple \"MergeTarget\" occurrences")); 1535 break; 1536 } 1340 1537 } 1341 1538 … … 1399 1596 /* next */ 1400 1597 iLevel--; 1598 iImageIdx--; 1401 1599 pCurNode = CFGMR3GetParent(pCurNode); 1600 } 1601 1602 if ( RT_SUCCESS(rc) 1603 && pThis->fMergePending 1604 && ( pThis->uMergeSource == VD_LAST_IMAGE 1605 || pThis->uMergeTarget == VD_LAST_IMAGE)) 1606 { 1607 rc = PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRIVER_INVALID_PROPERTIES, 1608 N_("DrvVD: Configuration error: Inconsistent image merge data")); 1402 1609 } 1403 1610 -
trunk/src/VBox/Devices/Storage/VBoxHDD.cpp
r27736 r27806 2007 2007 AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature)); 2008 2008 2009 rc2 = vdThreadStartRead(pDisk); 2009 /* For simplicity reasons lock for writing as the image reopen below 2010 * might need it. After all the reopen is usually needed. */ 2011 rc2 = vdThreadStartWrite(pDisk); 2010 2012 AssertRC(rc2); 2011 2013 fLockRead = true; … … 2032 2034 /* Get size of destination image. */ 2033 2035 uint64_t cbSize = pImageTo->Backend->pfnGetSize(pImageTo->pvBackendData); 2034 rc2 = vdThreadFinish Read(pDisk);2036 rc2 = vdThreadFinishWrite(pDisk); 2035 2037 AssertRC(rc2); 2036 2038 fLockRead = false; … … 2106 2108 if (pCbProgress && pCbProgress->pfnProgress) 2107 2109 { 2110 /** @todo r=klaus: this can update the progress to the same 2111 * percentage over and over again if the image format makes 2112 * relatively small increments. */ 2108 2113 rc = pCbProgress->pfnProgress(pIfProgress->pvUser, 2109 2114 uOffset * 99 / cbSize); … … 2188 2193 if (pCbProgress && pCbProgress->pfnProgress) 2189 2194 { 2195 /** @todo r=klaus: this can update the progress to the same 2196 * percentage over and over again if the image format makes 2197 * relatively small increments. */ 2190 2198 rc = pCbProgress->pfnProgress(pIfProgress->pvUser, 2191 2199 uOffset * 99 / cbSize); … … 2589 2597 if (pCbProgress && pCbProgress->pfnProgress) 2590 2598 { 2599 /** @todo r=klaus: this can update the progress to the same 2600 * percentage over and over again if the image format makes 2601 * relatively small increments. */ 2591 2602 rc = pCbProgress->pfnProgress(pIfProgress->pvUser, 2592 2603 uOffset * 99 / cbSize); … … 2596 2607 if (pDstCbProgress && pDstCbProgress->pfnProgress) 2597 2608 { 2609 /** @todo r=klaus: this can update the progress to the same 2610 * percentage over and over again if the image format makes 2611 * relatively small increments. */ 2598 2612 rc = pDstCbProgress->pfnProgress(pDstIfProgress->pvUser, 2599 2613 uOffset * 99 / cbSize);
Note:
See TracChangeset
for help on using the changeset viewer.