VirtualBox

Changeset 31921 in vbox for trunk


Ignore:
Timestamp:
Aug 24, 2010 12:54:12 PM (14 years ago)
Author:
vboxsync
Message:

VHD/Resize: Initial support

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Storage/VHDHDDCore.cpp

    r31776 r31921  
    184184    /** Current end offset of the file (without the disk footer). */
    185185    uint64_t        uCurrentEndOfFile;
    186     /** Start offset of data blocks. */
    187     uint64_t        uDataBlockStart;
    188186    /** Size of the data block bitmap in sectors. */
    189187    uint32_t        cDataBlockBitmapSectors;
     
    547545
    548546/**
     547 * Internal: Update the VHD footer.
     548 */
     549static int vhdUpdateFooter(PVHDIMAGE pImage)
     550{
     551    int rc = VINF_SUCCESS;
     552
     553    /* Update fields which can change. */
     554    pImage->vhdFooterCopy.CurSize              = RT_H2BE_U64(pImage->cbSize);
     555    pImage->vhdFooterCopy.DiskGeometryCylinder = RT_H2BE_U16(pImage->PCHSGeometry.cCylinders);
     556    pImage->vhdFooterCopy.DiskGeometryHeads    = pImage->PCHSGeometry.cHeads;
     557    pImage->vhdFooterCopy.DiskGeometrySectors  = pImage->PCHSGeometry.cSectors;
     558
     559    pImage->vhdFooterCopy.Checksum = 0;
     560    pImage->vhdFooterCopy.Checksum = RT_H2BE_U32(vhdChecksum(&pImage->vhdFooterCopy, sizeof(VHDFooter)));
     561
     562    if (pImage->pBlockAllocationTable)
     563        rc = vhdFileWriteSync(pImage, 0, &pImage->vhdFooterCopy, sizeof(VHDFooter), NULL);
     564
     565    if (RT_SUCCESS(rc))
     566        rc = vhdFileWriteSync(pImage, pImage->uCurrentEndOfFile, &pImage->vhdFooterCopy, sizeof(VHDFooter), NULL);
     567
     568    return rc;
     569}
     570
     571/**
    549572 * Internal: Update dynamic disk header from VHDIMAGE.
    550573 */
     
    600623    /* Update parent's UUID */
    601624    memcpy(ddh.ParentUuid, pImage->ParentUuid.au8, sizeof(ddh.ParentUuid));
     625
     626    /* Update data offset and number of table entries. */
     627    ddh.MaxTableEntries = RT_H2BE_U32(pImage->cBlockAllocationTableEntries);
     628
    602629    ddh.Checksum = 0;
    603630    ddh.Checksum = RT_H2BE_U32(vhdChecksum(&ddh, sizeof(ddh)));
     
    606633        return rc;
    607634
    608     /* Update the VHD footer copy. */
    609     rc = vhdFileWriteSync(pImage, 0, &pImage->vhdFooterCopy, sizeof(VHDFooter), NULL);
     635    /* Update the VHD footer. */
     636    rc = vhdUpdateFooter(pImage);
    610637
    611638out:
     
    890917    pImage->uBlockAllocationTableOffset = uBlockAllocationTableOffset;
    891918    rc = vhdFileReadSync(pImage, uBlockAllocationTableOffset, pBlockAllocationTable, pImage->cBlockAllocationTableEntries * sizeof(uint32_t), NULL);
    892     pImage->uDataBlockStart = uBlockAllocationTableOffset + pImage->cBlockAllocationTableEntries * sizeof(uint32_t);
    893     LogFlowFunc(("uDataBlockStart=%llu\n", pImage->uDataBlockStart));
    894919
    895920    /*
     
    10921117    /* Image must be opened and the new flags must be valid. Just readonly and
    10931118     * info flags are supported. */
    1094     if (!pImage || (uOpenFlags & ~(VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO | VD_OPEN_FLAGS_SHAREABLE)))
     1119    if (!pImage || (uOpenFlags & ~(VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO | VD_OPEN_FLAGS_SHAREABLE  | VD_OPEN_FLAGS_ASYNC_IO)))
    10951120    {
    10961121        rc = VERR_INVALID_PARAMETER;
     
    15221547         */
    15231548        vhdFileWriteSync(pImage, pImage->uBlockAllocationTableOffset, pBlockAllocationTableToWrite, cbBlockAllocationTableToWrite, NULL);
    1524         vhdFileWriteSync(pImage, pImage->uCurrentEndOfFile, &pImage->vhdFooterCopy, sizeof(VHDFooter), NULL);
    15251549        if (pImage->fDynHdrNeedsUpdate)
    15261550            vhdDynamicHeaderUpdate(pImage);
    15271551        RTMemFree(pBlockAllocationTableToWrite);
    15281552    }
     1553
     1554    vhdUpdateFooter(pImage);
    15291555
    15301556    int rc = vhdFileFlushSync(pImage);
     
    26572683                                                        NULL, NULL);
    26582684}
     2685
     2686
     2687/** @copydoc VBOXHDDBACKEND::pfnResize */
     2688static int vhdResize(void *pvBackendData, uint64_t cbSize,
     2689                     PCPDMMEDIAGEOMETRY pPCHSGeometry, PCPDMMEDIAGEOMETRY pLCHSGeometry,
     2690                     unsigned uPercentStart, unsigned uPercentSpan,
     2691                     PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage,
     2692                     PVDINTERFACE pVDIfsOperation)
     2693{
     2694    PVHDIMAGE pImage = (PVHDIMAGE)pvBackendData;
     2695    int rc = VINF_SUCCESS;
     2696
     2697    PFNVDPROGRESS pfnProgress = NULL;
     2698    void *pvUser = NULL;
     2699    PVDINTERFACE pIfProgress = VDInterfaceGet(pVDIfsOperation,
     2700                                              VDINTERFACETYPE_PROGRESS);
     2701    PVDINTERFACEPROGRESS pCbProgress = NULL;
     2702    if (pIfProgress)
     2703    {
     2704        pCbProgress = VDGetInterfaceProgress(pIfProgress);
     2705        if (pCbProgress)
     2706            pfnProgress = pCbProgress->pfnProgress;
     2707        pvUser = pIfProgress->pvUser;
     2708    }
     2709
     2710    /* Making the image smaller is not supported at the moment. */
     2711    if (   cbSize < pImage->cbSize
     2712        || pImage->uImageFlags & VD_IMAGE_FLAGS_FIXED)
     2713        rc = VERR_NOT_SUPPORTED;
     2714    else if (cbSize > pImage->cbSize)
     2715    {
     2716        unsigned cBlocksAllocated = 0;
     2717        size_t cbBlock = pImage->cbDataBlock + pImage->cbDataBlockBitmap;     /** < Size of a block including the sector bitmap. */
     2718        uint32_t cBlocksNew = cbSize / pImage->cbDataBlock;                   /** < New number of blocks in the image after the resize */
     2719        if (cbSize % pImage->cbDataBlock)
     2720            cBlocksNew++;
     2721
     2722        uint32_t cBlocksOld      = pImage->cBlockAllocationTableEntries;      /** < Number of blocks before the resize. */
     2723        uint64_t cbBlockspaceNew = RT_ALIGN_32(cBlocksNew * sizeof(uint32_t), VHD_SECTOR_SIZE);                         /** < Required space for the block array after the resize. */
     2724        uint64_t offStartDataNew = RT_ALIGN_32(pImage->uBlockAllocationTableOffset + cbBlockspaceNew, VHD_SECTOR_SIZE); /** < New start offset for block data after the resize */
     2725        uint64_t offStartDataOld = ~0ULL;
     2726
     2727        /* Go through the BAT and finde the data start offset. */
     2728        for (unsigned idxBlock = 0; idxBlock < pImage->cBlockAllocationTableEntries; idxBlock++)
     2729        {
     2730            if (pImage->pBlockAllocationTable[idxBlock] != ~0U)
     2731            {
     2732                uint64_t offStartBlock = pImage->pBlockAllocationTable[idxBlock] * VHD_SECTOR_SIZE;
     2733                if (offStartBlock < offStartDataOld)
     2734                    offStartDataOld = offStartBlock;
     2735                cBlocksAllocated++;
     2736            }
     2737        }
     2738
     2739        if (   offStartDataOld != offStartDataNew
     2740            && cBlocksAllocated > 0)
     2741        {
     2742            /* Calculate how many sectors nee to be relocated. */
     2743            uint64_t cbOverlapping = offStartDataNew - offStartDataOld;
     2744            unsigned cBlocksReloc = cbOverlapping / cbBlock;
     2745            if (cbOverlapping % cbBlock)
     2746                cBlocksReloc++;
     2747
     2748            cBlocksReloc = RT_MIN(cBlocksReloc, cBlocksAllocated);
     2749            offStartDataNew = offStartDataOld;
     2750
     2751            /* Do the relocation. */
     2752            LogFlow(("Relocating %u blocks\n", cBlocksReloc));
     2753
     2754            /*
     2755             * Get the blocks we need to relocate first, they are appended to the end
     2756             * of the image.
     2757             */
     2758            void *pvBuf = NULL, *pvZero = NULL;
     2759            do
     2760            {
     2761                /* Allocate data buffer. */
     2762                pvBuf = RTMemAllocZ(cbBlock);
     2763                if (!pvBuf)
     2764                {
     2765                    rc = VERR_NO_MEMORY;
     2766                    break;
     2767                }
     2768
     2769                /* Allocate buffer for overwrting with zeroes. */
     2770                pvZero = RTMemAllocZ(cbBlock);
     2771                if (!pvZero)
     2772                {
     2773                    rc = VERR_NO_MEMORY;
     2774                    break;
     2775                }
     2776
     2777                for (unsigned i = 0; i < cBlocksReloc; i++)
     2778                {
     2779                    uint32_t uBlock = offStartDataNew / VHD_SECTOR_SIZE;
     2780
     2781                    /* Search the index in the block table. */
     2782                    for (unsigned idxBlock = 0; idxBlock < cBlocksOld; idxBlock++)
     2783                    {
     2784                        if (pImage->pBlockAllocationTable[idxBlock] == uBlock)
     2785                        {
     2786                            /* Read data and append to the end of the image. */
     2787                            rc = vhdFileReadSync(pImage, offStartDataNew, pvBuf, cbBlock, NULL);
     2788                            if (RT_FAILURE(rc))
     2789                                break;
     2790
     2791                            rc = vhdFileWriteSync(pImage, pImage->uCurrentEndOfFile, pvBuf, cbBlock, NULL);
     2792                            if (RT_FAILURE(rc))
     2793                                break;
     2794
     2795                            /* Zero out the old block area. */
     2796                            rc = vhdFileWriteSync(pImage, offStartDataNew, pvZero, cbBlock, NULL);
     2797                            if (RT_FAILURE(rc))
     2798                                break;
     2799
     2800                            /* Update block counter. */
     2801                            pImage->pBlockAllocationTable[idxBlock] = pImage->uCurrentEndOfFile / VHD_SECTOR_SIZE;
     2802
     2803                            pImage->uCurrentEndOfFile += cbBlock;
     2804
     2805                            /* Continue with the next block. */
     2806                            break;
     2807                        }
     2808                    }
     2809
     2810                    if (RT_FAILURE(rc))
     2811                        break;
     2812
     2813                    offStartDataNew += cbBlock;
     2814                }
     2815            } while (0);
     2816
     2817            if (pvBuf)
     2818                RTMemFree(pvBuf);
     2819            if (pvZero)
     2820                RTMemFree(pvZero);
     2821        }
     2822
     2823        /*
     2824         * Relocation done, expand the block array and update the header with
     2825         * the new data.
     2826         */
     2827        if (RT_SUCCESS(rc))
     2828        {
     2829            uint32_t *paBlocksNew = (uint32_t *)RTMemRealloc(pImage->pBlockAllocationTable, cBlocksNew * sizeof(uint32_t));
     2830            if (paBlocksNew)
     2831            {
     2832                pImage->pBlockAllocationTable = paBlocksNew;
     2833
     2834                /* Mark the new blocks as unallocated. */
     2835                for (unsigned idxBlock = cBlocksOld; idxBlock < cBlocksNew; idxBlock++)
     2836                    pImage->pBlockAllocationTable[idxBlock] = ~0U;
     2837            }
     2838            else
     2839                rc = VERR_NO_MEMORY;
     2840
     2841            if (RT_SUCCESS(rc))
     2842            {
     2843                /* Write the block array before updating the rest. */
     2844                rc = vhdFileWriteSync(pImage, pImage->uBlockAllocationTableOffset, pImage->pBlockAllocationTable,
     2845                                      cBlocksNew * sizeof(uint32_t), NULL);
     2846            }
     2847
     2848            if (RT_SUCCESS(rc))
     2849            {
     2850                /* Update size and new block count. */
     2851                pImage->cBlockAllocationTableEntries = cBlocksNew;
     2852                pImage->cbSize = cbSize;
     2853
     2854                /* Update geometry. */
     2855                pImage->PCHSGeometry = *pPCHSGeometry;
     2856                pImage->LCHSGeometry = *pLCHSGeometry;
     2857            }
     2858        }
     2859
     2860        /* Update header information in base image file. */
     2861        pImage->fDynHdrNeedsUpdate = true;
     2862        vhdFlush(pImage);
     2863    }
     2864    /* Same size doesn't change the image at all. */
     2865
     2866    LogFlowFunc(("returns %Rrc\n", rc));
     2867    return rc;
     2868}
     2869
    26592870
    26602871VBOXHDDBACKEND g_VhdBackend =
     
    27572968    NULL,
    27582969    /* pfnResize */
    2759     NULL
     2970    vhdResize
    27602971};
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