Fairly straightforward. I'd love for type export to be a bit more
flexible to make description optional, but could not figure out how to
decode that from the C side of things, so for now this just requires
the caller to supply a description for all exports during
.list_exports.
Signed-off-by: Eric Blake <eblake(a)redhat.com>
---
plugins/ocaml/NBDKit.mli | 9 ++++
plugins/ocaml/NBDKit.ml | 17 ++++++++
plugins/ocaml/example.ml | 33 ++++++++++-----
plugins/ocaml/ocaml.c | 89 ++++++++++++++++++++++++++++++++++++++++
4 files changed, 138 insertions(+), 10 deletions(-)
diff --git a/plugins/ocaml/NBDKit.mli b/plugins/ocaml/NBDKit.mli
index 3ebbf18f..0d7e325b 100644
--- a/plugins/ocaml/NBDKit.mli
+++ b/plugins/ocaml/NBDKit.mli
@@ -51,6 +51,12 @@ type extent = {
}
(** The type of the extent list returned by [.extents]. *)
+type export = {
+ name : string;
+ description : string;
+}
+(** The type of the export list returned by [.list_exports]. *)
+
type thread_model =
| THREAD_MODEL_SERIALIZE_CONNECTIONS
| THREAD_MODEL_SERIALIZE_ALL_REQUESTS
@@ -78,10 +84,13 @@ type 'a plugin = {
after_fork : (unit -> unit) option;
preconnect : (bool -> unit) option;
+ list_exports : (bool -> bool -> export list) option;
+ default_export : (bool -> bool -> string) option;
open_connection : (bool -> 'a) option; (* required *)
close : ('a -> unit) option;
get_size : ('a -> int64) option; (* required *)
+ export_description : ('a -> string) option;
can_cache : ('a -> cache_flag) option;
can_extents : ('a -> bool) option;
diff --git a/plugins/ocaml/NBDKit.ml b/plugins/ocaml/NBDKit.ml
index 9ce3bf3e..1d014934 100644
--- a/plugins/ocaml/NBDKit.ml
+++ b/plugins/ocaml/NBDKit.ml
@@ -53,6 +53,11 @@ type extent = {
is_zero : bool;
}
+type export = {
+ name : string;
+ description : string;
+}
+
type 'a plugin = {
name : string;
longname : string;
@@ -73,10 +78,13 @@ type 'a plugin = {
after_fork : (unit -> unit) option;
preconnect : (bool -> unit) option;
+ list_exports : (bool -> bool -> export list) option;
+ default_export : (bool -> bool -> string) option;
open_connection : (bool -> 'a) option;
close : ('a -> unit) option;
get_size : ('a -> int64) option;
+ export_description : ('a -> string) option;
can_cache : ('a -> cache_flag) option;
can_extents : ('a -> bool) option;
@@ -118,10 +126,13 @@ let default_callbacks = {
after_fork = None;
preconnect = None;
+ list_exports = None;
+ default_export = None;
open_connection = None;
close = None;
get_size = None;
+ export_description = None;
can_cache = None;
can_extents = None;
@@ -162,10 +173,13 @@ external set_get_ready : (unit -> unit) -> unit =
"ocaml_nbdkit_set_get_ready"
external set_after_fork : (unit -> unit) -> unit =
"ocaml_nbdkit_set_after_fork"
external set_preconnect : (bool -> unit) -> unit =
"ocaml_nbdkit_set_preconnect"
+external set_list_exports : (bool -> bool -> export list) -> unit =
"ocaml_nbdkit_set_list_exports"
+external set_default_export : (bool -> bool -> string) -> unit =
"ocaml_nbdkit_set_default_export"
external set_open : (bool -> 'a) -> unit = "ocaml_nbdkit_set_open"
external set_close : ('a -> unit) -> unit = "ocaml_nbdkit_set_close"
external set_get_size : ('a -> int64) -> unit =
"ocaml_nbdkit_set_get_size"
+external set_export_description : ('a -> string) -> unit =
"ocaml_nbdkit_set_export_description"
external set_can_cache : ('a -> cache_flag) -> unit =
"ocaml_nbdkit_set_can_cache"
external set_can_extents : ('a -> bool) -> unit =
"ocaml_nbdkit_set_can_extents"
@@ -225,10 +239,13 @@ let register_plugin plugin =
may set_after_fork plugin.after_fork;
may set_preconnect plugin.preconnect;
+ may set_list_exports plugin.list_exports;
+ may set_default_export plugin.default_export;
may set_open plugin.open_connection;
may set_close plugin.close;
may set_get_size plugin.get_size;
+ may set_export_description plugin.export_description;
may set_can_cache plugin.can_cache;
may set_can_extents plugin.can_extents;
diff --git a/plugins/ocaml/example.ml b/plugins/ocaml/example.ml
index 448de8c4..5dc7b374 100644
--- a/plugins/ocaml/example.ml
+++ b/plugins/ocaml/example.ml
@@ -41,6 +41,13 @@ let ocamlexample_config key value =
| _ ->
failwith (Printf.sprintf "unknown parameter: %s" key)
+let ocamlexample_list_exports ro tls : NBDKit.export list =
+ [ { name = "name1"; description = "desc1" };
+ { name = "name2"; description = "desc2" } ]
+
+let ocamlexample_default_export ro tls =
+ "name1"
+
(* Any type (even unit) can be used as a per-connection handle.
* This is just an example. The same value that you return from
* your [open_connection] function is passed back as the first
@@ -58,6 +65,9 @@ let ocamlexample_open readonly =
incr id;
{ h_id = !id }
+let ocamlexample_export_description h =
+ "some description"
+
let ocamlexample_get_size h =
Int64.of_int (Bytes.length !disk)
@@ -80,20 +90,23 @@ let plugin = {
(* name, open_connection, get_size and pread are required,
* everything else is optional.
*)
- NBDKit.name = "ocamlexample";
- version = "1.0";
+ NBDKit.name = "ocamlexample";
+ version = "1.0";
- load = Some ocamlexample_load;
- unload = Some ocamlexample_unload;
+ load = Some ocamlexample_load;
+ unload = Some ocamlexample_unload;
- config = Some ocamlexample_config;
+ config = Some ocamlexample_config;
- open_connection = Some ocamlexample_open;
- get_size = Some ocamlexample_get_size;
- pread = Some ocamlexample_pread;
- pwrite = Some ocamlexample_pwrite;
+ list_exports = Some ocamlexample_list_exports;
+ default_export = Some ocamlexample_default_export;
+ open_connection = Some ocamlexample_open;
+ export_description = Some ocamlexample_export_description;
+ get_size = Some ocamlexample_get_size;
+ pread = Some ocamlexample_pread;
+ pwrite = Some ocamlexample_pwrite;
- thread_model = Some ocamlexample_thread_model;
+ thread_model = Some ocamlexample_thread_model;
}
let () = NBDKit.register_plugin plugin
diff --git a/plugins/ocaml/ocaml.c b/plugins/ocaml/ocaml.c
index d8b61108..a34f67ca 100644
--- a/plugins/ocaml/ocaml.c
+++ b/plugins/ocaml/ocaml.c
@@ -123,10 +123,13 @@ static value get_ready_fn;
static value after_fork_fn;
static value preconnect_fn;
+static value list_exports_fn;
+static value default_export_fn;
static value open_fn;
static value close_fn;
static value get_size_fn;
+static value export_description_fn;
static value can_cache_fn;
static value can_extents_fn;
@@ -311,6 +314,64 @@ preconnect_wrapper (int readonly)
CAMLreturnT (int, 0);
}
+static int
+list_exports_wrapper (int readonly, int is_tls, struct nbdkit_exports *exports)
+{
+ CAMLparam0 ();
+ CAMLlocal2 (rv, v);
+
+ caml_leave_blocking_section ();
+
+ rv = caml_callback2_exn (list_exports_fn, Val_bool (readonly),
+ Val_bool (is_tls));
+ if (Is_exception_result (rv)) {
+ nbdkit_error ("%s", caml_format_exception (Extract_exception (rv)));
+ caml_enter_blocking_section ();
+ CAMLreturnT (int, -1);
+ }
+
+ /* Convert exports list into calls to nbdkit_add_export. */
+ while (rv != Val_int (0)) {
+ const char *name, *desc;
+
+ v = Field (rv, 0); /* export struct */
+ name = String_val (Field (v, 0));
+ desc = String_val (Field (v, 1));
+ if (nbdkit_add_export (exports, name, desc) == -1) {
+ caml_enter_blocking_section ();
+ CAMLreturnT (int, -1);
+ }
+
+ rv = Field (rv, 1);
+ }
+
+ caml_enter_blocking_section ();
+ CAMLreturnT (int, 0);
+}
+
+static const char *
+default_export_wrapper (int readonly, int is_tls)
+{
+ const char *name;
+ CAMLparam0 ();
+ CAMLlocal1 (rv);
+
+ caml_leave_blocking_section ();
+
+ rv = caml_callback2_exn (default_export_fn, Val_bool (readonly),
+ Val_bool (is_tls));
+ if (Is_exception_result (rv)) {
+ nbdkit_error ("%s", caml_format_exception (Extract_exception (rv)));
+ caml_enter_blocking_section ();
+ CAMLreturnT (const char *, NULL);
+ }
+
+ name = nbdkit_strdup_intern (String_val (rv));
+
+ caml_enter_blocking_section ();
+ CAMLreturnT (const char *, name);
+}
+
static void *
open_wrapper (int readonly)
{
@@ -358,6 +419,28 @@ close_wrapper (void *h)
CAMLreturn0;
}
+static const char *
+export_description_wrapper (void *h)
+{
+ const char *desc;
+ CAMLparam0 ();
+ CAMLlocal1 (rv);
+
+ caml_leave_blocking_section ();
+
+ rv = caml_callback_exn (export_description_fn, *(value *) h);
+ if (Is_exception_result (rv)) {
+ nbdkit_error ("%s", caml_format_exception (Extract_exception (rv)));
+ caml_enter_blocking_section ();
+ CAMLreturnT (const char *, NULL);
+ }
+
+ desc = nbdkit_strdup_intern (String_val (rv));
+
+ caml_enter_blocking_section ();
+ CAMLreturnT (const char *, desc);
+}
+
static int64_t
get_size_wrapper (void *h)
{
@@ -856,10 +939,13 @@ SET(get_ready)
SET(after_fork)
SET(preconnect)
+SET(list_exports)
+SET(default_export)
SET(open)
SET(close)
SET(get_size)
+SET(export_description)
SET(can_write)
SET(can_flush)
@@ -900,10 +986,13 @@ remove_roots (void)
REMOVE (after_fork);
REMOVE (preconnect);
+ REMOVE (list_exports);
+ REMOVE (default_export);
REMOVE (open);
REMOVE (close);
REMOVE (get_size);
+ REMOVE (export_description);
REMOVE (can_cache);
REMOVE (can_extents);
--
2.28.0