VirtualBox

Changeset 44400 in vbox for trunk/src/VBox/Storage


Ignore:
Timestamp:
Jan 27, 2013 9:16:10 PM (12 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
83374
Message:

Storage/VD: Further I/O path unification, drop synchronous vdDiscardHelper and use async version for VDDiscardRanges

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Storage/VD.cpp

    r44396 r44400  
    3939#include <iprt/list.h>
    4040#include <iprt/avl.h>
     41#include <iprt/semaphore.h>
    4142
    4243#include <VBox/vd-plugin.h>
     
    260261    /** Pointer to the discard state if any. */
    261262    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;
    262268};
    263269
     
    12331239
    12341240/**
    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     do
    1250     {
    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             else
    1265                 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                     else
    1297                         rc = VINF_SUCCESS;
    1298                 }
    1299                 else
    1300                 {
    1301                     RTMemFree(pbmAllocated);
    1302                     rc = VERR_NO_MEMORY;
    1303                 }
    1304             }
    1305         }
    1306         else
    1307         {
    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             else
    1354             {
    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 /**
    14051241 * Marks the given range as allocated in the image.
    14061242 * Required if there are discards in progress and a write to a block which can get discarded
     
    15001336                                         void *pvUser1, void *pvUser2,
    15011337                                         void *pvAllocation,
    1502                                          PFNVDIOCTXTRANSFER pfnIoCtxTransfer)
     1338                                         PFNVDIOCTXTRANSFER pfnIoCtxTransfer,
     1339                                         uint32_t fFlags)
    15031340{
    15041341    PVDIOCTX pIoCtx = NULL;
     
    15131350        pIoCtx->cMetaTransfersPending     = 0;
    15141351        pIoCtx->fComplete                 = false;
    1515         pIoCtx->fFlags                    = 0;
     1352        pIoCtx->fFlags                    = fFlags;
    15161353        pIoCtx->pvAllocation              = pvAllocation;
    15171354        pIoCtx->pfnIoCtxTransfer          = pfnIoCtxTransfer;
     
    39983835}
    39993836
    4000 /** 
     3837/**
    40013838 * Processes a list of waiting I/O tasks. The disk lock must be held by caller.
    40023839 *
     
    40373874        pCur = pHead;
    40383875        pHead = pHead->pNext;
    4039         vdIoTaskFree(pDisk, pCur); 
    4040     }
    4041 }
    4042 
    4043 /** 
     3876        vdIoTaskFree(pDisk, pCur);
     3877    }
     3878}
     3879
     3880/**
    40443881 * Process any I/O context on the halted list.
    40453882 *
     
    41013938     * Afterwards comes the list of new I/O contexts.
    41023939     */
    4103 
    41043940    vdIoTaskProcessWaitingList(pDisk);
    41053941    vdIoCtxProcessHaltedList(pDisk);
     
    41573993    if (ASMAtomicCmpXchgBool(&pDisk->fLocked, true, false))
    41583994    {
    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. */
    41633996        vdDiskUnlock(pDisk, NULL);
    41643997    }
     
    52195052
    52205053/**
     5054 * Internally used completion handler for synchronous I/O contexts.
     5055 */
     5056static 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/**
    52215065 * Initializes HDD backends.
    52225066 *
     
    54115255            pDisk->pIoCtxHead              = NULL;
    54125256            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;
    54135264
    54145265            /* Create the I/O ctx cache */
     
    54165267                                  NULL, NULL, NULL, 0);
    54175268            if (RT_FAILURE(rc))
    5418             {
    5419                 RTMemFree(pDisk);
    54205269                break;
    5421             }
    54225270
    54235271            /* Create the I/O task cache */
     
    54255273                                  NULL, NULL, NULL, 0);
    54265274            if (RT_FAILURE(rc))
    5427             {
    5428                 RTMemCacheDestroy(pDisk->hMemCacheIoCtx);
    5429                 RTMemFree(pDisk);
    54305275                break;
    5431             }
    54325276
    54335277            pDisk->pInterfaceError      = VDIfErrorGet(pVDIfsDisk);
     
    54425286        }
    54435287    } 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    }
    54445299
    54455300    LogFlowFunc(("returns %Rrc (pDisk=%#p)\n", rc, pDisk));
     
    54685323        RTMemCacheDestroy(pDisk->hMemCacheIoCtx);
    54695324        RTMemCacheDestroy(pDisk->hMemCacheIoTask);
     5325        RTSemEventDestroy(pDisk->hEventSemSyncIo);
    54705326        RTMemFree(pDisk);
    54715327    } while (0);
     
    96679523                           rc = VERR_NOT_SUPPORTED);
    96689524
    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);
    96719548    } while (0);
    96729549
     
    99049781        pIoCtx = vdIoCtxDiscardAlloc(pDisk, paRanges, cRanges,
    99059782                                     pfnComplete, pvUser1, pvUser2, NULL,
    9906                                      vdDiscardHelperAsync);
     9783                                     vdDiscardHelperAsync,
     9784                                     0 /* fFlags */);
    99079785        if (!pIoCtx)
    99089786        {
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette