- Timestamp:
- Aug 24, 2010 12:54:12 PM (14 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Storage/VHDHDDCore.cpp
r31776 r31921 184 184 /** Current end offset of the file (without the disk footer). */ 185 185 uint64_t uCurrentEndOfFile; 186 /** Start offset of data blocks. */187 uint64_t uDataBlockStart;188 186 /** Size of the data block bitmap in sectors. */ 189 187 uint32_t cDataBlockBitmapSectors; … … 547 545 548 546 /** 547 * Internal: Update the VHD footer. 548 */ 549 static int vhdUpdateFooter(PVHDIMAGE pImage) 550 { 551 int rc = VINF_SUCCESS; 552 553 /* Update fields which can change. */ 554 pImage->vhdFooterCopy.CurSize = RT_H2BE_U64(pImage->cbSize); 555 pImage->vhdFooterCopy.DiskGeometryCylinder = RT_H2BE_U16(pImage->PCHSGeometry.cCylinders); 556 pImage->vhdFooterCopy.DiskGeometryHeads = pImage->PCHSGeometry.cHeads; 557 pImage->vhdFooterCopy.DiskGeometrySectors = pImage->PCHSGeometry.cSectors; 558 559 pImage->vhdFooterCopy.Checksum = 0; 560 pImage->vhdFooterCopy.Checksum = RT_H2BE_U32(vhdChecksum(&pImage->vhdFooterCopy, sizeof(VHDFooter))); 561 562 if (pImage->pBlockAllocationTable) 563 rc = vhdFileWriteSync(pImage, 0, &pImage->vhdFooterCopy, sizeof(VHDFooter), NULL); 564 565 if (RT_SUCCESS(rc)) 566 rc = vhdFileWriteSync(pImage, pImage->uCurrentEndOfFile, &pImage->vhdFooterCopy, sizeof(VHDFooter), NULL); 567 568 return rc; 569 } 570 571 /** 549 572 * Internal: Update dynamic disk header from VHDIMAGE. 550 573 */ … … 600 623 /* Update parent's UUID */ 601 624 memcpy(ddh.ParentUuid, pImage->ParentUuid.au8, sizeof(ddh.ParentUuid)); 625 626 /* Update data offset and number of table entries. */ 627 ddh.MaxTableEntries = RT_H2BE_U32(pImage->cBlockAllocationTableEntries); 628 602 629 ddh.Checksum = 0; 603 630 ddh.Checksum = RT_H2BE_U32(vhdChecksum(&ddh, sizeof(ddh))); … … 606 633 return rc; 607 634 608 /* Update the VHD footer copy. */609 rc = vhd FileWriteSync(pImage, 0, &pImage->vhdFooterCopy, sizeof(VHDFooter), NULL);635 /* Update the VHD footer. */ 636 rc = vhdUpdateFooter(pImage); 610 637 611 638 out: … … 890 917 pImage->uBlockAllocationTableOffset = uBlockAllocationTableOffset; 891 918 rc = vhdFileReadSync(pImage, uBlockAllocationTableOffset, pBlockAllocationTable, pImage->cBlockAllocationTableEntries * sizeof(uint32_t), NULL); 892 pImage->uDataBlockStart = uBlockAllocationTableOffset + pImage->cBlockAllocationTableEntries * sizeof(uint32_t);893 LogFlowFunc(("uDataBlockStart=%llu\n", pImage->uDataBlockStart));894 919 895 920 /* … … 1092 1117 /* Image must be opened and the new flags must be valid. Just readonly and 1093 1118 * info flags are supported. */ 1094 if (!pImage || (uOpenFlags & ~(VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO | VD_OPEN_FLAGS_SHAREABLE )))1119 if (!pImage || (uOpenFlags & ~(VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO | VD_OPEN_FLAGS_SHAREABLE | VD_OPEN_FLAGS_ASYNC_IO))) 1095 1120 { 1096 1121 rc = VERR_INVALID_PARAMETER; … … 1522 1547 */ 1523 1548 vhdFileWriteSync(pImage, pImage->uBlockAllocationTableOffset, pBlockAllocationTableToWrite, cbBlockAllocationTableToWrite, NULL); 1524 vhdFileWriteSync(pImage, pImage->uCurrentEndOfFile, &pImage->vhdFooterCopy, sizeof(VHDFooter), NULL);1525 1549 if (pImage->fDynHdrNeedsUpdate) 1526 1550 vhdDynamicHeaderUpdate(pImage); 1527 1551 RTMemFree(pBlockAllocationTableToWrite); 1528 1552 } 1553 1554 vhdUpdateFooter(pImage); 1529 1555 1530 1556 int rc = vhdFileFlushSync(pImage); … … 2657 2683 NULL, NULL); 2658 2684 } 2685 2686 2687 /** @copydoc VBOXHDDBACKEND::pfnResize */ 2688 static int vhdResize(void *pvBackendData, uint64_t cbSize, 2689 PCPDMMEDIAGEOMETRY pPCHSGeometry, PCPDMMEDIAGEOMETRY pLCHSGeometry, 2690 unsigned uPercentStart, unsigned uPercentSpan, 2691 PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage, 2692 PVDINTERFACE pVDIfsOperation) 2693 { 2694 PVHDIMAGE pImage = (PVHDIMAGE)pvBackendData; 2695 int rc = VINF_SUCCESS; 2696 2697 PFNVDPROGRESS pfnProgress = NULL; 2698 void *pvUser = NULL; 2699 PVDINTERFACE pIfProgress = VDInterfaceGet(pVDIfsOperation, 2700 VDINTERFACETYPE_PROGRESS); 2701 PVDINTERFACEPROGRESS pCbProgress = NULL; 2702 if (pIfProgress) 2703 { 2704 pCbProgress = VDGetInterfaceProgress(pIfProgress); 2705 if (pCbProgress) 2706 pfnProgress = pCbProgress->pfnProgress; 2707 pvUser = pIfProgress->pvUser; 2708 } 2709 2710 /* Making the image smaller is not supported at the moment. */ 2711 if ( cbSize < pImage->cbSize 2712 || pImage->uImageFlags & VD_IMAGE_FLAGS_FIXED) 2713 rc = VERR_NOT_SUPPORTED; 2714 else if (cbSize > pImage->cbSize) 2715 { 2716 unsigned cBlocksAllocated = 0; 2717 size_t cbBlock = pImage->cbDataBlock + pImage->cbDataBlockBitmap; /** < Size of a block including the sector bitmap. */ 2718 uint32_t cBlocksNew = cbSize / pImage->cbDataBlock; /** < New number of blocks in the image after the resize */ 2719 if (cbSize % pImage->cbDataBlock) 2720 cBlocksNew++; 2721 2722 uint32_t cBlocksOld = pImage->cBlockAllocationTableEntries; /** < Number of blocks before the resize. */ 2723 uint64_t cbBlockspaceNew = RT_ALIGN_32(cBlocksNew * sizeof(uint32_t), VHD_SECTOR_SIZE); /** < Required space for the block array after the resize. */ 2724 uint64_t offStartDataNew = RT_ALIGN_32(pImage->uBlockAllocationTableOffset + cbBlockspaceNew, VHD_SECTOR_SIZE); /** < New start offset for block data after the resize */ 2725 uint64_t offStartDataOld = ~0ULL; 2726 2727 /* Go through the BAT and finde the data start offset. */ 2728 for (unsigned idxBlock = 0; idxBlock < pImage->cBlockAllocationTableEntries; idxBlock++) 2729 { 2730 if (pImage->pBlockAllocationTable[idxBlock] != ~0U) 2731 { 2732 uint64_t offStartBlock = pImage->pBlockAllocationTable[idxBlock] * VHD_SECTOR_SIZE; 2733 if (offStartBlock < offStartDataOld) 2734 offStartDataOld = offStartBlock; 2735 cBlocksAllocated++; 2736 } 2737 } 2738 2739 if ( offStartDataOld != offStartDataNew 2740 && cBlocksAllocated > 0) 2741 { 2742 /* Calculate how many sectors nee to be relocated. */ 2743 uint64_t cbOverlapping = offStartDataNew - offStartDataOld; 2744 unsigned cBlocksReloc = cbOverlapping / cbBlock; 2745 if (cbOverlapping % cbBlock) 2746 cBlocksReloc++; 2747 2748 cBlocksReloc = RT_MIN(cBlocksReloc, cBlocksAllocated); 2749 offStartDataNew = offStartDataOld; 2750 2751 /* Do the relocation. */ 2752 LogFlow(("Relocating %u blocks\n", cBlocksReloc)); 2753 2754 /* 2755 * Get the blocks we need to relocate first, they are appended to the end 2756 * of the image. 2757 */ 2758 void *pvBuf = NULL, *pvZero = NULL; 2759 do 2760 { 2761 /* Allocate data buffer. */ 2762 pvBuf = RTMemAllocZ(cbBlock); 2763 if (!pvBuf) 2764 { 2765 rc = VERR_NO_MEMORY; 2766 break; 2767 } 2768 2769 /* Allocate buffer for overwrting with zeroes. */ 2770 pvZero = RTMemAllocZ(cbBlock); 2771 if (!pvZero) 2772 { 2773 rc = VERR_NO_MEMORY; 2774 break; 2775 } 2776 2777 for (unsigned i = 0; i < cBlocksReloc; i++) 2778 { 2779 uint32_t uBlock = offStartDataNew / VHD_SECTOR_SIZE; 2780 2781 /* Search the index in the block table. */ 2782 for (unsigned idxBlock = 0; idxBlock < cBlocksOld; idxBlock++) 2783 { 2784 if (pImage->pBlockAllocationTable[idxBlock] == uBlock) 2785 { 2786 /* Read data and append to the end of the image. */ 2787 rc = vhdFileReadSync(pImage, offStartDataNew, pvBuf, cbBlock, NULL); 2788 if (RT_FAILURE(rc)) 2789 break; 2790 2791 rc = vhdFileWriteSync(pImage, pImage->uCurrentEndOfFile, pvBuf, cbBlock, NULL); 2792 if (RT_FAILURE(rc)) 2793 break; 2794 2795 /* Zero out the old block area. */ 2796 rc = vhdFileWriteSync(pImage, offStartDataNew, pvZero, cbBlock, NULL); 2797 if (RT_FAILURE(rc)) 2798 break; 2799 2800 /* Update block counter. */ 2801 pImage->pBlockAllocationTable[idxBlock] = pImage->uCurrentEndOfFile / VHD_SECTOR_SIZE; 2802 2803 pImage->uCurrentEndOfFile += cbBlock; 2804 2805 /* Continue with the next block. */ 2806 break; 2807 } 2808 } 2809 2810 if (RT_FAILURE(rc)) 2811 break; 2812 2813 offStartDataNew += cbBlock; 2814 } 2815 } while (0); 2816 2817 if (pvBuf) 2818 RTMemFree(pvBuf); 2819 if (pvZero) 2820 RTMemFree(pvZero); 2821 } 2822 2823 /* 2824 * Relocation done, expand the block array and update the header with 2825 * the new data. 2826 */ 2827 if (RT_SUCCESS(rc)) 2828 { 2829 uint32_t *paBlocksNew = (uint32_t *)RTMemRealloc(pImage->pBlockAllocationTable, cBlocksNew * sizeof(uint32_t)); 2830 if (paBlocksNew) 2831 { 2832 pImage->pBlockAllocationTable = paBlocksNew; 2833 2834 /* Mark the new blocks as unallocated. */ 2835 for (unsigned idxBlock = cBlocksOld; idxBlock < cBlocksNew; idxBlock++) 2836 pImage->pBlockAllocationTable[idxBlock] = ~0U; 2837 } 2838 else 2839 rc = VERR_NO_MEMORY; 2840 2841 if (RT_SUCCESS(rc)) 2842 { 2843 /* Write the block array before updating the rest. */ 2844 rc = vhdFileWriteSync(pImage, pImage->uBlockAllocationTableOffset, pImage->pBlockAllocationTable, 2845 cBlocksNew * sizeof(uint32_t), NULL); 2846 } 2847 2848 if (RT_SUCCESS(rc)) 2849 { 2850 /* Update size and new block count. */ 2851 pImage->cBlockAllocationTableEntries = cBlocksNew; 2852 pImage->cbSize = cbSize; 2853 2854 /* Update geometry. */ 2855 pImage->PCHSGeometry = *pPCHSGeometry; 2856 pImage->LCHSGeometry = *pLCHSGeometry; 2857 } 2858 } 2859 2860 /* Update header information in base image file. */ 2861 pImage->fDynHdrNeedsUpdate = true; 2862 vhdFlush(pImage); 2863 } 2864 /* Same size doesn't change the image at all. */ 2865 2866 LogFlowFunc(("returns %Rrc\n", rc)); 2867 return rc; 2868 } 2869 2659 2870 2660 2871 VBOXHDDBACKEND g_VhdBackend = … … 2757 2968 NULL, 2758 2969 /* pfnResize */ 2759 NULL2970 vhdResize 2760 2971 };
Note:
See TracChangeset
for help on using the changeset viewer.