VirtualBox

Changeset 38621 in vbox for trunk/src/VBox/Storage/VDI.cpp


Ignore:
Timestamp:
Sep 4, 2011 4:56:56 PM (13 years ago)
Author:
vboxsync
Message:

VD: Initial support to discard unused blocks in an image + support for VDI images

File:
1 edited

Legend:

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

    r38469 r38621  
    102102        }
    103103
     104        if (pImage->paBlocksRev)
     105        {
     106            RTMemFree(pImage->paBlocksRev);
     107            pImage->paBlocksRev = NULL;
     108        }
     109
    104110        if (fDelete && pImage->pszFilename)
    105111            vdIfIoIntFileDelete(pImage->pIfIo, pImage->pszFilename);
     
    703709                               getImageBlocks(&pImage->Header) * sizeof(VDIIMAGEBLOCKPOINTER),
    704710                               NULL);
     711
     712    if (uOpenFlags & VD_OPEN_FLAGS_DISCARD)
     713    {
     714        /*
     715         * Create the back resolving table for discards.
     716         * any error or inconsistency results in a fail because this might
     717         * get us into trouble later on.
     718         */
     719        pImage->paBlocksRev = (unsigned *)RTMemAllocZ(sizeof(unsigned) * getImageBlocks(&pImage->Header));
     720        if (pImage->paBlocksRev)
     721        {
     722            unsigned cBlocksAllocated = getImageBlocksAllocated(&pImage->Header);
     723            unsigned cBlocks = getImageBlocks(&pImage->Header);
     724
     725            for (unsigned i = 0; i < cBlocksAllocated; i++)
     726                pImage->paBlocksRev[i] = VDI_IMAGE_BLOCK_FREE;
     727
     728            for (unsigned i = 0; i < cBlocks; i++)
     729            {
     730                VDIIMAGEBLOCKPOINTER ptrBlock = pImage->paBlocks[i];
     731                if (IS_VDI_IMAGE_BLOCK_ALLOCATED(ptrBlock))
     732                {
     733                    if (ptrBlock < cBlocksAllocated)
     734                    {
     735                        if (pImage->paBlocksRev[ptrBlock] == VDI_IMAGE_BLOCK_FREE)
     736                            pImage->paBlocksRev[ptrBlock] = i;
     737                        else
     738                        {
     739                            rc = VERR_VD_VDI_INVALID_HEADER;
     740                            break;
     741                        }
     742                    }
     743                    else
     744                    {
     745                        rc = VERR_VD_VDI_INVALID_HEADER;
     746                        break;
     747                    }
     748                }
     749            }
     750        }
     751        else
     752            rc = VERR_NO_MEMORY;
     753    }
    705754
    706755out:
     
    12051254                    goto out;
    12061255                pImage->paBlocks[uBlock] = cBlocksAllocated;
     1256
     1257                if (pImage->paBlocksRev)
     1258                    pImage->paBlocksRev[cBlocksAllocated] = uBlock;
     1259
    12071260                setImageBlocksAllocated(&pImage->Header, cBlocksAllocated + 1);
    12081261
     
    14881541
    14891542    /* Image must be opened and the new flags must be valid. */
    1490     if (!pImage || (uOpenFlags & ~(VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO | VD_OPEN_FLAGS_ASYNC_IO | VD_OPEN_FLAGS_SHAREABLE | VD_OPEN_FLAGS_SEQUENTIAL)))
     1543    if (!pImage || (uOpenFlags & ~(VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO | VD_OPEN_FLAGS_ASYNC_IO | VD_OPEN_FLAGS_SHAREABLE | VD_OPEN_FLAGS_SEQUENTIAL | VD_OPEN_FLAGS_DISCARD)))
    14911544    {
    14921545        rc = VERR_INVALID_PARAMETER;
     
    20042057                    goto out;
    20052058                pImage->paBlocks[uBlock] = cBlocksAllocated;
     2059
     2060                if (pImage->paBlocksRev)
     2061                    pImage->paBlocksRev[cBlocksAllocated] = uBlock;
     2062
    20062063                setImageBlocksAllocated(&pImage->Header, cBlocksAllocated + 1);
    20072064
     
    24812538
    24822539
     2540/** @copydoc VBOXHDDBACKEND::pfnDiscard */
     2541static DECLCALLBACK(int) vdiDiscard(void *pBackendData,
     2542                                    uint64_t uOffset, size_t cbDiscard,
     2543                                    size_t *pcbPreAllocated,
     2544                                    size_t *pcbPostAllocated,
     2545                                    size_t *pcbActuallyDiscarded,
     2546                                    void   **ppbmAllocationBitmap,
     2547                                    unsigned fDiscard)
     2548{
     2549    PVDIIMAGEDESC pImage = (PVDIIMAGEDESC)pBackendData;
     2550    unsigned uBlock;
     2551    unsigned offDiscard;
     2552    int rc = VINF_SUCCESS;
     2553    void *pvBlock = NULL;
     2554
     2555    LogFlowFunc(("pBackendData=%#p uOffset=%llu cbDiscard=%zu pcbPreAllocated=%#p pcbPostAllocated=%#p pcbActuallyDiscarded=%#p ppbmAllocationBitmap=%#p fDiscard=%#x\n",
     2556                 pBackendData, uOffset, cbDiscard, pcbPreAllocated, pcbPostAllocated, pcbActuallyDiscarded, ppbmAllocationBitmap, fDiscard));
     2557
     2558    AssertPtr(pImage);
     2559    Assert(!(uOffset % 512));
     2560    Assert(!(cbDiscard % 512));
     2561
     2562    do
     2563    {
     2564        AssertMsgBreakStmt(!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY),
     2565                           ("Image is opened readonly\n"),
     2566                           rc = VERR_VD_IMAGE_READ_ONLY);
     2567
     2568        AssertMsgBreakStmt(cbDiscard,
     2569                           ("cbDiscard=%u\n", cbDiscard),
     2570                           rc = VERR_INVALID_PARAMETER);
     2571
     2572        /* Calculate starting block number and offset inside it. */
     2573        uBlock = (unsigned)(uOffset >> pImage->uShiftOffset2Index);
     2574        offDiscard = (unsigned)uOffset & pImage->uBlockMask;
     2575
     2576        /* Clip range to at most the rest of the block. */
     2577        cbDiscard = RT_MIN(cbDiscard, getImageBlockSize(&pImage->Header) - offDiscard);
     2578        Assert(!(cbDiscard % 512));
     2579
     2580        if (pcbPreAllocated)
     2581            *pcbPreAllocated = 0;
     2582
     2583        if (pcbPostAllocated)
     2584            *pcbPostAllocated = 0;
     2585
     2586        if (IS_VDI_IMAGE_BLOCK_ALLOCATED(pImage->paBlocks[uBlock]))
     2587        {
     2588            uint8_t *pbBlockData;
     2589            size_t cbPreAllocated, cbPostAllocated;
     2590
     2591            cbPreAllocated = offDiscard % getImageBlockSize(&pImage->Header);
     2592            cbPostAllocated = getImageBlockSize(&pImage->Header) - cbDiscard - cbPreAllocated;
     2593
     2594            /* Read the block data. */
     2595            pvBlock = RTMemAlloc(pImage->cbTotalBlockData);
     2596            if (!pvBlock)
     2597            {
     2598                rc = VERR_NO_MEMORY;
     2599                break;
     2600            }
     2601            pbBlockData = (uint8_t *)pvBlock + pImage->offStartBlockData;
     2602
     2603            uint64_t u64Offset = (uint64_t)pImage->paBlocks[uBlock] * pImage->cbTotalBlockData + pImage->offStartData;
     2604            rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage, u64Offset,
     2605                                       pvBlock, pImage->cbTotalBlockData, NULL);
     2606            if (RT_FAILURE(rc))
     2607                break;
     2608
     2609            /* Clear data. */
     2610            memset(pbBlockData + offDiscard , 0, cbDiscard);
     2611
     2612            Assert(!(cbDiscard % 4));
     2613            Assert(cbDiscard * 8 <= UINT32_MAX);
     2614            if (ASMBitFirstSet((volatile void *)pbBlockData, getImageBlockSize(&pImage->Header) * 8) == -1)
     2615            {
     2616                uint64_t cbImage;
     2617                unsigned idxLastBlock = getImageBlocksAllocated(&pImage->Header) - 1;
     2618                unsigned uBlockLast = pImage->paBlocksRev[idxLastBlock];
     2619
     2620                pImage->paBlocksRev[idxLastBlock] = VDI_IMAGE_BLOCK_FREE;
     2621
     2622                /*
     2623                 * The block is empty, remove it.
     2624                 * Read the last block of the image first.
     2625                 */
     2626                if (idxLastBlock != pImage->paBlocks[uBlock])
     2627                {
     2628                    u64Offset = (uint64_t)idxLastBlock * pImage->cbTotalBlockData + pImage->offStartData;
     2629                    rc = vdIfIoIntFileReadSync(pImage->pIfIo, pImage->pStorage, u64Offset,
     2630                                               pvBlock, pImage->cbTotalBlockData, NULL);
     2631                    if (RT_FAILURE(rc))
     2632                        break;
     2633
     2634                    /* Write to the now unallocated block. */
     2635                    u64Offset = (uint64_t)pImage->paBlocks[uBlock] * pImage->cbTotalBlockData + pImage->offStartData;
     2636                    rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage, u64Offset,
     2637                                                pvBlock, pImage->cbTotalBlockData, NULL);
     2638                    if (RT_FAILURE(rc))
     2639                        break;
     2640
     2641                    /* Update block and reverse block tables. */
     2642                    pImage->paBlocks[uBlockLast] = pImage->paBlocks[uBlock];
     2643                    rc = vdiUpdateBlockInfo(pImage, uBlockLast);
     2644                    if (RT_FAILURE(rc))
     2645                        break;
     2646                }
     2647
     2648                pImage->paBlocks[uBlock] = VDI_IMAGE_BLOCK_ZERO;
     2649
     2650                /* Update the block pointers. */
     2651                setImageBlocksAllocated(&pImage->Header, idxLastBlock);
     2652                rc = vdiUpdateBlockInfo(pImage, uBlock);
     2653                if (RT_FAILURE(rc))
     2654                    break;
     2655
     2656                /* Set new file size. */
     2657                rc = vdIfIoIntFileGetSize(pImage->pIfIo, pImage->pStorage, &cbImage);
     2658                if (RT_FAILURE(rc))
     2659                    break;
     2660
     2661                rc = vdIfIoIntFileSetSize(pImage->pIfIo, pImage->pStorage, cbImage - pImage->cbTotalBlockData);
     2662            }
     2663            else /* if (fDiscard & VD_DISCARD_MARK_UNUSED) */
     2664            {
     2665                /* Write changed data to the image. */
     2666                rc = vdIfIoIntFileWriteSync(pImage->pIfIo, pImage->pStorage, u64Offset + offDiscard,
     2667                                            pbBlockData + offDiscard, cbDiscard, NULL);
     2668            }
     2669#if 0
     2670            else
     2671            {
     2672                /* Block has data, create allocation bitmap. */
     2673                *pcbPreAllocated = cbPreAllocated;
     2674                *pcbPostAllocated = cbPostAllocated;
     2675                *ppbmAllocationBitmap = vdAllocationBitmapCreate(pvBlock, getImageBlockSize(&pImage->Header));
     2676                if (RT_UNLIKELY(!*ppbmAllocationBitmap))
     2677                    rc = VERR_NO_MEMORY;
     2678                else
     2679                    rc = VERR_VD_DISCARD_ALIGNMENT_NOT_MET;
     2680            }
     2681#endif
     2682        }
     2683        /* else: nothing to do. */
     2684    } while (0);
     2685
     2686    if (pcbActuallyDiscarded)
     2687        *pcbActuallyDiscarded = cbDiscard;
     2688
     2689    if (pvBlock)
     2690        RTMemFree(pvBlock);
     2691
     2692    LogFlowFunc(("returns %Rrc\n", rc));
     2693    return rc;
     2694}
     2695
    24832696VBOXHDDBACKEND g_VDIBackend =
    24842697{
     
    24892702    /* uBackendCaps */
    24902703      VD_CAP_UUID | VD_CAP_CREATE_FIXED | VD_CAP_CREATE_DYNAMIC
    2491     | VD_CAP_DIFF | VD_CAP_FILE | VD_CAP_ASYNC | VD_CAP_VFS,
     2704    | VD_CAP_DIFF | VD_CAP_FILE | VD_CAP_ASYNC | VD_CAP_VFS | VD_CAP_DISCARD,
    24922705    /* paFileExtensions */
    24932706    s_aVdiFileExtensions,
     
    25772790    vdiCompact,
    25782791    /* pfnResize */
    2579     vdiResize
     2792    vdiResize,
     2793    /* pfnDiscard */
     2794    vdiDiscard
    25802795};
Note: See TracChangeset for help on using the changeset viewer.

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