19.08.2019 20:57, Eric Blake wrote:
> A server may have a reason to reject a request for structured replies,
> beyond just not recognizing them as a valid request.  It doesn't hurt
> us to continue talking to such a server; otherwise 'qemu-nbd --list'
> of such a server fails to display all possible details about the
> export.
> 
> Encountered when temporarily tweaking nbdkit to reply with
> NBD_REP_ERR_POLICY.  Present since structured reply support was first
> added (commit d795299b reused starttls handling, but starttls has to
> reject all errors).
> 
> Signed-off-by: Eric Blake <ebl...@redhat.com>
> ---
>   nbd/client.c | 39 +++++++++++++++++++++++----------------
>   1 file changed, 23 insertions(+), 16 deletions(-)
> 
> diff --git a/nbd/client.c b/nbd/client.c
> index 8f524c3e3502..204f6e928d14 100644
> --- a/nbd/client.c
> +++ b/nbd/client.c
> @@ -1,5 +1,5 @@
>   /*
> - *  Copyright (C) 2016-2018 Red Hat, Inc.
> + *  Copyright (C) 2016-2019 Red Hat, Inc.
>    *  Copyright (C) 2005  Anthony Liguori <anth...@codemonkey.ws>
>    *
>    *  Network Block Device Client Side
> @@ -141,17 +141,19 @@ static int nbd_receive_option_reply(QIOChannel *ioc, 
> uint32_t opt,
>       return 0;
>   }
> 
> -/* If reply represents success, return 1 without further action.
> - * If reply represents an error, consume the optional payload of
> - * the packet on ioc.  Then return 0 for unsupported (so the client
> - * can fall back to other approaches), or -1 with errp set for other
> - * errors.
> +/*
> + * If reply represents success, return 1 without further action.  If
> + * reply represents an error, consume the optional payload of the
> + * packet on ioc.  Then return 0 for unsupported (so the client can
> + * fall back to other approaches), where @strict determines if only
> + * ERR_UNSUP or all errors fit that category, or -1 with errp set for

hmm not all but "errors returned by server accordingly to protocol", as "all"
a bit in contrast with following "result = -1", but it's OK as is anyway:

Reviewed-by: Vladimir Sementsov-Ogievskiy <vsement...@virtuozzo.com>

> + * other errors.
>    */
>   static int nbd_handle_reply_err(QIOChannel *ioc, NBDOptionReply *reply,
> -                                Error **errp)
> +                                bool strict, Error **errp)
>   {
>       char *msg = NULL;
> -    int result = -1;
> +    int result = strict ? -1 : 0;
> 
>       if (!(reply->type & (1 << 31))) {
>           return 1;
> @@ -162,6 +164,7 @@ static int nbd_handle_reply_err(QIOChannel *ioc, 
> NBDOptionReply *reply,
>               error_setg(errp, "server error %" PRIu32
>                          " (%s) message is too long",
>                          reply->type, nbd_rep_lookup(reply->type));
> +            result = -1;
>               goto cleanup;
>           }
>           msg = g_malloc(reply->length + 1);
> @@ -169,6 +172,7 @@ static int nbd_handle_reply_err(QIOChannel *ioc, 
> NBDOptionReply *reply,
>               error_prepend(errp, "Failed to read option error %" PRIu32
>                             " (%s) message: ",
>                             reply->type, nbd_rep_lookup(reply->type));
> +            result = -1;
>               goto cleanup;
>           }
>           msg[reply->length] = '\0';
> @@ -257,7 +261,7 @@ static int nbd_receive_list(QIOChannel *ioc, char **name, 
> char **description,
>       if (nbd_receive_option_reply(ioc, NBD_OPT_LIST, &reply, errp) < 0) {
>           return -1;
>       }
> -    error = nbd_handle_reply_err(ioc, &reply, errp);
> +    error = nbd_handle_reply_err(ioc, &reply, true, errp);
>       if (error <= 0) {
>           return error;
>       }
> @@ -370,7 +374,7 @@ static int nbd_opt_info_or_go(QIOChannel *ioc, uint32_t 
> opt,
>           if (nbd_receive_option_reply(ioc, opt, &reply, errp) < 0) {
>               return -1;
>           }
> -        error = nbd_handle_reply_err(ioc, &reply, errp);
> +        error = nbd_handle_reply_err(ioc, &reply, true, errp);
>           if (error <= 0) {
>               return error;
>           }
> @@ -545,12 +549,15 @@ static int nbd_receive_query_exports(QIOChannel *ioc,
>       }
>   }
> 
> -/* nbd_request_simple_option: Send an option request, and parse the reply
> +/*
> + * nbd_request_simple_option: Send an option request, and parse the reply.
> + * @strict controls whether ERR_UNSUP or all errors produce 0 status.
>    * return 1 for successful negotiation,
>    *        0 if operation is unsupported,
>    *        -1 with errp set for any other error
>    */
> -static int nbd_request_simple_option(QIOChannel *ioc, int opt, Error **errp)
> +static int nbd_request_simple_option(QIOChannel *ioc, int opt, bool strict,
> +                                     Error **errp)
>   {
>       NBDOptionReply reply;
>       int error;
> @@ -562,7 +569,7 @@ static int nbd_request_simple_option(QIOChannel *ioc, int 
> opt, Error **errp)
>       if (nbd_receive_option_reply(ioc, opt, &reply, errp) < 0) {
>           return -1;
>       }
> -    error = nbd_handle_reply_err(ioc, &reply, errp);
> +    error = nbd_handle_reply_err(ioc, &reply, strict, errp);
>       if (error <= 0) {
>           return error;
>       }
> @@ -594,7 +601,7 @@ static QIOChannel *nbd_receive_starttls(QIOChannel *ioc,
>       QIOChannelTLS *tioc;
>       struct NBDTLSHandshakeData data = { 0 };
> 
> -    ret = nbd_request_simple_option(ioc, NBD_OPT_STARTTLS, errp);
> +    ret = nbd_request_simple_option(ioc, NBD_OPT_STARTTLS, true, errp);
>       if (ret <= 0) {
>           if (ret == 0) {
>               error_setg(errp, "Server don't support STARTTLS option");
> @@ -694,7 +701,7 @@ static int nbd_receive_one_meta_context(QIOChannel *ioc,
>           return -1;
>       }
> 
> -    ret = nbd_handle_reply_err(ioc, &reply, errp);
> +    ret = nbd_handle_reply_err(ioc, &reply, true, errp);
>       if (ret <= 0) {
>           return ret;
>       }
> @@ -950,7 +957,7 @@ static int nbd_start_negotiate(AioContext *aio_context, 
> QIOChannel *ioc,
>               if (structured_reply) {
>                   result = nbd_request_simple_option(ioc,
>                                                      NBD_OPT_STRUCTURED_REPLY,
> -                                                   errp);
> +                                                   false, errp);
>                   if (result < 0) {
>                       return -EINVAL;
>                   }
> 


-- 
Best regards,
Vladimir

Reply via email to