VirtualBox

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


Ignore:
Timestamp:
Apr 8, 2011 9:33:09 PM (14 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
71096
Message:

VHD: Code drop for compaction, completely untested so don't yet use if you want to keep your data\!

File:
1 edited

Legend:

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

    r34147 r36632  
    28262826    /* No need to write anything here. Data is always updated on a write. */
    28272827    return vhdFileFlushAsync(pImage, pIoCtx, NULL, NULL);
     2828}
     2829
     2830/** @copydoc VBOXHDDBACKEND::pfnCompact */
     2831static int vhdCompact(void *pBackendData, unsigned uPercentStart,
     2832                      unsigned uPercentSpan, PVDINTERFACE pVDIfsDisk,
     2833                      PVDINTERFACE pVDIfsImage, PVDINTERFACE pVDIfsOperation)
     2834{
     2835    PVHDIMAGE pImage = (PVHDIMAGE)pBackendData;
     2836    int rc = VINF_SUCCESS;
     2837    void *pvBuf = NULL, *pvReplace = NULL;
     2838    uint32_t *paBlocks = NULL;
     2839
     2840    int (*pfnParentRead)(void *, uint64_t, void *, size_t) = NULL;
     2841    void *pvParent = NULL;
     2842    PVDINTERFACE pIfParentState = VDInterfaceGet(pVDIfsOperation,
     2843                                                 VDINTERFACETYPE_PARENTSTATE);
     2844    PVDINTERFACEPARENTSTATE pCbParentState = NULL;
     2845    if (pIfParentState)
     2846    {
     2847        pCbParentState = VDGetInterfaceParentState(pIfParentState);
     2848        if (pCbParentState)
     2849            pfnParentRead = pCbParentState->pfnParentRead;
     2850        pvParent = pIfParentState->pvUser;
     2851    }
     2852
     2853    PFNVDPROGRESS pfnProgress = NULL;
     2854    void *pvUser = NULL;
     2855    PVDINTERFACE pIfProgress = VDInterfaceGet(pVDIfsOperation,
     2856                                              VDINTERFACETYPE_PROGRESS);
     2857    PVDINTERFACEPROGRESS pCbProgress = NULL;
     2858    if (pIfProgress)
     2859    {
     2860        pCbProgress = VDGetInterfaceProgress(pIfProgress);
     2861        if (pCbProgress)
     2862            pfnProgress = pCbProgress->pfnProgress;
     2863        pvUser = pIfProgress->pvUser;
     2864    }
     2865
     2866    do
     2867    {
     2868        AssertBreakStmt(pImage, rc = VERR_INVALID_PARAMETER);
     2869
     2870        AssertBreakStmt(!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY),
     2871                        rc = VERR_VD_IMAGE_READ_ONLY);
     2872
     2873        /* Reject fixed images as they don't have a BAT. */
     2874        if (pImage->uImageFlags & VD_IMAGE_FLAGS_FIXED)
     2875        {
     2876            rc = VERR_NOT_SUPPORTED;
     2877            break;
     2878        }
     2879
     2880        if (pfnParentRead)
     2881        {
     2882            pvParent = RTMemTmpAlloc(pImage->cbDataBlock);
     2883            AssertBreakStmt(VALID_PTR(pvBuf), rc = VERR_NO_MEMORY);
     2884        }
     2885        pvBuf = RTMemTmpAlloc(pImage->cbDataBlock);
     2886        AssertBreakStmt(VALID_PTR(pvBuf), rc = VERR_NO_MEMORY);
     2887
     2888        unsigned cBlocksAllocated = 0;
     2889        unsigned cBlocksToMove    = 0;
     2890        unsigned cBlocks          = pImage->cBlockAllocationTableEntries;
     2891        uint32_t offBlocksStart   = ~0U; /* Start offset of data blocks in sectors. */
     2892        uint32_t *paBat           = pImage->pBlockAllocationTable;
     2893
     2894        /* Count the number of allocated blocks and find the start offset for the data blocks. */
     2895        for (unsigned i = 0; i < cBlocks; i++)
     2896            if (paBat[i] != ~0U)
     2897            {
     2898                cBlocksAllocated++;
     2899                if (paBat[i] < offBlocksStart)
     2900                    offBlocksStart = paBat[i];
     2901            }
     2902
     2903        if (!cBlocksAllocated)
     2904        {
     2905            /* Nothing to do. */
     2906            rc = VINF_SUCCESS;
     2907            break;
     2908        }
     2909
     2910        paBlocks = (uint32_t *)RTMemTmpAllocZ(cBlocksAllocated * sizeof(uint32_t));
     2911        AssertBreakStmt(VALID_PTR(paBlocks), rc = VERR_NO_MEMORY);
     2912
     2913        /* Invalidate the back resolving array. */
     2914        for (unsigned i = 0; i < cBlocksAllocated; i++)
     2915            paBlocks[i] = ~0U;
     2916
     2917        /* Fill the back resolving table. */
     2918        for (unsigned i = 0; i < cBlocks; i++)
     2919            if (paBat[i] != ~0U)
     2920            {
     2921                unsigned idxBlock = (paBat[i] - offBlocksStart) / pImage->cSectorsPerDataBlock;
     2922                if (   idxBlock < cBlocksAllocated
     2923                    && paBlocks[idxBlock] == ~0U)
     2924                    paBlocks[idxBlock] = i;
     2925                else
     2926                {
     2927                    /* The image is in an inconsistent state. Don't go further. */
     2928                    rc = VERR_INVALID_STATE;
     2929                    break;
     2930                }
     2931            }
     2932
     2933        if (RT_FAILURE(rc))
     2934            break;
     2935
     2936        /* Find redundant information and update the block pointers
     2937         * accordingly, creating bubbles. Keep disk up to date, as this
     2938         * enables cancelling. */
     2939        for (unsigned i = 0; i < cBlocks; i++)
     2940        {
     2941            if (paBat[i] != ~0U)
     2942            {
     2943                unsigned idxBlock = (paBat[i] - offBlocksStart) / pImage->cSectorsPerDataBlock;
     2944
     2945                /* Block present in image file, read relevant data. */
     2946                uint64_t u64Offset = ((uint64_t)paBat[i] + pImage->cDataBlockBitmapSectors) * VHD_SECTOR_SIZE;
     2947                rc = vhdFileReadSync(pImage, u64Offset, pvBuf, pImage->cbDataBlock, NULL);
     2948                if (RT_FAILURE(rc))
     2949                    break;
     2950
     2951                if (ASMBitFirstSet((volatile void *)pvBuf, (uint32_t)pImage->cbDataBlock * 8) == -1)
     2952                {
     2953                    paBat[i] = ~0;
     2954                    paBlocks[idxBlock] = ~0U;
     2955                    /* Adjust progress info, one block to be relocated. */
     2956                    cBlocksToMove++;
     2957                }
     2958                else if (pfnParentRead)
     2959                {
     2960                    rc = pfnParentRead(pvParent, i * pImage->cbDataBlock, pvParent, pImage->cbDataBlock);
     2961                    if (RT_FAILURE(rc))
     2962                        break;
     2963                    if (!memcmp(pvParent, pvBuf, pImage->cbDataBlock))
     2964                    {
     2965                        paBat[i] = ~0U;
     2966                        paBlocks[idxBlock] = ~0U;
     2967                        /* Adjust progress info, one block to be relocated. */
     2968                        cBlocksToMove++;
     2969                    }
     2970                }
     2971            }
     2972
     2973            if (pCbProgress && pCbProgress->pfnProgress)
     2974            {
     2975                rc = pCbProgress->pfnProgress(pIfProgress->pvUser,
     2976                                              (uint64_t)i * uPercentSpan / (cBlocks + cBlocksToMove) + uPercentStart);
     2977                if (RT_FAILURE(rc))
     2978                    break;
     2979            }
     2980        }
     2981
     2982        if (RT_SUCCESS(rc))
     2983        {
     2984            /* Fill bubbles with other data (if available). */
     2985            unsigned cBlocksMoved = 0;
     2986            unsigned uBlockUsedPos = cBlocksAllocated;
     2987            size_t   cbBlock = pImage->cbDataBlock + pImage->cbDataBlockBitmap; /** < Size of whole block containing the bitmap and the user data. */
     2988
     2989            /* Allocate data buffer to hold the data block and allocation bitmap in front of the actual data. */
     2990            RTMemTmpFree(pvBuf);
     2991            pvBuf = RTMemTmpAllocZ(cbBlock);
     2992            AssertBreakStmt(VALID_PTR(pvBuf), rc = VERR_NO_MEMORY);
     2993
     2994            for (unsigned i = 0; i < cBlocksAllocated; i++)
     2995            {
     2996                unsigned uBlock = paBlocks[i];
     2997                if (uBlock == ~0U)
     2998                {
     2999                    unsigned uBlockData = ~0U;
     3000                    while (uBlockUsedPos > i && uBlockData == ~0U)
     3001                    {
     3002                        uBlockUsedPos--;
     3003                        uBlockData = paBlocks[uBlockUsedPos];
     3004                    }
     3005                    /* Terminate early if there is no block which needs copying. */
     3006                    if (uBlockUsedPos == i)
     3007                        break;
     3008                    uint64_t u64Offset = (uint64_t)uBlockUsedPos * cbBlock
     3009                                       + (offBlocksStart * VHD_SECTOR_SIZE);
     3010                    rc = vhdFileReadSync(pImage, u64Offset, pvBuf, cbBlock, NULL);
     3011                    if (RT_FAILURE(rc))
     3012                        break;
     3013
     3014                    u64Offset = (uint64_t)i * cbBlock
     3015                                       + (offBlocksStart * VHD_SECTOR_SIZE);
     3016                    rc = vhdFileWriteSync(pImage, u64Offset, pvBuf, cbBlock, NULL);
     3017                    if (RT_FAILURE(rc))
     3018                        break;
     3019
     3020                    paBat[uBlockData] = i*pImage->cSectorsPerDataBlock + offBlocksStart;
     3021
     3022                    /* Truncate the file but leave enough room for the footer to avoid
     3023                     * races if other processes fill the whole harddisk. */
     3024                    rc = vhdFileSetSize(pImage, pImage->uCurrentEndOfFile - cbBlock + VHD_SECTOR_SIZE);
     3025                    if (RT_FAILURE(rc))
     3026                        break;
     3027
     3028                    /* Update pointers and write footer. */
     3029                    pImage->uCurrentEndOfFile -= cbBlock;
     3030
     3031                    /* We're kinda screwed if this failes. */
     3032                    rc = vhdUpdateFooter(pImage);
     3033                    if (RT_FAILURE(rc))
     3034                        break;
     3035
     3036                    paBlocks[i] = uBlockData;
     3037                    paBlocks[uBlockUsedPos] = ~0U;
     3038                    cBlocksMoved++;
     3039                }
     3040
     3041                if (pCbProgress && pCbProgress->pfnProgress)
     3042                {
     3043                    rc = pCbProgress->pfnProgress(pIfProgress->pvUser,
     3044                                                  (uint64_t)(cBlocks + cBlocksMoved) * uPercentSpan / (cBlocks + cBlocksToMove) + uPercentStart);
     3045
     3046                    if (RT_FAILURE(rc))
     3047                        break;
     3048                }
     3049            }
     3050        }
     3051
     3052        /* Write the new BAT in any case. */
     3053        rc = vhdFlushImage(pImage);
     3054    } while (0);
     3055
     3056    if (paBlocks)
     3057        RTMemTmpFree(paBlocks);
     3058    if (pvParent)
     3059        RTMemTmpFree(pvParent);
     3060    if (pvBuf)
     3061        RTMemTmpFree(pvBuf);
     3062
     3063    if (RT_SUCCESS(rc) && pCbProgress && pCbProgress->pfnProgress)
     3064    {
     3065        pCbProgress->pfnProgress(pIfProgress->pvUser,
     3066                                 uPercentStart + uPercentSpan);
     3067    }
     3068
     3069    LogFlowFunc(("returns %Rrc\n", rc));
     3070    return rc;
    28283071}
    28293072
     
    31093352    genericFileComposeName,
    31103353    /* pfnCompact */
    3111     NULL,
     3354    vhdCompact,
    31123355    /* pfnResize */
    31133356    vhdResize
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