VirtualBox

Changeset 19176 in vbox for trunk/src/VBox/Devices


Ignore:
Timestamp:
Apr 24, 2009 6:19:57 PM (16 years ago)
Author:
vboxsync
Message:

VBoxHDD/generic+VDI: implemented and documented

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

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Storage/VBoxHDD-Internal.h

    r17970 r19176  
    159159     *
    160160     * @returns VBox status code.
    161      * @returns VINF_VD_BLOCK_FREE if this image contains no data for this block.
    162      * @returns VINF_VD_BLOCK_ZERO if this image contains a zero data block.
    163      * @param   pvBackendData   Opaque state data for this image.
    164      * @param   off             Offset to start reading from.
     161     * @returns VERR_VD_BLOCK_FREE if this image contains no data for this block.
     162     * @param   pvBackendData   Opaque state data for this image.
     163     * @param   uOffset         Offset to start reading from.
    165164     * @param   pvBuf           Where to store the read bits.
    166165     * @param   cbRead          Number of bytes to read.
    167166     * @param   pcbActuallyRead Pointer to returned number of bytes read.
    168167     */
    169     DECLR3CALLBACKMEMBER(int, pfnRead, (void *pvBackendData, uint64_t off, void *pvBuf,
     168    DECLR3CALLBACKMEMBER(int, pfnRead, (void *pvBackendData, uint64_t uOffset, void *pvBuf,
    170169                                        size_t cbRead, size_t *pcbActuallyRead));
    171170
     
    175174     *
    176175     * @returns VBox status code.
    177      * @returns VINF_VD_BLOCK_FREE if this image contains no data for this block and
     176     * @returns VERR_VD_BLOCK_FREE if this image contains no data for this block and
    178177     *          this is not a full-block write. The write must be repeated with
    179178     *          the correct amount of prefix/postfix data read from the images below
     
    182181     *          stack uses different block sizes.
    183182     * @param   pvBackendData   Opaque state data for this image.
    184      * @param   off             Offset to start writing to.
     183     * @param   uOffset         Offset to start writing to.
    185184     * @param   pvBuf           Where to retrieve the written bits.
    186185     * @param   cbWrite         Number of bytes to write.
    187186     * @param   pcbWriteProcess Pointer to returned number of bytes that could
    188187     *                          be processed. In case the function returned
    189      *                          VINF_VD_BLOCK_FREE this is the number of bytes
     188     *                          VERR_VD_BLOCK_FREE this is the number of bytes
    190189     *                          that could be written in a full block write,
    191190     *                          when prefixed/postfixed by the appropriate
     
    198197     *                          of the VD_WRITE_* flags.
    199198     */
    200     DECLR3CALLBACKMEMBER(int, pfnWrite, (void *pvBackendData, uint64_t off,
     199    DECLR3CALLBACKMEMBER(int, pfnWrite, (void *pvBackendData, uint64_t uOffset,
    201200                                         const void *pvBuf, size_t cbWrite,
    202201                                         size_t *pcbWriteProcess, size_t *pcbPreRead,
     
    495494     *  VD_CAP_FILE and NULL otherwise. */
    496495    DECLR3CALLBACKMEMBER(int, pfnComposeName, (PVDINTERFACE pConfig, char **pszName));
     496
     497    /**
     498     * Compact the image. The pointer may be NULL, indicating that this
     499     * isn't supported yet (for file-based images) or not necessary.
     500     *
     501     * @returns VBox status code.
     502     * @returns VERR_NOT_SUPPORTED if this image cannot be compacted yet.
     503     * @param   pvBackendData   Opaque state data for this image.
     504     * @param   uPercentStart   Starting value for progress percentage.
     505     * @param   uPercentSpan    Span for varying progress percentage.
     506     * @param   pVDIfsOperation Pointer to the per-operation VD interface list.
     507     */
     508    DECLR3CALLBACKMEMBER(int, pfnCompact, (void *pvBackendData,
     509                                           unsigned uPercentStart, unsigned uPercentSpan,
     510                                           PVDINTERFACE pVDIfsOperation));
    497511
    498512} VBOXHDDBACKEND;
  • trunk/src/VBox/Devices/Storage/VBoxHDD.cpp

    r19034 r19176  
    119119
    120120
     121/**
     122 * VBox parent read descriptor, used internally for compaction.
     123 */
     124typedef struct VDPARENTSTATEDESC
     125{
     126    /** Pointer to disk descriptor. */
     127    PVBOXHDD pDisk;
     128    /** Pointer to image descriptor. */
     129    PVDIMAGE pImage;
     130} VDPARENTSTATEDESC, *PVDPARENTSTATEDESC;
     131
     132
    121133extern VBOXHDDBACKEND g_RawBackend;
    122134extern VBOXHDDBACKEND g_VmdkBackend;
     
    304316
    305317    return rc;
     318}
     319
     320/**
     321 * internal: parent image read wrapper for compacting.
     322 */
     323static int vdParentRead(void *pvUser, uint64_t uOffset, void *pvBuf,
     324                        size_t cbRead)
     325{
     326    PVDPARENTSTATEDESC pParentState = (PVDPARENTSTATEDESC)pvUser;
     327    return vdReadHelper(pParentState->pDisk, pParentState->pImage, uOffset,
     328                        pvBuf, cbRead);
    306329}
    307330
     
    21192142 * @return  VERR_VD_IMAGE_NOT_FOUND if image with specified number was not opened.
    21202143 * @return  VERR_VD_IMAGE_READ_ONLY if image is not writable.
    2121  * @return  VERR_NOT_SUPPORTED if this kind of image cannot be compacted.
    2122  * @return  VERR_NOT_IMPLEMENTED if this kind of image can be compacted, but
    2123  *                               the code for this isn't implemented yet.
     2144 * @return  VERR_NOT_SUPPORTED if this kind of image can be compacted, but
     2145 *                             the code for this isn't implemented yet.
    21242146 * @param   pDisk           Pointer to HDD container.
    21252147 * @param   nImage          Image number, counts from 0. 0 is always base image of container.
     
    21292151                            PVDINTERFACE pVDIfsOperation)
    21302152{
    2131     return VERR_NOT_SUPPORTED;
     2153    int rc;
     2154    void *pvBuf = NULL;
     2155    void *pvTmp = NULL;
     2156
     2157    LogFlowFunc(("pDisk=%#p nImage=%u pVDIfsOperation=%#p\n",
     2158                 pDisk, nImage, pVDIfsOperation));
     2159
     2160    PVDINTERFACE pIfProgress = VDInterfaceGet(pVDIfsOperation,
     2161                                              VDINTERFACETYPE_PROGRESS);
     2162    PVDINTERFACEPROGRESS pCbProgress = NULL;
     2163    if (pIfProgress)
     2164        pCbProgress = VDGetInterfaceProgress(pIfProgress);
     2165
     2166    do {
     2167        /* Check arguments. */
     2168        AssertMsgBreakStmt(VALID_PTR(pDisk), ("pDisk=%#p\n", pDisk),
     2169                           rc = VERR_INVALID_PARAMETER);
     2170        AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE,
     2171                  ("u32Signature=%08x\n", pDisk->u32Signature));
     2172
     2173        PVDIMAGE pImage = vdGetImageByNumber(pDisk, nImage);
     2174        AssertPtrBreakStmt(pImage, rc = VERR_VD_IMAGE_NOT_FOUND);
     2175
     2176        /* If there is no compact callback for not file based backends then
     2177         * the backend doesn't need compaction. No need to make much fuss about
     2178         * this. For file based ones signal this as not yet supported. */
     2179        if (!pImage->Backend->pfnCompact)
     2180        {
     2181            if (pImage->Backend->uBackendCaps & VD_CAP_FILE)
     2182                rc = VERR_NOT_SUPPORTED;
     2183            else
     2184                rc = VINF_SUCCESS;
     2185            break;
     2186        }
     2187
     2188        /* Insert interface for reading parent state into per-operation list,
     2189         * if there is a parent image. */
     2190        VDINTERFACE IfOpParent;
     2191        VDINTERFACEPARENTSTATE ParentCb;
     2192        VDPARENTSTATEDESC ParentUser;
     2193        if (pImage->pPrev)
     2194        {
     2195            ParentCb.cbSize = sizeof(ParentCb);
     2196            ParentCb.enmInterface = VDINTERFACETYPE_PARENTSTATE;
     2197            ParentCb.pfnParentRead = vdParentRead;
     2198            ParentUser.pDisk = pDisk;
     2199            ParentUser.pImage = pImage->pPrev;
     2200            rc = VDInterfaceAdd(&IfOpParent, "VDCompact_ParentState", VDINTERFACETYPE_PARENTSTATE,
     2201                                &ParentCb, &ParentUser, &pVDIfsOperation);
     2202            AssertRC(rc);
     2203        }
     2204
     2205        rc = pImage->Backend->pfnCompact(pImage->pvBackendData,
     2206                                         0, 99,
     2207                                         pVDIfsOperation);
     2208    } while (0);
     2209
     2210    if (pvBuf)
     2211        RTMemTmpFree(pvBuf);
     2212    if (pvTmp)
     2213        RTMemTmpFree(pvTmp);
     2214
     2215    if (RT_SUCCESS(rc))
     2216    {
     2217        if (pCbProgress && pCbProgress->pfnProgress)
     2218            pCbProgress->pfnProgress(NULL /* WARNING! pVM=NULL */, 100,
     2219                                     pIfProgress->pvUser);
     2220    }
     2221
     2222    LogFlowFunc(("returns %Rrc\n", rc));
     2223    return rc;
    21322224}
    21332225
  • trunk/src/VBox/Devices/Storage/VDIHDDCore.cpp

    r18567 r19176  
    17781778}
    17791779
    1780 static int vdiGetTimeStamp(void *pvBackendData, PRTTIMESPEC pTimeStamp)
     1780static int vdiGetTimeStamp(void *pBackendData, PRTTIMESPEC pTimeStamp)
    17811781{
    17821782    int rc = VERR_NOT_IMPLEMENTED;
     
    17851785}
    17861786
    1787 static int vdiGetParentTimeStamp(void *pvBackendData, PRTTIMESPEC pTimeStamp)
     1787static int vdiGetParentTimeStamp(void *pBackendData, PRTTIMESPEC pTimeStamp)
    17881788{
    17891789    int rc = VERR_NOT_IMPLEMENTED;
     
    17921792}
    17931793
    1794 static int vdiSetParentTimeStamp(void *pvBackendData, PCRTTIMESPEC pTimeStamp)
     1794static int vdiSetParentTimeStamp(void *pBackendData, PCRTTIMESPEC pTimeStamp)
    17951795{
    17961796    int rc = VERR_NOT_IMPLEMENTED;
     
    17991799}
    18001800
    1801 static int vdiGetParentFilename(void *pvBackendData, char **ppszParentFilename)
     1801static int vdiGetParentFilename(void *pBackendData, char **ppszParentFilename)
    18021802{
    18031803    int rc = VERR_NOT_IMPLEMENTED;
     
    18061806}
    18071807
    1808 static int vdiSetParentFilename(void *pvBackendData, const char *pszParentFilename)
     1808static int vdiSetParentFilename(void *pBackendData, const char *pszParentFilename)
    18091809{
    18101810    int rc = VERR_NOT_IMPLEMENTED;
     
    18131813}
    18141814
    1815 static bool vdiIsAsyncIOSupported(void *pvBackendData)
     1815static bool vdiIsAsyncIOSupported(void *pBackendData)
    18161816{
    18171817    return false;
    18181818}
    18191819
    1820 static int vdiAsyncRead(void *pvBackendData, uint64_t uOffset, size_t cbRead,
     1820static int vdiAsyncRead(void *pBackendData, uint64_t uOffset, size_t cbRead,
    18211821                        PPDMDATASEG paSeg, unsigned cSeg, void *pvUser)
    18221822{
     
    18261826}
    18271827
    1828 static int vdiAsyncWrite(void *pvBackendData, uint64_t uOffset, size_t cbWrite,
     1828static int vdiAsyncWrite(void *pBackendData, uint64_t uOffset, size_t cbWrite,
    18291829                         PPDMDATASEG paSeg, unsigned cSeg, void *pvUser)
    18301830{
    18311831    int rc = VERR_NOT_IMPLEMENTED;
     1832    LogFlowFunc(("returns %Rrc\n", rc));
     1833    return rc;
     1834}
     1835
     1836/** @copydoc VBOXHDDBACKEND::pfnCompact */
     1837static int vdiCompact(void *pBackendData, unsigned uPercentStart,
     1838                      unsigned uPercentSpan, PVDINTERFACE pVDIfsOperation)
     1839{
     1840    PVDIIMAGEDESC pImage = (PVDIIMAGEDESC)pBackendData;
     1841    int rc = VINF_SUCCESS;
     1842    void *pvBuf = NULL, *pvTmp = NULL;
     1843    unsigned *paBlocks2 = NULL;
     1844
     1845    int (*pfnParentRead)(void *, uint64_t, void *, size_t) = NULL;
     1846    void *pvParent = NULL;
     1847    PVDINTERFACE pIfParentState = VDInterfaceGet(pVDIfsOperation,
     1848                                                 VDINTERFACETYPE_PARENTSTATE);
     1849    PVDINTERFACEPARENTSTATE pCbParentState = NULL;
     1850    if (pIfParentState)
     1851    {
     1852        pCbParentState = VDGetInterfaceParentState(pIfParentState);
     1853        if (pCbParentState)
     1854            pfnParentRead = pCbParentState->pfnParentRead;
     1855        pvParent = pIfParentState->pvUser;
     1856    }
     1857
     1858    PFNVMPROGRESS pfnProgress = NULL;
     1859    void *pvUser = NULL;
     1860    PVDINTERFACE pIfProgress = VDInterfaceGet(pVDIfsOperation,
     1861                                              VDINTERFACETYPE_PROGRESS);
     1862    PVDINTERFACEPROGRESS pCbProgress = NULL;
     1863    if (pIfProgress)
     1864    {
     1865        pCbProgress = VDGetInterfaceProgress(pIfProgress);
     1866        if (pCbProgress)
     1867            pfnProgress = pCbProgress->pfnProgress;
     1868        pvUser = pIfProgress->pvUser;
     1869    }
     1870
     1871    do {
     1872        AssertBreakStmt(pImage, rc = VERR_INVALID_PARAMETER);
     1873
     1874        AssertBreakStmt(!(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY),
     1875                        rc = VERR_VD_IMAGE_READ_ONLY);
     1876
     1877        unsigned cBlocks;
     1878        unsigned cBlocksToMove = 0;
     1879        size_t cbBlock;
     1880        cBlocks = getImageBlocks(&pImage->Header);
     1881        cbBlock = getImageBlockSize(&pImage->Header);
     1882        if (pfnParentRead)
     1883        {
     1884            pvBuf = RTMemTmpAlloc(cbBlock);
     1885            AssertBreakStmt(VALID_PTR(pvBuf), rc = VERR_NO_MEMORY);
     1886        }
     1887        pvTmp = RTMemTmpAlloc(cbBlock);
     1888        AssertBreakStmt(VALID_PTR(pvTmp), rc = VERR_NO_MEMORY);
     1889
     1890        uint64_t cbFile;
     1891        rc = RTFileGetSize(pImage->File, &cbFile);
     1892        AssertRCBreak(rc);
     1893        unsigned cBlocksAllocated = (unsigned)((cbFile - pImage->offStartData - pImage->offStartBlockData) >> pImage->uShiftOffset2Index);
     1894
     1895        /* Allocate block array for back resolving. */
     1896        paBlocks2 = (unsigned *)RTMemAlloc(sizeof(unsigned *) * cBlocksAllocated);
     1897        AssertBreakStmt(VALID_PTR(paBlocks2), rc = VERR_NO_MEMORY);
     1898        /* Fill out back resolving, check/fix allocation errors before
     1899         * compacting the image, just to be on the safe side. Update the
     1900         * image contents straight away, as this enables cancelling. */
     1901        for (unsigned i = 0; i < cBlocks; i++)
     1902            paBlocks2[i] = VDI_IMAGE_BLOCK_FREE;
     1903        rc = VINF_SUCCESS;
     1904        for (unsigned i = 0; i < cBlocks; i++)
     1905        {
     1906            VDIIMAGEBLOCKPOINTER ptrBlock = pImage->paBlocks[i];
     1907            if (IS_VDI_IMAGE_BLOCK_ALLOCATED(ptrBlock))
     1908            {
     1909                if (ptrBlock < cBlocksAllocated)
     1910                {
     1911                    if (paBlocks2[ptrBlock] == VDI_IMAGE_BLOCK_FREE)
     1912                        paBlocks2[ptrBlock] = i;
     1913                    else
     1914                    {
     1915                        LogFunc(("Freed cross-linked block %u in file \"%s\"\n",
     1916                                 i, pImage->pszFilename));
     1917                        pImage->paBlocks[i] = VDI_IMAGE_BLOCK_FREE;
     1918                        rc = vdiUpdateBlockInfo(pImage, i);
     1919                        if (RT_FAILURE(rc))
     1920                            break;
     1921                    }
     1922                }
     1923                else
     1924                {
     1925                    LogFunc(("Freed out of bounds reference for block %u in file \"%s\"\n",
     1926                             i, pImage->pszFilename));
     1927                    pImage->paBlocks[i] = VDI_IMAGE_BLOCK_FREE;;
     1928                    rc = vdiUpdateBlockInfo(pImage, i);
     1929                    if (RT_FAILURE(rc))
     1930                        break;
     1931                }
     1932            }
     1933        }
     1934        if (RT_FAILURE(rc))
     1935            break;
     1936
     1937        /* Find redundant information and update the block pointers
     1938         * accordingly, creating bubbles. Keep disk up to date, as this
     1939         * enables cancelling. */
     1940        for (unsigned i = 0; i < cBlocks; i++)
     1941        {
     1942            VDIIMAGEBLOCKPOINTER ptrBlock = pImage->paBlocks[i];
     1943            if (IS_VDI_IMAGE_BLOCK_ALLOCATED(ptrBlock))
     1944            {
     1945                /* Block present in image file, read relevant data. */
     1946                uint64_t u64Offset = (uint64_t)ptrBlock * pImage->cbTotalBlockData
     1947                                   + (pImage->offStartData + pImage->offStartBlockData);
     1948                rc = RTFileReadAt(pImage->File, u64Offset, pvTmp, cbBlock, NULL);
     1949                if (RT_FAILURE(rc))
     1950                    break;
     1951
     1952                if (ASMBitFirstSet((volatile void *)pvTmp, (uint32_t)cbBlock * 8) == -1)
     1953                {
     1954                    pImage->paBlocks[i] = VDI_IMAGE_BLOCK_ZERO;
     1955                    rc = vdiUpdateBlockInfo(pImage, i);
     1956                    if (RT_FAILURE(rc))
     1957                        break;
     1958                    paBlocks2[ptrBlock] = VDI_IMAGE_BLOCK_FREE;
     1959                    /* Adjust progress info, one block to be relocated. */
     1960                    cBlocksToMove++;
     1961                }
     1962                else if (pfnParentRead)
     1963                {
     1964                    rc = pfnParentRead(pvParent, i * cbBlock, pvBuf, cbBlock);
     1965                    if (RT_FAILURE(rc))
     1966                        break;
     1967                    if (memcmp(pvTmp, pvBuf, cbBlock))
     1968                    {
     1969                        pImage->paBlocks[i] = VDI_IMAGE_BLOCK_FREE;
     1970                        rc = vdiUpdateBlockInfo(pImage, i);
     1971                        if (RT_FAILURE(rc))
     1972                            break;
     1973                        paBlocks2[ptrBlock] = VDI_IMAGE_BLOCK_FREE;
     1974                        /* Adjust progress info, one block to be relocated. */
     1975                        cBlocksToMove++;
     1976                    }
     1977                }
     1978            }
     1979
     1980            if (pCbProgress && pCbProgress->pfnProgress)
     1981            {
     1982                rc = pCbProgress->pfnProgress(NULL /* WARNING! pVM=NULL */,
     1983                                              (uint64_t)i * uPercentSpan / (cBlocks + cBlocksToMove) + uPercentStart,
     1984                                              pIfProgress->pvUser);
     1985                if (RT_FAILURE(rc))
     1986                    break;
     1987            }
     1988        }
     1989        if (RT_FAILURE(rc))
     1990            break;
     1991
     1992        /* Fill bubbles with other data (if available). */
     1993        unsigned cBlocksMoved = 0;
     1994        unsigned uBlockUsedPos = cBlocksAllocated;
     1995        for (unsigned i = 0; i < cBlocksAllocated; i++)
     1996        {
     1997            unsigned uBlock = paBlocks2[i];
     1998            if (uBlock == VDI_IMAGE_BLOCK_FREE)
     1999            {
     2000                unsigned uBlockData;
     2001                do {
     2002                    uBlockUsedPos--;
     2003                    uBlockData = paBlocks2[uBlockUsedPos];
     2004                } while (uBlockUsedPos > i && uBlockData == VDI_IMAGE_BLOCK_FREE);
     2005                /* Terminate early if there is no block which needs copying. */
     2006                if (uBlockUsedPos == i)
     2007                    break;
     2008                uint64_t u64Offset = (uint64_t)uBlockUsedPos * pImage->cbTotalBlockData
     2009                                   + (pImage->offStartData + pImage->offStartBlockData);
     2010                rc = RTFileReadAt(pImage->File, u64Offset, pvTmp, cbBlock, NULL);
     2011                u64Offset = (uint64_t)i * pImage->cbTotalBlockData
     2012                          + (pImage->offStartData + pImage->offStartBlockData);
     2013                rc = RTFileWriteAt(pImage->File, u64Offset, pvTmp, cbBlock, NULL);
     2014                pImage->paBlocks[uBlockData] = i;
     2015                setImageBlocksAllocated(&pImage->Header, cBlocksAllocated - cBlocksMoved);
     2016                rc = vdiUpdateBlockInfo(pImage, uBlockData);
     2017                if (RT_FAILURE(rc))
     2018                    break;
     2019                paBlocks2[i] = uBlockData;
     2020                paBlocks2[uBlockUsedPos] = VDI_IMAGE_BLOCK_FREE;
     2021                cBlocksMoved++;
     2022            }
     2023
     2024            if (pCbProgress && pCbProgress->pfnProgress)
     2025            {
     2026                rc = pCbProgress->pfnProgress(NULL /* WARNING! pVM=NULL */,
     2027                                              (uint64_t)(cBlocks + cBlocksMoved) * uPercentSpan / (cBlocks + cBlocksToMove) + uPercentStart,
     2028                                              pIfProgress->pvUser);
     2029                if (RT_FAILURE(rc))
     2030                    break;
     2031            }
     2032        }
     2033        if (RT_FAILURE(rc))
     2034            break;
     2035
     2036        /* Update image header. */
     2037        setImageBlocksAllocated(&pImage->Header, uBlockUsedPos);
     2038        vdiUpdateHeader(pImage);
     2039
     2040        /* Truncate the image to the proper size to finish compacting. */
     2041        rc = RTFileSetSize(pImage->File,
     2042                           (uint64_t)uBlockUsedPos * pImage->cbTotalBlockData
     2043                           + (pImage->offStartData + pImage->offStartBlockData));
     2044    } while (0);
     2045
     2046    if (paBlocks2)
     2047        RTMemTmpFree(paBlocks2);
     2048    if (pvTmp)
     2049        RTMemTmpFree(pvTmp);
     2050    if (pvBuf)
     2051        RTMemTmpFree(pvBuf);
     2052
     2053    if (RT_SUCCESS(rc) && pCbProgress && pCbProgress->pfnProgress)
     2054    {
     2055        pCbProgress->pfnProgress(NULL /* WARNING! pVM=NULL */,
     2056                                 uPercentStart + uPercentSpan,
     2057                                 pIfProgress->pvUser);
     2058    }
     2059
    18322060    LogFlowFunc(("returns %Rrc\n", rc));
    18332061    return rc;
     
    19272155    genericFileComposeLocation,
    19282156    /* pfnComposeName */
    1929     genericFileComposeName
     2157    genericFileComposeName,
     2158    /* pfnCompact */
     2159    vdiCompact
    19302160};
    19312161
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