[Libguestfs] [libnbd PATCH v4 07/25] generator: Support Extent64 arg in OCaml code

Richard W.M. Jones rjones at redhat.com
Fri Aug 4 09:21:18 UTC 2023


On Wed, Aug 02, 2023 at 08:50:27PM -0500, Eric Blake wrote:
> See the earlier commit "Add Extent64 arg type" for rationale in
> supporting a new generator arg type.  This patch adds the OCaml
> bindings for use of Extent64, which required adding a counterpart
> OCaml type.
> 
> Note that we intend to guarantee that the size is always a positive
> value.  If we were using using structured_reply_in_bounds() like we do
> for REPLY_TYPE_DATA, this would be trivial; but in practice, the NBD
> protocol says we have to accept server responses that extend beyond
> the bounds of the client's request.  Still, the state machine can
> easily check that the server's cumulative size has not exceeded the
> export's length, which in practice is limited by off_t; furthermore,
> the NBD protocol allows truncation of the response as long as the
> client makes progress, and the client does not have to know whether
> that truncation happened at the server or in our state machine.
> Therefore, our assertion of a positive size viable.
> 
> However, the flags can be negative: OCaml's only native 64-bit integer
> is inherently signed, but at least it does have a logical shift
> operator for performing unsigned bit-twiddling operations.
> 
> Signed-off-by: Eric Blake <eblake at redhat.com>
> ---
> 
> v4: split out of larger patch [Laszlo], avoid awkward slice since we
> can't use copy() anyway [Laszlo]
> ---
>  generator/OCaml.ml | 18 +++++++++++++++---
>  ocaml/helpers.c    | 21 +++++++++++++++++++++
>  ocaml/nbd-c.h      |  1 +
>  3 files changed, 37 insertions(+), 3 deletions(-)
> 
> diff --git a/generator/OCaml.ml b/generator/OCaml.ml
> index 7971ac40..621a4348 100644
> --- a/generator/OCaml.ml
> +++ b/generator/OCaml.ml
> @@ -44,7 +44,7 @@ and
>    | Closure { cbargs } ->
>       sprintf "(%s)" (ocaml_closuredecl_to_string cbargs)
>    | Enum (_, { enum_prefix }) -> sprintf "%s.t" enum_prefix
> -  | Extent64 _ -> assert false (* only used in extent64_closure *)
> +  | Extent64 _ -> "extent"
>    | Fd _ -> "Unix.file_descr"
>    | Flags (_, { flag_prefix }) -> sprintf "%s.t list" flag_prefix
>    | Int _ -> "int"
> @@ -149,6 +149,9 @@ let
> 
>  type cookie = int64
> 
> +type extent = int64 * int64
> +(** Length and flags of an extent in block_status_64 callback. *)

If you write:

(** Length and flags of an extent in {!block_status_64} callback. *)

then ocamldoc will link this to the definition of block_status_64.

> +
>  ";
> 
>    List.iter (
> @@ -270,6 +273,7 @@ let
>  exception Error of string * Unix.error option
>  exception Closed of string
>  type cookie = int64
> +type extent = int64 * int64
> 
>  (* Give the exceptions names so that they can be raised from the C code. *)
>  let () =
> @@ -500,7 +504,7 @@ let
>    let argnames =
>      List.map (
>        function
> -      | CBArrayAndLen (UInt32 n, _) | CBBytesIn (n, _)
> +      | CBArrayAndLen ((UInt32 n | Extent64 n), _) | CBBytesIn (n, _)
>        | CBInt n | CBInt64 n
>        | CBMutable (Int n) | CBString n | CBUInt n | CBUInt64 n ->
>           n ^ "v"
> @@ -533,6 +537,14 @@ let
>         pr "%s  %s,\n" indent n;
>         pr "%s  %s\n" indent count;
>         pr "%s);\n" indent
> +    | CBArrayAndLen (Extent64 n, count) ->
> +       pr "  %sv = " n;
> +       let fncol = output_column () in
> +       let indent = spaces fncol in
> +       pr "nbd_internal_ocaml_alloc_extent64_array (\n";
> +       pr "%s  %s,\n" indent n;
> +       pr "%s  %s\n" indent count;
> +       pr "%s);\n" indent
>      | CBBytesIn (n, len) ->
>         pr "  %sv = caml_alloc_initialized_string (%s, %s);\n" n len n
>      | CBInt n | CBUInt n ->
> @@ -556,7 +568,7 @@ let
> 
>    List.iter (
>      function
> -    | CBArrayAndLen (UInt32 _, _)
> +    | CBArrayAndLen ((UInt32 _ | Extent64 _), _)
>      | CBBytesIn _
>      | CBInt _
>      | CBInt64 _
> diff --git a/ocaml/helpers.c b/ocaml/helpers.c
> index 3361a696..7f40534a 100644
> --- a/ocaml/helpers.c
> +++ b/ocaml/helpers.c
> @@ -133,6 +133,27 @@ nbd_internal_ocaml_alloc_i64_from_u32_array (uint32_t *a, size_t len)
>    CAMLreturn (rv);
>  }
> 
> +value
> +nbd_internal_ocaml_alloc_extent64_array (nbd_extent *a, size_t len)
> +{
> +  CAMLparam0 ();
> +  CAMLlocal3 (s, v, rv);
> +  size_t i;
> +
> +  rv = caml_alloc (len, 0);
> +  for (i = 0; i < len; ++i) {
> +    s = caml_alloc (2, 0);
> +    assert (a[i].length <= INT64_MAX);  /* API ensures size fits in 63 bits */
> +    v = caml_copy_int64 (a[i].length);
> +    Store_field (s, 0, v);
> +    v = caml_copy_int64 (a[i].flags);
> +    Store_field (s, 1, v);
> +    Store_field (rv, i, s);
> +  }
> +
> +  CAMLreturn (rv);
> +}

This function looks good.

>  /* Convert a Unix.sockaddr to a C struct sockaddr. */
>  void
>  nbd_internal_unix_sockaddr_to_sa (value sockaddrv,
> diff --git a/ocaml/nbd-c.h b/ocaml/nbd-c.h
> index e3abb912..adcdd15a 100644
> --- a/ocaml/nbd-c.h
> +++ b/ocaml/nbd-c.h
> @@ -62,6 +62,7 @@ extern void nbd_internal_ocaml_raise_closed (const char *func) Noreturn;
> 
>  extern const char **nbd_internal_ocaml_string_list (value);
>  extern value nbd_internal_ocaml_alloc_i64_from_u32_array (uint32_t *, size_t);
> +extern value nbd_internal_ocaml_alloc_extent64_array (nbd_extent *, size_t);
>  extern void nbd_internal_unix_sockaddr_to_sa (value, struct sockaddr_storage *,
>                                                socklen_t *);
>  extern void nbd_internal_ocaml_exception_in_wrapper (const char *, value);

Reviewed-by: Richard W.M. Jones <rjones at redhat.com>

Rich.

-- 
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
Read my programming and virtualization blog: http://rwmj.wordpress.com
libguestfs lets you edit virtual machines.  Supports shell scripting,
bindings from many languages.  http://libguestfs.org


More information about the Libguestfs mailing list