예제 #1
0
        public const int BackupBufferSizeLBA = 128; // there are about 180 contiguous free sectors in a private region

        /// <summary>
        /// Move extent to another disk
        /// </summary>
        public static void MoveExtentToAnotherDisk(List<DynamicDisk> disks, DynamicVolume volume, DynamicDiskExtent sourceExtent, DiskExtent relocatedExtent, ref long bytesCopied)
        {
            DiskGroupDatabase database = DiskGroupDatabase.ReadFromDisks(disks, volume.DiskGroupGuid);
            if (database == null)
            {
                throw new DatabaseNotFoundException();
            }

            // copy the data
            long transferSizeLBA = Settings.MaximumTransferSizeLBA;
            for (long sectorIndex = 0; sectorIndex < relocatedExtent.TotalSectors; sectorIndex += transferSizeLBA)
            {
                long sectorsLeft = relocatedExtent.TotalSectors - sectorIndex;
                int sectorsToRead = (int)Math.Min(transferSizeLBA, sectorsLeft);

                byte[] data = sourceExtent.ReadSectors(sectorIndex, sectorsToRead);
                
                relocatedExtent.WriteSectors(sectorIndex, data);

                bytesCopied += sectorsToRead * sourceExtent.BytesPerSector;
            }

            // Update the database to point to the relocated extent
            DynamicDisk targetDisk = DynamicDisk.ReadFromDisk(relocatedExtent.Disk);
            DynamicDiskExtent dynamicRelocatedExtent = new DynamicDiskExtent(relocatedExtent, sourceExtent.ExtentID);
            dynamicRelocatedExtent.Name = sourceExtent.Name;
            dynamicRelocatedExtent.DiskGuid = targetDisk.DiskGuid;
            VolumeManagerDatabaseHelper.UpdateExtentLocation(database, volume, dynamicRelocatedExtent);
        }
        /// <returns>In bytes</returns>
        public static long GetMaxNewExtentLength(DynamicDisk disk, long alignInSectors)
        {
            List <DiskExtent> unallocatedExtents = GetUnallocatedExtents(disk);

            if (unallocatedExtents == null)
            {
                return(-1);
            }

            long result = 0;

            for (int index = 0; index < unallocatedExtents.Count; index++)
            {
                DiskExtent extent = unallocatedExtents[index];
                if (alignInSectors > 1)
                {
                    extent = DiskExtentHelper.GetAlignedDiskExtent(extent, alignInSectors);
                }
                if (extent.Size > result)
                {
                    result = extent.Size;
                }
            }
            return(result);
        }
예제 #3
0
        public static VolumeManagerDatabase ReadFromDisk(Disk disk, PrivateHeader privateHeader, TOCBlock tocBlock)
        {
            VolumeManagerDatabaseHeader databaseHeader = VolumeManagerDatabaseHeader.ReadFromDisk(disk, privateHeader, tocBlock);

            if (databaseHeader == null || !databaseHeader.IsVersionSupported)
            {
                return(null);
            }

            // The first VBLK entry is the subsequent entry to the VMDB header.
            // Note: On a disk with 4KB sectors, VBLKs will reside in the same sector as the VMDB header.
            ulong firstSector    = privateHeader.PrivateRegionStartLBA + tocBlock.ConfigStart; // we skip the VMDB
            int   databaseLength = (int)(databaseHeader.HeaderSize + databaseHeader.NumberOfVBlks * databaseHeader.BlockSize);
            int   sectorCount    = (int)Math.Ceiling(databaseLength / (double)disk.BytesPerSector);

            byte[] databaseBytes     = disk.ReadSectors((long)firstSector, sectorCount);
            int    numberOfFragments = (int)(databaseHeader.NumberOfVBlks - FirstSequenceNumber);
            List <DatabaseRecord> databaseRecords = ReadDatabaseRecords(databaseBytes, (int)databaseHeader.HeaderSize, (int)databaseHeader.BlockSize, numberOfFragments);

            // read all KLog blocks
            KernelUpdateLog kernelUpdateLog = KernelUpdateLog.ReadFromDisk(disk, privateHeader, tocBlock);
            DynamicDisk     dynamicDisk     = new DynamicDisk(disk, privateHeader, tocBlock);

            return(new VolumeManagerDatabaseCopy(dynamicDisk, databaseHeader, databaseRecords, kernelUpdateLog));
        }
