(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 library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version,
+ with the OCaml linking exception described in ../COPYING.LIB.
- This program is distributed in the hope that it will be useful,
+ This library 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.
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser 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.
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Support for LVM2 PVs.
*)
open Printf
open ExtList
-open Diskimage_utils
+open Diskimage_impl
open Diskimage_lvm2_metadata
open Int63.Operators
-let plugin_id = "LVM2"
+let id = "LVM2"
let sector_size_int = 512
let sector_size = ~^sector_size_int
+(*let attach_private_data, get_private_data =
+ private_data_functions (fun {lvm_cb = {lvm_cb_uq = u}} -> u)*)
+
(*----------------------------------------------------------------------*)
(* Block device which can do linear maps, same as the kernel dm-linear.c *)
class linear_map_device name extent_size segments =
(*----------------------------------------------------------------------*)
(* Probe to see if it's an LVM2 PV. *)
-let rec probe lvm_plugin_id dev =
+let rec probe dev =
try
- let uuid, _ = read_pv_label dev in
+ 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; pv_dev = dev }
+ { pv_cb = callbacks (); pv_uuid = uuid; pv_dev = dev }
with exn ->
if !debug then prerr_endline (Printexc.to_string exn);
raise Not_found
*)
let bits = dev#read_bitstring ~^0 (~^9 *^ sector_size) in
- (*Bitmatch.hexdump_bitstring stdout bits;*)
-
bitmatch bits with
| {
(* sector 0 *)
- sector0 : sector_size_int*8 : bitstring;
+ _ : sector_size_int*8 : bitstring;
(* sector 1 *)
"LABELONE" : 64 : string; (* "LABELONE" *)
_ : 128 : bitstring; (* Seems to contain something. *)
"LVM2 001" : 64 : string; (* "LVM2 001" *)
- uuid : 256 : string; (* UUID *)
- endsect : (sector_size_int-64)*8 : bitstring;(* to end of second sector *)
+ uuid : 256 : string; (* PV UUID *)
+ _ : (sector_size_int-64)*8 : bitstring;(* to end of second sector *)
(* sectors 2-7 *)
- sectors234567 : sector_size_int*8 * 6 : bitstring;
+ _ : sector_size_int*8 * 6 : bitstring;
(* sector 8 *)
_ : 320 : bitstring; (* start of sector 8 *)
(* Metadata offset is relative to end of PV label. *)
let metadata_offset = Int63.of_int32 metadata_offset +^ ~^0x1000 in
(* Metadata length appears to include the trailing \000 which
- * we don't want.
+ * we don't want, so subtract 1 to get the true length.
*)
let metadata_length = Int63.of_int32 metadata_length -^ ~^1 in
- let metadata = read_metadata dev metadata_offset metadata_length in
+ (* Check the metadata offset and length are sensible. *)
+ if metadata_offset <= ~^0x1200 || metadata_offset >= dev#size
+ || metadata_length <= ~^0
+ || metadata_offset +^ metadata_length >= dev#size then
+ invalid_arg "LVM2: read_metadata: bad metadata offset or length";
- uuid, metadata
+ uuid, metadata_offset, metadata_length
| { _ } ->
invalid_arg
(sprintf "LVM2: read_pv_label: %s: not an LVM2 physical volume"
dev#name)
-and read_metadata dev offset len =
- if !debug then
- eprintf "metadata: offset %s len %s bytes\n%!"
- (Int63.to_string offset) (Int63.to_string len);
-
- (* Check the offset and length are sensible. *)
- if offset <= ~^0x1200 || offset >= dev#size
- || len <= ~^0 || offset +^ len >= 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 offset len
-
(*----------------------------------------------------------------------*)
(* 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 devs =
- (* Read the UUID and metadata (again) from each device to end up with
- * an assoc list of PVs, keyed on the UUID.
+and list_lvs pvs =
+ (* Read the PV label (again) for each PV, and this time also
+ * read out the metadata, which is a big block of text.
*)
- let pvs = List.map (
- fun dev ->
- let uuid, metadata = read_pv_label dev in
+ let pvsmap = List.map (
+ fun { pv_dev = dev } ->
+ let uuid, metadata_offset, metadata_length = read_pv_label dev in
+ let metadata = dev#read metadata_offset metadata_length in
+
+ if !debug then
+ eprintf "list_lvs: metadata for PV %s (offset %s len %s):\n%s\n%!"
+ dev#name
+ (Int63.to_string metadata_offset) (Int63.to_string metadata_length)
+ metadata;
+
(uuid, (metadata, dev))
- ) devs in
+ ) pvs in
(* Parse the metadata using the external lexer/parser. *)
- let pvs = List.map (
+ let pvsmap = List.map (
fun (uuid, (metadata, dev)) ->
uuid, (Diskimage_lvm2_lexer.parse_lvm2_metadata_from_string metadata,
dev)
- ) pvs in
+ ) pvsmap in
(* Print the parsed metadata. *)
if !debug then
fun (uuid, (metadata, dev)) ->
eprintf "metadata for PV UUID %s on %s:\n" uuid dev#name;
output_metadata stderr metadata
- ) pvs;
+ ) pvsmap;
(* Scan for volume groups. The first entry in the metadata
* appears to be the volume group name. This gives us a
| pvuuid, (((vgname, Metadata vgmeta) :: _), dev) ->
Some (vgname, (pvuuid, vgmeta))
| _ -> None
- ) pvs in
+ ) pvsmap in
let cmp ((a:string),_) ((b:string),_) = compare a b in
let vgnames = List.sort ~cmp vgnames in
let pvuuid = canonical_uuid pvuuid in
(* Get the underlying physical device. *)
- let _, dev = List.assoc pvuuid pvs in
+ let _, dev = List.assoc pvuuid pvsmap in
(* Construct a PV device. *)
let pe_start = get_int63 "pe_start" meta in
flush stderr
);
+(* List.iter (fun pv -> attach_private_data pv vgs) pvs; *)
+
(* Finally we can set up devices for the LVs. *)
let lvs =
List.map (
- fun (vgname, (pvuuid, vgmeta, pvdevs, extent_size, lvs)) ->
+ fun (vgname, (pvuuids, vgmeta, pvdevs, extent_size, lvs)) ->
try
List.map (
fun (lvname, segments) ->
(* Return the list of LV devices. *)
lvs
+
+(* XXX We need to reparse the metadata in a different way in
+ * order to calculate this. Need to generalize metadata handling.
+ *)
+and offset_is_free _ _ = false
+
+and callbacks =
+ let i = ref 0 in
+ fun () -> {
+ lvm_cb_uq = (incr i; !i);
+ lvm_cb_name = id;
+ lvm_cb_list_lvs = list_lvs;
+ lvm_cb_offset_is_free = offset_is_free;
+ }
+
+(* Register the plugin. *)
+let () = register_plugin ~lvm:probe id