Changeset 44400 in vbox for trunk/src/VBox/Storage
- Timestamp:
- Jan 27, 2013 9:16:10 PM (12 years ago)
- svn:sync-xref-src-repo-rev:
- 83374
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Storage/VD.cpp
r44396 r44400 39 39 #include <iprt/list.h> 40 40 #include <iprt/avl.h> 41 #include <iprt/semaphore.h> 41 42 42 43 #include <VBox/vd-plugin.h> … … 260 261 /** Pointer to the discard state if any. */ 261 262 PVDDISCARDSTATE pDiscard; 263 264 /** Event semaphore for synchronous I/O. */ 265 RTSEMEVENT hEventSemSyncIo; 266 /** Status code of the last synchronous I/O request. */ 267 int rcSync; 262 268 }; 263 269 … … 1233 1239 1234 1240 /** 1235 * Discards the given range from the underlying block.1236 *1237 * @returns VBox status code.1238 * @param pDisk VD container data.1239 * @param offStart Where to start discarding.1240 * @param cbDiscard How many bytes to discard.1241 */1242 static int vdDiscardRange(PVBOXHDD pDisk, PVDDISCARDSTATE pDiscard, uint64_t offStart, size_t cbDiscard)1243 {1244 int rc = VINF_SUCCESS;1245 1246 LogFlowFunc(("pDisk=%#p pDiscard=%#p offStart=%llu cbDiscard=%zu\n",1247 pDisk, pDiscard, offStart, cbDiscard));1248 1249 do1250 {1251 size_t cbThisDiscard;1252 1253 /* Look for a matching block in the AVL tree first. */1254 PVDDISCARDBLOCK pBlock = (PVDDISCARDBLOCK)RTAvlrU64GetBestFit(pDiscard->pTreeBlocks, offStart, false);1255 if (!pBlock || pBlock->Core.KeyLast < offStart)1256 {1257 void *pbmAllocated = NULL;1258 size_t cbPreAllocated, cbPostAllocated;1259 PVDDISCARDBLOCK pBlockAbove = (PVDDISCARDBLOCK)RTAvlrU64GetBestFit(pDiscard->pTreeBlocks, offStart, true);1260 1261 /* Clip range to remain in the current block. */1262 if (pBlockAbove)1263 cbThisDiscard = RT_MIN(cbDiscard, pBlockAbove->Core.KeyLast - offStart + 1);1264 else1265 cbThisDiscard = cbDiscard;1266 1267 Assert(!(cbThisDiscard % 512));1268 1269 /* No block found, try to discard using the backend first. */1270 VDIOCTX IoCtx;1271 1272 vdIoCtxInit(&IoCtx, pDisk, VDIOCTXTXDIR_DISCARD, 0, 0, NULL,1273 NULL, NULL, NULL, VDIOCTX_FLAGS_SYNC);1274 rc = pDisk->pLast->Backend->pfnDiscard(pDisk->pLast->pBackendData,1275 &IoCtx, offStart,1276 cbThisDiscard, &cbPreAllocated,1277 &cbPostAllocated, &cbThisDiscard,1278 &pbmAllocated, 0);1279 if (rc == VERR_VD_DISCARD_ALIGNMENT_NOT_MET)1280 {1281 /* Create new discard block. */1282 pBlock = (PVDDISCARDBLOCK)RTMemAllocZ(sizeof(VDDISCARDBLOCK));1283 if (pBlock)1284 {1285 pBlock->Core.Key = offStart - cbPreAllocated;1286 pBlock->Core.KeyLast = offStart + cbThisDiscard + cbPostAllocated - 1;1287 pBlock->cbDiscard = cbPreAllocated + cbThisDiscard + cbPostAllocated;1288 pBlock->pbmAllocated = pbmAllocated;1289 bool fInserted = RTAvlrU64Insert(pDiscard->pTreeBlocks, &pBlock->Core);1290 Assert(fInserted);1291 1292 RTListPrepend(&pDiscard->ListLru, &pBlock->NodeLru);1293 pDiscard->cbDiscarding += pBlock->cbDiscard;1294 if (pDiscard->cbDiscarding > VD_DISCARD_REMOVE_THRESHOLD)1295 rc = vdDiscardRemoveBlocks(pDisk, pDiscard, VD_DISCARD_REMOVE_THRESHOLD);1296 else1297 rc = VINF_SUCCESS;1298 }1299 else1300 {1301 RTMemFree(pbmAllocated);1302 rc = VERR_NO_MEMORY;1303 }1304 }1305 }1306 else1307 {1308 /* Range lies partly in the block, update allocation bitmap. */1309 int32_t idxStart, idxEnd;1310 1311 cbThisDiscard = RT_MIN(cbDiscard, pBlock->Core.KeyLast - offStart + 1);1312 1313 AssertPtr(pBlock);1314 1315 Assert(!(cbThisDiscard % 512));1316 Assert(!((offStart - pBlock->Core.Key) % 512));1317 1318 idxStart = (offStart - pBlock->Core.Key) / 512;1319 idxEnd = idxStart + (cbThisDiscard / 512);1320 1321 ASMBitClearRange(pBlock->pbmAllocated, idxStart, idxEnd);1322 1323 /* Call the backend to discard the block if it is completely unallocated now. */1324 if (ASMBitFirstSet((volatile void *)pBlock->pbmAllocated, pBlock->cbDiscard / 512) == -1)1325 {1326 VDIOCTX IoCtx;1327 size_t cbPreAllocated, cbPostAllocated, cbActuallyDiscarded;1328 1329 vdIoCtxInit(&IoCtx, pDisk, VDIOCTXTXDIR_DISCARD, 0, 0, NULL,1330 NULL, NULL, NULL, VDIOCTX_FLAGS_SYNC);1331 rc = pDisk->pLast->Backend->pfnDiscard(pDisk->pLast->pBackendData,1332 &IoCtx, pBlock->Core.Key,1333 pBlock->cbDiscard, &cbPreAllocated,1334 &cbPostAllocated, &cbActuallyDiscarded,1335 NULL, 0);1336 Assert(rc != VERR_VD_DISCARD_ALIGNMENT_NOT_MET);1337 Assert(!cbPreAllocated);1338 Assert(!cbPostAllocated);1339 Assert(cbActuallyDiscarded == pBlock->cbDiscard || RT_FAILURE(rc));1340 1341 /* Remove the block on success. */1342 if (RT_SUCCESS(rc))1343 {1344 PVDDISCARDBLOCK pBlockRemove = (PVDDISCARDBLOCK)RTAvlrU64RangeRemove(pDiscard->pTreeBlocks, pBlock->Core.Key);1345 Assert(pBlockRemove == pBlock);1346 1347 pDiscard->cbDiscarding -= pBlock->cbDiscard;1348 RTListNodeRemove(&pBlock->NodeLru);1349 RTMemFree(pBlock->pbmAllocated);1350 RTMemFree(pBlock);1351 }1352 }1353 else1354 {1355 RTListNodeRemove(&pBlock->NodeLru);1356 RTListPrepend(&pDiscard->ListLru, &pBlock->NodeLru);1357 rc = VINF_SUCCESS;1358 }1359 }1360 1361 Assert(cbDiscard >= cbThisDiscard);1362 1363 cbDiscard -= cbThisDiscard;1364 offStart += cbThisDiscard;1365 } while (cbDiscard != 0 && RT_SUCCESS(rc));1366 1367 LogFlowFunc(("returns rc=%Rrc\n", rc));1368 return rc;1369 }1370 1371 /**1372 * Discard helper.1373 *1374 * @returns VBox status code.1375 * @param pDisk VD container data.1376 * @param paRanges The array of ranges to discard.1377 * @param cRanges The number of ranges in the array.1378 */1379 static int vdDiscardHelper(PVBOXHDD pDisk, PCRTRANGE paRanges, unsigned cRanges)1380 {1381 int rc = VINF_SUCCESS;1382 PVDDISCARDSTATE pDiscard = pDisk->pDiscard;1383 1384 if (RT_UNLIKELY(!pDiscard))1385 {1386 pDiscard = vdDiscardStateCreate();1387 if (!pDiscard)1388 return VERR_NO_MEMORY;1389 1390 pDisk->pDiscard = pDiscard;1391 }1392 1393 /* Go over the range array and discard individual blocks. */1394 for (unsigned i = 0; i < cRanges; i++)1395 {1396 rc = vdDiscardRange(pDisk, pDiscard, paRanges[i].offStart, paRanges[i].cbRange);1397 if (RT_FAILURE(rc))1398 break;1399 }1400 1401 return rc;1402 }1403 1404 /**1405 1241 * Marks the given range as allocated in the image. 1406 1242 * Required if there are discards in progress and a write to a block which can get discarded … … 1500 1336 void *pvUser1, void *pvUser2, 1501 1337 void *pvAllocation, 1502 PFNVDIOCTXTRANSFER pfnIoCtxTransfer) 1338 PFNVDIOCTXTRANSFER pfnIoCtxTransfer, 1339 uint32_t fFlags) 1503 1340 { 1504 1341 PVDIOCTX pIoCtx = NULL; … … 1513 1350 pIoCtx->cMetaTransfersPending = 0; 1514 1351 pIoCtx->fComplete = false; 1515 pIoCtx->fFlags = 0;1352 pIoCtx->fFlags = fFlags; 1516 1353 pIoCtx->pvAllocation = pvAllocation; 1517 1354 pIoCtx->pfnIoCtxTransfer = pfnIoCtxTransfer; … … 3998 3835 } 3999 3836 4000 /** 3837 /** 4001 3838 * Processes a list of waiting I/O tasks. The disk lock must be held by caller. 4002 3839 * … … 4037 3874 pCur = pHead; 4038 3875 pHead = pHead->pNext; 4039 vdIoTaskFree(pDisk, pCur); 4040 } 4041 } 4042 4043 /** 3876 vdIoTaskFree(pDisk, pCur); 3877 } 3878 } 3879 3880 /** 4044 3881 * Process any I/O context on the halted list. 4045 3882 * … … 4101 3938 * Afterwards comes the list of new I/O contexts. 4102 3939 */ 4103 4104 3940 vdIoTaskProcessWaitingList(pDisk); 4105 3941 vdIoCtxProcessHaltedList(pDisk); … … 4157 3993 if (ASMAtomicCmpXchgBool(&pDisk->fLocked, true, false)) 4158 3994 { 4159 /* Disk locked, process the list. */ 4160 vdIoTaskProcessWaitingList(pDisk); 4161 4162 /* Release disk lock. */ 3995 /* Release disk lock, it will take care of processing all lists. */ 4163 3996 vdDiskUnlock(pDisk, NULL); 4164 3997 } … … 5219 5052 5220 5053 /** 5054 * Internally used completion handler for synchronous I/O contexts. 5055 */ 5056 static DECLCALLBACK(void) vdIoCtxSyncComplete(void *pvUser1, void *pvUser2, int rcReq) 5057 { 5058 PVBOXHDD pDisk = (PVBOXHDD)pvUser1; 5059 5060 pDisk->rcSync = rcReq; 5061 RTSemEventSignal(pDisk->hEventSemSyncIo); 5062 } 5063 5064 /** 5221 5065 * Initializes HDD backends. 5222 5066 * … … 5411 5255 pDisk->pIoCtxHead = NULL; 5412 5256 pDisk->fLocked = false; 5257 pDisk->hEventSemSyncIo = NIL_RTSEMEVENT; 5258 pDisk->hMemCacheIoCtx = NIL_RTMEMCACHE; 5259 pDisk->hMemCacheIoTask = NIL_RTMEMCACHE; 5260 5261 rc = RTSemEventCreate(&pDisk->hEventSemSyncIo); 5262 if (RT_FAILURE(rc)) 5263 break; 5413 5264 5414 5265 /* Create the I/O ctx cache */ … … 5416 5267 NULL, NULL, NULL, 0); 5417 5268 if (RT_FAILURE(rc)) 5418 {5419 RTMemFree(pDisk);5420 5269 break; 5421 }5422 5270 5423 5271 /* Create the I/O task cache */ … … 5425 5273 NULL, NULL, NULL, 0); 5426 5274 if (RT_FAILURE(rc)) 5427 {5428 RTMemCacheDestroy(pDisk->hMemCacheIoCtx);5429 RTMemFree(pDisk);5430 5275 break; 5431 }5432 5276 5433 5277 pDisk->pInterfaceError = VDIfErrorGet(pVDIfsDisk); … … 5442 5286 } 5443 5287 } while (0); 5288 5289 if ( RT_FAILURE(rc) 5290 && pDisk) 5291 { 5292 if (pDisk->hEventSemSyncIo != NIL_RTSEMEVENT) 5293 RTSemEventDestroy(pDisk->hEventSemSyncIo); 5294 if (pDisk->hMemCacheIoCtx != NIL_RTMEMCACHE) 5295 RTMemCacheDestroy(pDisk->hMemCacheIoCtx); 5296 if (pDisk->hMemCacheIoTask != NIL_RTMEMCACHE) 5297 RTMemCacheDestroy(pDisk->hMemCacheIoTask); 5298 } 5444 5299 5445 5300 LogFlowFunc(("returns %Rrc (pDisk=%#p)\n", rc, pDisk)); … … 5468 5323 RTMemCacheDestroy(pDisk->hMemCacheIoCtx); 5469 5324 RTMemCacheDestroy(pDisk->hMemCacheIoTask); 5325 RTSemEventDestroy(pDisk->hEventSemSyncIo); 5470 5326 RTMemFree(pDisk); 5471 5327 } while (0); … … 9667 9523 rc = VERR_NOT_SUPPORTED); 9668 9524 9669 vdSetModifiedFlag(pDisk); 9670 rc = vdDiscardHelper(pDisk, paRanges, cRanges); 9525 PVDIOCTX pIoCtx = vdIoCtxDiscardAlloc(pDisk, paRanges, cRanges, 9526 vdIoCtxSyncComplete, pDisk, NULL, NULL, 9527 vdDiscardHelperAsync, 9528 VDIOCTX_FLAGS_SYNC); 9529 if (!pIoCtx) 9530 { 9531 rc = VERR_NO_MEMORY; 9532 break; 9533 } 9534 9535 rc = vdIoCtxProcessTryLockDefer(pIoCtx); 9536 if (rc == VINF_VD_ASYNC_IO_FINISHED) 9537 rc = VINF_SUCCESS; 9538 9539 if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS) 9540 { 9541 rc = RTSemEventWait(pDisk->hEventSemSyncIo, RT_INDEFINITE_WAIT); 9542 AssertRC(rc); 9543 9544 rc = pDisk->rcSync; 9545 } 9546 else /* Success or error. */ 9547 vdIoCtxFree(pDisk, pIoCtx); 9671 9548 } while (0); 9672 9549 … … 9904 9781 pIoCtx = vdIoCtxDiscardAlloc(pDisk, paRanges, cRanges, 9905 9782 pfnComplete, pvUser1, pvUser2, NULL, 9906 vdDiscardHelperAsync); 9783 vdDiscardHelperAsync, 9784 0 /* fFlags */); 9907 9785 if (!pIoCtx) 9908 9786 {
Note:
See TracChangeset
for help on using the changeset viewer.