]}
*)
-(**
- {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 Device class and specialized subclasses} *)
class virtual device :
object
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
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.
-class offset_device : string -> int64 -> int64 -> 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 -> 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]).
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. *)
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. *)
and filesystem = {
fs_plugin_id : fs_plugin_id; (** Filesystem type. *)
- fs_block_size : int64; (** Block size (bytes). *)
+ fs_dev : device; (** Device containing the filesystem. *)
+ fs_blocksize : int; (** Block size (bytes). *)
fs_blocks_total : int64; (** Total blocks. *)
fs_is_swap : bool; (** If swap, following not valid. *)
fs_blocks_reserved : int64; (** Blocks reserved for super-user. *)
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
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.
*)
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.
*)