예제 #4
0
 public VolumeManagerDatabaseCopy(DynamicDisk disk, VolumeManagerDatabaseHeader databaseHeader, List <DatabaseRecord> databaseRecords, KernelUpdateLog kernelUpdateLog) :
     base(databaseHeader, databaseRecords, kernelUpdateLog)
 {
     m_disk            = disk;
     m_databaseHeader  = databaseHeader;
     m_databaseRecords = databaseRecords;
     m_kernelUpdateLog = kernelUpdateLog;
 }
        public VolumeManagerDatabase(DynamicDisk disk, VolumeManagerDatabaseHeader databaseHeader, List <DatabaseRecord> databaseRecords, KernelUpdateLog kernelUpdateLog)
        {
            m_disk            = disk;
            m_databaseHeader  = databaseHeader;
            m_databaseRecords = databaseRecords;
            m_kernelUpdateLog = kernelUpdateLog;

            m_nextRecordID = m_databaseHeader.CommitTransactionID + 1;
        }
        public static VolumeManagerDatabase ReadFromDisk(Disk disk, PrivateHeader privateHeader, TOCBlock tocBlock)
        {
            VolumeManagerDatabaseHeader databaseHeader = VolumeManagerDatabaseHeader.ReadFromDisk(disk, privateHeader, tocBlock);

            if (databaseHeader == null)
            {
                return(null);
            }
            List <DatabaseRecord> databaseRecords = new List <DatabaseRecord>();

            // The first VBLK entry is the subsequent entry to the VMDB, which located at (ConfigurationStartLBA + Item1Start)
            ulong firstSector = privateHeader.PrivateRegionStartLBA + tocBlock.ConfigStart + 1;  // we skip the VMDB
            int   sectorCount = (int)Math.Ceiling((long)databaseHeader.NumberOfVBlks * databaseHeader.BlockSize / (decimal)disk.BytesPerSector);

            byte[] databaseBytes = disk.ReadSectors((long)firstSector, sectorCount);

            // read all VBLK blocks:
            // Note: fragments are not necessarily contiguous!
            Dictionary <uint, List <DatabaseRecordFragment> > fragments = new Dictionary <uint, List <DatabaseRecordFragment> >();

            for (uint index = 0; index < databaseHeader.NumberOfVBlks - 4; index++)
            {
                byte[] fragmentBytes = new byte[databaseHeader.BlockSize];
#warning long array index not supported
                Array.Copy(databaseBytes, (int)(index * databaseHeader.BlockSize), fragmentBytes, 0, (int)databaseHeader.BlockSize);
                DatabaseRecordFragment fragment = DatabaseRecordFragment.GetDatabaseRecordFragment(fragmentBytes);

                if (fragment != null) // null fragment means VBLK is empty
                {
                    if (fragments.ContainsKey(fragment.GroupNumber))
                    {
                        fragments[fragment.GroupNumber].Add(fragment);
                    }
                    else
                    {
                        List <DatabaseRecordFragment> recordFragments = new List <DatabaseRecordFragment>();
                        recordFragments.Add(fragment);
                        fragments.Add(fragment.GroupNumber, recordFragments);
                    }
                }
            }

            // We have all the fragments and we can now assemble the records:
            // We assume that fragments with lower FragmentNumber appear in the database before fragments
            // of the same group with higher FragmentNumber.
            foreach (List <DatabaseRecordFragment> recorFragments in fragments.Values)
            {
                DatabaseRecord databaseRecord = DatabaseRecord.GetDatabaseRecord(recorFragments);
                databaseRecords.Add(databaseRecord);
            }

            // read all KLog blocks
            KernelUpdateLog kernelUpdateLog = KernelUpdateLog.ReadFromDisk(disk, privateHeader, tocBlock);
            DynamicDisk     dynamicDisk     = new DynamicDisk(disk, privateHeader, tocBlock);
            return(new VolumeManagerDatabase(dynamicDisk, databaseHeader, databaseRecords, kernelUpdateLog));
        }
