1 (* 'df' command for virtual domains.
3 (C) Copyright 2007 Richard W.M. Jones, Red Hat Inc.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 open Virt_df_gettext.Gettext
27 let plugin_name = "LVM2"
30 let sector_size64 = 512L
32 (* Probe to see if it's an LVM2 PV. Look for the "LABELONE" label. *)
33 let rec probe_pv lvm_plugin_id dev =
35 let uuid, _ = read_pv_label dev in
37 eprintf "LVM2 detected PV UUID %s\n%!" uuid;
38 { lvm_plugin_id = lvm_plugin_id; pv_uuid = uuid }
40 if debug then prerr_endline (Printexc.to_string exn);
43 and read_pv_label dev =
44 (* Load the first 8 sectors. I found by experimentation that
45 * the second sector contains the header ("LABELONE" etc) and
46 * the nineth sector contains some additional information about
47 * the location of the current metadata.
49 let bits = dev#read_bitstring 0L (9 * sector_size) in
51 (*Bitmatch.hexdump_bitstring stdout bits;*)
54 | sector0 : sector_size*8 : bitstring; (* sector 0 *)
55 labelone : 8*8 : bitstring; (* "LABELONE" *)
56 padding : 16*8 : bitstring; (* Seems to contain something. *)
57 lvm2_ver : 8*8 : bitstring; (* "LVM2 001" *)
58 uuid : 32*8 : bitstring; (* UUID *)
59 padding2 : (sector_size-64)*8 : bitstring; (* to end of second sector *)
60 sector234567 : sector_size*8 * 6 : bitstring; (* sectors 2-6 *)
61 padding3 : 0x28*8 : bitstring; (* start of sector 8 *)
62 metadata_offset : 32 : littleendian;(* metadata offset *)
63 padding4 : 4*8 : bitstring;
64 metadata_length : 32 : littleendian (* length of metadata (bytes) *)
65 when Bitmatch.string_of_bitstring labelone = "LABELONE" &&
66 Bitmatch.string_of_bitstring lvm2_ver = "LVM2 001" ->
67 let metadata_offset = metadata_offset +* 0x1000_l in
68 let metadata = read_metadata dev metadata_offset metadata_length in
69 (*prerr_endline metadata;*)
70 let uuid = Bitmatch.string_of_bitstring uuid in
76 (sprintf "LVM2: read_pv_label: %s: not an LVM2 physical volume" dev#name)
78 and read_metadata dev offset32 len32 =
80 eprintf "metadata: offset 0x%lx len %ld bytes\n" offset32 len32;
82 (* Check the offset and length are sensible. *)
84 if offset32 <= Int32.max_int then Int64.of_int32 offset32
85 else invalid_arg "LVM2: read_metadata: metadata offset too large" in
87 if len32 <= 2_147_483_647_l then Int64.of_int32 len32
88 else invalid_arg "LVM2: read_metadata: metadata length too large" in
90 if offset64 <= 0x1200L || offset64 >= dev#size
91 || len64 <= 0L || offset64 +^ len64 >= dev#size then
92 invalid_arg "LVM2: read_metadata: bad metadata offset or length";
94 (* If it is outside the disk boundaries, this will throw an exception,
95 * otherwise it will read and return the metadata string.
97 dev#read offset64 (Int64.to_int len64)
99 (* We are passed a list of devices which we previously identified
100 * as PVs belonging to us. From these produce a list of all LVs
101 * (as devices) and return them. Note that we don't try to detect
102 * what is on these LVs - that will be done in the main code.
107 (* Register with main code. *)
109 lvm_type_register plugin_name probe_pv list_lvs