An upcoming commit will add the ability to query which meta contexts a
server is advertising; but first we need to be able to present a
different list of meta context requests in response to what we learn
from the server. Add APIs for reviewing which requests have already
been registered, as well as a way to reset the list of requests.
This adds some testsuite coverage; and more will appear with the
addition of nbd_opt_list_meta_contexts in later patches.
---
generator/API.ml | 78 ++++++++++++++++++++++++++++++++++--
lib/handle.c | 32 +++++++++++++++
tests/meta-base-allocation.c | 36 +++++++++++++++--
3 files changed, 139 insertions(+), 7 deletions(-)
diff --git a/generator/API.ml b/generator/API.ml
index 0a876c4..938ace4 100644
--- a/generator/API.ml
+++ b/generator/API.ml
@@ -974,7 +974,10 @@ this is whether blocks of data are allocated, zero or sparse).
This call adds one metadata context to the list to be negotiated.
You can call it as many times as needed. The list is initially
-empty when the handle is created.
+empty when the handle is created; you can check the contents of
+the list with L<nbd_get_nr_meta_contexts(3)> and
+L<nbd_get_meta_context(3)>, or clear it with
+L<nbd_clear_meta_contexts(3)>.
The NBD protocol limits meta context names to 4096 bytes, but
servers may not support the full length. The encoding of meta
@@ -991,9 +994,73 @@ C<LIBNBD_CONTEXT_> for some well-known contexts, but you are
free
to pass in other contexts.
Other metadata contexts are server-specific, but include
-C<\"qemu:dirty-bitmap:...\"> for qemu-nbd
-(see qemu-nbd I<-B> option).";
- see_also = [Link "block_status"];
+C<\"qemu:dirty-bitmap:...\"> and
C<\"qemu:allocation-depth\"> for
+qemu-nbd (see qemu-nbd I<-B> and I<-A> options).";
+ see_also = [Link "block_status"; Link "can_meta_context";
+ Link "get_nr_meta_contexts"; Link
"get_meta_context";
+ Link "clear_meta_contexts"];
+ };
+
+ "get_nr_meta_contexts", {
+ default_call with
+ args = []; ret = RInt;
+ shortdesc = "return the current number of requested meta contexts";
+ longdesc = "\
+During connection libnbd can negotiate zero or more metadata
+contexts with the server. Metadata contexts are features (such
+as C<\"base:allocation\">) which describe information returned
+by the L<nbd_block_status(3)> command (for C<\"base:allocation\">
+this is whether blocks of data are allocated, zero or sparse).
+
+This command returns how many meta contexts have been added to
+the list to request from the server via L<nbd_add_meta_context(3)>.
+The server is not obligated to honor all of the requests; to see
+what it actually supports, see L<nbd_can_meta_context(3)>.";
+ see_also = [Link "block_status"; Link "can_meta_context";
+ Link "add_meta_context"; Link "get_meta_context";
+ Link "clear_meta_contexts"];
+ };
+
+ "get_meta_context", {
+ default_call with
+ args = [ Int "i" ]; ret = RString;
+ shortdesc = "return the i'th meta context request";
+ longdesc = "\
+During connection libnbd can negotiate zero or more metadata
+contexts with the server. Metadata contexts are features (such
+as C<\"base:allocation\">) which describe information returned
+by the L<nbd_block_status(3)> command (for C<\"base:allocation\">
+this is whether blocks of data are allocated, zero or sparse).
+
+This command returns the i'th meta context request, as added by
+L<nbd_add_meta_context(3)>, and bounded by
+L<nbd_get_nr_meta_contexts(3)>.";
+ see_also = [Link "block_status"; Link "can_meta_context";
+ Link "add_meta_context"; Link
"get_nr_meta_contexts";
+ Link "clear_meta_contexts"];
+ };
+
+ "clear_meta_contexts", {
+ default_call with
+ args = []; ret = RErr;
+ permitted_states = [ Created; Negotiating ];
+ shortdesc = "reset the list of requested meta contexts";
+ longdesc = "\
+During connection libnbd can negotiate zero or more metadata
+contexts with the server. Metadata contexts are features (such
+as C<\"base:allocation\">) which describe information returned
+by the L<nbd_block_status(3)> command (for C<\"base:allocation\">
+this is whether blocks of data are allocated, zero or sparse).
+
+This command resets the list of meta contexts to request back to
+an empty list, for re-population by further use of
+L<nbd_add_meta_context(3)>. It is primarily useful when option
+negotiation mode is selected (see L<nbd_set_opt_mode(3)>), for
+altering the list of attempted contexts between subsequent export
+queries.";
+ see_also = [Link "block_status"; Link "can_meta_context";
+ Link "add_meta_context"; Link
"get_nr_meta_contexts";
+ Link "get_meta_context"; Link "set_opt_mode"];
};
"set_uri_allow_transports", {
@@ -2814,6 +2881,9 @@ let first_version = [
(* Added in 1.5.x development cycle, will be stable and supported in 1.6. *)
"set_strict_mode", (1, 6);
"get_strict_mode", (1, 6);
+ "get_nr_meta_contexts", (1, 6);
+ "get_meta_context", (1, 6);
+ "clear_meta_contexts", (1, 6);
(* These calls are proposed for a future version of libnbd, but
* have not been added to any released version so far.
diff --git a/lib/handle.c b/lib/handle.c
index a6b2172..e0047b7 100644
--- a/lib/handle.c
+++ b/lib/handle.c
@@ -313,6 +313,38 @@ nbd_unlocked_add_meta_context (struct nbd_handle *h, const char
*name)
return 0;
}
+int
+nbd_unlocked_get_nr_meta_contexts (struct nbd_handle *h)
+{
+ return nbd_internal_string_list_length (h->request_meta_contexts);
+}
+
+char *
+nbd_unlocked_get_meta_context (struct nbd_handle *h, int i)
+{
+ size_t len = nbd_internal_string_list_length (h->request_meta_contexts);
+ char *ret;
+
+ if (i < 0 || i >= len) {
+ set_error (EINVAL, "meta context request out of range");
+ return NULL;
+ }
+
+ ret = strdup (h->request_meta_contexts[i]);
+ if (ret == NULL)
+ set_error (errno, "strdup");
+
+ return ret;
+}
+
+int
+nbd_unlocked_clear_meta_contexts (struct nbd_handle *h)
+{
+ nbd_internal_free_string_list (h->request_meta_contexts);
+ h->request_meta_contexts = NULL;
+ return 0;
+}
+
int
nbd_unlocked_set_request_structured_replies (struct nbd_handle *h,
bool request)
diff --git a/tests/meta-base-allocation.c b/tests/meta-base-allocation.c
index 3de4c34..5ed57d8 100644
--- a/tests/meta-base-allocation.c
+++ b/tests/meta-base-allocation.c
@@ -1,5 +1,5 @@
/* NBD client library in userspace
- * Copyright (C) 2013-2019 Red Hat Inc.
+ * Copyright (C) 2013-2020 Red Hat Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -30,6 +30,8 @@
#include <libnbd.h>
+#define BOGUS_CONTEXT "x-libnbd:nosuch"
+
static int check_extent (void *data,
const char *metacontext,
uint64_t offset,
@@ -58,6 +60,18 @@ main (int argc, char *argv[])
exit (EXIT_FAILURE);
}
+ /* No contexts requested by default */
+ if ((r = nbd_get_nr_meta_contexts (nbd)) != 0) {
+ fprintf (stderr, "unexpected number of contexts: %d\n", r);
+ exit (EXIT_FAILURE);
+ }
+
+ /* Clearing an empty list is not fatal */
+ if (nbd_clear_meta_contexts (nbd) != 0) {
+ fprintf (stderr, "unable to clear requested contexts\n");
+ exit (EXIT_FAILURE);
+ }
+
/* Negotiate metadata context "base:allocation" with the server.
* This is supported in nbdkit >= 1.12.
*/
@@ -69,11 +83,27 @@ main (int argc, char *argv[])
/* Also request negotiation of a bogus context, which should not
* fail here nor affect block status later.
*/
- if (nbd_add_meta_context (nbd, "x-libnbd:nosuch") == -1) {
+ if (nbd_add_meta_context (nbd, BOGUS_CONTEXT) == -1) {
fprintf (stderr, "%s\n", nbd_get_error ());
exit (EXIT_FAILURE);
}
+ /* Test that we can read back what we have requested */
+ if ((r = nbd_get_nr_meta_contexts (nbd)) != 2) {
+ fprintf (stderr, "unexpected number of contexts: %d\n", r);
+ exit (EXIT_FAILURE);
+ }
+ s = nbd_get_meta_context (nbd, 1);
+ if (s == NULL) {
+ fprintf (stderr, "unable to read back requested context 1: %s\n",
+ nbd_get_error ());
+ exit (EXIT_FAILURE);
+ }
+ if (strcmp (s, BOGUS_CONTEXT) != 0) {
+ fprintf (stderr, "read back wrong context: %s\n", s);
+ exit (EXIT_FAILURE);
+ }
+
if (nbd_connect_command (nbd, args) == -1) {
fprintf (stderr, "%s\n", nbd_get_error ());
exit (EXIT_FAILURE);
@@ -92,7 +122,7 @@ main (int argc, char *argv[])
exit (EXIT_FAILURE);
}
- switch (nbd_can_meta_context (nbd, "x-libnbd:nosuch")) {
+ switch (nbd_can_meta_context (nbd, BOGUS_CONTEXT)) {
case -1:
fprintf (stderr, "%s\n", nbd_get_error ());
exit (EXIT_FAILURE);
--
2.28.0