/// <param name="fragments">Must be sorted</param>
        public static DatabaseRecord GetDatabaseRecord(List <DatabaseRecordFragment> fragments)
        {
            DatabaseRecord result = null;

            if (fragments.Count != 0)
            {
                // Make sure we have all the records and that the first record is at the top of the fragment list
                if (fragments[0].NumberInGroup == 0 && fragments[0].FragmentCount == fragments.Count)
                {
                    RecordType recordType = (RecordType)(fragments[0].Data[0x03] & 0xF);
                    switch (recordType)
                    {
                    case RecordType.Volume:
                        result = new VolumeRecord(fragments);
                        break;

                    case RecordType.Component:
                        result = new ComponentRecord(fragments);
                        break;

                    case RecordType.Extent:
                        result = new ExtentRecord(fragments);
                        break;

                    case RecordType.Disk:
                        result = new DiskRecord(fragments);
                        break;

                    case RecordType.DiskGroup:
                        result = new DiskGroupRecord(fragments);
                        break;

                    default:
                        throw new NotImplementedException("Unrecognized record type: " + recordType);
                    }
                }
                else
                {
                    throw new InvalidDataException("Incomplete or unsorted record");
                }
            }
            return(result);
        }
Exemple #2
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);
        }
Exemple #3
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);
        }
Exemple #4
0
        public static void ExtendSimpleVolume(DiskGroupDatabase database, SimpleVolume volume, long numberOfAdditionalSectors)
        {
            VolumeRecord volumeRecord = database.FindVolumeByVolumeGuid(volume.VolumeGuid);

            volumeRecord          = (VolumeRecord)volumeRecord.Clone();
            volumeRecord.SizeLBA += (ulong)PublicRegionHelper.TranslateToPublicRegionSizeLBA(numberOfAdditionalSectors, volume.BytesPerSector);
            ExtentRecord extentRecord = database.FindExtentByExtentID(volume.DiskExtent.ExtentID);

            extentRecord          = (ExtentRecord)extentRecord.Clone();
            extentRecord.SizeLBA += (ulong)PublicRegionHelper.TranslateToPublicRegionSizeLBA(numberOfAdditionalSectors, volume.BytesPerSector);
            DiskRecord diskRecord = database.FindDiskByDiskID(extentRecord.DiskId); // we should update the disk, see Database.cs

            diskRecord = (DiskRecord)diskRecord.Clone();

            List <DatabaseRecord> records = new List <DatabaseRecord>();

            records.Add(volumeRecord);
            records.Add(extentRecord);
            records.Add(diskRecord);

            database.UpdateDatabase(records);
        }
Exemple #5
0
        public static void ExtendSimpleVolume(DiskGroupDatabase database, SimpleVolume volume, long additionalNumberOfSectors)
        {
            VolumeRecord volumeRecord = database.FindVolumeByVolumeGuid(volume.VolumeGuid);

            volumeRecord          = (VolumeRecord)volumeRecord.Clone();
            volumeRecord.SizeLBA += (ulong)additionalNumberOfSectors;
            ExtentRecord extentRecord = database.FindExtentByExtentID(volume.DiskExtent.ExtentID);

            extentRecord          = (ExtentRecord)extentRecord.Clone();
            extentRecord.SizeLBA += (ulong)additionalNumberOfSectors;
            DiskRecord diskRecord = database.FindDiskByDiskID(extentRecord.DiskId); // we should update the disk, see Database.cs

            diskRecord = (DiskRecord)diskRecord.Clone();

            List <DatabaseRecord> records = new List <DatabaseRecord>();

            records.Add(volumeRecord);
            records.Add(extentRecord);
            records.Add(diskRecord);

            database.UpdateDatabase(records);
        }
        /// <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);
        }
Exemple #7
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");
            }
        }