예제 #7
0
        public static PrivateHeader FindDiskPrivateHeader(Guid diskGuid)
        {
            DynamicDisk disk = FindDisk(diskGuid);

            if (disk != null)
            {
                return(disk.PrivateHeader);
            }
            return(null);
        }
예제 #8
0
 public static VolumeManagerDatabase ReadFromDisk(Disk disk)
 {
     if (DynamicDisk.IsDynamicDisk(disk))
     {
         PrivateHeader privateHeader = PrivateHeader.ReadFromDisk(disk);
         if (privateHeader != null)
         {
             return(ReadFromDisk(disk, privateHeader));
         }
     }
     return(null);
 }
예제 #9
0
        /// <summary>
        /// Support null disks
        /// </summary>
        public static long GetExtentStartSector(DynamicDisk disk, ExtentRecord extentRecord)
        {
            long publicRegionStartLBA = 0;
            int  bytesPerDiskSector   = DynamicColumn.DefaultBytesPerSector; // default for missing disks

            if (disk != null)
            {
                bytesPerDiskSector = disk.BytesPerSector;
                PrivateHeader privateHeader = disk.PrivateHeader;
                publicRegionStartLBA = (long)privateHeader.PublicRegionStartLBA;
            }
            return(PublicRegionHelper.TranslateFromPublicRegionLBA((long)extentRecord.DiskOffsetLBA, publicRegionStartLBA, bytesPerDiskSector));
        }
예제 #10
0
        public static List <DynamicDisk> GetPhysicalDynamicDisks()
        {
            List <PhysicalDisk> disks  = PhysicalDiskHelper.GetPhysicalDisks();
            List <DynamicDisk>  result = new List <DynamicDisk>();

            foreach (PhysicalDisk disk in disks)
            {
                DynamicDisk dynamicDisk = DynamicDisk.ReadFromDisk(disk);
                if (dynamicDisk != null)
                {
                    result.Add(dynamicDisk);
                }
            }
            return(result);
        }
        /// <param name="targetOffset">in bytes</param>
        public static bool IsMoveLocationValid(DynamicDiskExtent sourceExtent, DynamicDisk targetDisk, long targetOffset)
        {
            bool isSameDisk = (sourceExtent.Disk == targetDisk.Disk);
            List <DynamicDiskExtent> extents = GetDiskExtents(targetDisk);

            // extents are sorted by first sector
            if (extents == null)
            {
                return(false);
            }

            PrivateHeader privateHeader = targetDisk.PrivateHeader;

            if (sourceExtent.BytesPerSector != targetDisk.BytesPerSector)
            {
                // We must not move an extent to another disk that has different sector size
                return(false);
            }
            if (targetOffset % privateHeader.BytesPerSector > 0)
            {
                return(false);
            }
            long       targetSector = targetOffset / targetDisk.BytesPerSector;
            DiskExtent targetExtent = new DiskExtent(targetDisk.Disk, targetSector, sourceExtent.Size);

            List <DiskExtent> usedExtents = new List <DiskExtent>();

            foreach (DynamicDiskExtent extent in extents)
            {
                if (!isSameDisk || extent.FirstSector != sourceExtent.FirstSector)
                {
                    usedExtents.Add(extent);
                }
            }

            long publicRegionStartSector         = (long)privateHeader.PublicRegionStartLBA;
            long publicRegionSize                = (long)privateHeader.PublicRegionSizeLBA * targetDisk.BytesPerSector;
            List <DiskExtent> unallocatedExtents = DiskExtentsHelper.GetUnallocatedExtents(targetDisk.Disk, publicRegionStartSector, publicRegionSize, usedExtents);

            foreach (DiskExtent extent in unallocatedExtents)
            {
                if (extent.FirstSector <= targetExtent.FirstSector && targetExtent.LastSector <= extent.LastSector)
                {
                    return(true);
                }
            }
            return(false);
        }
