On 03/12/2018 10:21 AM, Vladimir Sementsov-Ogievskiy wrote:
Minimal realization: only one extent in server answer is supported.
Signed-off-by: Vladimir Sementsov-Ogievskiy
---
v2: - constants and type defs were splitted out by Eric, except for
NBD_META_ID_BASE_ALLOCATION
The constant for NBD_META_ID_BASE_ALLOCATION was intentionally not split
out; it is the only constant that is relevant only to the server side ;)
In fact,...
- add nbd_opt_skip, to skip meta query remainder, if we are already sure,
that the query selects nothing
- check meta export name in OPT_EXPORT_NAME and OPT_GO
- always set context_id = 0 for NBD_OPT_LIST_META_CONTEXT
- negotiation rewritten to avoid wasting time and memory on reading long,
obviously invalid meta queries
- fixed ERR_INVALID->ERR_UNKNOWN if export not found in
nbd_negotiate_meta_queries
- check client->export_meta.valid in "case NBD_CMD_BLOCK_STATUS"
include/block/nbd.h | 2 +
nbd/server.c| 310
2 files changed, 312 insertions(+)
diff --git a/include/block/nbd.h b/include/block/nbd.h
index 2285637e67..9f2be18186 100644
--- a/include/block/nbd.h
+++ b/include/block/nbd.h
@@ -188,6 +188,8 @@ typedef struct NBDExtent {
#define NBD_CMD_FLAG_REQ_ONE(1 << 3) /* only one extent in BLOCK_STATUS
* reply chunk */
+#define NBD_META_ID_BASE_ALLOCATION 0
+
...I will be squashing in a change to move it out of the .h and into the .c.
/* Supported request types */
enum {
NBD_CMD_READ = 0,
diff --git a/nbd/server.c b/nbd/server.c
index 085e14afbf..16d7388085 100644
--- a/nbd/server.c
@@ -371,6 +396,12 @@ static int nbd_negotiate_handle_list(NBDClient *client,
Error **errp)
return nbd_negotiate_send_rep(client, NBD_REP_ACK, errp);
}
+static void nbd_check_meta_export_name(NBDClient *client)
+{
+client->export_meta.valid = client->export_meta.valid &&
+strcmp(client->exp->name, client->export_meta.export_name) == 0;
The indentation makes this harder for me to parse (at first glance, I
thought you had (a) && (b), and were either missing a side effect or
return statement). It's a lot more obvious what you are doing with:
client->export_meta.valid &= !strcmp(client->exp->name,
client->export_meta.export_name);
+/* nbd_meta_base_query
+ *
+ * Handle query to 'base' namespace. For now, only base:allocation context is
+ * available in it.
+ *
+ * Return -errno on I/O error, 0 if option was completely handled by
+ * sending a reply about inconsistent lengths, or 1 on success. */
+static int nbd_meta_base_query(NBDClient *client, NBDExportMetaContexts *meta,
+ uint32_t len, Error **errp)
The comments don't describe what 'len' represents, I had to go read the
call-site before I could understand this function. If I understand
correctly, this function is called at the point that we have parsed
"base:" out of the longer overall name given to LIST or SET, and len is
the remaining length of the overall name that still needs parsing.
+{
+int ret;
+char query[sizeof("allocation") - 1];
Why discard the trailing NUL from the size? It doesn't hurt to leave it
in, unless...
+size_t alen = strlen("allocation");
...Better than strlen() would be sizeof(query), as long as the trailing
NUL is not changing the size of the array.
+
+if (len == 0) {
+if (client->opt == NBD_OPT_LIST_META_CONTEXT) {
+meta->base_allocation = true;
+}
+return 1;
+}
Okay, so here, the user requested "base:"; on list we return all
contexts that we know (base:allocation); on set we fall through.
+
+if (len != alen) {
+return nbd_opt_skip(client, len, errp);
+}
Here, the user requested "base:garbage", where the garbage (including
empty string on set) is a different length than "base:allocation". It
may be a valid string for a future NBD version, but for us, we know
right away it is is not something we recognize, so we gracefully skip it.
Checking myself: if nbd_opt_skip returned -1, we have detected
communication problems with the client; it does not matter if there is
any unparsed data remaining in the current option. It can only return 0
if nbd_opt_invalid has already finished parsing the entire option (we
are ready to parse the next NBD_OPT command, no further queries in the
current option matter). It can only return 1 if we finished parsing the
current query, and are positioned ready to parse the next query. [1]
+
+ret = nbd_opt_read(client, query, len, errp);
+if (ret <= 0) {
+return ret;
+}
+
+if (strncmp(query, "allocation", alen) == 0) {
Here, you HAD to use strncmp because you didn't leave room for the
trailing NUL in the array above. Tradeoffs. So I guess your