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