qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
To: Eric Blake <eblake@redhat.com>,
	"qemu-devel@nongnu.org" <qemu-devel@nongnu.org>
Cc: "nsoffer@redhat.com" <nsoffer@redhat.com>,
	"jsnow@redhat.com" <jsnow@redhat.com>,
	"rjones@redhat.com" <rjones@redhat.com>,
	"qemu-block@nongnu.org" <qemu-block@nongnu.org>
Subject: Re: [Qemu-devel] [PATCH v2 09/22] nbd/client: Refactor nbd_receive_list()
Date: Wed, 19 Dec 2018 13:11:00 +0000	[thread overview]
Message-ID: <f75b9dc8-c3c7-ff3e-2c20-551f764dd6a3@virtuozzo.com> (raw)
In-Reply-To: <20181215135324.152629-10-eblake@redhat.com>

15.12.2018 16:53, Eric Blake wrote:
> Right now, nbd_receive_list() is only called by
> nbd_receive_query_exports(), which in turn is only called if the
> server lacks NBD_OPT_GO but has working option negotiation, and is
> merely used as a quality-of-implementation trick since servers
> can't give decent errors for NBD_OPT_EXPORT_NAME.  However, servers
> that lack NBD_OPT_GO are becoming increasingly rare (nbdkit was a
> latecomer, in Aug 2018, but qemu has been such a server since commit
> f37708f6 in July 2017 and released in 2.10), so it no longer makes
> sense to micro-optimize that function for performance.
> 
> Furthermore, when debugging a server's implementation, tracing the
> full reply (both names and descriptions) is useful, not to mention
> that upcoming patches adding 'qemu-nbd --list' will want to collect
> that data.  And when you consider that a server can send an export
> name up to the NBD protocol length limit of 4k; but our current
> NBD_MAX_NAME_SIZE is only 256, we can't trace all valid server
> names without more storage, but 4k is large enough that the heap
> is better than the stack for long names.
> 
> Thus, I'm changing the division of labor, with nbd_receive_list()
> now always malloc'ing a result on success (the malloc is bounded
> by the fact that we reject servers with a reply length larger
> than 32M), and moving the comparison to 'wantname' to the caller.
> 
> There is a minor change in behavior where a server with 0 exports
> (an immediate NBD_REP_ACK reply) is now no longer distinguished
> from a server without LIST support (NBD_REP_ERR_UNSUP); this
> information could be preserved with a complication to the calling
> contract to provide a bit more information, but I didn't see the
> point.  After all, the worst that can happen if our guess at a
> match is wrong is that the caller will get a cryptic disconnect
> when NBD_OPT_EXPORT_NAME fails (which is no different from what
> would happen if we had not tried LIST), while treating an empty
> list as immediate failure would prevent connecting to really old
> servers that really did lack LIST.  Besides, NBD servers with 0
> exports are rare (qemu can do it when using QMP nbd-server-start
> without nbd-server-add - but qemu understands NBD_OPT_GO and
> thus won't tickle this change in behavior).
> 
> Signed-off-by: Eric Blake <eblake@redhat.com>
> 
> ---
> v2: Rewrite in a different manner (move the comparison to the
> caller)
> Fix free to g_free [Vladimir]
> ---
>   nbd/client.c     | 89 +++++++++++++++++++++++++++++++-----------------
>   nbd/trace-events |  1 +
>   2 files changed, 58 insertions(+), 32 deletions(-)
> 
> diff --git a/nbd/client.c b/nbd/client.c
> index 1a3a620fb6d..28f5a286cba 100644
> --- a/nbd/client.c
> +++ b/nbd/client.c
> @@ -232,18 +232,24 @@ static int nbd_handle_reply_err(QIOChannel *ioc, NBDOptionReply *reply,
>       return result;
>   }
> 
> -/* Process another portion of the NBD_OPT_LIST reply.  Set *@match if
> - * the current reply matches @want or if the server does not support
> - * NBD_OPT_LIST, otherwise leave @match alone.  Return 0 if iteration
> - * is complete, positive if more replies are expected, or negative
> - * with @errp set if an unrecoverable error occurred. */
> -static int nbd_receive_list(QIOChannel *ioc, const char *want, bool *match,
> +/* nbd_receive_list:
> + * Process another portion of the NBD_OPT_LIST reply, populating any
> + * name received into *@name. If @description is non-NULL, and the
> + * server provided a description, that is also populated. The caller
> + * must eventually call g_free() on success.
> + * Returns 1 if a name was received and iteration must continue,
> + *         0 if iteration is complete,

maybe, something like: if iteration is complete, or NBD_OPT_LIST is unsupported. @name and
  @description are not set.

(it's not obvious thing, that iteration complete assumes no new name received, and that 0
serves unsupported too)

> + *         -1 with @errp set if an unrecoverable error occurred.
> + */
> +static int nbd_receive_list(QIOChannel *ioc, char **name, char **description,
>                               Error **errp)
>   {
> +    int ret = -1;
>       NBDOptionReply reply;
>       uint32_t len;
>       uint32_t namelen;
> -    char name[NBD_MAX_NAME_SIZE + 1];
> +    char *local_name = NULL;
> +    char *local_desc = NULL;
>       int error;
> 
>       if (nbd_receive_option_reply(ioc, NBD_OPT_LIST, &reply, errp) < 0) {
> @@ -251,9 +257,6 @@ static int nbd_receive_list(QIOChannel *ioc, const char *want, bool *match,
>       }
>       error = nbd_handle_reply_err(ioc, &reply, errp);
>       if (error <= 0) {
> -        /* The server did not support NBD_OPT_LIST, so set *match on
> -         * the assumption that any name will be accepted.  */
> -        *match = true;

hm, actually, match was wrongly set to true on negative error, but it doesn't matter.

>           return error;
>       }
>       len = reply.length;
> @@ -290,33 +293,38 @@ static int nbd_receive_list(QIOChannel *ioc, const char *want, bool *match,
>           nbd_send_opt_abort(ioc);
>           return -1;
>       }
> -    if (namelen != strlen(want)) {
> -        if (nbd_drop(ioc, len, errp) < 0) {
> -            error_prepend(errp,
> -                          "failed to skip export name with wrong length: ");
> -            nbd_send_opt_abort(ioc);
> -            return -1;
> -        }
> -        return 1;
> -    }
> 
> -    assert(namelen < sizeof(name));
> -    if (nbd_read(ioc, name, namelen, errp) < 0) {
> +    local_name = g_malloc(namelen + 1);
> +    if (nbd_read(ioc, local_name, namelen, errp) < 0) {
>           error_prepend(errp, "failed to read export name: ");
>           nbd_send_opt_abort(ioc);
> -        return -1;
> +        goto out;
>       }
> -    name[namelen] = '\0';
> +    local_name[namelen] = '\0';
>       len -= namelen;
> -    if (nbd_drop(ioc, len, errp) < 0) {
> -        error_prepend(errp, "failed to read export description: ");
> -        nbd_send_opt_abort(ioc);
> -        return -1;
> +    if (len) {
> +        local_desc = g_malloc(len + 1);
> +        if (nbd_read(ioc, local_desc, len, errp) < 0) {
> +            error_prepend(errp, "failed to read export description: ");
> +            nbd_send_opt_abort(ioc);
> +            goto out;
> +        }
> +        local_desc[len] = '\0';
>       }
> -    if (!strcmp(name, want)) {
> -        *match = true;
> +
> +    trace_nbd_receive_list(local_name, local_desc ?: "");
> +    *name = local_name;
> +    local_name = NULL;
> +    if (description) {
> +        *description = local_desc;
> +        local_desc = NULL;
>       }
> -    return 1;
> +    ret = 1;
> +
> + out:
> +    g_free(local_name);
> +    g_free(local_desc);
> +    return ret;
>   }
> 
> 
> @@ -491,6 +499,7 @@ static int nbd_receive_query_exports(QIOChannel *ioc,
>                                        const char *wantname,
>                                        Error **errp)
>   {
> +    bool listEmpty = true;
>       bool foundExport = false;

being here, better is to fix naming to Qemu coding style, list_empty and found_export

> 
>       trace_nbd_receive_query_exports_start(wantname);
> @@ -499,14 +508,25 @@ static int nbd_receive_query_exports(QIOChannel *ioc,
>       }
> 
>       while (1) {
> -        int ret = nbd_receive_list(ioc, wantname, &foundExport, errp);
> +        char *name;
> +        int ret = nbd_receive_list(ioc, &name, NULL, errp);
> 
>           if (ret < 0) {
>               /* Server gave unexpected reply */
>               return -1;
>           } else if (ret == 0) {
>               /* Done iterating. */
> -            if (!foundExport) {
> +            if (listEmpty) {
> +                /*
> +                 * We don't have enough context to tell a server that
> +                 * sent an empty list apart from a server that does
> +                 * not support the list command; but as this function
> +                 * is just used to trigger a nicer error message
> +                 * before trying NBD_OPT_EXPORT_NAME, assume the
> +                 * export is available.
> +                 */
> +                return 0;
> +            } else if (!foundExport) {
>                   error_setg(errp, "No export with name '%s' available",
>                              wantname);
>                   nbd_send_opt_abort(ioc);
> @@ -515,6 +535,11 @@ static int nbd_receive_query_exports(QIOChannel *ioc,
>               trace_nbd_receive_query_exports_success(wantname);
>               return 0;
>           }
> +        listEmpty = false;
> +        if (!strcmp(name, wantname)) {
> +            foundExport = true;
> +        }
> +        g_free(name);
>       }
>   }
> 
> diff --git a/nbd/trace-events b/nbd/trace-events
> index 5e1d4afe8e6..8e9fc024c28 100644
> --- a/nbd/trace-events
> +++ b/nbd/trace-events
> @@ -2,6 +2,7 @@
>   nbd_send_option_request(uint32_t opt, const char *name, uint32_t len) "Sending option request %" PRIu32" (%s), len %" PRIu32
>   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
>   nbd_reply_err_unsup(uint32_t option, const char *name) "server doesn't understand request %" PRIu32 " (%s), attempting fallback"
> +nbd_receive_list(const char *name, const char *desc) "export list includes '%s', description '%s'"
>   nbd_opt_go_start(const char *name) "Attempting NBD_OPT_GO for export '%s'"
>   nbd_opt_go_success(void) "Export is good to go"
>   nbd_opt_go_info_unknown(int info, const char *name) "Ignoring unknown info %d (%s)"
> 


New semantics of nbd_receive_list is much more simple, thank you! With or without my tiny suggestions:
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>


-- 
Best regards,
Vladimir

  parent reply	other threads:[~2018-12-19 13:11 UTC|newest]

Thread overview: 55+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-12-15 13:53 [Qemu-devel] [PATCH v2 00/22] nbd: add qemu-nbd --list Eric Blake
2018-12-15 13:53 ` [Qemu-devel] [PATCH v2 01/22] qemu-nbd: Use program name in error messages Eric Blake
2018-12-15 13:53 ` [Qemu-devel] [PATCH v2 02/22] nbd: Document timeline of various features Eric Blake
2018-12-15 14:02   ` Richard W.M. Jones
2018-12-18 13:03   ` Vladimir Sementsov-Ogievskiy
2018-12-15 13:53 ` [Qemu-devel] [PATCH v2 03/22] maint: Allow for EXAMPLES in texi2pod Eric Blake
2018-12-15 14:04   ` Richard W.M. Jones
2018-12-18 13:46   ` Vladimir Sementsov-Ogievskiy
2019-01-04 23:45     ` Eric Blake
2019-01-11  2:56       ` Eric Blake
2018-12-15 13:53 ` [Qemu-devel] [PATCH v2 04/22] qemu-nbd: Enhance man page Eric Blake
2018-12-15 14:13   ` Richard W.M. Jones
2018-12-17 15:19     ` Eric Blake
2019-01-04 23:47       ` Eric Blake
2018-12-15 13:53 ` [Qemu-devel] [PATCH v2 05/22] nbd/client: More consistent error messages Eric Blake
2018-12-15 13:53 ` [Qemu-devel] [PATCH v2 06/22] qemu-nbd: Fail earlier for -c/-d on non-linux Eric Blake
2018-12-15 14:15   ` Richard W.M. Jones
2018-12-18 14:26   ` Vladimir Sementsov-Ogievskiy
2018-12-15 13:53 ` [Qemu-devel] [PATCH v2 07/22] qemu-nbd: Avoid strtol open-coding Eric Blake
2018-12-15 14:17   ` Richard W.M. Jones
2018-12-18 15:11   ` Vladimir Sementsov-Ogievskiy
2019-01-04 23:50     ` Eric Blake
2019-01-11 22:47       ` Eric Blake
2018-12-15 13:53 ` [Qemu-devel] [PATCH v2 08/22] nbd/client: Drop pointless buf variable Eric Blake
2019-01-05 13:54   ` Eric Blake
2018-12-15 13:53 ` [Qemu-devel] [PATCH v2 09/22] nbd/client: Refactor nbd_receive_list() Eric Blake
2018-12-15 15:07   ` Richard W.M. Jones
2018-12-19 13:11   ` Vladimir Sementsov-Ogievskiy [this message]
2018-12-15 13:53 ` [Qemu-devel] [PATCH v2 10/22] nbd/client: Move export name into NBDExportInfo Eric Blake
2018-12-15 13:53 ` [Qemu-devel] [PATCH v2 11/22] nbd/client: Change signature of nbd_negotiate_simple_meta_context() Eric Blake
2018-12-15 15:12   ` Richard W.M. Jones
2018-12-20 13:37   ` Vladimir Sementsov-Ogievskiy
2018-12-15 13:53 ` [Qemu-devel] [PATCH v2 12/22] nbd/client: Improve error handling in nbd_negotiate_simple_meta_context() Eric Blake
2018-12-15 15:19   ` Richard W.M. Jones
2018-12-17 15:26     ` Eric Blake
2018-12-17 15:30     ` Eric Blake
2018-12-20 14:13       ` Vladimir Sementsov-Ogievskiy
2018-12-15 13:53 ` [Qemu-devel] [PATCH v2 13/22] nbd/client: Split out nbd_send_one_meta_context() Eric Blake
2018-12-15 15:22   ` Richard W.M. Jones
2018-12-17 15:34     ` Eric Blake
2018-12-15 13:53 ` [Qemu-devel] [PATCH v2 14/22] nbd/client: Split out nbd_receive_one_meta_context() Eric Blake
2018-12-15 15:30   ` Richard W.M. Jones
2018-12-15 13:53 ` [Qemu-devel] [PATCH v2 15/22] nbd/client: Refactor return of nbd_receive_negotiate() Eric Blake
2018-12-15 13:53 ` [Qemu-devel] [PATCH v2 16/22] nbd/client: Split handshake into two functions Eric Blake
2018-12-15 13:53 ` [Qemu-devel] [PATCH v2 17/22] nbd/client: Pull out oldstyle size determination Eric Blake
2018-12-15 15:31   ` Richard W.M. Jones
2018-12-15 13:53 ` [Qemu-devel] [PATCH v2 18/22] nbd/client: Add nbd_receive_export_list() Eric Blake
2018-12-15 15:42   ` Richard W.M. Jones
2018-12-17 15:43     ` Eric Blake
2018-12-15 13:53 ` [Qemu-devel] [PATCH v2 19/22] nbd/client: Add meta contexts to nbd_receive_export_list() Eric Blake
2018-12-15 15:59   ` Richard W.M. Jones
2018-12-15 13:53 ` [Qemu-devel] [PATCH v2 20/22] qemu-nbd: Add --list option Eric Blake
2018-12-15 16:02   ` Richard W.M. Jones
2018-12-15 13:53 ` [Qemu-devel] [PATCH v2 21/22] nbd/client: Work around 3.0 bug for listing meta contexts Eric Blake
2018-12-15 13:53 ` [Qemu-devel] [PATCH v2 22/22] iotests: Enhance 223, 233 to cover 'qemu-nbd --list' 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=f75b9dc8-c3c7-ff3e-2c20-551f764dd6a3@virtuozzo.com \
    --to=vsementsov@virtuozzo.com \
    --cc=eblake@redhat.com \
    --cc=jsnow@redhat.com \
    --cc=nsoffer@redhat.com \
    --cc=qemu-block@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    --cc=rjones@redhat.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).