Add a fs_dev field to filesystem
[virt-df.git] / lib / diskimage.mli
index b0ecd8d..09d791e 100644 (file)
  *)
 
 (**
-   {2 Machine/device model}
-
-   The "machine/device model" that we currently understand looks
-   like this:
-
-{v
-machines
-  |
-  \--- host partitions / disk image files
-         ||
-       guest block devices
-         |
-         +--> guest partitions (eg. using MBR)
-         |      |
-         \-(1)->+--- filesystems (eg. ext3)
-                |
-                \--- PVs for LVM
-                       |||
-                     VGs and LVs
-v}
-
-   (1) Filesystems and PVs may also appear directly on guest
-   block devices.
-
-   Partition schemes (eg. MBR) and filesystems register themselves
-   with this main module and they are queried first to get an idea
-   of the physical devices, partitions and filesystems potentially
-   available to the guest.
-
-   Volume management schemes (eg. LVM2) register themselves here
-   and are called later with "spare" physical devices and partitions
-   to see if they contain LVM data.  If this results in additional
-   logical volumes then these are checked for filesystems.
-
-   Swap space is considered to be a dumb filesystem for the purposes
-   of this discussion.
+   {2 Examples}
+
+{[
+  let machine = open_machine "host" ["hda", "/dev/hda"] in
+  let machine = scan_machine machine in
+  (* do what you want with the scan results ... *)
+  close_machine machine
+]}
 *)
 
+(** {2 Device class and specialized subclasses} *)
+
 class virtual device :
   object
     method virtual name : string
@@ -66,14 +40,28 @@ class virtual device :
          Note: For some types of devices, the device may have
          "holes", alignment requirements, etc. so this method doesn't
          imply that every byte from [0..size-1] is readable. *)
-    method close : unit -> unit
-      (** Close the device.  This must be called to fully free up
-         any resources used by the device. *)
-    method virtual read : int64 -> int -> string
-      (** [read offset len] reads len bytes starting at offset. *)
+    method read : int64 -> int -> string
+      (** [read offset len] reads len bytes starting at offset.
+
+         Note: A default implementation is provided for [read],
+         but it is fairly inefficient because it uses {!mapblock} to
+         map each block in the request. *)
     method read_bitstring : int64 -> int -> Bitmatch.bitstring
       (** [read_bitstring] is the same as [read] but returns
          a pa_bitmatch-style bitstring. *)
+    method virtual blocksize : int
+      (** [blocksize] returns the natural block size of the device. *)
+    method virtual mapblock : int64 -> (device * int64) list
+      (** [mapblock] describes how a block in this device is
+         mapped down to any underlying device(s).
+
+         Returns [[]] (empty list) if there is no underlying
+         device for this block.  Otherwise returns a list of
+         [(device, byte-offset)] locations where this block is mapped.
+
+         Normally the returned list has length 1, but in cases
+         such as mirroring you can have the same block mapped
+         to several underlying devices. *)
   end
   (**
      A virtual (or physical!) device, encapsulating any translation
@@ -84,27 +72,35 @@ class virtual device :
      Note this very rare use of OOP in OCaml!
   *)
 
-class block_device : string ->
+class block_device : string -> int ->
   object
     method name : string
     method size : int64
-    method close : unit -> unit
     method read : int64 -> int -> string
     method read_bitstring : int64 -> int -> Bitmatch.bitstring
+    method blocksize : int
+    method mapblock : int64 -> (device * int64) list
+    method close : unit -> unit
+      (** Close the device, freeing up the file descriptor. *)
   end
-    (** A concrete device which just direct-maps a file or /dev device. *)
+    (** A concrete device which just direct-maps a file or /dev device.
+
+       Create the device with [new block_device filename blocksize]
+       where [filename] is the path to the file or device and
+       [blocksize] is the blocksize of the device. *)
 
-class offset_device : string -> int64 -> int64 -> device ->
+class offset_device : string -> int64 -> int64 -> int -> device ->
   object
     method name : string
     method size : int64
-    method close : unit -> unit
     method read : int64 -> int -> string
     method read_bitstring : int64 -> int -> Bitmatch.bitstring