Exemple #8
0
        /// <summary>
        /// Update the database (add the new extent)
        /// </summary>
        /// <param name="volume">RAID-5 or striped volume</param>
        /// <returns>new extent ID</returns>
        public static ulong AddNewExtentToVolume(DiskGroupDatabase database, DynamicVolume volume, DiskExtent newExtent)
        {
            PrivateHeader privateHeader = PrivateHeader.ReadFromDisk(newExtent.Disk);

            List <DatabaseRecord> records = new List <DatabaseRecord>();

            VolumeRecord volumeRecord = database.FindVolumeByVolumeGuid(volume.VolumeGuid);

            if (volumeRecord == null)
            {
                throw new MissingDatabaseRecordException("Volume record is missing");
            }
            volumeRecord          = (VolumeRecord)volumeRecord.Clone();
            volumeRecord.SizeLBA += (ulong)PublicRegionHelper.TranslateToPublicRegionSizeLBA(newExtent.TotalSectors, privateHeader);
            records.Add(volumeRecord);

            ComponentRecord componentRecord = database.FindComponentsByVolumeID(volumeRecord.VolumeId)[0];

            if (componentRecord == null)
            {
                throw new MissingDatabaseRecordException("Component record is missing");
            }
            componentRecord = (ComponentRecord)componentRecord.Clone();
            componentRecord.NumberOfExtents++;
            componentRecord.NumberOfColumns++;
            records.Add(componentRecord);

            DiskRecord diskRecord = database.FindDiskByDiskGuid(privateHeader.DiskGuid);

            if (diskRecord == null)
            {
                throw new MissingDatabaseRecordException("Disk record is missing");
            }
            diskRecord = (DiskRecord)diskRecord.Clone();
            records.Add(diskRecord);

            ExtentRecord newExtentRecord = new ExtentRecord();

            newExtentRecord.Name               = GetNextExtentName(database.ExtentRecords, diskRecord.Name);
            newExtentRecord.ComponentId        = componentRecord.ComponentId;
            newExtentRecord.DiskId             = diskRecord.DiskId;
            newExtentRecord.DiskOffsetLBA      = (ulong)PublicRegionHelper.TranslateToPublicRegionLBA(newExtent.FirstSector, privateHeader);
            newExtentRecord.SizeLBA            = (ulong)PublicRegionHelper.TranslateToPublicRegionSizeLBA(newExtent.TotalSectors, privateHeader);
            newExtentRecord.HasColumnIndexFlag = true;
            newExtentRecord.ColumnIndex        = (uint)volume.Columns.Count; // zero based

            records.Add(newExtentRecord);

            // we should update the disk records and extent records
            foreach (DynamicDiskExtent extent in volume.Extents)
            {
                ExtentRecord extentRecord = database.FindExtentByExtentID(extent.ExtentID);
                if (extentRecord == null)
                {
                    throw new MissingDatabaseRecordException("Extent record is missing");
                }
                extentRecord = (ExtentRecord)extentRecord.Clone();
                records.Add(extentRecord);

                diskRecord = database.FindDiskByDiskID(extentRecord.DiskId);
                if (diskRecord == null)
                {
                    throw new MissingDatabaseRecordException("Disk record is missing");
                }
                // there could be multiple extents on the same disk, make sure we only add each disk once
                if (!records.Contains(diskRecord))
                {
                    diskRecord = (DiskRecord)diskRecord.Clone();
                    records.Add(diskRecord);
                }
            }

            database.UpdateDatabase(records);

            return(newExtentRecord.ExtentId);
        }
