DynamicVolumeHelper.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. /* Copyright (C) 2014 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
  2. *
  3. * You can redistribute this program and/or modify it under the terms of
  4. * the GNU Lesser Public License as published by the Free Software Foundation,
  5. * either version 3 of the License, or (at your option) any later version.
  6. */
  7. using System;
  8. using System.Collections.Generic;
  9. using System.IO;
  10. using System.Text;
  11. using Utilities;
  12. namespace DiskAccessLibrary.LogicalDiskManager
  13. {
  14. public partial class DynamicVolumeHelper
  15. {
  16. public static List<Guid> GetVolumeGuids(List<DynamicVolume> volumes)
  17. {
  18. List<Guid> volumeGuids = new List<Guid>();
  19. foreach (DynamicVolume volume in volumes)
  20. {
  21. volumeGuids.Add(volume.VolumeGuid);
  22. }
  23. return volumeGuids;
  24. }
  25. public static DynamicVolume GetVolumeByGuid(List<DynamicDisk> disks, Guid volumeGuid)
  26. {
  27. List<DynamicVolume> volumes = GetDynamicVolumes(disks);
  28. foreach (DynamicVolume volume in volumes)
  29. {
  30. if (volume.VolumeGuid == volumeGuid)
  31. {
  32. return volume;
  33. }
  34. }
  35. return null;
  36. }
  37. public static List<DynamicVolume> GetDynamicVolumes(List<DynamicDisk> disks)
  38. {
  39. List<DynamicVolume> result = new List<DynamicVolume>();
  40. List<DiskGroupDatabase> diskGroupDatabases = DiskGroupDatabase.ReadFromDisks(disks);
  41. foreach (DiskGroupDatabase database in diskGroupDatabases)
  42. {
  43. foreach (VolumeRecord volumeRecord in database.VolumeRecords)
  44. {
  45. DynamicVolume volume = GetVolume(disks, database, volumeRecord);
  46. result.Add(volume);
  47. }
  48. }
  49. return result;
  50. }
  51. public static DynamicVolume GetVolume(List<DynamicDisk> disks, VolumeManagerDatabase database, VolumeRecord volumeRecord)
  52. {
  53. List<ComponentRecord> componentRecords = database.FindComponentsByVolumeID(volumeRecord.VolumeId);
  54. if (volumeRecord.NumberOfComponents != (ulong)componentRecords.Count || componentRecords.Count == 0)
  55. {
  56. // database record is invalid
  57. throw new InvalidDataException("Number of components in volume record does not match actual number of component records");
  58. }
  59. if (componentRecords.Count == 1)
  60. {
  61. ComponentRecord componentRecord = componentRecords[0];
  62. return GetVolume(disks, database, volumeRecord, componentRecord);
  63. }
  64. else // Mirrored volume
  65. {
  66. // Mirrored Simple Volume is the only kind of mirror suppored by Windows (only 2-way mirror is supported)
  67. // Veritas also supports Mirrored Stripe / Mirrored RAID-5 / Mirrored Spanned Volume (up to 32-way mirror is supported)
  68. List<DynamicVolume> volumes = new List<DynamicVolume>();
  69. foreach (ComponentRecord componentRecord in componentRecords)
  70. {
  71. DynamicVolume volume = GetVolume(disks, database, volumeRecord, componentRecord);
  72. volumes.Add(volume);
  73. }
  74. MirroredVolume mirroredVolume = new MirroredVolume(volumes, volumeRecord.VolumeGuid, database.DiskGroupGuid);
  75. mirroredVolume.VolumeID = volumeRecord.VolumeId;
  76. mirroredVolume.Name = volumeRecord.Name;
  77. return mirroredVolume;
  78. }
  79. }
  80. private static DynamicVolume GetVolume(List<DynamicDisk> disks, VolumeManagerDatabase database, VolumeRecord volumeRecord, ComponentRecord componentRecord)
  81. {
  82. if (componentRecord.ExtentLayout == ExtentLayoutName.Concatenated)
  83. {
  84. if (componentRecord.NumberOfExtents == 1)
  85. {
  86. // Simple volume
  87. return GetSimpleVolume(disks, database, componentRecord, volumeRecord); ;
  88. }
  89. else
  90. {
  91. // spanned volume
  92. SpannedVolume volume = GetSpannedVolume(disks, database, componentRecord, volumeRecord);
  93. return volume;
  94. }
  95. }
  96. else if (componentRecord.ExtentLayout == ExtentLayoutName.Stripe)
  97. {
  98. // striped volume
  99. StripedVolume volume = GetStripedVolume(disks, database, componentRecord, volumeRecord);
  100. return volume;
  101. }
  102. else if (componentRecord.ExtentLayout == ExtentLayoutName.RAID5)
  103. {
  104. Raid5Volume volume = GetRAID5Volume(disks, database, componentRecord, volumeRecord);
  105. return volume;
  106. }
  107. else
  108. {
  109. return null;
  110. }
  111. }
  112. private static List<DynamicColumn> GetDynamicVolumeColumns(List<DynamicDisk> disks, VolumeManagerDatabase database, ComponentRecord componentRecord, VolumeRecord volumeRecord)
  113. {
  114. // extentRecords are sorted by offset in column
  115. List<ExtentRecord> extentRecords = database.FindExtentsByComponentID(componentRecord.ComponentId);
  116. if (componentRecord.NumberOfExtents != extentRecords.Count || extentRecords.Count == 0)
  117. {
  118. // database record is invalid
  119. throw new InvalidDataException("Number of extents in component record does not match actual number of extent records");
  120. }
  121. SortedList<uint, List<DynamicDiskExtent>> columns = new SortedList<uint,List<DynamicDiskExtent>>();
  122. foreach (ExtentRecord extentRecord in extentRecords)
  123. {
  124. DiskRecord diskRecord = database.FindDiskByDiskID(extentRecord.DiskId);
  125. DynamicDisk disk = DynamicDiskHelper.FindDisk(disks, diskRecord.DiskGuid); // we add nulls as well
  126. DynamicDiskExtent extent = DynamicDiskExtentHelper.GetDiskExtent(disk, extentRecord);
  127. if (columns.ContainsKey(extentRecord.ColumnIndex))
  128. {
  129. columns[extentRecord.ColumnIndex].Add(extent);
  130. }
  131. else
  132. {
  133. List<DynamicDiskExtent> list = new List<DynamicDiskExtent>();
  134. list.Add(extent);
  135. columns.Add(extentRecord.ColumnIndex, list);
  136. }
  137. }
  138. List<DynamicColumn> result = new List<DynamicColumn>();
  139. foreach (List<DynamicDiskExtent> extents in columns.Values)
  140. {
  141. result.Add(new DynamicColumn(extents));
  142. }
  143. return result;
  144. }
  145. private static SimpleVolume GetSimpleVolume(List<DynamicDisk> disks, VolumeManagerDatabase database, ComponentRecord componentRecord, VolumeRecord volumeRecord)
  146. {
  147. List<ExtentRecord> extentRecords = database.FindExtentsByComponentID(componentRecord.ComponentId);
  148. if (extentRecords.Count == 1)
  149. {
  150. ExtentRecord extentRecord = extentRecords[0];
  151. DiskRecord diskRecord = database.FindDiskByDiskID(extentRecord.DiskId);
  152. DynamicDisk disk = DynamicDiskHelper.FindDisk(disks, diskRecord.DiskGuid); // we add nulls as well
  153. DynamicDiskExtent extent = DynamicDiskExtentHelper.GetDiskExtent(disk, extentRecord);
  154. SimpleVolume volume = new SimpleVolume(extent, volumeRecord.VolumeGuid, database.DiskGroupGuid);
  155. volume.VolumeID = volumeRecord.VolumeId;
  156. volume.Name = volumeRecord.Name;
  157. volume.DiskGroupName = database.DiskGroupName;
  158. return volume;
  159. }
  160. else
  161. {
  162. // component / extent records are invalid
  163. throw new InvalidDataException("Number of extents in component record does not match actual number of extent records");
  164. }
  165. }
  166. private static Raid5Volume GetRAID5Volume(List<DynamicDisk> disks, VolumeManagerDatabase database, ComponentRecord componentRecord, VolumeRecord volumeRecord)
  167. {
  168. List<DynamicColumn> columns = GetDynamicVolumeColumns(disks, database, componentRecord, volumeRecord);
  169. int bytesPerSector = DynamicVolume.GetBytesPerSector(columns, DynamicColumn.DefaultBytesPerSector);
  170. int sectorsPerStripe = (int)PublicRegionHelper.TranslateFromPublicRegionSizeLBA((int)componentRecord.StripeSizeLBA, bytesPerSector);
  171. Raid5Volume volume = new Raid5Volume(columns, sectorsPerStripe, volumeRecord.VolumeGuid, database.DiskGroupGuid);
  172. volume.VolumeID = volumeRecord.VolumeId;
  173. volume.Name = volumeRecord.Name;
  174. volume.DiskGroupName = database.DiskGroupName;
  175. return volume;
  176. }
  177. private static StripedVolume GetStripedVolume(List<DynamicDisk> disks, VolumeManagerDatabase database, ComponentRecord componentRecord, VolumeRecord volumeRecord)
  178. {
  179. List<DynamicColumn> columns = GetDynamicVolumeColumns(disks, database, componentRecord, volumeRecord);
  180. int bytesPerSector = DynamicVolume.GetBytesPerSector(columns, DynamicColumn.DefaultBytesPerSector);
  181. int sectorsPerStripe = (int)PublicRegionHelper.TranslateFromPublicRegionSizeLBA((int)componentRecord.StripeSizeLBA, bytesPerSector);
  182. StripedVolume volume = new StripedVolume(columns, sectorsPerStripe, volumeRecord.VolumeGuid, database.DiskGroupGuid);
  183. volume.VolumeID = volumeRecord.VolumeId;
  184. volume.Name = volumeRecord.Name;
  185. volume.DiskGroupName = database.DiskGroupName;
  186. return volume;
  187. }
  188. private static SpannedVolume GetSpannedVolume(List<DynamicDisk> disks, VolumeManagerDatabase database, ComponentRecord componentRecord, VolumeRecord volumeRecord)
  189. {
  190. List<DynamicColumn> columns = GetDynamicVolumeColumns(disks, database, componentRecord, volumeRecord);
  191. SpannedVolume volume = new SpannedVolume(columns[0], volumeRecord.VolumeGuid, database.DiskGroupGuid);
  192. volume.VolumeID = volumeRecord.VolumeId;
  193. volume.Name = volumeRecord.Name;
  194. volume.DiskGroupName = database.DiskGroupName;
  195. return volume;
  196. }
  197. }
  198. }