Changeset 19176 in vbox for trunk/src/VBox/Devices
- Timestamp:
- Apr 24, 2009 6:19:57 PM (16 years ago)
- Location:
- trunk/src/VBox/Devices/Storage
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Storage/VBoxHDD-Internal.h
r17970 r19176 159 159 * 160 160 * @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. 165 164 * @param pvBuf Where to store the read bits. 166 165 * @param cbRead Number of bytes to read. 167 166 * @param pcbActuallyRead Pointer to returned number of bytes read. 168 167 */ 169 DECLR3CALLBACKMEMBER(int, pfnRead, (void *pvBackendData, uint64_t off, void *pvBuf,168 DECLR3CALLBACKMEMBER(int, pfnRead, (void *pvBackendData, uint64_t uOffset, void *pvBuf, 170 169 size_t cbRead, size_t *pcbActuallyRead)); 171 170 … … 175 174 * 176 175 * @returns VBox status code. 177 * @returns V INF_VD_BLOCK_FREE if this image contains no data for this block and176 * @returns VERR_VD_BLOCK_FREE if this image contains no data for this block and 178 177 * this is not a full-block write. The write must be repeated with 179 178 * the correct amount of prefix/postfix data read from the images below … … 182 181 * stack uses different block sizes. 183 182 * @param pvBackendData Opaque state data for this image. 184 * @param offOffset to start writing to.183 * @param uOffset Offset to start writing to. 185 184 * @param pvBuf Where to retrieve the written bits. 186 185 * @param cbWrite Number of bytes to write. 187 186 * @param pcbWriteProcess Pointer to returned number of bytes that could 188 187 * be processed. In case the function returned 189 * V INF_VD_BLOCK_FREE this is the number of bytes188 * VERR_VD_BLOCK_FREE this is the number of bytes 190 189 * that could be written in a full block write, 191 190 * when prefixed/postfixed by the appropriate … … 198 197 * of the VD_WRITE_* flags. 199 198 */ 200 DECLR3CALLBACKMEMBER(int, pfnWrite, (void *pvBackendData, uint64_t off,199 DECLR3CALLBACKMEMBER(int, pfnWrite, (void *pvBackendData, uint64_t uOffset, 201 200 const void *pvBuf, size_t cbWrite, 202 201 size_t *pcbWriteProcess, size_t *pcbPreRead, … … 495 494 * VD_CAP_FILE and NULL otherwise. */ 496 495 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)); 497 511 498 512 } VBOXHDDBACKEND; -
trunk/src/VBox/Devices/Storage/VBoxHDD.cpp
r19034 r19176 119 119 120 120 121 /** 122 * VBox parent read descriptor, used internally for compaction. 123 */ 124 typedef struct VDPARENTSTATEDESC 125 { 126 /** Pointer to disk descriptor. */ 127 PVBOXHDD pDisk; 128 /** Pointer to image descriptor. */ 129 PVDIMAGE pImage; 130 } VDPARENTSTATEDESC, *PVDPARENTSTATEDESC; 131 132 121 133 extern VBOXHDDBACKEND g_RawBackend; 122 134 extern VBOXHDDBACKEND g_VmdkBackend; … … 304 316 305 317 return rc; 318 } 319 320 /** 321 * internal: parent image read wrapper for compacting. 322 */ 323 static 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); 306 329 } 307 330 … … 2119 2142 * @return VERR_VD_IMAGE_NOT_FOUND if image with specified number was not opened. 2120 2143 * @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. 2124 2146 * @param pDisk Pointer to HDD container. 2125 2147 * @param nImage Image number, counts from 0. 0 is always base image of container. … … 2129 2151 PVDINTERFACE pVDIfsOperation) 2130 2152 { 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; 2132 2224 } 2133 2225 -
trunk/src/VBox/Devices/Storage/VDIHDDCore.cpp
r18567 r19176 1778 1778 } 1779 1779 1780 static int vdiGetTimeStamp(void *p vBackendData, PRTTIMESPEC pTimeStamp)1780 static int vdiGetTimeStamp(void *pBackendData, PRTTIMESPEC pTimeStamp) 1781 1781 { 1782 1782 int rc = VERR_NOT_IMPLEMENTED; … … 1785 1785 } 1786 1786 1787 static int vdiGetParentTimeStamp(void *p vBackendData, PRTTIMESPEC pTimeStamp)1787 static int vdiGetParentTimeStamp(void *pBackendData, PRTTIMESPEC pTimeStamp) 1788 1788 { 1789 1789 int rc = VERR_NOT_IMPLEMENTED; … … 1792 1792 } 1793 1793 1794 static int vdiSetParentTimeStamp(void *p vBackendData, PCRTTIMESPEC pTimeStamp)1794 static int vdiSetParentTimeStamp(void *pBackendData, PCRTTIMESPEC pTimeStamp) 1795 1795 { 1796 1796 int rc = VERR_NOT_IMPLEMENTED; … … 1799 1799 } 1800 1800 1801 static int vdiGetParentFilename(void *p vBackendData, char **ppszParentFilename)1801 static int vdiGetParentFilename(void *pBackendData, char **ppszParentFilename) 1802 1802 { 1803 1803 int rc = VERR_NOT_IMPLEMENTED; … … 1806 1806 } 1807 1807 1808 static int vdiSetParentFilename(void *p vBackendData, const char *pszParentFilename)1808 static int vdiSetParentFilename(void *pBackendData, const char *pszParentFilename) 1809 1809 { 1810 1810 int rc = VERR_NOT_IMPLEMENTED; … … 1813 1813 } 1814 1814 1815 static bool vdiIsAsyncIOSupported(void *p vBackendData)1815 static bool vdiIsAsyncIOSupported(void *pBackendData) 1816 1816 { 1817 1817 return false; 1818 1818 } 1819 1819 1820 static int vdiAsyncRead(void *p vBackendData, uint64_t uOffset, size_t cbRead,1820 static int vdiAsyncRead(void *pBackendData, uint64_t uOffset, size_t cbRead, 1821 1821 PPDMDATASEG paSeg, unsigned cSeg, void *pvUser) 1822 1822 { … … 1826 1826 } 1827 1827 1828 static int vdiAsyncWrite(void *p vBackendData, uint64_t uOffset, size_t cbWrite,1828 static int vdiAsyncWrite(void *pBackendData, uint64_t uOffset, size_t cbWrite, 1829 1829 PPDMDATASEG paSeg, unsigned cSeg, void *pvUser) 1830 1830 { 1831 1831 int rc = VERR_NOT_IMPLEMENTED; 1832 LogFlowFunc(("returns %Rrc\n", rc)); 1833 return rc; 1834 } 1835 1836 /** @copydoc VBOXHDDBACKEND::pfnCompact */ 1837 static 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 1832 2060 LogFlowFunc(("returns %Rrc\n", rc)); 1833 2061 return rc; … … 1927 2155 genericFileComposeLocation, 1928 2156 /* pfnComposeName */ 1929 genericFileComposeName 2157 genericFileComposeName, 2158 /* pfnCompact */ 2159 vdiCompact 1930 2160 }; 1931 2161
Note:
See TracChangeset
for help on using the changeset viewer.