* Introduce a dereferencing type to camldm so that PVs can be referenced by ID rather than by device name. This is useful for passing a device-mapper table between hosts where the physical device for a particular PV is different.
* Implement device-mapper reload/suspend/resume so that a table can be changed without tearing down the device
* A few more helper functions for stdext
Signed-off-by: Jon Ludlam <Jonathan.Ludlam@eu.citrix.com>
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*)
+
+type devty =
+ | Dereferenced of string (* e.g. PV id *)
+ | Real of string (* device *)
+
type dev = {
- device : string;
+ device : devty;
offset : int64;
}
-
+
type stripety = {
- chunk_size : int64;
+ chunk_size : int64; (* In sectors - must be a power of 2 and at least as large as the system's PAGE_SIZE *)
dests : dev array;
}
type mapping = {
start : int64;
- len : int64;
+ len : int64;
map : mapty;
}
}
external _create : string -> (int64 * int64 * string * string) array -> unit = "camldm_create"
+external _reload : string -> (int64 * int64 * string * string) array -> unit = "camldm_reload"
external _table : string -> status = "camldm_table"
external _mknods : string -> unit = "camldm_mknods"
external _remove : string -> unit = "camldm_remove"
+external _suspend : string -> unit = "camldm_suspend"
+external _resume : string -> unit = "camldm_resume"
external _mknod : string -> int -> int -> int -> unit = "camldm_mknod"
(* Helper to convert from our type to the string*string
* type expected by libdevmapper *)
-let convert_mapty m =
+let resolve_device dev deref_table =
+ match dev with
+ | Real d -> d
+ | Dereferenced d -> List.assoc d deref_table
+
+let convert_mapty m deref_table =
let array_concat sep a = String.concat sep (Array.to_list a) in
match m with
| Linear dev ->
- "linear",Printf.sprintf "%s %Ld" dev.device dev.offset
+ "linear",Printf.sprintf "%s %Ld" (resolve_device dev.device deref_table) dev.offset
| Striped st ->
"striped",
Printf.sprintf "%d %Ld %s" (Array.length st.dests) st.chunk_size
(array_concat " "
(Array.map (fun dev ->
- Printf.sprintf "%s %Ld" dev.device dev.offset) st.dests))
+ Printf.sprintf "%s %Ld" (resolve_device dev.device deref_table) dev.offset) st.dests))
-let create dev map =
- let newmap = Array.map (fun m ->
- let (ty,params) = convert_mapty m.map in
- (m.start, m.len, ty, params)) map in
- _create dev newmap
+exception CreateError of (int64 * int64 * string * string) array
+exception ReloadError of (int64 * int64 * string * string) array
+
+let _writemap dev map =
+ let oc = open_out (Printf.sprintf "/tmp/%s.map" dev) in
+ Printf.fprintf oc "%s" (String.concat " " (Array.to_list (Array.map (fun (start,len,ty,params) -> Printf.sprintf "(start: %Ld len: %Ld ty: %s params: %s)" start len ty params) map)));
+ close_out oc
+
+let _getmap map dereference_table =
+ Array.map (fun m ->
+ let (ty,params) = convert_mapty m.map dereference_table in
+ (m.start, m.len, ty, params)) map
+
+let create dev map ?(dereference_table=[]) =
+ let newmap = _getmap map dereference_table in
+ try
+ _writemap dev newmap;
+ _create dev newmap
+ with e ->
+ raise (CreateError newmap)
+
+let reload dev map ?(dereference_table=[]) =
+ let newmap = _getmap map dereference_table in
+ try
+ _writemap dev newmap;
+ _reload dev newmap
+ with e ->
+ raise (ReloadError newmap)
+let get_sector_pos_of map sector ~dereference_table =
+ match map.map with
+ | Linear l -> (resolve_device l.device dereference_table, Int64.add l.offset sector)
+ | Striped s ->
+ (* Untested *)
+ let ndevs = Int64.of_int (Array.length s.dests) in
+ let chunk_num = Int64.div sector s.chunk_size in
+ let offset_in_chunk = Int64.rem sector s.chunk_size in
+ let dev_num = Int64.to_int (Int64.rem chunk_num ndevs) in
+ let dev_off = Int64.div chunk_num ndevs in
+ let device = s.dests.(dev_num) in
+ let offset_from_start = Int64.add (Int64.mul dev_off s.chunk_size) offset_in_chunk in
+ let total_offset = Int64.add offset_from_start device.offset in
+ (resolve_device device.device dereference_table, total_offset)
+
let remove = _remove
let table = _table
let mknods = _mknods
let mknod = _mknod
-
+let suspend = _suspend
+let resume = _resume
+let to_string (m : mapping array) = Marshal.to_string m []
+let of_string s = (Marshal.from_string s 0 : mapping array)
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*)
-type dev = { device : string; offset : int64; }
+
+type devty = | Dereferenced of string | Real of string
+type dev = { device : devty; offset : int64; }
type stripety = { chunk_size : int64; dests : dev array; }
type mapty = Linear of dev | Striped of stripety
type mapping = { start : int64; len : int64; map : mapty; }
read_only : bool;
targets : (int64 * int64 * string * string) list;
}
-val convert_mapty : mapty -> string * string
-val create : string -> mapping array -> unit
+
+exception CreateError of (int64 * int64 * string * string) array
+exception ReloadError of (int64 * int64 * string * string) array
+
+val convert_mapty : mapty -> (string * string) list -> string * string
+val create : string -> mapping array -> ?dereference_table : (string * string) list -> unit
+val reload : string -> mapping array -> ?dereference_table : (string * string) list -> unit
+val suspend : string -> unit
+val resume : string -> unit
val remove : string -> unit
val table : string -> status
val mknods : string -> unit
val mknod : string -> int -> int -> int -> unit
+val get_sector_pos_of : mapping -> int64 -> dereference_table:(string * string) list -> string * int64
+val to_string : mapping array -> string
+val of_string : string -> mapping array
CAMLreturn0;
}
+void camldm_reload(value name, value map)
+{
+ CAMLparam2(name,map);
+
+ struct dm_task *dmt;
+ int i;
+ uint64_t start, size;
+ char *ty,*params;
+
+ if(!(dmt = dm_task_create(DM_DEVICE_RELOAD)))
+ caml_failwith("Failed to create task!");
+
+ if(!dm_task_set_name(dmt, String_val(name)))
+ goto out;
+
+ for(i=0; i<Wosize_val(map); i++) {
+ start=Int64_val(Field(Field(map,i),0));
+ size=Int64_val(Field(Field(map,i),1));
+ ty=String_val(Field(Field(map,i),2));
+ params=String_val(Field(Field(map,i),3));
+
+ printf("%" PRIu64 " %" PRIu64 " %s %s\n", start, size, ty, params);
+
+ if(!dm_task_add_target(dmt, start, size, ty, params))
+ goto out;
+ }
+
+ if(!dm_task_run(dmt))
+ goto out;
+
+ goto win;
+
+ out:
+ dm_task_destroy(dmt);
+ caml_failwith("Failed!");
+
+ win:
+ CAMLreturn0;
+}
+
void camldm_mknods(value dev)
{
CAMLreturn0;
}
+void camldm_suspend(value device)
+{
+ CAMLparam1(device);
+ _simple(DM_DEVICE_SUSPEND,String_val(device));
+ CAMLreturn0;
+}
+
+void camldm_resume(value device)
+{
+ CAMLparam1(device);
+ _simple(DM_DEVICE_RESUME,String_val(device));
+ CAMLreturn0;
+}
+
void camldm_mknod(value path, value mode, value major, value minor)
{
CAMLparam4(path, mode, major, minor);
let set_equiv s1 s2 = (subset s1 s2) && (subset s2 s1)
let iteri f list = ignore (fold_left (fun i x -> f i x; i+1) 0 list)
+let iteri_right f list = ignore (fold_right (fun x i -> f i x; i+1) list 0)
let rec inv_assoc k = function
| [] -> raise Not_found
val iteri : (int -> 'a -> unit) -> 'a list -> unit
+ val iteri_right : (int -> 'a -> unit) -> 'a list -> unit
+
(** Map the given function over a list in reverse order. *)
val rev_mapi : (int -> 'a -> 'b) -> 'a list -> 'b list
external set_tcp_nodelay : Unix.file_descr -> bool -> unit = "stub_unixext_set_tcp_nodelay"
external fsync : Unix.file_descr -> unit = "stub_unixext_fsync"
+external blkgetsize64 : Unix.file_descr -> int64 = "stub_unixext_blkgetsize64"
external get_max_fd : unit -> int = "stub_unixext_get_max_fd"
let select_wo w t = _select_wo w t
end
+let wait_for_path path delay timeout =
+ let rec inner ttl =
+ if ttl=0 then failwith "No path!";
+ try
+ ignore(Unix.stat path)
+ with _ ->
+ delay 0.5;
+ inner (ttl - 1)
+ in
+ inner (timeout * 2)
+
+
let _ = Callback.register_exception "unixext.unix_error" (Unix_error (0))
(* HTTP helpers *)
= "stub_unixext_set_tcp_nodelay"
external fsync : Unix.file_descr -> unit = "stub_unixext_fsync"
external get_max_fd : unit -> int = "stub_unixext_get_max_fd"
+external blkgetsize64 : Unix.file_descr -> int64 = "stub_unixext_blkgetsize64"
+
val int_of_file_descr : Unix.file_descr -> int
val file_descr_of_int : int -> Unix.file_descr
val close_all_fds_except : Unix.file_descr list -> unit
val select_wo : t -> float -> t
end
+val wait_for_path : string -> (float -> unit) -> int -> unit
+
(** Download a file via an HTTP GET *)
val http_get: open_tcp:(server:string -> (in_channel * out_channel)) -> uri:string -> filename:string -> server:string -> unit
(** Upload a file via an HTTP PUT *)
#include <string.h>
#include <unistd.h> /* needed for _SC_OPEN_MAX */
#include <stdio.h> /* snprintf */
+#include <sys/ioctl.h>
+#include <linux/fs.h>
#include <caml/mlvalues.h>
#include <caml/memory.h>
CAMLreturn(Val_unit);
}
+CAMLprim value stub_unixext_blkgetsize64(value fd)
+{
+ CAMLparam1(fd);
+ uint64_t size;
+ int c_fd = Int_val(fd);
+ if(ioctl(c_fd,BLKGETSIZE64,&size)) {
+ failwith_errno();
+ }
+ CAMLreturn(caml_copy_int64(size));
+}
CAMLprim value stub_unixext_get_max_fd (value unit)
{