*)
let disk_block_size = ~^512
+(*----------------------------------------------------------------------*)
+(* The plug-ins. *)
let partition_types = [
Diskimage_mbr.plugin_id,
("MBR", Diskimage_mbr.probe);
let _, _, list_lvs_fn = List.assoc lvm_name lvm_types in
list_lvs_fn devs
+(*----------------------------------------------------------------------*)
(* Create machine description. *)
let open_machine name disks =
let disks = List.map (
m_disks = m_disks;
m_lv_filesystems = filesystems }
+(*----------------------------------------------------------------------*)
+
+(* We describe the ownership of each part of the disk using a
+ * segment tree. http://en.wikipedia.org/wiki/Segment_tree
+ *
+ * Note that each part can (and usually is) owned multiple times
+ * (eg. by a filesystem and by the partition that the filesystem
+ * lies inside). Also, the segment tree is effectively read-only.
+ * We build it up as a final step given the flat list of segments
+ * identified by the algorithm in 'iter_over_machine'.
+ *)
+
+type ownership = unit
+
+(* List of owned segments before we build the segment tree. *)
+type ownership_list =
+ (device * (* block_device (disk) *)
+ int63 * int63 * (* disk offset, size of segment *)
+ [ `Filesystem of filesystem
+ | `Partitions of partitions
+ | `PhysicalVolume of pv ] * (* owner *)
+ int63 (* owner offset *)
+ ) list
+
(* Ownership tables. *)
let create_ownership machine =
(* Iterate over all the things which can claim ownership of a
* disk block (filesystems, partitions, PVs).
- *
- * A single disk block can be "owned" by several things (eg. it
- * could contain an LV filesystem, on a PV, on a partition).
*)
let rec iter_over_machine
- {m_disks = disks; m_lv_filesystems = lv_filesystems} =
- List.iter (
- function
- | { d_content = (`Filesystem fs as owner) } ->
- iter_over_filesystem disks fs owner
- | { d_content = (`Partitions parts as owner) } ->
- iter_over_partitions disks parts owner
- | { d_content = (`PhysicalVolume pv as owner) } ->
- iter_over_pv disks pv owner
- | { d_content = `Unknown } -> ()
- ) disks;
- List.iter (
- fun (lv, fs) ->
- let owner = `Filesystem fs in
- iter_over_filesystem disks fs owner
- ) lv_filesystems
+ ({m_disks = disks; m_lv_filesystems = lv_filesystems} as machine) =
+
+ (* No segments to begin with. *)
+ let ownership = [] in
+
+ (* Iterate over disks. *)
+ let ownership =
+ List.fold_left (
+ fun ownership ->
+ function
+ | { d_content = (`Filesystem fs as owner) } ->
+ iter_over_filesystem machine ownership fs owner
+ | { d_content = (`Partitions parts as owner) } ->
+ iter_over_partitions machine ownership parts owner
+ | { d_content = (`PhysicalVolume pv as owner) } ->
+ iter_over_pv machine ownership pv owner
+ | { d_content = `Unknown } -> ownership
+ ) ownership disks in
+
+ (* Iterate over LV filesystems. *)
+ let ownership =
+ List.fold_left (
+ fun ownership (lv, fs) ->
+ let owner = `Filesystem fs in
+ iter_over_filesystem machine ownership fs owner
+ ) ownership lv_filesystems in
+
+ ownership
(* Iterate over the blocks in a single filesystem. *)
- and iter_over_filesystem disks {fs_dev = dev} owner =
- iter_over_device disks dev owner
+ and iter_over_filesystem machine ownership {fs_dev = dev} owner =
+ iter_over_device machine ownership dev owner
(* Iterate over the blocks in a set of partitions, then
* iterate over the contents of the partitions.
*)
- and iter_over_partitions disks {parts = parts; parts_dev = parts_dev} owner =
- iter_over_device disks parts_dev owner;
+ and iter_over_partitions machine ownership
+ {parts = parts; parts_dev = parts_dev} owner =
+ let ownership = iter_over_device machine ownership parts_dev owner in
- List.iter (
- function
- | { part_content = (`Filesystem fs as owner) } ->
- iter_over_filesystem disks fs owner
- | { part_content = (`PhysicalVolume pv as owner) } ->
- iter_over_pv disks pv owner
- | { part_content = `Unknown } -> ()
- ) parts
+ let ownership =
+ List.fold_left (
+ fun ownership ->
+ function
+ | { part_content = (`Filesystem fs as owner) } ->
+ iter_over_filesystem machine ownership fs owner
+ | { part_content = (`PhysicalVolume pv as owner) } ->
+ iter_over_pv machine ownership pv owner
+ | { part_content = `Unknown } -> ownership
+ ) ownership parts in
+
+ ownership
(* Iterate over the blocks in a PV. *)
- and iter_over_pv disks {pv_dev = dev} owner =
- iter_over_device disks dev owner
+ and iter_over_pv machine ownership {pv_dev = dev} owner =
+ iter_over_device machine ownership dev owner
(* Iterate over the blocks in a device, assigning ownership to 'owner'
*
* In reality (1): There can be several owners for each block, so we
- * incrementally add ownership. The add_ownership function takes
- * care of handling overlapping ranges, using an AVL tree.
+ * incrementally add ownership to the ownership_list (which eventually
+ * will be turned into a segment tree).
* In reality (2): Iterating over blocks would take ages and result
* in a very inefficient ownership representation. Instead we look
* at minimum contiguous extents.
*)
- and iter_over_device disks dev owner =
+ and iter_over_device { m_disks = disks } ownership dev owner =
let size = dev#size in
+ let disks = List.map (fun {d_dev = dev} -> (dev :> device)) disks in
- let rec loop offset =
+ let rec loop ownership offset =
if offset < size then (
- let extent =
- let devs, extent = get_next_extent disks dev offset in
- if devs = [] then
- eprintf "warning: no device found under %s\n"
- (string_of_owner owner);
- List.iter (
- fun (dev, dev_offset) ->
- add_ownership dev dev_offset extent owner
- ) devs;
- extent in
- loop (offset +^ extent)
+ let devs, extent = get_next_extent disks dev offset in
+ if devs = [] then
+ eprintf "warning: no device found under %s\n"
+ (string_of_owner owner);
+ let ownership =
+ List.fold_left (
+ fun ownership (disk, disk_offset) ->
+ let elem = disk, disk_offset, extent, owner, offset in
+ elem :: ownership
+ ) ownership devs in
+ loop ownership (offset +^ extent)
)
+ else ownership
in
- loop ~^0
+ loop ownership ~^0
(* Return the length of the next contiguous region in the device starting
* at the given byte offset. Also return the underlying block device(s)
* if there is one.
*)
and get_next_extent disks (dev : device) offset =
- let disks = List.map (fun { d_dev = dev } -> (dev :> device)) disks in
- map_recursively disks dev offset
-
- and map_recursively disks dev offset =
let this_extent = dev#contiguous offset in
(* If this disk is a block_device (a member of the 'disks' list)
let devs =
List.map
(fun (dev, dev_offset) ->
- map_recursively disks dev dev_offset)
+ get_next_extent disks dev dev_offset)
devs in
(* Work out the minimum contiguous extent from this offset. *)
"PV:" ^ pv_uuid
| `Partitions { parts_plugin_id = parts_plugin_id } ->
parts_plugin_id
-
- and add_ownership dev offset extent owner =
- let blocksize = dev#blocksize in
- let offset_in_blocks, offset_in_block =
- offset /^ blocksize, offset %^ blocksize in
- let extent_in_blocks, extent_in_block =
- extent /^ blocksize, extent %^ blocksize in
-
- eprintf "add_ownership: %s %s[%s:%s] %s[%s:%s] %s\n"
- dev#name
- (Int63.to_string offset)
- (Int63.to_string offset_in_blocks)
- (Int63.to_string offset_in_block)
- (Int63.to_string extent)
- (Int63.to_string extent_in_blocks)
- (Int63.to_string extent_in_block)
- (string_of_owner owner)
in
- iter_over_machine machine
-
+ let ownership = iter_over_machine machine in
+ (* If debugging, print the segments that we found. *)
+ if !debug then (
+ let ownership = List.rev ownership in
+ eprintf "ownership segment list of %s:\n" machine.m_name;
+ List.iter (
+ fun (disk, disk_offset, size, owner, owner_offset) ->
+ let blocksize = disk#blocksize in
+ let disk_offset_in_blocks, disk_offset_in_block =
+ disk_offset /^ blocksize, disk_offset %^ blocksize in
+ let size_in_blocks, size_in_block =
+ size /^ blocksize, size %^ blocksize in
+
+ eprintf "%s %s[%s:%s] %s[%s:%s] %s@%s\n"
+ disk#name
+ (Int63.to_string disk_offset)
+ (Int63.to_string disk_offset_in_blocks)
+ (Int63.to_string disk_offset_in_block)
+ (Int63.to_string size)
+ (Int63.to_string size_in_blocks)
+ (Int63.to_string size_in_block)
+ (string_of_owner owner)
+ (Int63.to_string owner_offset)
+ ) ownership
+ )