Add .gitignore file for git.
[virt-df.git] / lib / diskimage_lvm2.ml
index 2c2fa60..7e58cc9 100644 (file)
@@ -3,19 +3,20 @@
    (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.
 *)
@@ -33,6 +34,9 @@ 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 =
@@ -104,10 +108,10 @@ end
 (* Probe to see if it's an LVM2 PV. *)
 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;
-    { pv_cb = callbacks; 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
@@ -120,22 +124,20 @@ and read_pv_label dev =
    *)
   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 *)
@@ -147,34 +149,23 @@ and read_pv_label dev =
       (* 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
@@ -182,23 +173,29 @@ and read_metadata dev offset len =
  * what is on these LVs - that will be done in the main code.
  *)
 and list_lvs pvs =
-  (* Read the UUID and metadata (again) from each device to end up with
-   * an assoc list of PVs, keyed on the UUID.
-   *
-   * XXX We've already read this - we should save it in the pv struct.
+  (* 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 (
+  let pvsmap = List.map (
     fun { pv_dev = dev } ->
-      let uuid, metadata = read_pv_label dev in
+      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))
   ) 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
@@ -206,7 +203,7 @@ and list_lvs pvs =
       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
@@ -218,7 +215,7 @@ and list_lvs pvs =
       | 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
@@ -306,7 +303,7 @@ and list_lvs pvs =
                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
@@ -420,10 +417,12 @@ and list_lvs pvs =
     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) ->
@@ -450,17 +449,19 @@ and list_lvs pvs =
   (* Return the list of LV devices. *)
   lvs
 
-(* XXX We don't currently have enough information in the PV
- * structure to determine quickly which blocks are used.  Need
- * to store the parsed metadata in the structure ...
+(* 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 = {
-  lvm_cb_name = id;
-  lvm_cb_list_lvs = list_lvs;
-  lvm_cb_offset_is_free = offset_is_free;
-}
+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