None are supported at present, so this always returns an empty list.
---
docs/nbdkit-protocol.pod | 4 ++
server/protocol.h | 2 +
server/connections.c | 84 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 90 insertions(+)
diff --git a/docs/nbdkit-protocol.pod b/docs/nbdkit-protocol.pod
index 68438fa..4c65e00 100644
--- a/docs/nbdkit-protocol.pod
+++ b/docs/nbdkit-protocol.pod
@@ -128,6 +128,10 @@ However we don’t expose the capability to send structured replies to
plugins yet, nor do we send human-readable error messages using this
facility.
+=item Metadata Querying
+
+Supported in nbdkit E<ge> 1.11.8.
+
=item Block Status
I<Not supported>.
diff --git a/server/protocol.h b/server/protocol.h
index 0aadd46..b03555e 100644
--- a/server/protocol.h
+++ b/server/protocol.h
@@ -105,6 +105,8 @@ extern const char *name_of_nbd_opt (int);
#define NBD_OPT_INFO 6
#define NBD_OPT_GO 7
#define NBD_OPT_STRUCTURED_REPLY 8
+#define NBD_OPT_LIST_META_CONTEXT 9
+#define NBD_OPT_SET_META_CONTEXT 10
extern const char *name_of_nbd_rep (int);
#define NBD_REP_ACK 1
diff --git a/server/connections.c b/server/connections.c
index aeb27f8..7e32f00 100644
--- a/server/connections.c
+++ b/server/connections.c
@@ -926,6 +926,90 @@ _negotiate_handshake_newstyle_options (struct connection *conn)
conn->structured_replies = true;
break;
+ case NBD_OPT_LIST_META_CONTEXT:
+ case NBD_OPT_SET_META_CONTEXT:
+ {
+ uint32_t opt_index;
+ uint32_t exportnamelen;
+ uint32_t nr_queries;
+ uint32_t querylen;
+ const char *what;
+
+ optname = name_of_nbd_opt (option);
+ if (conn_recv_full (conn, data, optlen, "read: %s: %m", optname) ==
-1)
+ return -1;
+
+ if (!conn->structured_replies) {
+ if (send_newstyle_option_reply (conn, option, NBD_REP_ERR_INVALID)
+ == -1)
+ return -1;
+ continue;
+ }
+
+ /* Minimum length of the option payload is the 32 bit export
+ * name plus a zero length export name plus 32 bit number of
+ * queries followed by no queries.
+ */
+ what = "optlen < 8";
+ if (optlen < 8) {
+ opt_meta_invalid_option_len:
+ debug ("newstyle negotiation: %s: invalid option length: %s",
+ optname, what);
+
+ if (send_newstyle_option_reply (conn, option, NBD_REP_ERR_INVALID)
+ == -1)
+ return -1;
+ continue;
+ }
+
+ /* Discard the export name. */
+ memcpy (&exportnamelen, &data[0], 4);
+ exportnamelen = be32toh (exportnamelen);
+ opt_index = 4 + exportnamelen;
+
+ /* Read the number of queries. */
+ what = "reading number of queries";
+ if (opt_index+4 > optlen)
+ goto opt_meta_invalid_option_len;
+ memcpy (&nr_queries, &data[opt_index], 4);
+ nr_queries = be32toh (nr_queries);
+ opt_index += 4;
+
+ /* nr_queries == 0 means return all meta contexts. */
+ if (nr_queries == 0) {
+ /* Nothing is supported now. */
+ if (send_newstyle_option_reply (conn, option, NBD_REP_ACK) == -1)
+ return -1;
+ }
+ else {
+ /* Read and answer each query. */
+ while (nr_queries > 0) {
+ what = "reading query string length";
+ if (opt_index+4 > optlen)
+ goto opt_meta_invalid_option_len;
+ memcpy (&querylen, &data[opt_index], 4);
+ querylen = be32toh (querylen);
+ opt_index += 4;
+ what = "reading query string";
+ if (opt_index + querylen > optlen)
+ goto opt_meta_invalid_option_len;
+
+ debug ("newstyle negotiation: %s: %s %.*s",
+ optname,
+ option == NBD_OPT_LIST_META_CONTEXT ? "query" :
"set",
+ (int) querylen, &data[opt_index]);
+
+ /* Ignore query - nothing is supported. */
+
+ opt_index += querylen;
+ nr_queries--;
+ }
+ if (send_newstyle_option_reply (conn, option, NBD_REP_ACK) == -1)
+ return -1;
+ }
+ }
+ break;
+
default:
/* Unknown option. */
if (send_newstyle_option_reply (conn, option, NBD_REP_ERR_UNSUP) == -1)
--
2.20.1