DynamicVolumeHelper.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  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 DiskAccessLibrary.LogicalDiskManager;
  12. using Utilities;
  13. namespace DiskAccessLibrary
  14. {
  15. public partial class DynamicVolumeHelper
  16. {
  17. public static DynamicVolume GetVolumeByGuid(List<DynamicDisk> disks, Guid volumeGuid)
  18. {
  19. List<DynamicVolume> volumes = GetDynamicVolumes(disks);
  20. foreach (DynamicVolume volume in volumes)
  21. {
  22. if (volume.VolumeGuid == volumeGuid)
  23. {
  24. return volume;
  25. }
  26. }
  27. return null;
  28. }
  29. public static List<DynamicVolume> GetDynamicVolumes(List<DynamicDisk> disks)
  30. {
  31. List<DynamicVolume> result = new List<DynamicVolume>();
  32. List<DiskGroupDatabase> diskGroupDatabases = DiskGroupDatabase.ReadFromDisks(disks);
  33. foreach (DiskGroupDatabase database in diskGroupDatabases)
  34. {
  35. foreach (VolumeRecord volumeRecord in database.VolumeRecords)
  36. {
  37. DynamicVolume volume = GetVolume(disks, database, volumeRecord);
  38. result.Add(volume);
  39. }
  40. }
  41. return result;
  42. }
  43. /// <summary>
  44. /// Return volumes that are stored (or partially stored) on the given disk
  45. /// </summary>
  46. [Obsolete]
  47. public static List<DynamicVolume> GetDynamicDiskVolumes(DynamicDisk disk)
  48. {
  49. VolumeManagerDatabase database = VolumeManagerDatabase.ReadFromDisk(disk);
  50. List<DynamicDisk> disks = new List<DynamicDisk>();
  51. disks.Add(disk);
  52. List<DynamicVolume> result = new List<DynamicVolume>();
  53. if (database != null)
  54. {
  55. foreach (VolumeRecord volumeRecord in database.VolumeRecords)
  56. {
  57. DynamicVolume volume = GetVolume(disks, database, volumeRecord);
  58. if (volume != null)
  59. {
  60. foreach (DynamicDiskExtent extent in volume.Extents)
  61. {
  62. if (extent.DiskGuid == disk.DiskGuid)
  63. {
  64. result.Add(volume);
  65. break;
  66. }
  67. }
  68. }
  69. }
  70. }
  71. return result;
  72. }
  73. public static DynamicVolume GetVolume(List<DynamicDisk> disks, VolumeManagerDatabase database, VolumeRecord volumeRecord)
  74. {
  75. List<ComponentRecord> componentRecords = database.FindComponentsByVolumeID(volumeRecord.VolumeId);
  76. if (volumeRecord.NumberOfComponents != (ulong)componentRecords.Count || componentRecords.Count == 0)
  77. {
  78. // database record is invalid
  79. throw new InvalidDataException("Number of components in volume record does not match actual number of component records");
  80. }
  81. if (componentRecords.Count == 1)
  82. {
  83. ComponentRecord componentRecord = componentRecords[0];
  84. return GetVolume(disks, database, volumeRecord, componentRecord);
  85. }
  86. else // Mirrored volume
  87. {
  88. // Mirrored Simple Volume is the only kind of mirror suppored by Windows (only 2-way mirror is supported)
  89. // Veritas also supports Mirrored Stripe / Mirrored RAID-5 / Mirrored Spanned Volume (up to 32-way mirror is supported)
  90. List<DynamicVolume> volumes = new List<DynamicVolume>();
  91. foreach (ComponentRecord componentRecord in componentRecords)
  92. {
  93. DynamicVolume volume = GetVolume(disks, database, volumeRecord, componentRecord);
  94. volumes.Add(volume);
  95. }
  96. MirroredVolume mirroredVolume = new MirroredVolume(volumes, volumeRecord.VolumeGuid, database.DiskGroupGuid);
  97. mirroredVolume.VolumeID = volumeRecord.VolumeId;
  98. mirroredVolume.Name = volumeRecord.Name;
  99. return mirroredVolume;
  100. }
  101. }
  102. private static DynamicVolume GetVolume(List<DynamicDisk> disks, VolumeManagerDatabase database, VolumeRecord volumeRecord, ComponentRecord componentRecord)
  103. {
  104. if (componentRecord.ExtentLayout == ExtentLayoutName.Concatenated)
  105. {
  106. if (componentRecord.NumberOfExtents == 1)
  107. {
  108. // Simple volume
  109. return GetSimpleVolume(disks, database, componentRecord, volumeRecord); ;
  110. }
  111. else
  112. {
  113. // spanned volume
  114. SpannedVolume volume = GetSpannedVolume(disks, database, componentRecord, volumeRecord);
  115. return volume;
  116. }
  117. }
  118. else if (componentRecord.ExtentLayout == ExtentLayoutName.Stripe)
  119. {
  120. // striped volume
  121. StripedVolume volume = GetStripedVolume(disks, database, componentRecord, volumeRecord);
  122. return volume;
  123. }
  124. else if (componentRecord.ExtentLayout == ExtentLayoutName.RAID5)
  125. {
  126. Raid5Volume volume = GetRAID5Volume(disks, database, componentRecord, volumeRecord);
  127. return volume;
  128. }
  129. else
  130. {
  131. return null;
  132. }
  133. }
  134. private static List<DynamicColumn> GetDynamicVolumeColumns(List<DynamicDisk> disks, VolumeManagerDatabase database, ComponentRecord componentRecord, VolumeRecord volumeRecord)
  135. {
  136. // extentRecords are sorted by offset in column
  137. List<ExtentRecord> extentRecords = database.FindExtentsByComponentID(componentRecord.ComponentId);
  138. if (componentRecord.NumberOfExtents != extentRecords.Count || extentRecords.Count == 0)
  139. {
  140. // database record is invalid
  141. throw new InvalidDataException("Number of extents in component record does not match actual number of extent records");
  142. }
  143. SortedList<uint, List<DynamicDiskExtent>> columns = new SortedList<uint,List<DynamicDiskExtent>>();
  144. foreach (ExtentRecord extentRecord in extentRecords)
  145. {
  146. DiskRecord diskRecord = database.FindDiskByDiskID(extentRecord.DiskId);
  147. DynamicDisk disk = DynamicDiskHelper.FindDisk(disks, diskRecord.DiskGuid); // we add nulls as well
  148. DynamicDiskExtent extent = DynamicDiskExtentHelper.GetDiskExtent(disk, extentRecord);
  149. if (columns.ContainsKey(extentRecord.ColumnIndex))
  150. {
  151. columns[extentRecord.ColumnIndex].Add(extent);
  152. }
  153. else
  154. {
  155. List<DynamicDiskExtent> list = new List<DynamicDiskExtent>();
  156. list.Add(extent);
  157. columns.Add(extentRecord.ColumnIndex, list);
  158. }
  159. }
  160. List<DynamicColumn> result = new List<DynamicColumn>();
  161. foreach (List<DynamicDiskExtent> extents in columns.Values)
  162. {
  163. result.Add(new DynamicColumn(extents));
  164. }
  165. return result;
  166. }
  167. private static SimpleVolume GetSimpleVolume(List<DynamicDisk> disks, VolumeManagerDatabase database, ComponentRecord componentRecord, VolumeRecord volumeRecord)
  168. {
  169. List<ExtentRecord> extentRecords = database.FindExtentsByComponentID(componentRecord.ComponentId);
  170. if (extentRecords.Count == 1)
  171. {
  172. ExtentRecord extentRecord = extentRecords[0];
  173. DiskRecord diskRecord = database.FindDiskByDiskID(extentRecord.DiskId);
  174. DynamicDisk disk = DynamicDiskHelper.FindDisk(disks, diskRecord.DiskGuid); // we add nulls as well
  175. DynamicDiskExtent extent = DynamicDiskExtentHelper.GetDiskExtent(disk, extentRecord);
  176. SimpleVolume volume = new SimpleVolume(extent, volumeRecord.VolumeGuid, database.DiskGroupGuid);
  177. volume.VolumeID = volumeRecord.VolumeId;
  178. volume.Name = volumeRecord.Name;
  179. volume.DiskGroupName = database.DiskGroupName;
  180. return volume;
  181. }
  182. else
  183. {
  184. // component / extent records are invalid
  185. throw new InvalidDataException("Number of extents in component record does not match actual number of extent records");
  186. }
  187. }
  188. private static Raid5Volume GetRAID5Volume(List<DynamicDisk> disks, VolumeManagerDatabase database, ComponentRecord componentRecord, VolumeRecord volumeRecord)
  189. {
  190. List<DynamicColumn> columns = GetDynamicVolumeColumns(disks, database, componentRecord, volumeRecord);
  191. Raid5Volume volume = new Raid5Volume(columns, (int)componentRecord.StripeSizeLBA, volumeRecord.VolumeGuid, database.DiskGroupGuid);
  192. volume.VolumeID = volumeRecord.VolumeId;
  193. volume.Name = volumeRecord.Name;
  194. volume.DiskGroupName = database.DiskGroupName;
  195. return volume;
  196. }
  197. private static StripedVolume GetStripedVolume(List<DynamicDisk> disks, VolumeManagerDatabase database, ComponentRecord componentRecord, VolumeRecord volumeRecord)
  198. {
  199. List<DynamicColumn> columns = GetDynamicVolumeColumns(disks, database, componentRecord, volumeRecord);
  200. StripedVolume volume = new StripedVolume(columns, (int)componentRecord.StripeSizeLBA, volumeRecord.VolumeGuid, database.DiskGroupGuid);
  201. volume.VolumeID = volumeRecord.VolumeId;
  202. volume.Name = volumeRecord.Name;
  203. volume.DiskGroupName = database.DiskGroupName;
  204. return volume;
  205. }
  206. private static SpannedVolume GetSpannedVolume(List<DynamicDisk> disks, VolumeManagerDatabase database, ComponentRecord componentRecord, VolumeRecord volumeRecord)
  207. {
  208. List<DynamicColumn> columns = GetDynamicVolumeColumns(disks, database, componentRecord, volumeRecord);
  209. SpannedVolume volume = new SpannedVolume(columns[0], volumeRecord.VolumeGuid, database.DiskGroupGuid);
  210. volume.VolumeID = volumeRecord.VolumeId;
  211. volume.Name = volumeRecord.Name;
  212. volume.DiskGroupName = database.DiskGroupName;
  213. return volume;
  214. }
  215. }
  216. }