|
|
7711c0 |
From ff100c505e2a1cdc0a405008513948caa935b6cb Mon Sep 17 00:00:00 2001
|
|
|
7711c0 |
From: John Snow <jsnow@redhat.com>
|
|
|
7711c0 |
Date: Wed, 27 Mar 2019 17:22:42 +0100
|
|
|
7711c0 |
Subject: [PATCH 104/163] nbd/client: Refactor nbd_receive_list()
|
|
|
7711c0 |
|
|
|
7711c0 |
RH-Author: John Snow <jsnow@redhat.com>
|
|
|
7711c0 |
Message-id: <20190327172308.31077-30-jsnow@redhat.com>
|
|
|
7711c0 |
Patchwork-id: 85210
|
|
|
7711c0 |
O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 29/55] nbd/client: Refactor nbd_receive_list()
|
|
|
7711c0 |
Bugzilla: 1691009
|
|
|
7711c0 |
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
|
|
|
7711c0 |
RH-Acked-by: Max Reitz <mreitz@redhat.com>
|
|
|
7711c0 |
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
|
|
7711c0 |
|
|
|
7711c0 |
From: Eric Blake <eblake@redhat.com>
|
|
|
7711c0 |
|
|
|
7711c0 |
Right now, nbd_receive_list() is only called by
|
|
|
7711c0 |
nbd_receive_query_exports(), which in turn is only called if the
|
|
|
7711c0 |
server lacks NBD_OPT_GO but has working option negotiation, and is
|
|
|
7711c0 |
merely used as a quality-of-implementation trick since servers
|
|
|
7711c0 |
can't give decent errors for NBD_OPT_EXPORT_NAME. However, servers
|
|
|
7711c0 |
that lack NBD_OPT_GO are becoming increasingly rare (nbdkit was a
|
|
|
7711c0 |
latecomer, in Aug 2018, but qemu has been such a server since commit
|
|
|
7711c0 |
f37708f6 in July 2017 and released in 2.10), so it no longer makes
|
|
|
7711c0 |
sense to micro-optimize that function for performance.
|
|
|
7711c0 |
|
|
|
7711c0 |
Furthermore, when debugging a server's implementation, tracing the
|
|
|
7711c0 |
full reply (both names and descriptions) is useful, not to mention
|
|
|
7711c0 |
that upcoming patches adding 'qemu-nbd --list' will want to collect
|
|
|
7711c0 |
that data. And when you consider that a server can send an export
|
|
|
7711c0 |
name up to the NBD protocol length limit of 4k; but our current
|
|
|
7711c0 |
NBD_MAX_NAME_SIZE is only 256, we can't trace all valid server
|
|
|
7711c0 |
names without more storage, but 4k is large enough that the heap
|
|
|
7711c0 |
is better than the stack for long names.
|
|
|
7711c0 |
|
|
|
7711c0 |
Thus, I'm changing the division of labor, with nbd_receive_list()
|
|
|
7711c0 |
now always malloc'ing a result on success (the malloc is bounded
|
|
|
7711c0 |
by the fact that we reject servers with a reply length larger
|
|
|
7711c0 |
than 32M), and moving the comparison to 'wantname' to the caller.
|
|
|
7711c0 |
|
|
|
7711c0 |
There is a minor change in behavior where a server with 0 exports
|
|
|
7711c0 |
(an immediate NBD_REP_ACK reply) is now no longer distinguished
|
|
|
7711c0 |
from a server without LIST support (NBD_REP_ERR_UNSUP); this
|
|
|
7711c0 |
information could be preserved with a complication to the calling
|
|
|
7711c0 |
contract to provide a bit more information, but I didn't see the
|
|
|
7711c0 |
point. After all, the worst that can happen if our guess at a
|
|
|
7711c0 |
match is wrong is that the caller will get a cryptic disconnect
|
|
|
7711c0 |
when NBD_OPT_EXPORT_NAME fails (which is no different from what
|
|
|
7711c0 |
would happen if we had not tried LIST), while treating an empty
|
|
|
7711c0 |
list as immediate failure would prevent connecting to really old
|
|
|
7711c0 |
servers that really did lack LIST. Besides, NBD servers with 0
|
|
|
7711c0 |
exports are rare (qemu can do it when using QMP nbd-server-start
|
|
|
7711c0 |
without nbd-server-add - but qemu understands NBD_OPT_GO and
|
|
|
7711c0 |
thus won't tickle this change in behavior).
|
|
|
7711c0 |
|
|
|
7711c0 |
Fix the spelling of foundExport to match coding standards while
|
|
|
7711c0 |
in the area.
|
|
|
7711c0 |
|
|
|
7711c0 |
Signed-off-by: Eric Blake <eblake@redhat.com>
|
|
|
7711c0 |
Reviewed-by: Richard W.M. Jones <rjones@redhat.com>
|
|
|
7711c0 |
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
|
|
|
7711c0 |
Message-Id: <20190117193658.16413-9-eblake@redhat.com>
|
|
|
7711c0 |
(cherry picked from commit 091d0bf3c94737fc451a9b3f4eddf3a4d74c90b8)
|
|
|
7711c0 |
Signed-off-by: John Snow <jsnow@redhat.com>
|
|
|
7711c0 |
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
|
|
|
7711c0 |
---
|
|
|
7711c0 |
nbd/client.c | 91 ++++++++++++++++++++++++++++++++++++--------------------
|
|
|
7711c0 |
nbd/trace-events | 1 +
|
|
|
7711c0 |
2 files changed, 59 insertions(+), 33 deletions(-)
|
|
|
7711c0 |
|
|
|
7711c0 |
diff --git a/nbd/client.c b/nbd/client.c
|
|
|
7711c0 |
index f625c20..fd4ba8d 100644
|
|
|
7711c0 |
--- a/nbd/client.c
|
|
|
7711c0 |
+++ b/nbd/client.c
|
|
|
7711c0 |
@@ -234,18 +234,24 @@ static int nbd_handle_reply_err(QIOChannel *ioc, NBDOptionReply *reply,
|
|
|
7711c0 |
return result;
|
|
|
7711c0 |
}
|
|
|
7711c0 |
|
|
|
7711c0 |
-/* Process another portion of the NBD_OPT_LIST reply. Set *@match if
|
|
|
7711c0 |
- * the current reply matches @want or if the server does not support
|
|
|
7711c0 |
- * NBD_OPT_LIST, otherwise leave @match alone. Return 0 if iteration
|
|
|
7711c0 |
- * is complete, positive if more replies are expected, or negative
|
|
|
7711c0 |
- * with @errp set if an unrecoverable error occurred. */
|
|
|
7711c0 |
-static int nbd_receive_list(QIOChannel *ioc, const char *want, bool *match,
|
|
|
7711c0 |
+/* nbd_receive_list:
|
|
|
7711c0 |
+ * Process another portion of the NBD_OPT_LIST reply, populating any
|
|
|
7711c0 |
+ * name received into *@name. If @description is non-NULL, and the
|
|
|
7711c0 |
+ * server provided a description, that is also populated. The caller
|
|
|
7711c0 |
+ * must eventually call g_free() on success.
|
|
|
7711c0 |
+ * Returns 1 if name and description were set and iteration must continue,
|
|
|
7711c0 |
+ * 0 if iteration is complete (including if OPT_LIST unsupported),
|
|
|
7711c0 |
+ * -1 with @errp set if an unrecoverable error occurred.
|
|
|
7711c0 |
+ */
|
|
|
7711c0 |
+static int nbd_receive_list(QIOChannel *ioc, char **name, char **description,
|
|
|
7711c0 |
Error **errp)
|
|
|
7711c0 |
{
|
|
|
7711c0 |
+ int ret = -1;
|
|
|
7711c0 |
NBDOptionReply reply;
|
|
|
7711c0 |
uint32_t len;
|
|
|
7711c0 |
uint32_t namelen;
|
|
|
7711c0 |
- char name[NBD_MAX_NAME_SIZE + 1];
|
|
|
7711c0 |
+ char *local_name = NULL;
|
|
|
7711c0 |
+ char *local_desc = NULL;
|
|
|
7711c0 |
int error;
|
|
|
7711c0 |
|
|
|
7711c0 |
if (nbd_receive_option_reply(ioc, NBD_OPT_LIST, &reply, errp) < 0) {
|
|
|
7711c0 |
@@ -253,9 +259,6 @@ static int nbd_receive_list(QIOChannel *ioc, const char *want, bool *match,
|
|
|
7711c0 |
}
|
|
|
7711c0 |
error = nbd_handle_reply_err(ioc, &reply, errp);
|
|
|
7711c0 |
if (error <= 0) {
|
|
|
7711c0 |
- /* The server did not support NBD_OPT_LIST, so set *match on
|
|
|
7711c0 |
- * the assumption that any name will be accepted. */
|
|
|
7711c0 |
- *match = true;
|
|
|
7711c0 |
return error;
|
|
|
7711c0 |
}
|
|
|
7711c0 |
len = reply.length;
|
|
|
7711c0 |
@@ -292,33 +295,38 @@ static int nbd_receive_list(QIOChannel *ioc, const char *want, bool *match,
|
|
|
7711c0 |
nbd_send_opt_abort(ioc);
|
|
|
7711c0 |
return -1;
|
|
|
7711c0 |
}
|
|
|
7711c0 |
- if (namelen != strlen(want)) {
|
|
|
7711c0 |
- if (nbd_drop(ioc, len, errp) < 0) {
|
|
|
7711c0 |
- error_prepend(errp,
|
|
|
7711c0 |
- "failed to skip export name with wrong length: ");
|
|
|
7711c0 |
- nbd_send_opt_abort(ioc);
|
|
|
7711c0 |
- return -1;
|
|
|
7711c0 |
- }
|
|
|
7711c0 |
- return 1;
|
|
|
7711c0 |
- }
|
|
|
7711c0 |
|
|
|
7711c0 |
- assert(namelen < sizeof(name));
|
|
|
7711c0 |
- if (nbd_read(ioc, name, namelen, errp) < 0) {
|
|
|
7711c0 |
+ local_name = g_malloc(namelen + 1);
|
|
|
7711c0 |
+ if (nbd_read(ioc, local_name, namelen, errp) < 0) {
|
|
|
7711c0 |
error_prepend(errp, "failed to read export name: ");
|
|
|
7711c0 |
nbd_send_opt_abort(ioc);
|
|
|
7711c0 |
- return -1;
|
|
|
7711c0 |
+ goto out;
|
|
|
7711c0 |
}
|
|
|
7711c0 |
- name[namelen] = '\0';
|
|
|
7711c0 |
+ local_name[namelen] = '\0';
|
|
|
7711c0 |
len -= namelen;
|
|
|
7711c0 |
- if (nbd_drop(ioc, len, errp) < 0) {
|
|
|
7711c0 |
- error_prepend(errp, "failed to read export description: ");
|
|
|
7711c0 |
- nbd_send_opt_abort(ioc);
|
|
|
7711c0 |
- return -1;
|
|
|
7711c0 |
+ if (len) {
|
|
|
7711c0 |
+ local_desc = g_malloc(len + 1);
|
|
|
7711c0 |
+ if (nbd_read(ioc, local_desc, len, errp) < 0) {
|
|
|
7711c0 |
+ error_prepend(errp, "failed to read export description: ");
|
|
|
7711c0 |
+ nbd_send_opt_abort(ioc);
|
|
|
7711c0 |
+ goto out;
|
|
|
7711c0 |
+ }
|
|
|
7711c0 |
+ local_desc[len] = '\0';
|
|
|
7711c0 |
}
|
|
|
7711c0 |
- if (!strcmp(name, want)) {
|
|
|
7711c0 |
- *match = true;
|
|
|
7711c0 |
+
|
|
|
7711c0 |
+ trace_nbd_receive_list(local_name, local_desc ?: "");
|
|
|
7711c0 |
+ *name = local_name;
|
|
|
7711c0 |
+ local_name = NULL;
|
|
|
7711c0 |
+ if (description) {
|
|
|
7711c0 |
+ *description = local_desc;
|
|
|
7711c0 |
+ local_desc = NULL;
|
|
|
7711c0 |
}
|
|
|
7711c0 |
- return 1;
|
|
|
7711c0 |
+ ret = 1;
|
|
|
7711c0 |
+
|
|
|
7711c0 |
+ out:
|
|
|
7711c0 |
+ g_free(local_name);
|
|
|
7711c0 |
+ g_free(local_desc);
|
|
|
7711c0 |
+ return ret;
|
|
|
7711c0 |
}
|
|
|
7711c0 |
|
|
|
7711c0 |
|
|
|
7711c0 |
@@ -493,7 +501,8 @@ static int nbd_receive_query_exports(QIOChannel *ioc,
|
|
|
7711c0 |
const char *wantname,
|
|
|
7711c0 |
Error **errp)
|
|
|
7711c0 |
{
|
|
|
7711c0 |
- bool foundExport = false;
|
|
|
7711c0 |
+ bool list_empty = true;
|
|
|
7711c0 |
+ bool found_export = false;
|
|
|
7711c0 |
|
|
|
7711c0 |
trace_nbd_receive_query_exports_start(wantname);
|
|
|
7711c0 |
if (nbd_send_option_request(ioc, NBD_OPT_LIST, 0, NULL, errp) < 0) {
|
|
|
7711c0 |
@@ -501,14 +510,25 @@ static int nbd_receive_query_exports(QIOChannel *ioc,
|
|
|
7711c0 |
}
|
|
|
7711c0 |
|
|
|
7711c0 |
while (1) {
|
|
|
7711c0 |
- int ret = nbd_receive_list(ioc, wantname, &foundExport, errp);
|
|
|
7711c0 |
+ char *name;
|
|
|
7711c0 |
+ int ret = nbd_receive_list(ioc, &name, NULL, errp);
|
|
|
7711c0 |
|
|
|
7711c0 |
if (ret < 0) {
|
|
|
7711c0 |
/* Server gave unexpected reply */
|
|
|
7711c0 |
return -1;
|
|
|
7711c0 |
} else if (ret == 0) {
|
|
|
7711c0 |
/* Done iterating. */
|
|
|
7711c0 |
- if (!foundExport) {
|
|
|
7711c0 |
+ if (list_empty) {
|
|
|
7711c0 |
+ /*
|
|
|
7711c0 |
+ * We don't have enough context to tell a server that
|
|
|
7711c0 |
+ * sent an empty list apart from a server that does
|
|
|
7711c0 |
+ * not support the list command; but as this function
|
|
|
7711c0 |
+ * is just used to trigger a nicer error message
|
|
|
7711c0 |
+ * before trying NBD_OPT_EXPORT_NAME, assume the
|
|
|
7711c0 |
+ * export is available.
|
|
|
7711c0 |
+ */
|
|
|
7711c0 |
+ return 0;
|
|
|
7711c0 |
+ } else if (!found_export) {
|
|
|
7711c0 |
error_setg(errp, "No export with name '%s' available",
|
|
|
7711c0 |
wantname);
|
|
|
7711c0 |
nbd_send_opt_abort(ioc);
|
|
|
7711c0 |
@@ -517,6 +537,11 @@ static int nbd_receive_query_exports(QIOChannel *ioc,
|
|
|
7711c0 |
trace_nbd_receive_query_exports_success(wantname);
|
|
|
7711c0 |
return 0;
|
|
|
7711c0 |
}
|
|
|
7711c0 |
+ list_empty = false;
|
|
|
7711c0 |
+ if (!strcmp(name, wantname)) {
|
|
|
7711c0 |
+ found_export = true;
|
|
|
7711c0 |
+ }
|
|
|
7711c0 |
+ g_free(name);
|
|
|
7711c0 |
}
|
|
|
7711c0 |
}
|
|
|
7711c0 |
|
|
|
7711c0 |
diff --git a/nbd/trace-events b/nbd/trace-events
|
|
|
7711c0 |
index 5492042..d1e1ca6 100644
|
|
|
7711c0 |
--- a/nbd/trace-events
|
|
|
7711c0 |
+++ b/nbd/trace-events
|
|
|
7711c0 |
@@ -3,6 +3,7 @@ nbd_send_option_request(uint32_t opt, const char *name, uint32_t len) "Sending o
|
|
|
7711c0 |
nbd_receive_option_reply(uint32_t option, const char *optname, uint32_t type, const char *typename, uint32_t length) "Received option reply %" PRIu32" (%s), type %" PRIu32" (%s), len %" PRIu32
|
|
|
7711c0 |
nbd_server_error_msg(uint32_t err, const char *type, const char *msg) "server reported error 0x%" PRIx32 " (%s) with additional message: %s"
|
|
|
7711c0 |
nbd_reply_err_unsup(uint32_t option, const char *name) "server doesn't understand request %" PRIu32 " (%s), attempting fallback"
|
|
|
7711c0 |
+nbd_receive_list(const char *name, const char *desc) "export list includes '%s', description '%s'"
|
|
|
7711c0 |
nbd_opt_go_start(const char *name) "Attempting NBD_OPT_GO for export '%s'"
|
|
|
7711c0 |
nbd_opt_go_success(void) "Export is good to go"
|
|
|
7711c0 |
nbd_opt_go_info_unknown(int info, const char *name) "Ignoring unknown info %d (%s)"
|
|
|
7711c0 |
--
|
|
|
7711c0 |
1.8.3.1
|
|
|
7711c0 |
|