From: Richard W.M. Jones <"Richard W.M. Jones "> Date: Wed, 30 Apr 2008 13:30:31 +0000 (+0100) Subject: First steps to building ownership tables. X-Git-Url: http://git.annexia.org/?a=commitdiff_plain;h=de49d4605c37574f38b55b400db310f368640c94;p=virt-df.git First steps to building ownership tables. --- diff --git a/.hgignore b/.hgignore index d9e44d7..0a14c78 100644 --- 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 diff --git a/lib/diskimage.ml b/lib/diskimage.ml index 6f9ef1f..389358b 100644 --- a/lib/diskimage.ml +++ b/lib/diskimage.ml @@ -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 + + diff --git a/lib/diskimage.mli b/lib/diskimage.mli index b926193..0689a69 100644 --- a/lib/diskimage.mli +++ b/lib/diskimage.mli @@ -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 diff --git a/lib/diskimage_lvm2.ml b/lib/diskimage_lvm2.ml index 4432e90..143f32b 100644 --- a/lib/diskimage_lvm2.ml +++ b/lib/diskimage_lvm2.ml @@ -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 diff --git a/lib/diskimage_mbr.ml b/lib/diskimage_mbr.ml index 30c5dc4..34e4061 100644 --- a/lib/diskimage_mbr.ml +++ b/lib/diskimage_mbr.ml @@ -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 *) diff --git a/lib/diskimage_utils.ml b/lib/diskimage_utils.ml index 80a7e3a..6abb608 100644 --- a/lib/diskimage_utils.ml +++ b/lib/diskimage_utils.ml @@ -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. *) } diff --git a/lib/diskimage_utils.mli b/lib/diskimage_utils.mli index 641483d..6f813fe 100644 --- a/lib/diskimage_utils.mli +++ b/lib/diskimage_utils.mli @@ -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 = {