First steps to building ownership tables.
authorRichard W.M. Jones <rjones@redhat.com>
Wed, 30 Apr 2008 13:30:31 +0000 (14:30 +0100)
committerRichard W.M. Jones <rjones@redhat.com>
Wed, 30 Apr 2008 13:30:31 +0000 (14:30 +0100)
.hgignore
lib/diskimage.ml
lib/diskimage.mli
lib/diskimage_lvm2.ml
lib/diskimage_mbr.ml
lib/diskimage_utils.ml
lib/diskimage_utils.mli

index d9e44d7..0a14c78 100644 (file)
--- a/.hgignore
+++ b/.hgignore
@@ -36,4 +36,5 @@ po/*.po.bak
 lib/diskimage_lvm2_lexer.ml
 lib/diskimage_lvm2_parser.ml
 lib/diskimage_lvm2_parser.mli
-lib/int63.ml
\ No newline at end of file
+lib/int63.ml
+*.img
index 6f9ef1f..389358b 100644 (file)
@@ -132,6 +132,7 @@ let close_machine { m_disks = m_disks } =
   (* Only close the disks, assume all other devices are derived from them. *)
   List.iter (fun { d_dev = d_dev } -> d_dev#close ()) m_disks
 
+(* Main scanning function for filesystems. *)
 let scan_machine ({ m_disks = m_disks } as machine) =
   let m_disks = List.map (
     fun ({ d_dev = dev } as disk) ->
@@ -247,3 +248,156 @@ let scan_machine ({ m_disks = m_disks } as machine) =
   { machine with
       m_disks = m_disks;
       m_lv_filesystems = filesystems }
+
+(* 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
+
+  (* Iterate over the blocks in a single filesystem. *)
+  and iter_over_filesystem disks {fs_dev = dev} owner =
+    iter_over_device disks 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;
+
+    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
+
+  (* Iterate over the blocks in a PV. *)
+  and iter_over_pv disks {pv_dev = dev} owner =
+    iter_over_device disks 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.
+   * 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 =
+    let size = dev#size in
+
+    let rec loop 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)
+      )
+    in
+    loop ~^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)
+     * then we've hit the bottom layer of devices, so just return it.
+     *)
+    if List.memq dev disks then
+      [dev, offset], this_extent
+    else (
+      let blocksize = dev#blocksize in
+      let block = offset /^ blocksize in
+      let offset_in_block = offset -^ block *^ blocksize in
+
+      (* Map from this block to the devices one layer down. *)
+      let devs = dev#map_block block in
+
+      (* Get the real device offsets, adding the offset from start of block. *)
+      let devs =
+       List.map
+         (fun (dev, dev_offset) -> dev, dev_offset +^ offset_in_block)
+         devs in
+
+      let devs =
+       List.map
+         (fun (dev, dev_offset) ->
+            map_recursively disks dev dev_offset)
+         devs in
+
+      (* Work out the minimum contiguous extent from this offset. *)
+      let devs, extent =
+       let extents = List.map snd devs in
+       let devs = List.concat (List.map fst devs) in
+       let extent = List.fold_left min this_extent extents in
+       devs, extent in
+
+      devs, extent
+    )
+
+  and string_of_owner = function
+    | `Filesystem {fs_plugin_id = fs_plugin_id; fs_dev = fs_dev} ->
+       sprintf "%s(%s)" fs_dev#name fs_plugin_id
+    | `PhysicalVolume { pv_uuid = pv_uuid } ->
+       "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
+
+
index b926193..0689a69 100644 (file)
@@ -203,6 +203,7 @@ and disk_content =
 
 and partitions = {
   parts_plugin_id : parts_plugin_id;   (** Partitioning scheme. *)
+  parts_dev : device;                  (** Partitions (whole) device. *)
   parts : partition list;              (** Partitions. *)
 }
 and partition = {
@@ -239,6 +240,7 @@ and filesystem = {
 and pv = {
   lvm_plugin_id : lvm_plugin_id;        (** The LVM plug-in which detected
                                            this. *)
+  pv_dev : device;                     (** Device covering whole PV. *)
   pv_uuid : string;                    (** UUID. *)
 }
 and lv = {
@@ -256,7 +258,9 @@ val name_of_filesystem : fs_plugin_id -> string
 val name_of_lvm : lvm_plugin_id -> string
   (** Convert plug-in IDs to printable strings. *)
 
-(** {2 Scanning functions} *)
+(** {2 Functions} *)
+
+(** {3 Create 'machine'} *)
 
 val open_machine : string -> (string * string) list -> machine
   (** [open_machine m_name devs]
@@ -278,6 +282,8 @@ val close_machine : machine -> unit
       opened by these devices.
   *)
 
+(** {3 Scanning for filesystems} *)
+
 val scan_machine : machine -> machine
   (** This does a complete scan of all devices owned by a machine,
       identifying all partitions, filesystems, physical and logical
@@ -288,6 +294,13 @@ val scan_machine : machine -> machine
       Returns an updated {!machine} structure with the scan results.
   *)
 
+(** {3 Create ownership tables} *)
+
+val create_ownership : machine -> (*ownership*)unit
+  (** This creates the ownership tables (mapping disk blocks to the
+      ultimate filesystem, etc., which owns each).
+  *)
+
 (** {2 Debugging} *)
 
 val debug : bool ref
index 4432e90..143f32b 100644 (file)
@@ -107,7 +107,7 @@ let rec probe lvm_plugin_id dev =
     let uuid, _ = read_pv_label dev in
     if !debug then
       eprintf "LVM2 detected PV UUID %s\n%!" uuid;
-    { lvm_plugin_id = lvm_plugin_id; pv_uuid = uuid }
+    { lvm_plugin_id = lvm_plugin_id; pv_uuid = uuid; pv_dev = dev }
   with exn ->
     if !debug then prerr_endline (Printexc.to_string exn);
     raise Not_found
index 30c5dc4..34e4061 100644 (file)
@@ -91,7 +91,7 @@ let rec probe dev =
       let extendeds = List.concat extendeds in
       primaries @ extendeds
 *)
-      { parts_plugin_id = plugin_id; parts = primaries }
+      { parts_plugin_id = plugin_id; parts_dev = dev; parts = primaries }
 
   | { _ } ->
       raise Not_found                  (* not an MBR *)
index 80a7e3a..6abb608 100644 (file)
@@ -186,6 +186,7 @@ and disk_content =
 
 and partitions = {
   parts_plugin_id : parts_plugin_id;   (* Partitioning scheme. *)
+  parts_dev : device;                  (* Partitions (whole) device. *)
   parts : partition list               (* Partitions. *)
 }
 and partition = {
@@ -220,6 +221,7 @@ and filesystem = {
 (* Physical volumes. *)
 and pv = {
   lvm_plugin_id : lvm_plugin_id;        (* The LVM plug-in. *)
+  pv_dev : device;                     (* Device covering whole PV. *)
   pv_uuid : string;                    (* UUID. *)
 }
 
index 641483d..6f813fe 100644 (file)
@@ -91,6 +91,7 @@ and disk_content =
 
 and partitions = {
   parts_plugin_id : parts_plugin_id;
+  parts_dev : device;
   parts : partition list;
 }
 and partition = {
@@ -124,6 +125,7 @@ and filesystem = {
 
 and pv = {
   lvm_plugin_id : lvm_plugin_id;
+  pv_dev : device;
   pv_uuid : string;
 }
 and lv = {