+(*----------------------------------------------------------------------*)
+(* Block device which can do linear maps, same as the kernel dm-linear.c *)
+class linear_map_device name extent_size segments =
+ (* The segments are passed containing (start_extent, extent_count, ...)
+ * but it's easier to deal with (start_extent, end_extent, ...) so
+ * rewrite them.
+ *)
+ let segments = List.map
+ (fun (start_extent, extent_count, dev, pvoffset) ->
+ (start_extent, start_extent +^ extent_count, dev, pvoffset)
+ ) segments in
+
+ (* Calculate the size of the device (in bytes). Note that because
+ * of the random nature of the mapping this doesn't imply that we can
+ * satisfy any read request up to the full size.
+ *)
+ let size_in_extents =
+ List.fold_left max 0L
+ (List.map (fun (_, end_extent, _, _) -> end_extent) segments) in
+ let size = size_in_extents *^ extent_size in
+object
+ inherit device
+ method name = name
+ method size = size
+
+ (* Read method checks which segment the request lies inside and
+ * maps it to the underlying device. If there is no mapping then
+ * we have to return an error.
+ *
+ * The request must lie inside a single extent, otherwise this is
+ * also an error (XXX - should lift this restriction, however default
+ * extent size is 4 MB so we probably won't hit this very often).
+ *)
+ method read offset len =
+ let offset_in_extents = offset /^ extent_size in
+
+ (* Check we don't cross an extent boundary. *)
+ if (offset +^ Int64.of_int (len-1)) /^ extent_size <> offset_in_extents
+ then invalid_arg "linear_map_device: request crosses extent boundary";
+
+ if offset_in_extents < 0L || offset_in_extents >= size_in_extents then
+ invalid_arg "linear_map_device: read outside device";
+
+ let rec loop = function
+ | [] ->
+ invalid_arg "linear_map_device: offset not mapped"
+ | (start_extent, end_extent, dev, pvoffset) :: rest ->
+ eprintf "pvoffset = %Ld\n" pvoffset;
+ if start_extent <= offset_in_extents &&
+ offset_in_extents < end_extent
+ then dev#read (offset +^ pvoffset *^ extent_size) len
+ else loop rest
+ in
+ loop segments
+end
+
+(*----------------------------------------------------------------------*)