VirtualBox

Changeset 31804 in vbox


Ignore:
Timestamp:
Aug 19, 2010 9:10:57 PM (14 years ago)
Author:
vboxsync
Message:

VBoxHDD/VDI: Support for increasing the size of a disk, completely untested\!

Location:
trunk/src/VBox/Devices/Storage
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Storage/VDICore.h

    r28800 r31804  
    356356}
    357357
    358 DECLINLINE(unsigned) getImageDataOffset(PVDIHEADER ph)
     358DECLINLINE(uint32_t) getImageDataOffset(PVDIHEADER ph)
    359359{
    360360    switch (GET_MAJOR_HEADER_VERSION(ph))
     
    366366    AssertFailed();
    367367    return 0;
     368}
     369
     370DECLINLINE(void) setImageDataOffset(PVDIHEADER ph, uint32_t offData)
     371{
     372    switch (GET_MAJOR_HEADER_VERSION(ph))
     373    {
     374        case 0: return;
     375        case 1: ph->u.v1.offData = offData;
     376    }
     377    AssertFailed();
    368378}
    369379
     
    398408}
    399409
     410DECLINLINE(void) setImageDiskSize(PVDIHEADER ph, uint64_t cbDisk)
     411{
     412    switch (GET_MAJOR_HEADER_VERSION(ph))
     413    {
     414        case 0: ph->u.v0.cbDisk = cbDisk; return;
     415        case 1: ph->u.v1.cbDisk = cbDisk; return;
     416    }
     417    AssertFailed();
     418}
     419
    400420DECLINLINE(unsigned) getImageBlockSize(PVDIHEADER ph)
    401421{
     
    430450    return 0;
    431451}
     452
     453DECLINLINE(void) setImageBlocks(PVDIHEADER ph, unsigned cBlocks)
     454{
     455    switch (GET_MAJOR_HEADER_VERSION(ph))
     456    {
     457        case 0: ph->u.v0.cBlocks = cBlocks; return;
     458        case 1: ph->u.v1.cBlocks = cBlocks; return;
     459    }
     460    AssertFailed();
     461}
     462
    432463
    433464DECLINLINE(unsigned) getImageBlocksAllocated(PVDIHEADER ph)
  • trunk/src/VBox/Devices/Storage/VDIHDDCore.cpp

    r31776 r31804  
    25132513                                 uPercentStart + uPercentSpan);
    25142514    }
     2515
     2516    LogFlowFunc(("returns %Rrc\n", rc));
     2517    return rc;
     2518}
     2519
     2520
     2521/** @copydoc VBOXHDDBACKEND::pfnResize */
     2522static int vdiResize(void *pBackendData, uint64_t cbSize,
     2523                     PCPDMMEDIAGEOMETRY pPCHSGeometry, PCPDMMEDIAGEOMETRY pLCHSGeometry,
     2524                     unsigned uPercentStart, unsigned uPercentSpan,
     2525                     PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage,
     2526                     PVDINTERFACE pVDIfsOperation)
     2527{
     2528    PVDIIMAGEDESC pImage = (PVDIIMAGEDESC)pBackendData;
     2529    int rc = VINF_SUCCESS;
     2530
     2531    PFNVDPROGRESS pfnProgress = NULL;
     2532    void *pvUser = NULL;
     2533    PVDINTERFACE pIfProgress = VDInterfaceGet(pVDIfsOperation,
     2534                                              VDINTERFACETYPE_PROGRESS);
     2535    PVDINTERFACEPROGRESS pCbProgress = NULL;
     2536    if (pIfProgress)
     2537    {
     2538        pCbProgress = VDGetInterfaceProgress(pIfProgress);
     2539        if (pCbProgress)
     2540            pfnProgress = pCbProgress->pfnProgress;
     2541        pvUser = pIfProgress->pvUser;
     2542    }
     2543
     2544    /* Making the image smaller is not supported at the moment. */
     2545    if (cbSize < getImageDiskSize(&pImage->Header) || GET_MAJOR_HEADER_VERSION(&pImage->Header) == 0)
     2546        rc = VERR_NOT_SUPPORTED;
     2547    else if (cbSize > getImageDiskSize(&pImage->Header))
     2548    {
     2549        unsigned cBlocksAllocated = getImageBlocksAllocated(&pImage->Header);
     2550        uint64_t cbNew  = cbSize - getImageDiskSize(&pImage->Header);
     2551        uint32_t cBlocksNew = cbNew / getImageBlockSize(&pImage->Header);
     2552        if (cbNew % getImageBlockSize(&pImage->Header))
     2553            cBlocksNew++;
     2554        uint32_t cbAdditionalBlockspace = cBlocksNew * sizeof(VDIIMAGEBLOCKPOINTER);
     2555        uint64_t cbBlockspace = getImageBlocks(&pImage->Header) * sizeof(VDIIMAGEBLOCKPOINTER) + cbAdditionalBlockspace;
     2556
     2557        uint64_t offImageDataNew = RT_ALIGN_32(pImage->offStartBlocks + cbBlockspace, VDI_GEOMETRY_SECTOR_SIZE);
     2558
     2559        if (   pImage->offStartData != offImageDataNew
     2560            && getImageBlocksAllocated(&pImage->Header) > 0)
     2561        {
     2562            /* Calculate how many sectors nee to be relocated. */
     2563            uint64_t cbOverlapping = offImageDataNew - pImage->offStartData;
     2564            unsigned cBlocksReloc = cbOverlapping / getImageBlockSize(&pImage->Header);
     2565            if (cbOverlapping % getImageBlockSize(&pImage->Header))
     2566                cBlocksReloc++;
     2567
     2568            /* Do the relocation. */
     2569            LogFlow(("Relocating %u blocks\n", cBlocksReloc));
     2570
     2571            /*
     2572             * Get the blocks we need to relocate first, they are appended to the end
     2573             * of the image.
     2574             */
     2575            void *pvBuf = NULL, *pvZero = NULL;
     2576            do
     2577            {
     2578                uint64_t offBlockCur = pImage->offStartData;
     2579                VDIIMAGEBLOCKPOINTER uBlock = 0;
     2580
     2581                /* Allocate data buffer. */
     2582                pvBuf = RTMemAllocZ(pImage->cbTotalBlockData);
     2583                if (!pvBuf)
     2584                {
     2585                    rc = VERR_NO_MEMORY;
     2586                    break;
     2587                }
     2588
     2589                /* Allocate buffer for overwrting with zeroes. */
     2590                pvZero = RTMemAllocZ(pImage->cbTotalBlockData);
     2591                if (!pvZero)
     2592                {
     2593                    rc = VERR_NO_MEMORY;
     2594                    break;
     2595                }
     2596
     2597                for (unsigned i = 0; i < cBlocksReloc; i++)
     2598                {
     2599                    /* Search the index in the block table. */
     2600                    for (unsigned idxBlock = 0; idxBlock < cBlocksAllocated; idxBlock++)
     2601                    {
     2602                        if (pImage->paBlocks[idxBlock] == uBlock)
     2603                        {
     2604                            /* Read data and append to the end of the image. */
     2605                            rc = vdiFileReadSync(pImage, offBlockCur, pvBuf, pImage->cbTotalBlockData, NULL);
     2606                            if (RT_FAILURE(rc))
     2607                                break;
     2608
     2609                            uint64_t offBlockAppend;
     2610                            rc = vdiFileGetSize(pImage, &offBlockAppend);
     2611                            if (RT_FAILURE(rc))
     2612                                break;
     2613
     2614                            rc = vdiFileWriteSync(pImage, offBlockAppend, pvBuf, pImage->cbTotalBlockData, NULL);
     2615                            if (RT_FAILURE(rc))
     2616                                break;
     2617
     2618                            /* Zero out the old block area. */
     2619                            rc = vdiFileWriteSync(pImage, offBlockCur, pvZero, pImage->cbTotalBlockData, NULL);
     2620                            if (RT_FAILURE(rc))
     2621                                break;
     2622
     2623                            /* Update block counter. */
     2624                            pImage->paBlocks[idxBlock] = cBlocksAllocated;
     2625
     2626                            /*
     2627                             * Decrease the block number of all other entries in the array.
     2628                             * They were moved one block to the front.
     2629                             * Doing it as a separate step iterating over the array again
     2630                             * because an error while relocating the one block might end up
     2631                             * in a corrupted image otherwise.
     2632                             */
     2633                            for (unsigned idxBlock2 = 0; idxBlock2 < cBlocksAllocated; idxBlock2++)
     2634                            {
     2635                                if (   idxBlock2 != idxBlock
     2636                                    && IS_VDI_IMAGE_BLOCK_ALLOCATED(pImage->paBlocks[idxBlock2]))
     2637                                    pImage->paBlocks[idxBlock2]--;
     2638                            }
     2639                        }
     2640                    }
     2641
     2642                    if (RT_FAILURE(rc))
     2643                        break;
     2644
     2645                    uBlock++;
     2646                    offBlockCur += pImage->cbTotalBlockData;
     2647                }
     2648            } while (0);
     2649
     2650            if (pvBuf)
     2651                RTMemFree(pvBuf);
     2652            if (pvZero)
     2653                RTMemFree(pvZero);
     2654        }
     2655
     2656        /*
     2657         * Relocation done, expand the block array and update the header with
     2658         * the new data.
     2659         */
     2660        if (RT_SUCCESS(rc))
     2661        {
     2662            PVDIIMAGEBLOCKPOINTER paBlocksNew = (PVDIIMAGEBLOCKPOINTER)RTMemRealloc(pImage->paBlocks, getImageBlocks(&pImage->Header) + cBlocksNew);
     2663            if (paBlocksNew)
     2664            {
     2665                /* Mark the new blocks as unallocated. */
     2666                for (unsigned idxBlock = getImageBlocks(&pImage->Header); idxBlock < getImageBlocks(&pImage->Header) + cBlocksNew; idxBlock++)
     2667                    pImage->paBlocks[idxBlock] = VDI_IMAGE_BLOCK_FREE;
     2668            }
     2669            else
     2670                rc = VERR_NO_MEMORY;
     2671
     2672            /* Write the block array before updating the rest. */
     2673            rc = vdiFileWriteSync(pImage, pImage->offStartBlocks, pImage->paBlocks,
     2674                                  sizeof(VDIIMAGEBLOCKPOINTER) * (getImageBlocks(&pImage->Header) + cBlocksNew),
     2675                                  NULL);
     2676        }
     2677
     2678        if (RT_SUCCESS(rc))
     2679        {
     2680            /* Update size and new block count. */
     2681            setImageDiskSize(&pImage->Header, cbSize);
     2682            setImageBlocks(&pImage->Header, getImageBlocks(&pImage->Header) + cBlocksNew);
     2683            /* Update geometry. */
     2684            pImage->PCHSGeometry = *pPCHSGeometry;
     2685
     2686            PVDIDISKGEOMETRY pGeometry = getImageLCHSGeometry(&pImage->Header);
     2687            if (pGeometry)
     2688            {
     2689                pGeometry->cCylinders = pLCHSGeometry->cCylinders;
     2690                pGeometry->cHeads = pLCHSGeometry->cHeads;
     2691                pGeometry->cSectors = pLCHSGeometry->cSectors;
     2692                pGeometry->cbSector = VDI_GEOMETRY_SECTOR_SIZE;
     2693            }
     2694        }
     2695
     2696        /*
     2697         * We need to update the new offsets for the image data in the out of memory
     2698         * case too because we relocated the blocks already.
     2699         */
     2700        pImage->offStartData = offImageDataNew;
     2701        setImageDataOffset(&pImage->Header, offImageDataNew);
     2702
     2703        /* Update header information in base image file. */
     2704        vdiFlushImage(pImage);
     2705    }
     2706    /* Same size doesn't change the image at all. */
    25152707
    25162708    LogFlowFunc(("returns %Rrc\n", rc));
     
    26172809    vdiCompact,
    26182810    /* pfnResize */
    2619     NULL
     2811    vdiResize
    26202812};
    26212813
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