Changeset 36632 in vbox for trunk/src/VBox/Storage
- Timestamp:
- Apr 8, 2011 9:33:09 PM (14 years ago)
- svn:sync-xref-src-repo-rev:
- 71096
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Storage/VHD.cpp
r34147 r36632 2826 2826 /* No need to write anything here. Data is always updated on a write. */ 2827 2827 return vhdFileFlushAsync(pImage, pIoCtx, NULL, NULL); 2828 } 2829 2830 /** @copydoc VBOXHDDBACKEND::pfnCompact */ 2831 static 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; 2828 3071 } 2829 3072 … … 3109 3352 genericFileComposeName, 3110 3353 /* pfnCompact */ 3111 NULL,3354 vhdCompact, 3112 3355 /* pfnResize */ 3113 3356 vhdResize
Note:
See TracChangeset
for help on using the changeset viewer.