+    method blocksize : int
+    method mapblock : int64 -> (device * int64) list
   end
     (** A concrete device which maps a linear part of an underlying device.
 
-       [new offset_device name start size dev] creates a new
+       [new offset_device name start size blocksize dev] creates a new
        device which maps bytes from [start] to [start+size-1]
        of the underlying device [dev] (ie. in this device they
        appear as bytes [0] to [size-1]).
@@ -115,6 +111,47 @@ class offset_device : string -> int64 -> int64 -> device ->
 val null_device : device
     (** The null device.  Any attempt to read generates an error. *)
 
+(**
+   {2 Structures used to describe machines, disks, partitions and filesystems}
+
+   {3 Machine/device model}
+
+   The "machine/device model" that we currently understand looks
+   like this:
+
+{v
+machines
+  |
+  \--- host partitions / disk image files
+         ||
+       guest block devices
+         |
+         +--> guest partitions (eg. using MBR)
+         |      |
+         \-(1)->+--- filesystems (eg. ext3)
+                |
+                \--- PVs for LVM
+                       |||
+                     VGs and LVs
+v}
+
+   (1) Filesystems and PVs may also appear directly on guest
+   block devices.
+
+   Partition schemes (eg. MBR) and filesystems register themselves
+   with this main module and they are queried first to get an idea
+   of the physical devices, partitions and filesystems potentially
+   available to the guest.
+
+   Volume management schemes (eg. LVM2) register themselves here
+   and are called later with "spare" physical devices and partitions
+   to see if they contain LVM data.  If this results in additional
+   logical volumes then these are checked for filesystems.
+
+   Swap space is considered to be a dumb filesystem for the purposes
+   of this discussion.
+*)
+
 type machine = {
   m_name : string;                     (** Machine name. *)
   m_disks : disk list;                 (** Machine disks. *)
@@ -125,7 +162,7 @@ type machine = {
 
 and disk = {
   d_name : string;                     (** Device name (eg "hda") *)
-  d_dev : device;                      (** Disk device. *)
+  d_dev : block_device;                        (** Disk device. *)
   d_content : disk_content;            (** What's on it. *)
 }
     (** A single physical disk image. *)
@@ -138,7 +175,7 @@ and disk_content =
     ]
 
 and partitions = {
-  parts_name : string;                 (** Name of partitioning scheme. *)
+  parts_plugin_id : parts_plugin_id;   (** Partitioning scheme. *)
   parts : partition list;              (** Partitions. *)
 }
 and partition = {
@@ -157,7 +194,8 @@ and partition_content =
     ]
 
 and filesystem = {
-  fs_name : string;                    (** Name of filesystem. *)
+  fs_dev : device;                     (** Device containing the filesystem. *)
+  fs_plugin_id : fs_plugin_id;         (** Filesystem type. *)
   fs_block_size : int64;               (** Block size (bytes). *)
   fs_blocks_total : int64;             (** Total blocks. *)
   fs_is_swap : bool;                   (** If swap, following not valid. *)
@@ -169,7 +207,7 @@ and filesystem = {
   fs_inodes_avail : int64;             (** Inodes free (available). *)
   fs_inodes_used : int64;              (** Inodes in use. *)
 }
-    (** A filesystem. *)
+    (** A filesystem, with superblock contents. *)
 
 and pv = {
   lvm_plugin_id : lvm_plugin_id;        (** The LVM plug-in which detected
@@ -181,11 +219,15 @@ and lv = {
 }
     (** Physical and logical volumes as used by LVM plug-ins. *)
 
+and parts_plugin_id
+and fs_plugin_id
 and lvm_plugin_id
+  (** Opaque IDs used to refer to the plug-ins. *)
 
-val string_of_partition : partition -> string
-val string_of_filesystem : filesystem -> string
-  (** Convert a partition or filesystem struct to a string (for debugging). *)
+val name_of_parts : parts_plugin_id -> string
+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} *)
 
@@ -204,7 +246,7 @@ val open_machine : string -> (string * string) list -> machine
 
 val close_machine : machine -> unit
   (** This is a convenience function which calls the [dev#close]
-      method on any open devices owned by the machine.  This just
+      method on any open {!block_device}s owned by the machine.  This just
       has the effect of closing any file descriptors which are
       opened by these devices.
   *)
@@ -214,6 +256,8 @@ val scan_machine : machine -> machine
       identifying all partitions, filesystems, physical and logical
       volumes that are known to this library.
 
+      This scans down to the level of the filesystem superblocks.
+
       Returns an updated {!machine} structure with the scan results.
   *)