From e6cca10e5cf86b9bd280e371fb1195835a96bff0 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Fri, 28 Mar 2008 17:12:47 +0000 Subject: Internationalize virt-df program. --- virt-df/virt_df_lvm2.ml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) mode change 100755 => 100644 virt-df/virt_df_lvm2.ml (limited to 'virt-df/virt_df_lvm2.ml') diff --git a/virt-df/virt_df_lvm2.ml b/virt-df/virt_df_lvm2.ml old mode 100755 new mode 100644 index 8dc0c05..d01a5a8 --- a/virt-df/virt_df_lvm2.ml +++ b/virt-df/virt_df_lvm2.ml @@ -21,6 +21,7 @@ *) open Printf +open Virt_df_gettext.Gettext (* Int64 operators for convenience. *) let (+^) = Int64.add @@ -29,7 +30,7 @@ let ( *^ ) = Int64.mul let (/^) = Int64.div let probe_lvm2 target part_type fd start size = - Virt_df.ProbeFailed "LVM2 not supported yet" + Virt_df.ProbeFailed (s_ "LVM2 not supported yet") (* Register with main code. *) let () = -- cgit From e6050cae9eee80791c3bb26f34c61f7dc89b142f Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Mon, 14 Apr 2008 17:48:49 +0100 Subject: Complete rewrite of virt-df: - Uses pa_bitmatch for robust parsing of disk structures. - Completely modularized. --- virt-df/virt_df_lvm2.ml | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) (limited to 'virt-df/virt_df_lvm2.ml') diff --git a/virt-df/virt_df_lvm2.ml b/virt-df/virt_df_lvm2.ml index d01a5a8..a79ec7f 100644 --- a/virt-df/virt_df_lvm2.ml +++ b/virt-df/virt_df_lvm2.ml @@ -22,18 +22,11 @@ open Printf open Virt_df_gettext.Gettext +open Virt_df -(* Int64 operators for convenience. *) -let (+^) = Int64.add -let (-^) = Int64.sub -let ( *^ ) = Int64.mul -let (/^) = Int64.div - -let probe_lvm2 target part_type fd start size = - Virt_df.ProbeFailed (s_ "LVM2 not supported yet") +let probe_lvm2 (dev : device) = + raise Not_found (* Register with main code. *) let () = - Virt_df.fs_register - [ 0x8e ] (* Partition type. *) - probe_lvm2 + filesystem_type_register "LVM2" probe_lvm2 -- cgit From 0019c13c600d34f12778e849246711bb20ba4ee2 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Tue, 15 Apr 2008 11:26:46 +0100 Subject: Don't need the ': device' typecasts any more. --- virt-df/virt_df_lvm2.ml | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) (limited to 'virt-df/virt_df_lvm2.ml') diff --git a/virt-df/virt_df_lvm2.ml b/virt-df/virt_df_lvm2.ml index a79ec7f..4247dc3 100644 --- a/virt-df/virt_df_lvm2.ml +++ b/virt-df/virt_df_lvm2.ml @@ -24,9 +24,33 @@ open Printf open Virt_df_gettext.Gettext open Virt_df -let probe_lvm2 (dev : device) = - raise Not_found +let sector_size = 512 +let sector_size64 = 512L + +let pv_label_offset = sector_size64 + +let rec probe_pv dev = + try ignore (read_pv_label dev); true + with _ -> false + +and read_pv_label dev = + (* Load the second sector. *) + let bits = dev#read_bitstring pv_label_offset sector_size in + + bitmatch bits with + | labelone : 8*8 : bitstring; (* "LABELONE" *) + padding : 16*8 : bitstring; + lvm2_ver : 8*8 : bitstring; (* "LVM2 001" *) + uuid : 32*8 : bitstring (* UUID *) + when Bitmatch.string_of_bitstring labelone = "LABELONE" && + Bitmatch.string_of_bitstring lvm2_ver = "LVM2 001" -> + uuid + | _ -> + invalid_arg (sprintf "read_pv_label: %s: not an LVM2 physical volume" + dev#name) + +let list_lvs devs = [] (* Register with main code. *) let () = - filesystem_type_register "LVM2" probe_lvm2 + lvm_type_register "LVM2" probe_pv list_lvs -- cgit From bb0788a39d9b8675db60a61ecd2baebfdfb5ca10 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Tue, 15 Apr 2008 11:44:54 +0100 Subject: LVM2 PV detection. --- virt-df/virt_df_lvm2.ml | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'virt-df/virt_df_lvm2.ml') diff --git a/virt-df/virt_df_lvm2.ml b/virt-df/virt_df_lvm2.ml index 4247dc3..9355597 100644 --- a/virt-df/virt_df_lvm2.ml +++ b/virt-df/virt_df_lvm2.ml @@ -29,6 +29,7 @@ let sector_size64 = 512L let pv_label_offset = sector_size64 +(* Probe to see if it's an LVM2 PV. Look for the "LABELONE" label. *) let rec probe_pv dev = try ignore (read_pv_label dev); true with _ -> false @@ -37,6 +38,8 @@ and read_pv_label dev = (* Load the second sector. *) let bits = dev#read_bitstring pv_label_offset sector_size in + Bitmatch.hexdump_bitstring stdout bits; + bitmatch bits with | labelone : 8*8 : bitstring; (* "LABELONE" *) padding : 16*8 : bitstring; @@ -49,6 +52,11 @@ and read_pv_label dev = invalid_arg (sprintf "read_pv_label: %s: not an LVM2 physical volume" dev#name) +(* We are passed a list of devices which we previously identified + * as PVs belonging to us. From these produce a list of all LVs + * (as devices) and return them. Note that we don't try to detect + * what is on these LVs - that will be done in the main code. + *) let list_lvs devs = [] (* Register with main code. *) -- cgit From 2f24ddc7c65beb0df82f208bf7410ea09102f7a8 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Tue, 15 Apr 2008 13:51:57 +0100 Subject: Refactor the types so we have distinct PV & LV types. --- virt-df/virt_df_lvm2.ml | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'virt-df/virt_df_lvm2.ml') diff --git a/virt-df/virt_df_lvm2.ml b/virt-df/virt_df_lvm2.ml index 9355597..dc97656 100644 --- a/virt-df/virt_df_lvm2.ml +++ b/virt-df/virt_df_lvm2.ml @@ -24,21 +24,25 @@ open Printf open Virt_df_gettext.Gettext open Virt_df +let plugin_name = "LVM2" + let sector_size = 512 let sector_size64 = 512L let pv_label_offset = sector_size64 (* Probe to see if it's an LVM2 PV. Look for the "LABELONE" label. *) -let rec probe_pv dev = - try ignore (read_pv_label dev); true - with _ -> false +let rec probe_pv lvm_plugin_id dev = + try + let uuid = read_pv_label dev in + { lvm_plugin_id = lvm_plugin_id; pv_uuid = uuid } + with _ -> raise Not_found and read_pv_label dev = (* Load the second sector. *) let bits = dev#read_bitstring pv_label_offset sector_size in - Bitmatch.hexdump_bitstring stdout bits; + (*Bitmatch.hexdump_bitstring stdout bits;*) bitmatch bits with | labelone : 8*8 : bitstring; (* "LABELONE" *) @@ -47,7 +51,7 @@ and read_pv_label dev = uuid : 32*8 : bitstring (* UUID *) when Bitmatch.string_of_bitstring labelone = "LABELONE" && Bitmatch.string_of_bitstring lvm2_ver = "LVM2 001" -> - uuid + Bitmatch.string_of_bitstring uuid | _ -> invalid_arg (sprintf "read_pv_label: %s: not an LVM2 physical volume" dev#name) @@ -61,4 +65,4 @@ let list_lvs devs = [] (* Register with main code. *) let () = - lvm_type_register "LVM2" probe_pv list_lvs + lvm_type_register plugin_name probe_pv list_lvs -- cgit From bf03017c3a390f75130d810bed403008abcbe7f4 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Tue, 15 Apr 2008 15:08:34 +0100 Subject: Read out metadata offset & length from PV header. --- virt-df/virt_df_lvm2.ml | 54 ++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 12 deletions(-) (limited to 'virt-df/virt_df_lvm2.ml') diff --git a/virt-df/virt_df_lvm2.ml b/virt-df/virt_df_lvm2.ml index dc97656..abc247e 100644 --- a/virt-df/virt_df_lvm2.ml +++ b/virt-df/virt_df_lvm2.ml @@ -29,29 +29,58 @@ let plugin_name = "LVM2" let sector_size = 512 let sector_size64 = 512L -let pv_label_offset = sector_size64 - (* Probe to see if it's an LVM2 PV. Look for the "LABELONE" label. *) let rec probe_pv lvm_plugin_id dev = try - let uuid = read_pv_label dev in + let uuid, metadata_offset, metadata_length = read_pv_label dev in + if debug then + eprintf "LVM2 detected UUID %s md offset 0x%lx len %ld\n%!" + uuid metadata_offset metadata_length; { lvm_plugin_id = lvm_plugin_id; pv_uuid = uuid } with _ -> raise Not_found and read_pv_label dev = - (* Load the second sector. *) - let bits = dev#read_bitstring pv_label_offset sector_size in + (* Load the first 8 sectors. I found by experimentation that + * the second sector contains the header ("LABELONE" etc) and + * the nineth sector contains some additional information about + * the location of the current metadata. + *) + let bits = dev#read_bitstring 0L (9 * sector_size) in - (*Bitmatch.hexdump_bitstring stdout bits;*) + Bitmatch.hexdump_bitstring stdout bits; bitmatch bits with - | labelone : 8*8 : bitstring; (* "LABELONE" *) - padding : 16*8 : bitstring; + | sector0 : sector_size*8 : bitstring; (* sector 0 *) + labelone : 8*8 : bitstring; (* "LABELONE" *) + padding : 16*8 : bitstring; (* Seems to contain something. *) lvm2_ver : 8*8 : bitstring; (* "LVM2 001" *) - uuid : 32*8 : bitstring (* UUID *) + uuid : 32*8 : bitstring; (* UUID *) + padding2 : (sector_size-64)*8 : bitstring; (* to end of second sector *) + sector234567 : sector_size*8 * 6 : bitstring; (* sectors 2-6 *) + padding3 : 0x28*8 : bitstring; (* start of sector 8 *) + metadata_offset : 32 : littleendian;(* metadata offset *) + padding4 : 4*8 : bitstring; + metadata_length : 32 : littleendian (* length of metadata (bytes) *) when Bitmatch.string_of_bitstring labelone = "LABELONE" && - Bitmatch.string_of_bitstring lvm2_ver = "LVM2 001" -> - Bitmatch.string_of_bitstring uuid + Bitmatch.string_of_bitstring lvm2_ver = "LVM2 001" -> + let metadata_offset = metadata_offset +* 0x1000_l in + + (* Check the metadata offset & length look reasonable for this + * device. Otherwise maybe it's a newer or older header which + * we don't really understand properly. + *) + let () = + let size = + if dev#size <= Int64.of_int32 Int32.max_int then Int64.to_int32 dev#size + else Int32.max_int in + if metadata_offset < 0x1200_l || metadata_offset >= size + || metadata_length < 0_l || metadata_offset+*metadata_length >= size + then + invalid_arg "read_pv_label: bad metadata offset or length" in + + Bitmatch.string_of_bitstring uuid, metadata_offset, metadata_length + + | _ -> invalid_arg (sprintf "read_pv_label: %s: not an LVM2 physical volume" dev#name) @@ -61,7 +90,8 @@ and read_pv_label dev = * (as devices) and return them. Note that we don't try to detect * what is on these LVs - that will be done in the main code. *) -let list_lvs devs = [] +let list_lvs devs = + [] (* Register with main code. *) let () = -- cgit From b25ac692bd7107b56850de8fa25123791dfdf73e Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Tue, 15 Apr 2008 15:27:06 +0100 Subject: Read out the actual metadata. --- virt-df/virt_df_lvm2.ml | 55 +++++++++++++++++++++++++++++-------------------- 1 file changed, 33 insertions(+), 22 deletions(-) (limited to 'virt-df/virt_df_lvm2.ml') diff --git a/virt-df/virt_df_lvm2.ml b/virt-df/virt_df_lvm2.ml index abc247e..afcab66 100644 --- a/virt-df/virt_df_lvm2.ml +++ b/virt-df/virt_df_lvm2.ml @@ -32,12 +32,13 @@ let sector_size64 = 512L (* Probe to see if it's an LVM2 PV. Look for the "LABELONE" label. *) let rec probe_pv lvm_plugin_id dev = try - let uuid, metadata_offset, metadata_length = read_pv_label dev in + let uuid, _ = read_pv_label dev in if debug then - eprintf "LVM2 detected UUID %s md offset 0x%lx len %ld\n%!" - uuid metadata_offset metadata_length; + eprintf "LVM2 detected PV UUID %s\n%!" uuid; { lvm_plugin_id = lvm_plugin_id; pv_uuid = uuid } - with _ -> raise Not_found + with exn -> + if debug then prerr_endline (Printexc.to_string exn); + raise Not_found and read_pv_label dev = (* Load the first 8 sectors. I found by experimentation that @@ -47,7 +48,7 @@ and read_pv_label dev = *) let bits = dev#read_bitstring 0L (9 * sector_size) in - Bitmatch.hexdump_bitstring stdout bits; + (*Bitmatch.hexdump_bitstring stdout bits;*) bitmatch bits with | sector0 : sector_size*8 : bitstring; (* sector 0 *) @@ -64,26 +65,36 @@ and read_pv_label dev = when Bitmatch.string_of_bitstring labelone = "LABELONE" && Bitmatch.string_of_bitstring lvm2_ver = "LVM2 001" -> let metadata_offset = metadata_offset +* 0x1000_l in + let metadata = read_metadata dev metadata_offset metadata_length in + (*prerr_endline metadata;*) + let uuid = Bitmatch.string_of_bitstring uuid in - (* Check the metadata offset & length look reasonable for this - * device. Otherwise maybe it's a newer or older header which - * we don't really understand properly. - *) - let () = - let size = - if dev#size <= Int64.of_int32 Int32.max_int then Int64.to_int32 dev#size - else Int32.max_int in - if metadata_offset < 0x1200_l || metadata_offset >= size - || metadata_length < 0_l || metadata_offset+*metadata_length >= size - then - invalid_arg "read_pv_label: bad metadata offset or length" in - - Bitmatch.string_of_bitstring uuid, metadata_offset, metadata_length - + uuid, metadata | _ -> - invalid_arg (sprintf "read_pv_label: %s: not an LVM2 physical volume" - dev#name) + invalid_arg + (sprintf "LVM2: read_pv_label: %s: not an LVM2 physical volume" dev#name) + +and read_metadata dev offset32 len32 = + if debug then + eprintf "metadata: offset 0x%lx len %ld bytes\n" offset32 len32; + + (* Check the offset and length are sensible. *) + let offset64 = + if offset32 <= Int32.max_int then Int64.of_int32 offset32 + else invalid_arg "LVM2: read_metadata: metadata offset too large" in + let len64 = + if len32 <= 2_147_483_647_l then Int64.of_int32 len32 + else invalid_arg "LVM2: read_metadata: metadata length too large" in + + if offset64 <= 0x1200L || offset64 >= dev#size + || len64 <= 0L || offset64 +^ len64 >= dev#size then + invalid_arg "LVM2: read_metadata: bad metadata offset or length"; + + (* If it is outside the disk boundaries, this will throw an exception, + * otherwise it will read and return the metadata string. + *) + dev#read offset64 (Int64.to_int len64) (* We are passed a list of devices which we previously identified * as PVs belonging to us. From these produce a list of all LVs -- cgit From 479659599edaaf6cd9385ce00750407d61baf0f0 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Tue, 15 Apr 2008 15:33:08 +0100 Subject: Cosmetic fixes and comments. --- virt-df/virt_df_lvm2.ml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'virt-df/virt_df_lvm2.ml') diff --git a/virt-df/virt_df_lvm2.ml b/virt-df/virt_df_lvm2.ml index afcab66..16d8e89 100644 --- a/virt-df/virt_df_lvm2.ml +++ b/virt-df/virt_df_lvm2.ml @@ -29,7 +29,7 @@ let plugin_name = "LVM2" let sector_size = 512 let sector_size64 = 512L -(* Probe to see if it's an LVM2 PV. Look for the "LABELONE" label. *) +(* Probe to see if it's an LVM2 PV. *) let rec probe_pv lvm_plugin_id dev = try let uuid, _ = read_pv_label dev in @@ -77,7 +77,7 @@ and read_pv_label dev = and read_metadata dev offset32 len32 = if debug then - eprintf "metadata: offset 0x%lx len %ld bytes\n" offset32 len32; + eprintf "metadata: offset 0x%lx len %ld bytes\n%!" offset32 len32; (* Check the offset and length are sensible. *) let offset64 = @@ -102,6 +102,8 @@ and read_metadata dev offset32 len32 = * what is on these LVs - that will be done in the main code. *) let list_lvs devs = + (* Read the UUID and metadata (again) from each device. *) + let uuidmetas = List.map read_pv_label devs in [] (* Register with main code. *) -- cgit From 81294675f6a5058a3381871f1dc99c806922d77c Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Tue, 15 Apr 2008 18:30:49 +0100 Subject: Metadata parser. --- virt-df/virt_df_lvm2.ml | 40 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) (limited to 'virt-df/virt_df_lvm2.ml') diff --git a/virt-df/virt_df_lvm2.ml b/virt-df/virt_df_lvm2.ml index 16d8e89..fcf1fd2 100644 --- a/virt-df/virt_df_lvm2.ml +++ b/virt-df/virt_df_lvm2.ml @@ -24,6 +24,8 @@ open Printf open Virt_df_gettext.Gettext open Virt_df +open Virt_df_lvm2_metadata + let plugin_name = "LVM2" let sector_size = 512 @@ -64,9 +66,16 @@ and read_pv_label dev = metadata_length : 32 : littleendian (* length of metadata (bytes) *) when Bitmatch.string_of_bitstring labelone = "LABELONE" && Bitmatch.string_of_bitstring lvm2_ver = "LVM2 001" -> + + (* Metadata offset is relative to end of PV label. *) let metadata_offset = metadata_offset +* 0x1000_l in + (* Metadata length appears to include the trailing \000 which + * we don't want. + *) + let metadata_length = metadata_length -* 1_l in + let metadata = read_metadata dev metadata_offset metadata_length in - (*prerr_endline metadata;*) + let uuid = Bitmatch.string_of_bitstring uuid in uuid, metadata @@ -101,11 +110,34 @@ and read_metadata dev offset32 len32 = * (as devices) and return them. Note that we don't try to detect * what is on these LVs - that will be done in the main code. *) -let list_lvs devs = - (* Read the UUID and metadata (again) from each device. *) - let uuidmetas = List.map read_pv_label devs in +let rec list_lvs devs = + (* Read the UUID and metadata (again) from each device to end up with + * an assoc list of PVs, keyed on the UUID. + *) + let pvs = List.map read_pv_label devs in + + (* Parse the metadata using the external lexer/parser. *) + let pvs = List.map ( + fun (uuid, metadata) -> + eprintf "parsing: %s\n<<<<\n" metadata; + uuid, Virt_df_lvm2_lexer.parse_lvm2_metadata_from_string metadata + ) pvs in + + (* Print the parsed metadata. *) + List.iter ( + fun (uuid, metadata) -> + eprintf "metadata for UUID %s:\n" uuid; + output_metadata stderr metadata + ) pvs; + [] + + + + + + (* Register with main code. *) let () = lvm_type_register plugin_name probe_pv list_lvs -- cgit From 291265b7171d332d2969e07ac189d876e3d7f26d Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Tue, 15 Apr 2008 22:31:24 +0100 Subject: Almost complete VG & LV metadata parsing. --- virt-df/virt_df_lvm2.ml | 140 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 130 insertions(+), 10 deletions(-) (limited to 'virt-df/virt_df_lvm2.ml') diff --git a/virt-df/virt_df_lvm2.ml b/virt-df/virt_df_lvm2.ml index fcf1fd2..af58f97 100644 --- a/virt-df/virt_df_lvm2.ml +++ b/virt-df/virt_df_lvm2.ml @@ -21,6 +21,8 @@ *) open Printf +open ExtList + open Virt_df_gettext.Gettext open Virt_df @@ -114,29 +116,147 @@ let rec list_lvs devs = (* Read the UUID and metadata (again) from each device to end up with * an assoc list of PVs, keyed on the UUID. *) - let pvs = List.map read_pv_label devs in + let pvs = List.map ( + fun dev -> + let uuid, metadata = read_pv_label dev in + (uuid, (metadata, dev)) + ) devs in (* Parse the metadata using the external lexer/parser. *) let pvs = List.map ( - fun (uuid, metadata) -> - eprintf "parsing: %s\n<<<<\n" metadata; - uuid, Virt_df_lvm2_lexer.parse_lvm2_metadata_from_string metadata + fun (uuid, (metadata, dev)) -> + uuid, (Virt_df_lvm2_lexer.parse_lvm2_metadata_from_string metadata, + dev) ) pvs in - (* Print the parsed metadata. *) + (* Print the parsed metadata. List.iter ( - fun (uuid, metadata) -> + fun (uuid, (metadata, dev)) -> eprintf "metadata for UUID %s:\n" uuid; output_metadata stderr metadata ) pvs; + *) - [] - - + (* Scan for volume groups. The first entry in the metadata + * appears to be the volume group name. This gives us a + * list of VGs and the metadata for each underlying PV. + *) + let vgnames = + List.filter_map ( + function + | pvuuid, (((vgname, Metadata vgmeta) :: _), dev) -> + Some (vgname, (pvuuid, vgmeta)) + | _ -> None + ) pvs in + + let cmp ((a:string),_) ((b:string),_) = compare a b in + let vgnames = List.sort ~cmp vgnames in + let vgs = group_by vgnames in + + (* Note that the metadata is supposed to be duplicated + * identically across all PVs (for redundancy purposes). + * In theory we should check this and use the 'seqno' + * field to find the latest metadata if it doesn't match, + * but in fact we don't check this. + *) + let vgs = List.map ( + fun (vgname, metas) -> + let pvuuids = List.map fst metas in + let _, vgmeta = List.hd metas in (* just pick any metadata *) + vgname, (pvuuids, vgmeta)) vgs in + (* Print the VGs. *) + if debug then + List.iter ( + fun (vgname, (pvuuids, vgmeta)) -> + eprintf "VG %s is on PVs: %s\n%!" vgname (String.concat "," pvuuids) + ) vgs; + (* Some useful getter functions. If these can't get a value + * from the metadata or if the type is wrong they raise Not_found. + *) + let rec get_int64 field meta = + match List.assoc field meta with + | Int i -> i + | _ -> raise Not_found + and get_int field meta min max = + match List.assoc field meta with + | Int i when Int64.of_int min <= i && i <= Int64.of_int max -> + Int64.to_int i + | _ -> raise Not_found + and get_string field meta = + match List.assoc field meta with + | String s -> s + | _ -> raise Not_found + and get_meta field meta = + match List.assoc field meta with + | Metadata md -> md + | _ -> raise Not_found in + in + + (* Scan for logical volumes. Each VG contains several LVs. + * This gives us a list of LVs within each VG (hence extends + * the vgs variable). + *) + let vgs = List.map ( + fun (vgname, (pvuuids, vgmeta)) -> + let lvs = + try + let extent_size = get_int "extent_size" vgmeta 0 (256*1024) in + let lvs = get_meta "logical_volumes" vgmeta in + let lvs = List.filter_map ( + function + | lvname, Metadata lvmeta -> + (try + let segment_count = get_int "segment_count" lvmeta 0 1024 in + + (* Get the segments for this LV. *) + let segments = range 1 (segment_count+1) in + let segments = + List.map + (fun i -> get_meta ("segment" ^ string_of_int i) lvmeta) + segments in + + let segments = + List.map ( + fun segmeta -> + let start_extent = + get_int64 "start_extent" segmeta in + let extent_count = + get_int64 "extent_count" segmeta in + let segtype = get_string "type" segmeta in + if segtype <> "striped" then raise Not_found; + let stripe_count = + get_int "stripe_count" segmeta 0 1024 in + (* let stripes = in *) + + (start_extent, extent_count, stripe_count) + ) segments in + + Some (lvname, (lvmeta, segments)) + with + (* Something went wrong with segments - omit this LV. *) + Not_found -> None) + | _ -> None + ) lvs in + + lvs + with + Not_found -> + (* Something went wrong - assume no LVs found. *) + [] in + (vgname, (pvuuids, vgmeta, lvs)) + ) vgs in + + (* Print the LVs. *) + if debug then + List.iter ( + fun (vgname, (pvuuids, vgmeta, lvs)) -> + let lvnames = List.map fst lvs in + eprintf "VG %s contains LVs: %s\n%!" vgname (String.concat ", " lvnames) + ) vgs; - + [] (* Register with main code. *) let () = -- cgit From 027b0d92ed236fa24f211e053e81189cddffe7d7 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Wed, 16 Apr 2008 08:15:56 +0100 Subject: Make debug selectable at runtime. --- virt-df/virt_df_lvm2.ml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'virt-df/virt_df_lvm2.ml') diff --git a/virt-df/virt_df_lvm2.ml b/virt-df/virt_df_lvm2.ml index af58f97..314586e 100644 --- a/virt-df/virt_df_lvm2.ml +++ b/virt-df/virt_df_lvm2.ml @@ -37,11 +37,11 @@ let sector_size64 = 512L let rec probe_pv lvm_plugin_id dev = try let uuid, _ = read_pv_label dev in - if debug then + if !debug then eprintf "LVM2 detected PV UUID %s\n%!" uuid; { lvm_plugin_id = lvm_plugin_id; pv_uuid = uuid } with exn -> - if debug then prerr_endline (Printexc.to_string exn); + if !debug then prerr_endline (Printexc.to_string exn); raise Not_found and read_pv_label dev = @@ -87,7 +87,7 @@ and read_pv_label dev = (sprintf "LVM2: read_pv_label: %s: not an LVM2 physical volume" dev#name) and read_metadata dev offset32 len32 = - if debug then + if !debug then eprintf "metadata: offset 0x%lx len %ld bytes\n%!" offset32 len32; (* Check the offset and length are sensible. *) @@ -166,7 +166,7 @@ let rec list_lvs devs = vgname, (pvuuids, vgmeta)) vgs in (* Print the VGs. *) - if debug then + if !debug then List.iter ( fun (vgname, (pvuuids, vgmeta)) -> eprintf "VG %s is on PVs: %s\n%!" vgname (String.concat "," pvuuids) @@ -249,7 +249,7 @@ let rec list_lvs devs = ) vgs in (* Print the LVs. *) - if debug then + if !debug then List.iter ( fun (vgname, (pvuuids, vgmeta, lvs)) -> let lvnames = List.map fst lvs in -- cgit From 81593022de32f72e6dd7430519009cb70659eab6 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Wed, 16 Apr 2008 12:08:54 +0100 Subject: LVM2 parsing complete and working. --- virt-df/virt_df_lvm2.ml | 207 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 188 insertions(+), 19 deletions(-) (limited to 'virt-df/virt_df_lvm2.ml') diff --git a/virt-df/virt_df_lvm2.ml b/virt-df/virt_df_lvm2.ml index 314586e..6a8f573 100644 --- a/virt-df/virt_df_lvm2.ml +++ b/virt-df/virt_df_lvm2.ml @@ -33,6 +33,63 @@ let plugin_name = "LVM2" let sector_size = 512 let sector_size64 = 512L +(*----------------------------------------------------------------------*) +(* Block device which can do linear maps, same as the kernel dm-linear.c *) +class linear_map_device name extent_size segments = + (* The segments are passed containing (start_extent, extent_count, ...) + * but it's easier to deal with (start_extent, end_extent, ...) so + * rewrite them. + *) + let segments = List.map + (fun (start_extent, extent_count, dev, pvoffset) -> + (start_extent, start_extent +^ extent_count, dev, pvoffset) + ) segments in + + (* Calculate the size of the device (in bytes). Note that because + * of the random nature of the mapping this doesn't imply that we can + * satisfy any read request up to the full size. + *) + let size_in_extents = + List.fold_left max 0L + (List.map (fun (_, end_extent, _, _) -> end_extent) segments) in + let size = size_in_extents *^ extent_size in +object + inherit device + method name = name + method size = size + + (* Read method checks which segment the request lies inside and + * maps it to the underlying device. If there is no mapping then + * we have to return an error. + * + * The request must lie inside a single extent, otherwise this is + * also an error (XXX - should lift this restriction, however default + * extent size is 4 MB so we probably won't hit this very often). + *) + method read offset len = + let offset_in_extents = offset /^ extent_size in + + (* Check we don't cross an extent boundary. *) + if (offset +^ Int64.of_int (len-1)) /^ extent_size <> offset_in_extents + then invalid_arg "linear_map_device: request crosses extent boundary"; + + if offset_in_extents < 0L || offset_in_extents >= size_in_extents then + invalid_arg "linear_map_device: read outside device"; + + let rec loop = function + | [] -> + invalid_arg "linear_map_device: offset not mapped" + | (start_extent, end_extent, dev, pvoffset) :: rest -> + eprintf "pvoffset = %Ld\n" pvoffset; + if start_extent <= offset_in_extents && + offset_in_extents < end_extent + then dev#read (offset +^ pvoffset *^ extent_size) len + else loop rest + in + loop segments +end + +(*----------------------------------------------------------------------*) (* Probe to see if it's an LVM2 PV. *) let rec probe_pv lvm_plugin_id dev = try @@ -107,6 +164,7 @@ and read_metadata dev offset32 len32 = *) dev#read offset64 (Int64.to_int len64) +(*----------------------------------------------------------------------*) (* We are passed a list of devices which we previously identified * as PVs belonging to us. From these produce a list of all LVs * (as devices) and return them. Note that we don't try to detect @@ -129,13 +187,13 @@ let rec list_lvs devs = dev) ) pvs in - (* Print the parsed metadata. - List.iter ( - fun (uuid, (metadata, dev)) -> - eprintf "metadata for UUID %s:\n" uuid; - output_metadata stderr metadata - ) pvs; - *) + (* Print the parsed metadata. *) + if !debug then + List.iter ( + fun (uuid, (metadata, dev)) -> + eprintf "metadata for PV UUID %s on %s:\n" uuid dev#name; + output_metadata stderr metadata + ) pvs; (* Scan for volume groups. The first entry in the metadata * appears to be the volume group name. This gives us a @@ -191,18 +249,76 @@ let rec list_lvs devs = and get_meta field meta = match List.assoc field meta with | Metadata md -> md - | _ -> raise Not_found in + | _ -> raise Not_found + and get_stripes field meta = (* List of (string,int) pairs. *) + match List.assoc field meta with + | List xs -> + let rec loop = function + | [] -> [] + | String pvname :: Int offset :: xs -> + (pvname, offset) :: loop xs + | _ -> raise Not_found + in + loop xs + | _ -> raise Not_found in + (* The volume groups refer to the physical volumes using their + * own naming system ("pv0", "pv1", etc.) instead of PV UUIDs. + * + * Each PV also has a start (in sectors) & count (in extents) + * of the writable area (the bit after the superblock and metadata) + * which normally starts at sector 384. + * + * Create a PV device (simple offset + size) and a map from PV + * names to these devices. + *) + let vgs = List.map ( + fun (vgname, (pvuuids, vgmeta)) -> + let pvdevs, extent_size = + try + (* NB: extent_size is in sectors here - we convert to bytes. *) + let extent_size = get_int "extent_size" vgmeta 0 (1024*1024) in + let extent_size = Int64.of_int extent_size *^ sector_size64 in + + (* Get the physical_volumes section of the metadata. *) + let pvdevs = get_meta "physical_volumes" vgmeta in + + List.filter_map ( + function + | (pvname, Metadata meta) -> + (* Get the UUID. *) + let pvuuid = get_string "id" meta in + let pvuuid = canonical_uuid pvuuid in + + (* Get the underlying physical device. *) + let _, dev = List.assoc pvuuid pvs in + + (* Construct a PV device. *) + let pe_start = get_int64 "pe_start" meta in + let pe_start = pe_start *^ sector_size64 in + let pe_count = get_int64 "pe_count" meta in + let pe_count = pe_count *^ extent_size in + let pvdev = new offset_device pvuuid pe_start pe_count dev in + + Some (pvname, pvdev) + | _ -> + None + ) pvdevs, extent_size + with + (* Something went wrong - just return an empty map. *) + Not_found -> [], 0L in + (vgname, (pvuuids, vgmeta, pvdevs, extent_size)) + ) vgs in + (* Scan for logical volumes. Each VG contains several LVs. * This gives us a list of LVs within each VG (hence extends * the vgs variable). *) let vgs = List.map ( - fun (vgname, (pvuuids, vgmeta)) -> + fun (vgname, (pvuuids, vgmeta, pvdevs, extent_size)) -> let lvs = try - let extent_size = get_int "extent_size" vgmeta 0 (256*1024) in let lvs = get_meta "logical_volumes" vgmeta in let lvs = List.filter_map ( function @@ -225,15 +341,29 @@ let rec list_lvs devs = let extent_count = get_int64 "extent_count" segmeta in let segtype = get_string "type" segmeta in + + (* Can only handle striped segments at the + * moment. XXX + *) if segtype <> "striped" then raise Not_found; + let stripe_count = get_int "stripe_count" segmeta 0 1024 in - (* let stripes = in *) + let stripes = get_stripes "stripes" segmeta in + + if List.length stripes <> stripe_count then + raise Not_found; - (start_extent, extent_count, stripe_count) + (* Can only handle linear striped segments at + * the moment. XXX + *) + if stripe_count <> 1 then raise Not_found; + let pvname, pvoffset = List.hd stripes in + + (start_extent, extent_count, pvname, pvoffset) ) segments in - Some (lvname, (lvmeta, segments)) + Some (lvname, segments) with (* Something went wrong with segments - omit this LV. *) Not_found -> None) @@ -245,19 +375,58 @@ let rec list_lvs devs = Not_found -> (* Something went wrong - assume no LVs found. *) [] in - (vgname, (pvuuids, vgmeta, lvs)) + (vgname, (pvuuids, vgmeta, pvdevs, extent_size, lvs)) ) vgs in (* Print the LVs. *) - if !debug then + if !debug then ( List.iter ( - fun (vgname, (pvuuids, vgmeta, lvs)) -> - let lvnames = List.map fst lvs in - eprintf "VG %s contains LVs: %s\n%!" vgname (String.concat ", " lvnames) + fun (vgname, (pvuuids, vgmeta, pvdevs, extent_size, lvs)) -> + eprintf "VG %s: (extent_size = %Ld bytes)\n" vgname extent_size; + List.iter ( + fun (lvname, segments) -> + eprintf " %s/%s:\n" vgname lvname; + List.iter ( + fun (start_extent, extent_count, pvname, pvoffset) -> + eprintf " start %Ld count %Ld at %s:%Ld\n" + start_extent extent_count pvname pvoffset + ) segments + ) lvs ) vgs; + flush stderr + ); + + (* Finally we can set up devices for the LVs. *) + let lvs = + List.map ( + fun (vgname, (pvuuid, vgmeta, pvdevs, extent_size, lvs)) -> + try + List.map ( + fun (lvname, segments) -> + let name = vgname ^ "/" ^ lvname in + let segments = List.map ( + fun (start_extent, extent_count, pvname, pvoffset) -> + (* Get the PV device. *) + let pvdev = List.assoc pvname pvdevs in + + (* Extents mapped to: *) + (start_extent, extent_count, pvdev, pvoffset) + ) segments in + + (* Create a linear mapping device. *) + let lv_dev = new linear_map_device name extent_size segments in + + { lv_dev = lv_dev } + ) lvs + with + Not_found -> [] + ) vgs in + let lvs = List.concat lvs in - [] + (* Return the list of LV devices. *) + lvs +(*----------------------------------------------------------------------*) (* Register with main code. *) let () = lvm_type_register plugin_name probe_pv list_lvs -- cgit From 02f1c03c9f81e25353aae4900ce19e194b507f71 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Wed, 16 Apr 2008 13:51:14 +0100 Subject: Removed virt-ctrl, virt-df, ocaml-libvirt - now in separate repositories. --- virt-df/virt_df_lvm2.ml | 432 ------------------------------------------------ 1 file changed, 432 deletions(-) delete mode 100644 virt-df/virt_df_lvm2.ml (limited to 'virt-df/virt_df_lvm2.ml') diff --git a/virt-df/virt_df_lvm2.ml b/virt-df/virt_df_lvm2.ml deleted file mode 100644 index 6a8f573..0000000 --- a/virt-df/virt_df_lvm2.ml +++ /dev/null @@ -1,432 +0,0 @@ -(* 'df' command for virtual domains. - - (C) Copyright 2007 Richard W.M. Jones, Red Hat Inc. - http://libvirt.org/ - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - Support for LVM2 PVs. -*) - -open Printf -open ExtList - -open Virt_df_gettext.Gettext -open Virt_df - -open Virt_df_lvm2_metadata - -let plugin_name = "LVM2" - -let sector_size = 512 -let sector_size64 = 512L - -(*----------------------------------------------------------------------*) -(* Block device which can do linear maps, same as the kernel dm-linear.c *) -class linear_map_device name extent_size segments = - (* The segments are passed containing (start_extent, extent_count, ...) - * but it's easier to deal with (start_extent, end_extent, ...) so - * rewrite them. - *) - let segments = List.map - (fun (start_extent, extent_count, dev, pvoffset) -> - (start_extent, start_extent +^ extent_count, dev, pvoffset) - ) segments in - - (* Calculate the size of the device (in bytes). Note that because - * of the random nature of the mapping this doesn't imply that we can - * satisfy any read request up to the full size. - *) - let size_in_extents = - List.fold_left max 0L - (List.map (fun (_, end_extent, _, _) -> end_extent) segments) in - let size = size_in_extents *^ extent_size in -object - inherit device - method name = name - method size = size - - (* Read method checks which segment the request lies inside and - * maps it to the underlying device. If there is no mapping then - * we have to return an error. - * - * The request must lie inside a single extent, otherwise this is - * also an error (XXX - should lift this restriction, however default - * extent size is 4 MB so we probably won't hit this very often). - *) - method read offset len = - let offset_in_extents = offset /^ extent_size in - - (* Check we don't cross an extent boundary. *) - if (offset +^ Int64.of_int (len-1)) /^ extent_size <> offset_in_extents - then invalid_arg "linear_map_device: request crosses extent boundary"; - - if offset_in_extents < 0L || offset_in_extents >= size_in_extents then - invalid_arg "linear_map_device: read outside device"; - - let rec loop = function - | [] -> - invalid_arg "linear_map_device: offset not mapped" - | (start_extent, end_extent, dev, pvoffset) :: rest -> - eprintf "pvoffset = %Ld\n" pvoffset; - if start_extent <= offset_in_extents && - offset_in_extents < end_extent - then dev#read (offset +^ pvoffset *^ extent_size) len - else loop rest - in - loop segments -end - -(*----------------------------------------------------------------------*) -(* Probe to see if it's an LVM2 PV. *) -let rec probe_pv lvm_plugin_id dev = - try - 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 } - with exn -> - if !debug then prerr_endline (Printexc.to_string exn); - raise Not_found - -and read_pv_label dev = - (* Load the first 8 sectors. I found by experimentation that - * the second sector contains the header ("LABELONE" etc) and - * the nineth sector contains some additional information about - * the location of the current metadata. - *) - let bits = dev#read_bitstring 0L (9 * sector_size) in - - (*Bitmatch.hexdump_bitstring stdout bits;*) - - bitmatch bits with - | sector0 : sector_size*8 : bitstring; (* sector 0 *) - labelone : 8*8 : bitstring; (* "LABELONE" *) - padding : 16*8 : bitstring; (* Seems to contain something. *) - lvm2_ver : 8*8 : bitstring; (* "LVM2 001" *) - uuid : 32*8 : bitstring; (* UUID *) - padding2 : (sector_size-64)*8 : bitstring; (* to end of second sector *) - sector234567 : sector_size*8 * 6 : bitstring; (* sectors 2-6 *) - padding3 : 0x28*8 : bitstring; (* start of sector 8 *) - metadata_offset : 32 : littleendian;(* metadata offset *) - padding4 : 4*8 : bitstring; - metadata_length : 32 : littleendian (* length of metadata (bytes) *) - when Bitmatch.string_of_bitstring labelone = "LABELONE" && - Bitmatch.string_of_bitstring lvm2_ver = "LVM2 001" -> - - (* Metadata offset is relative to end of PV label. *) - let metadata_offset = metadata_offset +* 0x1000_l in - (* Metadata length appears to include the trailing \000 which - * we don't want. - *) - let metadata_length = metadata_length -* 1_l in - - let metadata = read_metadata dev metadata_offset metadata_length in - - let uuid = Bitmatch.string_of_bitstring uuid in - - uuid, metadata - - | _ -> - invalid_arg - (sprintf "LVM2: read_pv_label: %s: not an LVM2 physical volume" dev#name) - -and read_metadata dev offset32 len32 = - if !debug then - eprintf "metadata: offset 0x%lx len %ld bytes\n%!" offset32 len32; - - (* Check the offset and length are sensible. *) - let offset64 = - if offset32 <= Int32.max_int then Int64.of_int32 offset32 - else invalid_arg "LVM2: read_metadata: metadata offset too large" in - let len64 = - if len32 <= 2_147_483_647_l then Int64.of_int32 len32 - else invalid_arg "LVM2: read_metadata: metadata length too large" in - - if offset64 <= 0x1200L || offset64 >= dev#size - || len64 <= 0L || offset64 +^ len64 >= dev#size then - invalid_arg "LVM2: read_metadata: bad metadata offset or length"; - - (* If it is outside the disk boundaries, this will throw an exception, - * otherwise it will read and return the metadata string. - *) - dev#read offset64 (Int64.to_int len64) - -(*----------------------------------------------------------------------*) -(* We are passed a list of devices which we previously identified - * as PVs belonging to us. From these produce a list of all LVs - * (as devices) and return them. Note that we don't try to detect - * what is on these LVs - that will be done in the main code. - *) -let rec list_lvs devs = - (* Read the UUID and metadata (again) from each device to end up with - * an assoc list of PVs, keyed on the UUID. - *) - let pvs = List.map ( - fun dev -> - let uuid, metadata = read_pv_label dev in - (uuid, (metadata, dev)) - ) devs in - - (* Parse the metadata using the external lexer/parser. *) - let pvs = List.map ( - fun (uuid, (metadata, dev)) -> - uuid, (Virt_df_lvm2_lexer.parse_lvm2_metadata_from_string metadata, - dev) - ) pvs in - - (* Print the parsed metadata. *) - if !debug then - List.iter ( - fun (uuid, (metadata, dev)) -> - eprintf "metadata for PV UUID %s on %s:\n" uuid dev#name; - output_metadata stderr metadata - ) pvs; - - (* Scan for volume groups. The first entry in the metadata - * appears to be the volume group name. This gives us a - * list of VGs and the metadata for each underlying PV. - *) - let vgnames = - List.filter_map ( - function - | pvuuid, (((vgname, Metadata vgmeta) :: _), dev) -> - Some (vgname, (pvuuid, vgmeta)) - | _ -> None - ) pvs in - - let cmp ((a:string),_) ((b:string),_) = compare a b in - let vgnames = List.sort ~cmp vgnames in - let vgs = group_by vgnames in - - (* Note that the metadata is supposed to be duplicated - * identically across all PVs (for redundancy purposes). - * In theory we should check this and use the 'seqno' - * field to find the latest metadata if it doesn't match, - * but in fact we don't check this. - *) - let vgs = List.map ( - fun (vgname, metas) -> - let pvuuids = List.map fst metas in - let _, vgmeta = List.hd metas in (* just pick any metadata *) - vgname, (pvuuids, vgmeta)) vgs in - - (* Print the VGs. *) - if !debug then - List.iter ( - fun (vgname, (pvuuids, vgmeta)) -> - eprintf "VG %s is on PVs: %s\n%!" vgname (String.concat "," pvuuids) - ) vgs; - - (* Some useful getter functions. If these can't get a value - * from the metadata or if the type is wrong they raise Not_found. - *) - let rec get_int64 field meta = - match List.assoc field meta with - | Int i -> i - | _ -> raise Not_found - and get_int field meta min max = - match List.assoc field meta with - | Int i when Int64.of_int min <= i && i <= Int64.of_int max -> - Int64.to_int i - | _ -> raise Not_found - and get_string field meta = - match List.assoc field meta with - | String s -> s - | _ -> raise Not_found - and get_meta field meta = - match List.assoc field meta with - | Metadata md -> md - | _ -> raise Not_found - and get_stripes field meta = (* List of (string,int) pairs. *) - match List.assoc field meta with - | List xs -> - let rec loop = function - | [] -> [] - | String pvname :: Int offset :: xs -> - (pvname, offset) :: loop xs - | _ -> raise Not_found - in - loop xs - | _ -> raise Not_found - in - - (* The volume groups refer to the physical volumes using their - * own naming system ("pv0", "pv1", etc.) instead of PV UUIDs. - * - * Each PV also has a start (in sectors) & count (in extents) - * of the writable area (the bit after the superblock and metadata) - * which normally starts at sector 384. - * - * Create a PV device (simple offset + size) and a map from PV - * names to these devices. - *) - let vgs = List.map ( - fun (vgname, (pvuuids, vgmeta)) -> - let pvdevs, extent_size = - try - (* NB: extent_size is in sectors here - we convert to bytes. *) - let extent_size = get_int "extent_size" vgmeta 0 (1024*1024) in - let extent_size = Int64.of_int extent_size *^ sector_size64 in - - (* Get the physical_volumes section of the metadata. *) - let pvdevs = get_meta "physical_volumes" vgmeta in - - List.filter_map ( - function - | (pvname, Metadata meta) -> - (* Get the UUID. *) - let pvuuid = get_string "id" meta in - let pvuuid = canonical_uuid pvuuid in - - (* Get the underlying physical device. *) - let _, dev = List.assoc pvuuid pvs in - - (* Construct a PV device. *) - let pe_start = get_int64 "pe_start" meta in - let pe_start = pe_start *^ sector_size64 in - let pe_count = get_int64 "pe_count" meta in - let pe_count = pe_count *^ extent_size in - let pvdev = new offset_device pvuuid pe_start pe_count dev in - - Some (pvname, pvdev) - | _ -> - None - ) pvdevs, extent_size - with - (* Something went wrong - just return an empty map. *) - Not_found -> [], 0L in - (vgname, (pvuuids, vgmeta, pvdevs, extent_size)) - ) vgs in - - (* Scan for logical volumes. Each VG contains several LVs. - * This gives us a list of LVs within each VG (hence extends - * the vgs variable). - *) - let vgs = List.map ( - fun (vgname, (pvuuids, vgmeta, pvdevs, extent_size)) -> - let lvs = - try - let lvs = get_meta "logical_volumes" vgmeta in - let lvs = List.filter_map ( - function - | lvname, Metadata lvmeta -> - (try - let segment_count = get_int "segment_count" lvmeta 0 1024 in - - (* Get the segments for this LV. *) - let segments = range 1 (segment_count+1) in - let segments = - List.map - (fun i -> get_meta ("segment" ^ string_of_int i) lvmeta) - segments in - - let segments = - List.map ( - fun segmeta -> - let start_extent = - get_int64 "start_extent" segmeta in - let extent_count = - get_int64 "extent_count" segmeta in - let segtype = get_string "type" segmeta in - - (* Can only handle striped segments at the - * moment. XXX - *) - if segtype <> "striped" then raise Not_found; - - let stripe_count = - get_int "stripe_count" segmeta 0 1024 in - let stripes = get_stripes "stripes" segmeta in - - if List.length stripes <> stripe_count then - raise Not_found; - - (* Can only handle linear striped segments at - * the moment. XXX - *) - if stripe_count <> 1 then raise Not_found; - let pvname, pvoffset = List.hd stripes in - - (start_extent, extent_count, pvname, pvoffset) - ) segments in - - Some (lvname, segments) - with - (* Something went wrong with segments - omit this LV. *) - Not_found -> None) - | _ -> None - ) lvs in - - lvs - with - Not_found -> - (* Something went wrong - assume no LVs found. *) - [] in - (vgname, (pvuuids, vgmeta, pvdevs, extent_size, lvs)) - ) vgs in - - (* Print the LVs. *) - if !debug then ( - List.iter ( - fun (vgname, (pvuuids, vgmeta, pvdevs, extent_size, lvs)) -> - eprintf "VG %s: (extent_size = %Ld bytes)\n" vgname extent_size; - List.iter ( - fun (lvname, segments) -> - eprintf " %s/%s:\n" vgname lvname; - List.iter ( - fun (start_extent, extent_count, pvname, pvoffset) -> - eprintf " start %Ld count %Ld at %s:%Ld\n" - start_extent extent_count pvname pvoffset - ) segments - ) lvs - ) vgs; - flush stderr - ); - - (* Finally we can set up devices for the LVs. *) - let lvs = - List.map ( - fun (vgname, (pvuuid, vgmeta, pvdevs, extent_size, lvs)) -> - try - List.map ( - fun (lvname, segments) -> - let name = vgname ^ "/" ^ lvname in - let segments = List.map ( - fun (start_extent, extent_count, pvname, pvoffset) -> - (* Get the PV device. *) - let pvdev = List.assoc pvname pvdevs in - - (* Extents mapped to: *) - (start_extent, extent_count, pvdev, pvoffset) - ) segments in - - (* Create a linear mapping device. *) - let lv_dev = new linear_map_device name extent_size segments in - - { lv_dev = lv_dev } - ) lvs - with - Not_found -> [] - ) vgs in - let lvs = List.concat lvs in - - (* Return the list of LV devices. *) - lvs - -(*----------------------------------------------------------------------*) -(* Register with main code. *) -let () = - lvm_type_register plugin_name probe_pv list_lvs -- cgit