/// <returns>Number of bytes</returns> public static long GetMaximumSizeToExtendDynamicDiskExtent(DynamicDiskExtent targetExtent) { DynamicDisk disk = DynamicDisk.ReadFromDisk(targetExtent.Disk); PrivateHeader privateHeader = disk.PrivateHeader; List <DynamicDiskExtent> extents = DynamicDiskHelper.GetDiskExtents(disk); if (extents == null) { throw new InvalidDataException("Cannot read extents information from disk"); } long endOfData = (long)((privateHeader.PublicRegionStartLBA + privateHeader.PublicRegionSizeLBA) * (ulong)disk.BytesPerSector); long max = endOfData - (targetExtent.FirstSector * targetExtent.BytesPerSector + targetExtent.Size); // space from the extent end to the end of the disk foreach (DynamicDiskExtent extent in extents) { if (extent.FirstSector > targetExtent.FirstSector) { long spaceBetweenExtents = (extent.FirstSector - targetExtent.FirstSector) * disk.BytesPerSector - targetExtent.Size; max = Math.Min(max, spaceBetweenExtents); } } return(max); }
public static void AddDiskToRaid5Volume(DiskGroupDatabase database, Raid5Volume volume, DiskExtent newExtent, ref long bytesCopied) { // If there will be a power failure during the conversion, our RAID volume will resync during boot, // To prevent destruction of the data, we temporarily convert the array to striped volume VolumeManagerDatabaseHelper.ConvertRaidToStripedVolume(database, volume.VolumeGuid); ulong newExtentID = VolumeManagerDatabaseHelper.AddNewExtentToVolume(database, volume, newExtent); // Backup the first sector of the first extent to the last sector of the new extent // (We replace the filesystem boot record with our own sector for recovery purposes) byte[] filesystemBootRecord = volume.Extents[0].ReadSector(0); newExtent.WriteSectors(newExtent.TotalSectors - 1, filesystemBootRecord); AddDiskOperationResumeRecord resumeRecord = new AddDiskOperationResumeRecord(); resumeRecord.VolumeGuid = volume.VolumeGuid; PrivateHeader privateHeader = PrivateHeader.ReadFromDisk(newExtent.Disk); // privateHeader cannot be null at this point resumeRecord.NumberOfCommittedSectors = 0; // we use volume.WriteSectors so that the parity information will be update // this way, we could recover the first sector of each extent if a disk will fail volume.WriteSectors(0, resumeRecord.GetBytes(volume.BytesPerSector)); ResumeAddDiskToRaid5Volume(database, volume, new DynamicDiskExtent(newExtent, newExtentID), resumeRecord, ref bytesCopied); }
public static long FindUnusedRegion(PrivateHeader privateHeader, TOCBlock tocBlock, int sectorCount) { bool[] bitmap = GetPrivateRegionUsageBitmap(privateHeader, tocBlock); // Reserve the first, second, third, third-last and second-last sectors for TOCBlocks bitmap[0] = true; bitmap[1] = true; bitmap[2] = true; bitmap[privateHeader.PrivateRegionSizeLBA - 3] = true; bitmap[privateHeader.PrivateRegionSizeLBA - 2] = true; int startIndex = 0; int freeCount = 0; for (int index = 0; index < bitmap.Length; index++) { if (bitmap[index] == false) // free { if (freeCount == 0) { startIndex = index; } freeCount++; if (freeCount == sectorCount) { return((long)privateHeader.PrivateRegionStartLBA + startIndex); } } else { freeCount = 0; } } return(-1); }
private void listDisks_SelectedIndexChanged(object sender, EventArgs e) { DynamicDisk dynamicDisk = (DynamicDisk)listDisks.SelectedValue; PrivateHeader privateHeader = dynamicDisk.PrivateHeader; long publicRegionEndLBA = (long)(privateHeader.PublicRegionStartLBA + privateHeader.PublicRegionSizeLBA); numericDiskOffset.Minimum = (long)privateHeader.PublicRegionStartLBA * dynamicDisk.BytesPerSector; numericDiskOffset.Maximum = publicRegionEndLBA * dynamicDisk.BytesPerSector - m_extent.Size; if (dynamicDisk.Disk != m_extent.Disk) { DiskExtent allocation = DynamicDiskHelper.FindExtentAllocation(dynamicDisk, m_extent.Size); numericDiskOffset.Enabled = (allocation != null); btnOK.Enabled = (allocation != null); if (allocation != null) { numericDiskOffset.Value = allocation.FirstSector * allocation.BytesPerSector; m_previousSuffixIndex = 0; listSuffixes.SelectedIndex = 0; CompactNumericOffset(); } } else { numericDiskOffset.Enabled = true; btnOK.Enabled = true; numericDiskOffset.Value = m_extent.FirstSector * m_extent.Disk.BytesPerSector; m_previousSuffixIndex = 0; listSuffixes.SelectedIndex = 0; CompactNumericOffset(); } }
public static void ListPhysicalDisks() { List <PhysicalDisk> disks = PhysicalDiskHelper.GetPhysicalDisks(); Console.WriteLine("Disk ## Size GPT Dyn DiskID Disk Group Name "); Console.WriteLine("------- ------- --- --- ------ ------------------"); foreach (PhysicalDisk disk in disks) { int index = disk.PhysicalDiskIndex; string diskNumber = index.ToString().PadLeft(2); MasterBootRecord mbr = MasterBootRecord.ReadFromDisk(disk); string isGPTStr = (mbr != null && mbr.IsGPTBasedDisk) ? " * " : " "; string isDynStr = DynamicDisk.IsDynamicDisk(disk) ? " * " : " "; string diskID = String.Empty; string diskGroupName = String.Empty; VolumeManagerDatabase database = VolumeManagerDatabase.ReadFromDisk(disk); if (database != null) { PrivateHeader privateHeader = PrivateHeader.ReadFromDisk(disk); DiskRecord diskRecord = database.FindDiskByDiskGuid(privateHeader.DiskGuid); diskID = diskRecord.DiskId.ToString(); diskGroupName = database.DiskGroupName; } diskID = diskID.PadLeft(6); Console.WriteLine("Disk {0} {1} {2} {3} {4} {5}", diskNumber, GetStandardSizeString(disk.Size), isGPTStr, isDynStr, diskID, diskGroupName); } }
/// <param name="targetOffset">in bytes</param> public static bool IsMoveLocationValid(DynamicDisk disk, DynamicDiskExtent sourceExtent, long targetOffset) { List <DynamicDiskExtent> extents = GetDiskExtents(disk); // extents are sorted by first sector if (extents == null) { return(false); } PrivateHeader privateHeader = disk.PrivateHeader; if (targetOffset % privateHeader.BytesPerSector > 0) { return(false); } int index = GetIndexOfExtentID(extents, sourceExtent.ExtentID); extents.RemoveAt(index); long targetStartSector = targetOffset / disk.BytesPerSector; long publicRegionStartSector = (long)privateHeader.PublicRegionStartLBA; long startSector = publicRegionStartSector; long publicRegionSizeLBA = (long)privateHeader.PublicRegionSizeLBA; if (targetStartSector < publicRegionStartSector) { return(false); } if (targetStartSector + sourceExtent.TotalSectors > publicRegionStartSector + publicRegionSizeLBA) { return(false); } foreach (DynamicDiskExtent extent in extents) { long extentStartSector = extent.FirstSector; long extentEndSector = extent.FirstSector + extent.Size / disk.BytesPerSector - 1; if (extentStartSector >= targetStartSector && extentStartSector <= targetStartSector + sourceExtent.TotalSectors) { // extent start within the requested region return(false); } if (extentEndSector >= targetStartSector && extentEndSector <= targetStartSector + sourceExtent.TotalSectors) { // extent end within the requested region return(false); } } return(true); }
// The secondary TOC is usually alternated between the third-last and the second-last sectors of the private region. public static long FindUnusedLBAForSecondaryToc(PrivateHeader privateHeader, TOCBlock tocBlock) { bool[] bitmap = GetPrivateRegionUsageBitmap(privateHeader, tocBlock); for (int index = bitmap.Length - 1; index >= 0; index--) { if (bitmap[index] == false) { return((long)privateHeader.PrivateRegionStartLBA + index); } } return(-1); }
/// <summary> /// Support null disks /// </summary> public static ulong GetExtentStartSector(DynamicDisk disk, ExtentRecord extentRecord) { ulong dataStartLBA = 0; if (disk != null) { PrivateHeader privateHeader = disk.PrivateHeader; dataStartLBA = privateHeader.PublicRegionStartLBA; } ulong extentStartSector = dataStartLBA + extentRecord.DiskOffsetLBA; return(extentStartSector); }
private static bool[] GetPrivateRegionUsageBitmap(PrivateHeader privateHeader, TOCBlock tocBlock) { // usage bitmap: bool[] bitmap = new bool[privateHeader.PrivateRegionSizeLBA]; bitmap[privateHeader.PrimaryPrivateHeaderLBA] = true; bitmap[privateHeader.SecondaryPrivateHeaderLBA] = true; bitmap[privateHeader.PrimaryTocLBA] = true; bitmap[privateHeader.SecondaryTocLBA] = true; foreach (TOCRegion region in tocBlock.Regions) { for (int index = 0; index < (int)region.SizeLBA; index++) { bitmap[(int)region.StartLBA + index] = true; } } return(bitmap); }
private static List <DiskExtent> GetUnallocatedSpace(DynamicDisk disk) { List <DynamicDiskExtent> extents = GetDiskExtents(disk); // extents are sorted by first sector if (extents == null) { return(null); } List <DiskExtent> result = new List <DiskExtent>(); PrivateHeader privateHeader = disk.PrivateHeader; long publicRegionStartSector = (long)privateHeader.PublicRegionStartLBA; long startSector = publicRegionStartSector; long publicRegionSize = (long)privateHeader.PublicRegionSizeLBA * disk.Disk.BytesPerSector; // see if there is room before each extent foreach (DynamicDiskExtent extent in extents) { long extentStartSector = extent.FirstSector; long nextStartSector = extent.FirstSector + extent.Size / disk.BytesPerSector; long freeSpaceInBytes = (extentStartSector - startSector) * disk.BytesPerSector; if (freeSpaceInBytes > 0) { result.Add(new DiskExtent(disk.Disk, startSector, freeSpaceInBytes)); } startSector = nextStartSector; } // see if there is room after the last extent long spaceInBytes = publicRegionSize - (startSector - publicRegionStartSector) * disk.Disk.BytesPerSector; if (spaceInBytes > 0) { result.Add(new DiskExtent(disk.Disk, startSector, spaceInBytes)); } return(result); }
/// <summary> /// Sorted by first sector /// </summary> /// <returns>null if there was a problem reading extent information from disk</returns> public static List <DynamicDiskExtent> GetDiskExtents(DynamicDisk disk) { List <DynamicDiskExtent> result = new List <DynamicDiskExtent>(); PrivateHeader privateHeader = disk.PrivateHeader; if (privateHeader != null) { VolumeManagerDatabase database = VolumeManagerDatabase.ReadFromDisk(disk); if (database != null) { DiskRecord diskRecord = database.FindDiskByDiskGuid(privateHeader.DiskGuid); List <ExtentRecord> extentRecords = database.FindExtentsByDiskID(diskRecord.DiskId); foreach (ExtentRecord extentRecord in extentRecords) { DynamicDiskExtent extent = GetDiskExtent(disk, extentRecord); result.Add(extent); } SortExtentsByFirstSector(result); return(result); } } return(null); }
public static long TranslateToPublicRegionSizeLBA(long sectorCount, PrivateHeader privateHeader) { return(TranslateToPublicRegionSizeLBA(sectorCount, (int)privateHeader.BytesPerSector)); }
public static long TranslateToPublicRegionLBA(long sectorIndex, PrivateHeader privateHeader) { return(TranslateToPublicRegionLBA(sectorIndex, (long)privateHeader.PublicRegionStartLBA, (int)privateHeader.BytesPerSector)); }
public static long FindUnusedSector(PrivateHeader privateHeader, TOCBlock tocBlock) { return(FindUnusedRegion(privateHeader, tocBlock, 1)); }