예제 #12
0
        /// <summary>
        /// Support null disks
        /// </summary>
        public static DynamicDiskExtent GetDiskExtent(DynamicDisk dynamicDisk, ExtentRecord extentRecord)
        {
            long extentStartSector = GetExtentStartSector(dynamicDisk, extentRecord);
            long extentSize        = (long)extentRecord.SizeLBA * PublicRegionHelper.BytesPerPublicRegionSector;
            Disk disk     = null;
            Guid diskGuid = Guid.Empty;

            if (dynamicDisk != null)
            {
                disk     = dynamicDisk.Disk;
                diskGuid = dynamicDisk.DiskGuid;
            }
            DynamicDiskExtent extent = new DynamicDiskExtent(disk, extentStartSector, extentSize, extentRecord.ExtentId);

            extent.Name     = extentRecord.Name;
            extent.DiskGuid = diskGuid;
            return(extent);
        }
예제 #13
0
        public static bool IsVolumeRetained(SimpleVolume volume, out bool isBootVolume)
        {
            isBootVolume = false;
            DynamicDisk         disk = DynamicDisk.ReadFromDisk(volume.Disk);
            long                bootPartitionStartLBA;
            List <ExtentRecord> retained = GetRetainedExtentsOnDisk(disk, out bootPartitionStartLBA);

            foreach (ExtentRecord record in retained)
            {
                if (record.ExtentId == volume.DiskExtent.ExtentID)
                {
                    if ((long)(disk.PrivateHeader.PublicRegionStartLBA + record.DiskOffsetLBA) == bootPartitionStartLBA)
                    {
                        isBootVolume = true;
                    }
                    return(true);
                }
            }
            return(false);
        }
예제 #14
0
        public static void WriteDatabaseRecordFragment(DynamicDisk disk, DatabaseRecordFragment fragment, int blockSize)
        {
            if (fragment.SequenceNumber < FirstSequenceNumber)
            {
                throw new ArgumentException("VBLK SequenceNumber must start from 4");
            }

            PrivateHeader privateHeader      = disk.PrivateHeader;
            TOCBlock      tocBlock           = disk.TOCBlock;
            ulong         sectorIndex        = privateHeader.PrivateRegionStartLBA + tocBlock.ConfigStart;
            int           fragmentsPerSector = (int)(disk.Disk.BytesPerSector / blockSize);

            sectorIndex += (ulong)(fragment.SequenceNumber / fragmentsPerSector);
            byte[] sectorBytes   = disk.Disk.ReadSector((long)sectorIndex);
            byte[] fragmentBytes = fragment.GetBytes(blockSize); // should we use the same database header?
            int    indexInSector = (int)(fragment.SequenceNumber % fragmentsPerSector);

            Array.Copy(fragmentBytes, 0, sectorBytes, indexInSector * blockSize, blockSize);
            disk.Disk.WriteSectors((long)sectorIndex, sectorBytes);
        }
