[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-block] [Qemu-devel] [PATCH v3 40/44] nbd: Implement NBD_OPT_GO
From: |
Alex Bligh |
Subject: |
Re: [Qemu-block] [Qemu-devel] [PATCH v3 40/44] nbd: Implement NBD_OPT_GO on client |
Date: |
Mon, 25 Apr 2016 11:31:46 +0100 |
On 23 Apr 2016, at 00:40, Eric Blake <address@hidden> wrote:
> 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 provides at least as much info as NBD_OPT_EXPORT_NAME sends.
>
> Signed-off-by: Eric Blake <address@hidden>
>
Reviewed-by: Alex Bligh <address@hidden>
> ---
> v3: revamp to match latest version of NBD protocol
> ---
> nbd/nbd-internal.h | 3 ++
> nbd/client.c | 120 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
> 2 files changed, 121 insertions(+), 2 deletions(-)
>
> diff --git a/nbd/nbd-internal.h b/nbd/nbd-internal.h
> index c597bb8..1935102 100644
> --- a/nbd/nbd-internal.h
> +++ b/nbd/nbd-internal.h
> @@ -55,8 +55,11 @@
> * 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)
> +
> #define NBD_REQUEST_MAGIC 0x25609513
> #define NBD_REPLY_MAGIC 0x67446698
> #define NBD_OPTS_MAGIC 0x49484156454F5054LL
> diff --git a/nbd/client.c b/nbd/client.c
> index 89fa2c3..dac4f29 100644
> --- a/nbd/client.c
> +++ b/nbd/client.c
> @@ -222,6 +222,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;
> +
> case NBD_REP_ERR_SHUTDOWN:
> error_setg(errp, "Server shutting down before option %" PRIx32,
> reply->option);
> @@ -311,6 +316,103 @@ static int nbd_receive_list(QIOChannel *ioc, const char
> *want, Error **errp)
> }
>
>
> +/* Returns -1 if NBD_OPT_GO proves the export @wantname 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 @size and @flags populated). */
> +static int nbd_opt_go(QIOChannel *ioc, const char *wantname,
> + NbdExportInfo *info, Error **errp)
> +{
> + nbd_opt_reply reply;
> + uint32_t len;
> + uint16_t type;
> + int error;
> +
> + /* The protocol requires that the server send NBD_INFO_EXPORT with
> + * a non-zero flags (at least NBD_FLAG_HAS_FLAGS must be set); so
> + * flags still 0 is a witness of a broken server. */
> + info->flags = 0;
> +
> + 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");
> + while (1) {
> + 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_ACK) {
> + /* Server is done sending info and moved into transmission
> + phase, but make sure it sent flags */
> + if (len) {
> + error_setg(errp, "server sent invalid NBD_REP_ACK");
> + return -1;
> + }
> + if (!info->flags) {
> + error_setg(errp, "broken server omitted NBD_INFO_EXPORT");
> + return -1;
> + }
> + TRACE("export is good to go");
> + return 1;
> + }
> + if (reply.type != NBD_REP_INFO) {
> + error_setg(errp, "unexpected reply type %" PRIx32 ", expected
> %x",
> + reply.type, NBD_REP_INFO);
> + return -1;
> + }
> + if (len < sizeof(type)) {
> + error_setg(errp, "NBD_REP_INFO length %" PRIu32 " is too short",
> + len);
> + return -1;
> + }
> + if (read_sync(ioc, &type, sizeof(type)) != sizeof(type)) {
> + error_setg(errp, "failed to read info type");
> + return -1;
> + }
> + len -= sizeof(type);
> + be16_to_cpus(&type);
> + switch (type) {
> + case NBD_INFO_EXPORT:
> + if (len != sizeof(info->size) + sizeof(info->flags)) {
> + error_setg(errp, "remaining export info len %" PRIu32
> + " is unexpected size", len);
> + return -1;
> + }
> + if (read_sync(ioc, &info->size, sizeof(info->size)) !=
> + sizeof(info->size)) {
> + error_setg(errp, "failed to read info size");
> + return -1;
> + }
> + be64_to_cpus(&info->size);
> + if (read_sync(ioc, &info->flags, sizeof(info->flags)) !=
> + sizeof(info->flags)) {
> + error_setg(errp, "failed to read info flags");
> + return -1;
> + }
> + be16_to_cpus(&info->flags);
> + TRACE("Size is %" PRIu64 ", export flags %" PRIx16,
> + info->size, info->flags);
> + break;
> +
> + default:
> + TRACE("ignoring unknown export info %" PRIu16, type);
> + if (drop_sync(ioc, len) != len) {
> + error_setg(errp, "Failed to read info payload");
> + return -1;
> + }
> + break;
> + }
> + }
> +}
> +
> /* Return -1 on failure, 0 if wantname is an available export. */
> static int nbd_receive_query_exports(QIOChannel *ioc,
> const char *wantname,
> @@ -515,11 +617,25 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char
> *name,
> 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, info, errp);
> + if (result < 0) {
> + goto fail;
> + }
> + if (result > 0) {
> + return 0;
> + }
> /* 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;
> --
> 2.5.5
>
>
--
Alex Bligh
- [Qemu-block] [PATCH v3 34/44] nbd: Less allocation during NBD_OPT_LIST, (continued)
[Qemu-block] [PATCH v3 39/44] nbd: Implement NBD_OPT_GO on server, Eric Blake, 2016/04/22
[Qemu-block] [PATCH v3 40/44] nbd: Implement NBD_OPT_GO on client, Eric Blake, 2016/04/22
- Re: [Qemu-block] [Qemu-devel] [PATCH v3 40/44] nbd: Implement NBD_OPT_GO on client,
Alex Bligh <=
[Qemu-block] [PATCH v3 37/44] nbd: Create struct for tracking export info, Eric Blake, 2016/04/22
[Qemu-block] [PATCH v3 42/44] nbd: Implement NBD_CMD_WRITE_ZEROES on client, Eric Blake, 2016/04/22