Exemple #9
0
        public static ulong CreateRAID5Volume(DiskGroupDatabase database, List <DiskExtent> extents, bool isDegraded)
        {
            int numberOfColumns;

            if (isDegraded)
            {
                numberOfColumns = extents.Count + 1;
            }
            else
            {
                numberOfColumns = extents.Count;
            }

            List <DatabaseRecord> records = new List <DatabaseRecord>();

            VolumeRecord volumeRecord = new VolumeRecord();

            volumeRecord.Id                 = database.AllocateNewRecordID();
            volumeRecord.Name               = GetNextRAIDVolumeName(database.VolumeRecords);
            volumeRecord.VolumeTypeString   = "raid5";
            volumeRecord.StateString        = "ACTIVE";
            volumeRecord.ReadPolicy         = ReadPolicyName.RAID;
            volumeRecord.VolumeNumber       = GetNextVolumeNumber(database.VolumeRecords);
            volumeRecord.VolumeFlags        = VolumeFlags.Writeback | VolumeFlags.Writecopy | VolumeFlags.DefaultUnknown;
            volumeRecord.NumberOfComponents = 1;
            volumeRecord.SizeLBA            = (ulong)PublicRegionHelper.TranslateToPublicRegionSizeLBA(extents[0].TotalSectors * (numberOfColumns - 1), extents[0].BytesPerSector);
            volumeRecord.PartitionType      = PartitionType.RAW;
            volumeRecord.VolumeGuid         = Guid.NewGuid();
            records.Add(volumeRecord);

            ComponentRecord componentRecord = new ComponentRecord();

            componentRecord.Id                    = database.AllocateNewRecordID();
            componentRecord.Name                  = volumeRecord.Name + "-01";
            componentRecord.StateString           = "ACTIVE";
            componentRecord.ExtentLayout          = ExtentLayoutName.RAID5;
            componentRecord.NumberOfExtents       = (uint)numberOfColumns;
            componentRecord.VolumeId              = volumeRecord.VolumeId;
            componentRecord.HasStripedExtentsFlag = true;
            componentRecord.StripeSizeLBA         = 128; // 64KB - the default
            componentRecord.NumberOfColumns       = (uint)numberOfColumns;
            records.Add(componentRecord);

            for (int index = 0; index < extents.Count; index++)
            {
                DiskExtent extent = extents[index];

                // we should update the disk records
                PrivateHeader privateHeader = PrivateHeader.ReadFromDisk(extent.Disk);
                DiskRecord    diskRecord    = database.FindDiskByDiskGuid(privateHeader.DiskGuid);
                diskRecord = (DiskRecord)diskRecord.Clone();
                records.Add(diskRecord);

                ExtentRecord extentRecord = new ExtentRecord();
                extentRecord.Name          = GetNextExtentName(database.ExtentRecords, diskRecord.Name);
                extentRecord.DiskOffsetLBA = (ulong)PublicRegionHelper.TranslateToPublicRegionLBA(extent.FirstSector, privateHeader);
                extentRecord.SizeLBA       = (ulong)PublicRegionHelper.TranslateToPublicRegionSizeLBA(extent.TotalSectors, extent.BytesPerSector);
                extentRecord.ComponentId   = componentRecord.ComponentId;
                extentRecord.DiskId        = diskRecord.DiskId;

                extentRecord.HasColumnIndexFlag = (index > 0);
                extentRecord.ColumnIndex        = (uint)index; // zero based

                records.Add(extentRecord);
            }

            if (isDegraded)
            {
                // we have to make-up a disk
                // The DiskFlags and ExtentFlags are not necessary (they will be added later anyway when the disk group is reimported)
                DiskRecord diskRecord = new DiskRecord();
                diskRecord.Id        = database.AllocateNewRecordID();
                diskRecord.Name      = "Miss" + new Random().Next(100);
                diskRecord.DiskGuid  = Guid.NewGuid();
                diskRecord.DiskFlags = DiskFlags.Detached;
                records.Add(diskRecord);

                ExtentRecord extentRecord = new ExtentRecord();
                extentRecord.Name               = diskRecord.Name + "-01";
                extentRecord.ExtentFlags        = ExtentFlags.Recover;
                extentRecord.SizeLBA            = (ulong)PublicRegionHelper.TranslateToPublicRegionSizeLBA(extents[0].TotalSectors, extents[0].BytesPerSector);
                extentRecord.ComponentId        = componentRecord.ComponentId;
                extentRecord.DiskId             = diskRecord.DiskId;
                extentRecord.HasColumnIndexFlag = true;
                extentRecord.ColumnIndex        = (uint)extents.Count; // zero based

                records.Add(extentRecord);
            }

            database.UpdateDatabase(records);

            return(volumeRecord.VolumeId);
        }