From: Eric Blake <eblake@redhat.com>
To: qemu-devel@nongnu.org
Cc: alex@alex.org.uk, Paolo Bonzini <pbonzini@redhat.com>,
Kevin Wolf <kwolf@redhat.com>,
"open list:Block layer core" <qemu-block@nongnu.org>
Subject: [Qemu-devel] [PATCH 14/18] nbd: Implement NBD_OPT_GO on client
Date: Fri, 8 Apr 2016 16:05:54 -0600 [thread overview]
Message-ID: <1460153158-21612-15-git-send-email-eblake@redhat.com> (raw)
In-Reply-To: <1460153158-21612-1-git-send-email-eblake@redhat.com>
NBD_OPT_EXPORT_NAME is lousy: it doesn't have any sane error
reporting. Upstream NBD recently added NBD_OPT_GO as the
improved version of the option that does what we want: it
reports sane errors on failures (including when a server
requires TLS but does not have NBD_OPT_GO!), and on success
it concludes with the same data as NBD_OPT_EXPORT_NAME sends.
Signed-off-by: Eric Blake <eblake@redhat.com>
---
include/block/nbd.h | 1 +
nbd/nbd-internal.h | 7 +++++
nbd/client.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++--
3 files changed, 92 insertions(+), 2 deletions(-)
diff --git a/include/block/nbd.h b/include/block/nbd.h
index 35c0ea3..d261dbc 100644
--- a/include/block/nbd.h
+++ b/include/block/nbd.h
@@ -88,6 +88,7 @@ typedef struct nbd_reply nbd_reply;
#define NBD_REP_ERR_POLICY ((UINT32_C(1) << 31) | 2) /* Server denied */
#define NBD_REP_ERR_INVALID ((UINT32_C(1) << 31) | 3) /* Invalid length. */
#define NBD_REP_ERR_TLS_REQD ((UINT32_C(1) << 31) | 5) /* TLS required */
+#define NBD_REP_ERR_UNKNOWN ((UINT32_C(1) << 31) | 6) /* Export unknown */
/* Request flags, sent from client to server during transmission phase */
#define NBD_CMD_FLAG_FUA (1 << 0)
diff --git a/nbd/nbd-internal.h b/nbd/nbd-internal.h
index b78d249..ddba1d0 100644
--- a/nbd/nbd-internal.h
+++ b/nbd/nbd-internal.h
@@ -55,8 +55,13 @@
* https://github.com/yoe/nbd/blob/master/doc/proto.md
*/
+/* Size of all NBD_OPT_*, without payload */
#define NBD_REQUEST_SIZE (4 + 2 + 2 + 8 + 8 + 4)
+/* Size of all NBD_REP_* sent in answer to most NBD_OPT_*, without payload */
#define NBD_REPLY_SIZE (4 + 4 + 8)
+/* Size of reply to NBD_OPT_EXPORT_NAME, without trailing zeroes */
+#define NBD_FINAL_REPLY_SIZE (8 + 2)
+
#define NBD_REQUEST_MAGIC 0x25609513
#define NBD_REPLY_MAGIC 0x67446698
#define NBD_OPTS_MAGIC 0x49484156454F5054LL
@@ -80,6 +85,8 @@
#define NBD_OPT_LIST (3)
#define NBD_OPT_PEEK_EXPORT (4)
#define NBD_OPT_STARTTLS (5)
+#define NBD_OPT_INFO (6)
+#define NBD_OPT_GO (7)
/* NBD errors are based on errno numbers, so there is a 1:1 mapping,
* but only a limited set of errno values is specified in the protocol.
diff --git a/nbd/client.c b/nbd/client.c
index 507ddc1..af17d4c 100644
--- a/nbd/client.c
+++ b/nbd/client.c
@@ -215,6 +215,11 @@ static int nbd_handle_reply_err(QIOChannel *ioc, nbd_opt_reply *reply,
reply->option);
break;
+ case NBD_REP_ERR_UNKNOWN:
+ error_setg(errp, "Requested export not available for option %" PRIx32,
+ reply->option);
+ break;
+
default:
error_setg(errp, "Unknown error code when asking for option %" PRIx32,
reply->option);
@@ -299,6 +304,67 @@ static int nbd_receive_list(QIOChannel *ioc, const char *want, Error **errp)
}
+/* Returns -1 if NBD_OPT_GO proves the export cannot be used, 0 if
+ * NBD_OPT_GO is unsupported (fall back to NBD_OPT_LIST and
+ * NBD_OPT_EXPORT_NAME in that case), and > 0 if the export is good to
+ * go (with the server data at the same point as it would be right
+ * after sending NBD_OPT_EXPORT_NAME). */
+static int nbd_opt_go(QIOChannel *ioc, const char *wantname, Error **errp)
+{
+ nbd_opt_reply reply;
+ uint32_t len;
+ uint32_t namelen;
+ int error;
+ char buf[NBD_MAX_NAME_SIZE];
+
+ TRACE("Attempting NBD_OPT_GO for export '%s'", wantname);
+ if (nbd_send_option_request(ioc, NBD_OPT_GO, -1, wantname, errp) < 0) {
+ return -1;
+ }
+
+ TRACE("Reading export info");
+ if (nbd_receive_option_reply(ioc, NBD_OPT_GO, &reply, errp) < 0) {
+ return -1;
+ }
+ error = nbd_handle_reply_err(ioc, &reply, errp);
+ if (error <= 0) {
+ return error;
+ }
+ len = reply.length;
+
+ if (reply.type != NBD_REP_SERVER) {
+ error_setg(errp, "unexpected reply type %" PRIx32 ", expected %x",
+ reply.type, NBD_REP_SERVER);
+ return -1;
+ }
+
+ if (len < sizeof(namelen) + NBD_FINAL_REPLY_SIZE ||
+ len > sizeof(namelen) + sizeof(buf) + NBD_FINAL_REPLY_SIZE) {
+ error_setg(errp, "reply with %" PRIu32 " bytes is unexpected size",
+ len);
+ return -1;
+ }
+
+ if (read_sync(ioc, &namelen, sizeof(namelen)) != sizeof(namelen)) {
+ error_setg(errp, "failed to read namelen");
+ return -1;
+ }
+ be32_to_cpus(&namelen);
+ if (len != sizeof(namelen) + namelen + NBD_FINAL_REPLY_SIZE) {
+ error_setg(errp, "namelen %" PRIu32 " is unexpected size",
+ len);
+ return -1;
+ }
+
+ if (read_sync(ioc, buf, namelen) != namelen) {
+ error_setg(errp, "failed to read name");
+ return -1;
+ }
+
+ TRACE("export is good to go");
+ return 1;
+}
+
/* Return -1 on failure, 0 if wantname is an available export. */
static int nbd_receive_query_exports(QIOChannel *ioc,
const char *wantname,
@@ -505,11 +571,26 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint32_t *flags,
name = "";
}
if (fixedNewStyle) {
+ int result;
+
+ /* Try NBD_OPT_GO first - if it works, we are done (it
+ * also gives us a good message if the server requires
+ * TLS). If it is not available, fall back to
+ * NBD_OPT_LIST for nicer error messages about a missing
+ * export, then use NBD_OPT_EXPORT_NAME. */
+ result = nbd_opt_go(ioc, name, errp);
+ if (result < 0) {
+ goto fail;
+ }
+ if (result > 0) {
+ zeroes = false;
+ goto success;
+ }
/* Check our desired export is present in the
* server export list. Since NBD_OPT_EXPORT_NAME
* cannot return an error message, running this
- * query gives us good error reporting if the
- * server required TLS
+ * query gives us better error reporting if the
+ * export name is not available.
*/
if (nbd_receive_query_exports(ioc, name, errp) < 0) {
goto fail;
@@ -522,6 +603,7 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint32_t *flags,
}
/* Read the response */
+ success:
if (read_sync(ioc, &s, sizeof(s)) != sizeof(s)) {
error_setg(errp, "Failed to read export length");
goto fail;
--
2.5.5
next prev parent reply other threads:[~2016-04-08 22:06 UTC|newest]
Thread overview: 48+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-04-08 22:05 [Qemu-devel] [RFC PATCH 00/18] NBD protocol additions Eric Blake
2016-04-08 22:05 ` [Qemu-devel] [PATCH 01/18] nbd: Don't kill server on client that doesn't request TLS Eric Blake
2016-04-09 10:28 ` Alex Bligh
2016-04-08 22:05 ` [Qemu-devel] [PATCH 02/18] nbd: Don't fail handshake on NBD_OPT_LIST descriptions Eric Blake
2016-04-09 10:30 ` Alex Bligh
2016-04-08 22:05 ` [Qemu-devel] [PATCH 03/18] nbd: More debug typo fixes, use correct formats Eric Blake
2016-04-09 10:30 ` Alex Bligh
2016-04-08 22:05 ` [Qemu-devel] [PATCH 04/18] nbd: Detect servers that send unexpected error values Eric Blake
2016-04-09 10:31 ` Alex Bligh
2016-04-08 22:05 ` [Qemu-devel] [PATCH 05/18] nbd: Reject unknown request flags Eric Blake
2016-04-09 10:32 ` Alex Bligh
2016-04-08 22:05 ` [Qemu-devel] [PATCH 06/18] nbd: Avoid magic number for NBD max name size Eric Blake
2016-04-09 10:35 ` Alex Bligh
2016-04-09 22:07 ` Eric Blake
2016-04-08 22:05 ` [Qemu-devel] [PATCH 07/18] nbd: Treat flags vs. command type as separate fields Eric Blake
2016-04-09 10:37 ` Alex Bligh
2016-04-08 22:05 ` [Qemu-devel] [PATCH 08/18] nbd: Limit nbdflags to 16 bits Eric Blake
2016-04-09 10:37 ` Alex Bligh
2016-04-08 22:05 ` [Qemu-devel] [PATCH 09/18] nbd: Share common reply-sending code in server Eric Blake
2016-04-09 10:38 ` Alex Bligh
2016-04-08 22:05 ` [Qemu-devel] [PATCH 10/18] nbd: Share common option-sending code in client Eric Blake
2016-04-09 10:38 ` Alex Bligh
2016-04-08 22:05 ` [Qemu-devel] [PATCH 11/18] nbd: Let client skip portions of server reply Eric Blake
2016-04-09 10:39 ` Alex Bligh
2016-04-08 22:05 ` [Qemu-devel] [PATCH 12/18] nbd: Less allocation during NBD_OPT_LIST Eric Blake
2016-04-09 10:41 ` Alex Bligh
2016-04-09 22:24 ` Eric Blake
2016-04-08 22:05 ` [Qemu-devel] [PATCH 13/18] nbd: Support shorter handshake Eric Blake
2016-04-09 10:42 ` Alex Bligh
2016-04-09 22:27 ` Eric Blake
2016-04-08 22:05 ` Eric Blake [this message]
2016-04-09 10:47 ` [Qemu-devel] [PATCH 14/18] nbd: Implement NBD_OPT_GO on client Alex Bligh
2016-04-09 22:38 ` Eric Blake
2016-04-08 22:05 ` [Qemu-devel] [PATCH 15/18] nbd: Implement NBD_OPT_GO on server Eric Blake
2016-04-09 10:48 ` Alex Bligh
2016-04-08 22:05 ` [Qemu-devel] [PATCH 16/18] nbd: Support NBD_CMD_CLOSE Eric Blake
2016-04-09 10:50 ` Alex Bligh
2016-04-09 23:12 ` Eric Blake
2016-04-10 5:28 ` Alex Bligh
2016-04-08 22:05 ` [Qemu-devel] [RFC PATCH 17/18] nbd: Implement NBD_CMD_WRITE_ZEROES on server Eric Blake
2016-04-09 9:39 ` Pavel Borzenkov
2016-04-09 10:54 ` Alex Bligh
2016-04-08 22:05 ` [Qemu-devel] [RFC PATCH 18/18] nbd: Implement NBD_CMD_WRITE_ZEROES on client Eric Blake
2016-04-09 10:57 ` Alex Bligh
2016-04-09 11:52 ` Pavel Borzenkov
2016-04-09 23:17 ` Eric Blake
2016-04-10 5:27 ` Alex Bligh
2016-04-09 10:21 ` [Qemu-devel] [Nbd] [RFC PATCH 00/18] NBD protocol additions Wouter Verhelst
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=1460153158-21612-15-git-send-email-eblake@redhat.com \
--to=eblake@redhat.com \
--cc=alex@alex.org.uk \
--cc=kwolf@redhat.com \
--cc=pbonzini@redhat.com \
--cc=qemu-block@nongnu.org \
--cc=qemu-devel@nongnu.org \
/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).