예제 #15
0
        private static List <ExtentRecord> GetRetainedExtentsOnDisk(DynamicDisk disk, out long bootPartitionStartLBA)
        {
            VolumeManagerDatabase database   = VolumeManagerDatabase.ReadFromDisk(disk);
            DiskRecord            diskRecord = database.FindDiskByDiskGuid(disk.DiskGuid);

            bootPartitionStartLBA = -1;

            List <ExtentRecord> result = new List <ExtentRecord>();

            foreach (VolumeRecord volume in database.VolumeRecords)
            {
                if ((volume.VolumeFlags & VolumeFlags.RetainPartition) > 0)
                {
                    List <ComponentRecord> components = database.FindComponentsByVolumeID(volume.VolumeId);
                    foreach (ComponentRecord componentRecord in components)
                    {
                        if (componentRecord.ExtentLayout == ExtentLayoutName.Concatenated)
                        {
                            if (componentRecord.NumberOfExtents == 1)
                            {
                                List <ExtentRecord> extents = database.FindExtentsByComponentID(componentRecord.ComponentId);
                                if (extents.Count == 1)
                                {
                                    ExtentRecord extent = extents[0];
                                    if (extent.DiskId == diskRecord.DiskId)
                                    {
                                        result.Add(extent);
                                        if ((volume.VolumeFlags & VolumeFlags.BootVolume) > 0)
                                        {
                                            bootPartitionStartLBA = (long)(disk.PrivateHeader.PublicRegionStartLBA + extent.DiskOffsetLBA);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

            return(result);
        }
        public static List <DiskExtent> GetUnallocatedExtents(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);
        }
예제 #17
0
        private static List <DynamicColumn> GetDynamicVolumeColumns(DiskGroupDatabase database, ComponentRecord componentRecord, VolumeRecord volumeRecord)
        {
            // extentRecords are sorted by offset in column
            List <ExtentRecord> extentRecords = database.FindExtentsByComponentID(componentRecord.ComponentId);

            if (componentRecord.NumberOfExtents != extentRecords.Count || extentRecords.Count == 0)
            {
                // database record is invalid
                throw new InvalidDataException("Number of extents in component record does not match actual number of extent records");
            }

            SortedList <uint, List <DynamicDiskExtent> > columns = new SortedList <uint, List <DynamicDiskExtent> >();

            foreach (ExtentRecord extentRecord in extentRecords)
            {
                DiskRecord        diskRecord = database.FindDiskByDiskID(extentRecord.DiskId);
                DynamicDisk       disk       = DynamicDiskHelper.FindDisk(database.Disks, diskRecord.DiskGuid); // we add nulls as well
                DynamicDiskExtent extent     = DynamicDiskExtentHelper.GetDiskExtent(disk, extentRecord);

                if (columns.ContainsKey(extentRecord.ColumnIndex))
                {
                    columns[extentRecord.ColumnIndex].Add(extent);
                }
                else
                {
                    List <DynamicDiskExtent> list = new List <DynamicDiskExtent>();
                    list.Add(extent);
                    columns.Add(extentRecord.ColumnIndex, list);
                }
            }

            List <DynamicColumn> result = new List <DynamicColumn>();

            foreach (List <DynamicDiskExtent> extents in columns.Values)
            {
                result.Add(new DynamicColumn(extents));
            }
            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 = DynamicDiskExtentHelper.GetDiskExtent(disk, extentRecord);
                        result.Add(extent);
                    }
                    DynamicDiskExtentsHelper.SortExtentsByFirstSector(result);
                    return(result);
                }
            }
            return(null);
        }
        /// <param name="allocationLength">In bytes</param>
        /// <param name="alignInSectors">0 or 1 for no alignment</param>
        /// <returns>Allocated DiskExtent or null if there is not enough free disk space</returns>
        public static DiskExtent FindExtentAllocation(DynamicDisk disk, long allocationLength, long alignInSectors)
        {
            List <DiskExtent> unallocatedExtents = DynamicDiskHelper.GetUnallocatedExtents(disk);

            if (unallocatedExtents == null)
            {
                return(null);
            }

            for (int index = 0; index < unallocatedExtents.Count; index++)
            {
                DiskExtent extent = unallocatedExtents[index];
                if (alignInSectors > 1)
                {
                    extent = DiskExtentHelper.GetAlignedDiskExtent(extent, alignInSectors);
                }
                if (extent.Size >= allocationLength)
                {
                    return(new DiskExtent(extent.Disk, extent.FirstSector, allocationLength));
                }
            }
            return(null);
        }
예제 #20
0
        public static DynamicDisk FindDisk(Guid diskGuid)
        {
            List <int> diskIndexList = PhysicalDiskControl.GetPhysicalDiskIndexList();

            foreach (int diskIndex in diskIndexList)
            {
                PhysicalDisk disk;
                try
                {
                    disk = new PhysicalDisk(diskIndex); // will throw an exception if disk is not valid
                }
                catch (DriveNotFoundException)
                {
                    // The disk must have been removed from the system
                    continue;
                }
                catch (DeviceNotReadyException)
                {
                    continue;
                }
                catch (SharingViolationException) // skip this disk, it's probably being used
                {
                    continue;
                }

                DynamicDisk dynamicDisk = DynamicDisk.ReadFromDisk(disk);
                if (dynamicDisk != null)
                {
                    if (dynamicDisk.DiskGuid == diskGuid)
                    {
                        return(dynamicDisk);
                    }
                }
            }
            return(null);
        }
예제 #21
0
        private static SimpleVolume GetSimpleVolume(DiskGroupDatabase database, ComponentRecord componentRecord, VolumeRecord volumeRecord)
        {
            List <ExtentRecord> extentRecords = database.FindExtentsByComponentID(componentRecord.ComponentId);

            if (extentRecords.Count == 1)
            {
                ExtentRecord extentRecord = extentRecords[0];

                DiskRecord        diskRecord = database.FindDiskByDiskID(extentRecord.DiskId);
                DynamicDisk       disk       = DynamicDiskHelper.FindDisk(database.Disks, diskRecord.DiskGuid); // we add nulls as well
                DynamicDiskExtent extent     = DynamicDiskExtentHelper.GetDiskExtent(disk, extentRecord);

                SimpleVolume volume = new SimpleVolume(extent, volumeRecord.VolumeGuid, database.DiskGroupGuid);
                volume.VolumeID      = volumeRecord.VolumeId;
                volume.Name          = volumeRecord.Name;
                volume.DiskGroupName = database.DiskGroupName;
                return(volume);
            }
            else
            {
                // component / extent records are invalid
                throw new InvalidDataException("Number of extents in component record does not match actual number of extent records");
            }
        }
예제 #22
0
 public static void WriteToDisk(DynamicDisk disk, VolumeManagerDatabaseHeader header)
 {
     WriteToDisk(disk.Disk, disk.PrivateHeader, disk.TOCBlock, header);
 }
예제 #23
0
        /// <summary>
        /// Move extent to a new location on the same disk
        /// </summary>
        public static void MoveExtentWithinSameDisk(List<DynamicDisk> disks, DynamicVolume volume, DynamicDiskExtent sourceExtent, DiskExtent relocatedExtent, ref long bytesCopied)
        {
            DiskGroupDatabase database = DiskGroupDatabase.ReadFromDisks(disks, volume.DiskGroupGuid);
            if (database == null)
            {
                throw new DatabaseNotFoundException();
            }

            MoveExtentOperationBootRecord resumeRecord = new MoveExtentOperationBootRecord();
            // If there will be a power failure during the move, a RAID volume will resync during boot,
            // To prevent destruction of the data, we temporarily convert the array to striped volume
            if (volume is Raid5Volume)
            {
                VolumeManagerDatabaseHelper.ConvertRaidToStripedVolume(database, volume.VolumeGuid);
                resumeRecord.RestoreRAID5 = true;
            }

            // We want to write our own volume boot sector for recovery purposes, so we must find where to backup the old boot sector.
            // We don't want to store the backup in the range of the existing or relocated extent, because then we would have to move
            // the backup around during the move operation, other options include:
            // 1. Store it between sectors 1-62 (cons: Could be in use, Windows occasionally start a volume from sector 1)
            // 2. Find an easily compressible sector (e.g. zero-filled) within the existing extent, overwrite it with the backup, and restore it when the operation is done.
            // 3. use the LDM private region to store the sector.

            DynamicDisk dynamicDisk = DynamicDisk.ReadFromDisk(relocatedExtent.Disk);
            // Note: backupSectorIndex will be from the beginning of the private region while backupBufferStartSector will be from the end
            // so there is no need to allocate them
            long backupSectorIndex = DynamicDiskHelper.FindUnusedSectorInPrivateRegion(dynamicDisk);

            resumeRecord.VolumeGuid = volume.VolumeGuid;
            resumeRecord.NumberOfCommittedSectors = 0;
            resumeRecord.ExtentID = sourceExtent.ExtentID;
            resumeRecord.OldStartSector = (ulong)sourceExtent.FirstSector;
            resumeRecord.NewStartSector = (ulong)relocatedExtent.FirstSector;
            resumeRecord.BootRecordBackupSector = (ulong)backupSectorIndex;

            long distanceLBA = Math.Abs((long)resumeRecord.NewStartSector - (long)resumeRecord.OldStartSector);
            if (distanceLBA < MoveHelper.BufferedModeThresholdLBA)
            {
                long backupBufferStartSector = DynamicDiskHelper.FindUnusedRegionInPrivateRegion(dynamicDisk, BackupBufferSizeLBA);
                if (backupBufferStartSector == -1)
                {
                    throw new Exception("Private region is full");
                }

                if (backupBufferStartSector <= backupSectorIndex)
                {
                    throw new Exception("Private region structure is unknown");
                }
                resumeRecord.BackupBufferStartSector = (ulong)backupBufferStartSector;
                resumeRecord.BackupBufferSizeLBA = BackupBufferSizeLBA;
            }

            // Backup the first sector of the first extent
            // (We replace the filesystem boot record with our own sector for recovery purposes)
            byte[] filesystemBootRecord = volume.ReadSector(0);
            relocatedExtent.Disk.WriteSectors(backupSectorIndex, filesystemBootRecord);

            // we write the resume record instead of the boot record
            volume.WriteSectors(0, resumeRecord.GetBytes());

            if (sourceExtent.FirstSector < relocatedExtent.FirstSector)
            {
                // move right
                MoveExtentRight(disks, volume, resumeRecord, ref bytesCopied);
            }
            else
            { 
                // move left

                // we write the resume record at the new location as well (to be able to resume if a power failure will occur immediately after updating the database)
                relocatedExtent.WriteSectors(0, resumeRecord.GetBytes());
                DynamicDiskExtent dynamicRelocatedExtent = new DynamicDiskExtent(relocatedExtent, sourceExtent.ExtentID);
                dynamicRelocatedExtent.Name = sourceExtent.Name;
                dynamicRelocatedExtent.DiskGuid = sourceExtent.DiskGuid;
                VolumeManagerDatabaseHelper.UpdateExtentLocation(database, volume, dynamicRelocatedExtent);
                int extentIndex = DynamicDiskExtentHelper.GetIndexOfExtentID(volume.DynamicExtents, sourceExtent.ExtentID);
                // get the updated volume (we just moved an extent)
                volume = DynamicVolumeHelper.GetVolumeByGuid(disks, volume.VolumeGuid);
                MoveExtentLeft(disks, volume, resumeRecord, ref bytesCopied);
            }
        }
예제 #24
0
 public static VolumeManagerDatabase ReadFromDisk(DynamicDisk disk)
 {
     return(ReadFromDisk(disk.Disk, disk.PrivateHeader, disk.TOCBlock));
 }
예제 #25
0
 public void SetLastEntry(DynamicDisk databaseDisk, ulong committedTransactionID, ulong pendingTransactionID)
 {
     SetLastEntry(databaseDisk.Disk, databaseDisk.PrivateHeader, databaseDisk.TOCBlock, committedTransactionID, pendingTransactionID);
 }
 public static DiskExtent FindExtentAllocation(DynamicDisk disk, long allocationLength)
 {
     return(FindExtentAllocation(disk, allocationLength, 0));
 }
예제 #27
0
 public static KernelUpdateLog ReadFromDisk(DynamicDisk databaseDisk)
 {
     return(ReadFromDisk(databaseDisk.Disk, databaseDisk.PrivateHeader, databaseDisk.TOCBlock));
 }
 public static long GetMaxNewExtentLength(DynamicDisk disk)
 {
     return(GetMaxNewExtentLength(disk, 1));
 }