From: Eric Blake <eblake@redhat.com>
To: qemu-devel@nongnu.org
Cc: pkrempa@redhat.com, vsementsov@virtuozzo.com, rjones@redhat.com,
qemu-block@nongnu.org
Subject: [PATCH 1/3] nbd: Simplify meta-context parsing
Date: Fri, 25 Sep 2020 15:32:47 -0500 [thread overview]
Message-ID: <20200925203249.155705-2-eblake@redhat.com> (raw)
In-Reply-To: <20200925203249.155705-1-eblake@redhat.com>
We had a premature optimization of trying to read as little from the
wire as possible while handling NBD_OPT_SET_META_CONTEXT in phases.
But in reality, we HAVE to read the entire string from the client
before we can get to the next command, and it is easier to just read
it all at once than it is to read it in pieces. And once we do that,
several functions end up no longer performing I/O, and no longer need
to return a value.
While simplifying this, take advantage of g_str_has_prefix for less
repetition of boilerplate string length computation.
Our iotests still pass; I also checked that libnbd's testsuite (which
covers more corner cases of odd meta context requests) still passes.
Signed-off-by: Eric Blake <eblake@redhat.com>
---
nbd/server.c | 172 ++++++++++++++-------------------------------------
1 file changed, 47 insertions(+), 125 deletions(-)
diff --git a/nbd/server.c b/nbd/server.c
index 982de67816a7..0d2d7e52058f 100644
--- a/nbd/server.c
+++ b/nbd/server.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016-2018 Red Hat, Inc.
+ * Copyright (C) 2016-2020 Red Hat, Inc.
* Copyright (C) 2005 Anthony Liguori <anthony@codemonkey.ws>
*
* Network Block Device Server Side
@@ -792,135 +792,64 @@ static int nbd_negotiate_send_meta_context(NBDClient *client,
return qio_channel_writev_all(client->ioc, iov, 2, errp) < 0 ? -EIO : 0;
}
-/* Read strlen(@pattern) bytes, and set @match to true if they match @pattern.
- * @match is never set to false.
- *
- * Return -errno on I/O error, 0 if option was completely handled by
- * sending a reply about inconsistent lengths, or 1 on success.
- *
- * Note: return code = 1 doesn't mean that we've read exactly @pattern.
- * It only means that there are no errors.
+
+/*
+ * Check @ns with @len bytes, and set @match to true if it matches @pattern,
+ * or if @len is 0 and the client is performing _LIST_. @match is never set
+ * to false.
*/
-static int nbd_meta_pattern(NBDClient *client, const char *pattern, bool *match,
- Error **errp)
+static void nbd_meta_empty_or_pattern(NBDClient *client, const char *pattern,
+ const char *ns, uint32_t len,
+ bool *match, Error **errp)
{
- int ret;
- char *query;
- size_t len = strlen(pattern);
-
- assert(len);
-
- query = g_malloc(len);
- ret = nbd_opt_read(client, query, len, errp);
- if (ret <= 0) {
- g_free(query);
- return ret;
- }
-
- if (strncmp(query, pattern, len) == 0) {
+ if (len == 0) {
+ if (client->opt == NBD_OPT_LIST_META_CONTEXT) {
+ *match = true;
+ }
+ trace_nbd_negotiate_meta_query_parse("empty");
+ } else if (strcmp(pattern, ns) == 0) {
trace_nbd_negotiate_meta_query_parse(pattern);
*match = true;
} else {
trace_nbd_negotiate_meta_query_skip("pattern not matched");
}
- g_free(query);
-
- return 1;
-}
-
-/*
- * Read @len bytes, and set @match to true if they match @pattern, or if @len
- * is 0 and the client is performing _LIST_. @match is never set to false.
- *
- * Return -errno on I/O error, 0 if option was completely handled by
- * sending a reply about inconsistent lengths, or 1 on success.
- *
- * Note: return code = 1 doesn't mean that we've read exactly @pattern.
- * It only means that there are no errors.
- */
-static int nbd_meta_empty_or_pattern(NBDClient *client, const char *pattern,
- uint32_t len, bool *match, Error **errp)
-{
- if (len == 0) {
- if (client->opt == NBD_OPT_LIST_META_CONTEXT) {
- *match = true;
- }
- trace_nbd_negotiate_meta_query_parse("empty");
- return 1;
- }
-
- if (len != strlen(pattern)) {
- trace_nbd_negotiate_meta_query_skip("different lengths");
- return nbd_opt_skip(client, len, errp);
- }
-
- return nbd_meta_pattern(client, pattern, match, errp);
}
/* nbd_meta_base_query
*
* Handle queries to 'base' namespace. For now, only the base:allocation
- * context is available. 'len' is the amount of text remaining to be read from
- * the current name, after the 'base:' portion has been stripped.
- *
- * Return -errno on I/O error, 0 if option was completely handled by
- * sending a reply about inconsistent lengths, or 1 on success.
+ * context is available. @len is the length of @ns, including the 'base:'
+ * prefix.
*/
-static int nbd_meta_base_query(NBDClient *client, NBDExportMetaContexts *meta,
- uint32_t len, Error **errp)
+static void nbd_meta_base_query(NBDClient *client, NBDExportMetaContexts *meta,
+ const char *ns, uint32_t len, Error **errp)
{
- return nbd_meta_empty_or_pattern(client, "allocation", len,
- &meta->base_allocation, errp);
+ nbd_meta_empty_or_pattern(client, "allocation", ns + 5, len - 5,
+ &meta->base_allocation, errp);
}
/* nbd_meta_bitmap_query
*
* Handle query to 'qemu:' namespace.
- * @len is the amount of text remaining to be read from the current name, after
- * the 'qemu:' portion has been stripped.
- *
- * 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_qemu_query(NBDClient *client, NBDExportMetaContexts *meta,
- uint32_t len, Error **errp)
+ * @len is the length of @ns, including the `qemu:' prefix.
+ */
+static void nbd_meta_qemu_query(NBDClient *client, NBDExportMetaContexts *meta,
+ const char *ns, uint32_t len, Error **errp)
{
- bool dirty_bitmap = false;
- size_t dirty_bitmap_len = strlen("dirty-bitmap:");
- int ret;
-
if (!meta->exp->export_bitmap) {
trace_nbd_negotiate_meta_query_skip("no dirty-bitmap exported");
- return nbd_opt_skip(client, len, errp);
- }
-
- if (len == 0) {
+ } else if (len == 0) {
if (client->opt == NBD_OPT_LIST_META_CONTEXT) {
meta->bitmap = true;
}
trace_nbd_negotiate_meta_query_parse("empty");
- return 1;
- }
-
- if (len < dirty_bitmap_len) {
- trace_nbd_negotiate_meta_query_skip("not dirty-bitmap:");
- return nbd_opt_skip(client, len, errp);
- }
-
- len -= dirty_bitmap_len;
- ret = nbd_meta_pattern(client, "dirty-bitmap:", &dirty_bitmap, errp);
- if (ret <= 0) {
- return ret;
- }
- if (!dirty_bitmap) {
+ } else if (!g_str_has_prefix(ns + 5, "dirty-bitmap:")) {
trace_nbd_negotiate_meta_query_skip("not dirty-bitmap:");
- return nbd_opt_skip(client, len, errp);
+ } else {
+ trace_nbd_negotiate_meta_query_parse("dirty-bitmap:");
+ nbd_meta_empty_or_pattern(client, meta->exp->export_bitmap_context,
+ ns, len, &meta->bitmap, errp);
}
-
- trace_nbd_negotiate_meta_query_parse("dirty-bitmap:");
-
- return nbd_meta_empty_or_pattern(
- client, meta->exp->export_bitmap_context +
- strlen("qemu:dirty_bitmap:"), len, &meta->bitmap, errp);
}
/* nbd_negotiate_meta_query
@@ -930,22 +859,13 @@ static int nbd_meta_qemu_query(NBDClient *client, NBDExportMetaContexts *meta,
*
* The only supported namespaces are 'base' and 'qemu'.
*
- * The function aims not wasting time and memory to read long unknown namespace
- * names.
- *
* 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_negotiate_meta_query(NBDClient *client,
NBDExportMetaContexts *meta, Error **errp)
{
- /*
- * Both 'qemu' and 'base' namespaces have length = 5 including a
- * colon. If another length namespace is later introduced, this
- * should certainly be refactored.
- */
int ret;
- size_t ns_len = 5;
- char ns[5];
+ g_autofree char *ns = NULL;
uint32_t len;
ret = nbd_opt_read(client, &len, sizeof(len), errp);
@@ -958,27 +878,29 @@ static int nbd_negotiate_meta_query(NBDClient *client,
trace_nbd_negotiate_meta_query_skip("length too long");
return nbd_opt_skip(client, len, errp);
}
- if (len < ns_len) {
- trace_nbd_negotiate_meta_query_skip("length too short");
- return nbd_opt_skip(client, len, errp);
- }
- len -= ns_len;
- ret = nbd_opt_read(client, ns, ns_len, errp);
+ ns = g_malloc(len + 1);
+ ret = nbd_opt_read(client, ns, len, errp);
if (ret <= 0) {
return ret;
}
+ ns[len] = '\0';
+ if (strlen(ns) != len) {
+ return nbd_opt_invalid(client, errp,
+ "Embedded NUL in query for option %s",
+ nbd_opt_lookup(client->opt));
+ }
- if (!strncmp(ns, "base:", ns_len)) {
+ if (g_str_has_prefix(ns, "base:")) {
trace_nbd_negotiate_meta_query_parse("base:");
- return nbd_meta_base_query(client, meta, len, errp);
- } else if (!strncmp(ns, "qemu:", ns_len)) {
+ nbd_meta_base_query(client, meta, ns, len, errp);
+ } else if (g_str_has_prefix(ns, "qemu:")) {
trace_nbd_negotiate_meta_query_parse("qemu:");
- return nbd_meta_qemu_query(client, meta, len, errp);
+ nbd_meta_qemu_query(client, meta, ns, len, errp);
+ } else {
+ trace_nbd_negotiate_meta_query_skip("unknown namespace");
}
-
- trace_nbd_negotiate_meta_query_skip("unknown namespace");
- return nbd_opt_skip(client, len, errp);
+ return 1;
}
/* nbd_negotiate_meta_queries
--
2.28.0
next prev parent reply other threads:[~2020-09-25 20:34 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-09-25 20:32 [PATCH 0/3] Exposing backing-chain allocation over NBD Eric Blake
2020-09-25 20:32 ` Eric Blake [this message]
2020-09-26 12:58 ` [PATCH 1/3] nbd: Simplify meta-context parsing Vladimir Sementsov-Ogievskiy
2020-09-28 14:05 ` Eric Blake
2020-09-25 20:32 ` [PATCH 2/3] nbd: Add new qemu:allocation-depth metacontext Eric Blake
2020-09-26 7:33 ` Richard W.M. Jones
2020-09-26 13:19 ` Vladimir Sementsov-Ogievskiy
2020-09-28 14:33 ` Eric Blake
2020-09-28 16:17 ` Richard W.M. Jones
2020-09-26 13:15 ` Vladimir Sementsov-Ogievskiy
2020-09-25 20:32 ` [PATCH 3/3] nbd: Add 'qemu-nbd -A' to expose allocation depth Eric Blake
2020-09-26 7:34 ` Richard W.M. Jones
2020-09-26 13:32 ` Vladimir Sementsov-Ogievskiy
2020-09-28 14:35 ` Eric Blake
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20200925203249.155705-2-eblake@redhat.com \
--to=eblake@redhat.com \
--cc=pkrempa@redhat.com \
--cc=qemu-block@nongnu.org \
--cc=qemu-devel@nongnu.org \
--cc=rjones@redhat.com \
--cc=vsementsov@virtuozzo.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).