From nobody Mon May 6 21:04:14 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (208.118.235.17 [208.118.235.17]) by mx.zohomail.com with SMTPS id 15093972439911.3322020172640805; Mon, 30 Oct 2017 14:00:43 -0700 (PDT) Received: from localhost ([::1]:42572 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1e9HAk-0002ml-2X for importer@patchew.org; Mon, 30 Oct 2017 17:00:38 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:50452) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1e9H77-0008Jo-1L for qemu-devel@nongnu.org; Mon, 30 Oct 2017 16:56:54 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1e9H75-000101-UQ for qemu-devel@nongnu.org; Mon, 30 Oct 2017 16:56:53 -0400 Received: from mx1.redhat.com ([209.132.183.28]:54888) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1e9H70-0000uk-KU; Mon, 30 Oct 2017 16:56:46 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 957C461460; Mon, 30 Oct 2017 20:56:45 +0000 (UTC) Received: from red.redhat.com (ovpn-123-123.rdu2.redhat.com [10.10.123.123]) by smtp.corp.redhat.com (Postfix) with ESMTP id 664A65C888; Mon, 30 Oct 2017 20:56:44 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 957C461460 Authentication-Results: ext-mx10.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx10.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=eblake@redhat.com From: Eric Blake To: qemu-devel@nongnu.org Date: Mon, 30 Oct 2017 21:56:25 +0100 Message-Id: <20171030205636.14236-2-eblake@redhat.com> In-Reply-To: <20171030205636.14236-1-eblake@redhat.com> References: <20171030205636.14236-1-eblake@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.39]); Mon, 30 Oct 2017 20:56:45 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL 01/12] nbd: Include error names in trace messages X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Paolo Bonzini , "open list:Network Block Dev..." Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" NBD errors were originally sent over the wire based on Linux errno values; but not all the world is Linux, and not all platforms share the same values. Since a number isn't very easy to decipher on all platforms, update the trace messages to include the name of NBD errors being sent/received over the wire. Tweak the trace messages to be at the point where we are using the NBD error, not the translation to the host errno values. Signed-off-by: Eric Blake Reviewed-by: Vladimir Sementsov-Ogievskiy Message-Id: <20171027104037.8319-2-eblake@redhat.com> --- nbd/nbd-internal.h | 1 + nbd/client.c | 3 ++- nbd/common.c | 23 +++++++++++++++++++++++ nbd/server.c | 3 ++- nbd/trace-events | 4 ++-- 5 files changed, 30 insertions(+), 4 deletions(-) diff --git a/nbd/nbd-internal.h b/nbd/nbd-internal.h index 11a130d050..4bfe5be884 100644 --- a/nbd/nbd-internal.h +++ b/nbd/nbd-internal.h @@ -126,6 +126,7 @@ const char *nbd_opt_lookup(uint32_t opt); const char *nbd_rep_lookup(uint32_t rep); const char *nbd_info_lookup(uint16_t info); const char *nbd_cmd_lookup(uint16_t info); +const char *nbd_err_lookup(int err); int nbd_drop(QIOChannel *ioc, size_t size, Error **errp); diff --git a/nbd/client.c b/nbd/client.c index cd5a2c80ac..59d7c9d49f 100644 --- a/nbd/client.c +++ b/nbd/client.c @@ -940,6 +940,8 @@ int nbd_receive_reply(QIOChannel *ioc, NBDReply *reply,= Error **errp) reply->error =3D ldl_be_p(buf + 4); reply->handle =3D ldq_be_p(buf + 8); + trace_nbd_receive_reply(magic, reply->error, nbd_err_lookup(reply->err= or), + reply->handle); reply->error =3D nbd_errno_to_system_errno(reply->error); if (reply->error =3D=3D ESHUTDOWN) { @@ -947,7 +949,6 @@ int nbd_receive_reply(QIOChannel *ioc, NBDReply *reply,= Error **errp) error_setg(errp, "server shutting down"); return -EINVAL; } - trace_nbd_receive_reply(magic, reply->error, reply->handle); if (magic !=3D NBD_SIMPLE_REPLY_MAGIC) { error_setg(errp, "invalid magic (got 0x%" PRIx32 ")", magic); diff --git a/nbd/common.c b/nbd/common.c index 59a5316be9..7456021f7e 100644 --- a/nbd/common.c +++ b/nbd/common.c @@ -148,3 +148,26 @@ const char *nbd_cmd_lookup(uint16_t cmd) return ""; } } + + +const char *nbd_err_lookup(int err) +{ + switch (err) { + case NBD_SUCCESS: + return "success"; + case NBD_EPERM: + return "EPERM"; + case NBD_EIO: + return "EIO"; + case NBD_ENOMEM: + return "ENOMEM"; + case NBD_EINVAL: + return "EINVAL"; + case NBD_ENOSPC: + return "ENOSPC"; + case NBD_ESHUTDOWN: + return "ESHUTDOWN"; + default: + return ""; + } +} diff --git a/nbd/server.c b/nbd/server.c index 3df3548d6d..459e00c553 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -1227,7 +1227,8 @@ static int nbd_co_send_simple_reply(NBDClient *client, {.iov_base =3D data, .iov_len =3D len} }; - trace_nbd_co_send_simple_reply(handle, nbd_err, len); + trace_nbd_co_send_simple_reply(handle, nbd_err, nbd_err_lookup(nbd_err= ), + len); set_be_simple_reply(&reply, nbd_err, handle); return nbd_co_send_iov(client, iov, len ? 2 : 1, errp); diff --git a/nbd/trace-events b/nbd/trace-events index e27614f050..920c8a0e5e 100644 --- a/nbd/trace-events +++ b/nbd/trace-events @@ -29,7 +29,7 @@ nbd_client_loop_ret(int ret, const char *error) "NBD loop= returned %d: %s" nbd_client_clear_queue(void) "Clearing NBD queue" nbd_client_clear_socket(void) "Clearing NBD socket" nbd_send_request(uint64_t from, uint32_t len, uint64_t handle, uint16_t fl= ags, uint16_t type, const char *name) "Sending request to server: { .from = =3D %" PRIu64", .len =3D %" PRIu32 ", .handle =3D %" PRIu64 ", .flags =3D 0= x%" PRIx16 ", .type =3D %" PRIu16 " (%s) }" -nbd_receive_reply(uint32_t magic, int32_t error, uint64_t handle) "Got rep= ly: { magic =3D 0x%" PRIx32 ", .error =3D % " PRId32 ", handle =3D %" PRIu6= 4" }" +nbd_receive_reply(uint32_t magic, int32_t error, const char *errname, uint= 64_t handle) "Got reply: { magic =3D 0x%" PRIx32 ", .error =3D %" PRId32 " = (%s), handle =3D %" PRIu64" }" # nbd/server.c nbd_negotiate_send_rep_len(uint32_t opt, const char *optname, uint32_t typ= e, const char *typename, uint32_t len) "Reply opt=3D0x%" PRIx32 " (%s), typ= e=3D0x%" PRIx32 " (%s), len=3D%" PRIu32 @@ -53,7 +53,7 @@ nbd_negotiate_success(void) "Negotiation succeeded" nbd_receive_request(uint32_t magic, uint16_t flags, uint16_t type, uint64_= t from, uint32_t len) "Got request: { magic =3D 0x%" PRIx32 ", .flags =3D 0= x%" PRIx16 ", .type =3D 0x%" PRIx16 ", from =3D %" PRIu64 ", len =3D %" PRI= u32 " }" nbd_blk_aio_attached(const char *name, void *ctx) "Export %s: Attaching cl= ients to AIO context %p\n" nbd_blk_aio_detach(const char *name, void *ctx) "Export %s: Detaching clie= nts from AIO context %p\n" -nbd_co_send_simple_reply(uint64_t handle, uint32_t error, int len) "Send s= imple reply: handle =3D %" PRIu64 ", error =3D %" PRIu32 ", len =3D %d" +nbd_co_send_simple_reply(uint64_t handle, uint32_t error, const char *errn= ame, int len) "Send simple reply: handle =3D %" PRIu64 ", error =3D %" PRIu= 32 " (%s), len =3D %d" nbd_co_receive_request_decode_type(uint64_t handle, uint16_t type, const c= har *name) "Decoding type: handle =3D %" PRIu64 ", type =3D %" PRIu16 " (%s= )" nbd_co_receive_request_payload_received(uint64_t handle, uint32_t len) "Pa= yload received: handle =3D %" PRIu64 ", len =3D %" PRIu32 nbd_co_receive_request_cmd_write(uint32_t len) "Reading %" PRIu32 " byte(s= )" --=20 2.13.6 From nobody Mon May 6 21:04:14 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (208.118.235.17 [208.118.235.17]) by mx.zohomail.com with SMTPS id 1509397127826417.24983284720315; Mon, 30 Oct 2017 13:58:47 -0700 (PDT) Received: from localhost ([::1]:42560 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1e9H8m-0001Bx-Ln for importer@patchew.org; Mon, 30 Oct 2017 16:58:36 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:50459) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1e9H77-0008Kb-H1 for qemu-devel@nongnu.org; Mon, 30 Oct 2017 16:56:54 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1e9H76-00010G-6R for qemu-devel@nongnu.org; Mon, 30 Oct 2017 16:56:53 -0400 Received: from mx1.redhat.com ([209.132.183.28]:59358) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1e9H73-0000w6-4H; Mon, 30 Oct 2017 16:56:49 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 0164349008; Mon, 30 Oct 2017 20:56:48 +0000 (UTC) Received: from red.redhat.com (ovpn-123-123.rdu2.redhat.com [10.10.123.123]) by smtp.corp.redhat.com (Postfix) with ESMTP id 134FB5C737; Mon, 30 Oct 2017 20:56:45 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 0164349008 Authentication-Results: ext-mx09.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx09.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=eblake@redhat.com From: Eric Blake To: qemu-devel@nongnu.org Date: Mon, 30 Oct 2017 21:56:26 +0100 Message-Id: <20171030205636.14236-3-eblake@redhat.com> In-Reply-To: <20171030205636.14236-1-eblake@redhat.com> References: <20171030205636.14236-1-eblake@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.38]); Mon, 30 Oct 2017 20:56:48 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL 02/12] nbd: Move nbd_errno_to_system_errno() to public header X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , Paolo Bonzini , "open list:Network Block Dev..." , Max Reitz Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" This is needed in preparation for structured reply handling, as we will be performing the translation from NBD error to system errno value higher in the stack at block/nbd-client.c. Signed-off-by: Eric Blake Reviewed-by: Vladimir Sementsov-Ogievskiy Message-Id: <20171027104037.8319-3-eblake@redhat.com> --- include/block/nbd.h | 13 +++++++++++++ nbd/nbd-internal.h | 12 ------------ nbd/client.c | 32 -------------------------------- nbd/common.c | 34 ++++++++++++++++++++++++++++++++++ nbd/trace-events | 4 +++- 5 files changed, 50 insertions(+), 45 deletions(-) diff --git a/include/block/nbd.h b/include/block/nbd.h index a6df5ce8b5..dc62b5cd19 100644 --- a/include/block/nbd.h +++ b/include/block/nbd.h @@ -149,6 +149,18 @@ enum { * aren't overflowing some other buffer. */ #define NBD_MAX_NAME_SIZE 256 +/* 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. + * Everything else is squashed to EINVAL. + */ +#define NBD_SUCCESS 0 +#define NBD_EPERM 1 +#define NBD_EIO 5 +#define NBD_ENOMEM 12 +#define NBD_EINVAL 22 +#define NBD_ENOSPC 28 +#define NBD_ESHUTDOWN 108 + /* Details collected by NBD_OPT_EXPORT_NAME and NBD_OPT_GO */ struct NBDExportInfo { /* Set by client before nbd_receive_negotiate() */ @@ -172,6 +184,7 @@ int nbd_send_request(QIOChannel *ioc, NBDRequest *reque= st); int nbd_receive_reply(QIOChannel *ioc, NBDReply *reply, Error **errp); int nbd_client(int fd); int nbd_disconnect(int fd); +int nbd_errno_to_system_errno(int err); typedef struct NBDExport NBDExport; typedef struct NBDClient NBDClient; diff --git a/nbd/nbd-internal.h b/nbd/nbd-internal.h index 4bfe5be884..df6c8b2f24 100644 --- a/nbd/nbd-internal.h +++ b/nbd/nbd-internal.h @@ -64,18 +64,6 @@ #define NBD_SET_TIMEOUT _IO(0xab, 9) #define NBD_SET_FLAGS _IO(0xab, 10) -/* 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. - * Everything else is squashed to EINVAL. - */ -#define NBD_SUCCESS 0 -#define NBD_EPERM 1 -#define NBD_EIO 5 -#define NBD_ENOMEM 12 -#define NBD_EINVAL 22 -#define NBD_ENOSPC 28 -#define NBD_ESHUTDOWN 108 - /* nbd_read_eof * Tries to read @size bytes from @ioc. * Returns 1 on success diff --git a/nbd/client.c b/nbd/client.c index 59d7c9d49f..50f36b511e 100644 --- a/nbd/client.c +++ b/nbd/client.c @@ -22,38 +22,6 @@ #include "trace.h" #include "nbd-internal.h" -static int nbd_errno_to_system_errno(int err) -{ - int ret; - switch (err) { - case NBD_SUCCESS: - ret =3D 0; - break; - case NBD_EPERM: - ret =3D EPERM; - break; - case NBD_EIO: - ret =3D EIO; - break; - case NBD_ENOMEM: - ret =3D ENOMEM; - break; - case NBD_ENOSPC: - ret =3D ENOSPC; - break; - case NBD_ESHUTDOWN: - ret =3D ESHUTDOWN; - break; - default: - trace_nbd_unknown_error(err); - /* fallthrough */ - case NBD_EINVAL: - ret =3D EINVAL; - break; - } - return ret; -} - /* Definitions for opaque data types */ static QTAILQ_HEAD(, NBDExport) exports =3D QTAILQ_HEAD_INITIALIZER(export= s); diff --git a/nbd/common.c b/nbd/common.c index 7456021f7e..593904f148 100644 --- a/nbd/common.c +++ b/nbd/common.c @@ -18,6 +18,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" +#include "trace.h" #include "nbd-internal.h" /* Discard length bytes from channel. Return -errno on failure and 0 on @@ -171,3 +172,36 @@ const char *nbd_err_lookup(int err) return ""; } } + + +int nbd_errno_to_system_errno(int err) +{ + int ret; + switch (err) { + case NBD_SUCCESS: + ret =3D 0; + break; + case NBD_EPERM: + ret =3D EPERM; + break; + case NBD_EIO: + ret =3D EIO; + break; + case NBD_ENOMEM: + ret =3D ENOMEM; + break; + case NBD_ENOSPC: + ret =3D ENOSPC; + break; + case NBD_ESHUTDOWN: + ret =3D ESHUTDOWN; + break; + default: + trace_nbd_unknown_error(err); + /* fallthrough */ + case NBD_EINVAL: + ret =3D EINVAL; + break; + } + return ret; +} diff --git a/nbd/trace-events b/nbd/trace-events index 920c8a0e5e..ab3d7dad4f 100644 --- a/nbd/trace-events +++ b/nbd/trace-events @@ -1,5 +1,4 @@ # nbd/client.c -nbd_unknown_error(int err) "Squashing unexpected error %d to EINVAL" nbd_send_option_request(uint32_t opt, const char *name, uint32_t len) "Sen= ding option request %" PRIu32" (%s), len %" PRIu32 nbd_receive_option_reply(uint32_t option, const char *optname, uint32_t ty= pe, const char *typename, uint32_t length) "Received option reply 0x%" PRIx= 32" (%s), type 0x%" PRIx32" (%s), len %" PRIu32 nbd_reply_err_unsup(uint32_t option, const char *name) "server doesn't und= erstand request 0x%" PRIx32 " (%s), attempting fallback" @@ -31,6 +30,9 @@ nbd_client_clear_socket(void) "Clearing NBD socket" nbd_send_request(uint64_t from, uint32_t len, uint64_t handle, uint16_t fl= ags, uint16_t type, const char *name) "Sending request to server: { .from = =3D %" PRIu64", .len =3D %" PRIu32 ", .handle =3D %" PRIu64 ", .flags =3D 0= x%" PRIx16 ", .type =3D %" PRIu16 " (%s) }" nbd_receive_reply(uint32_t magic, int32_t error, const char *errname, uint= 64_t handle) "Got reply: { magic =3D 0x%" PRIx32 ", .error =3D %" PRId32 " = (%s), handle =3D %" PRIu64" }" +# nbd/common.c +nbd_unknown_error(int err) "Squashing unexpected error %d to EINVAL" + # nbd/server.c nbd_negotiate_send_rep_len(uint32_t opt, const char *optname, uint32_t typ= e, const char *typename, uint32_t len) "Reply opt=3D0x%" PRIx32 " (%s), typ= e=3D0x%" PRIx32 " (%s), len=3D%" PRIu32 nbd_negotiate_send_rep_err(const char *msg) "sending error message \"%s\"" --=20 2.13.6 From nobody Mon May 6 21:04:14 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (208.118.235.17 [208.118.235.17]) by mx.zohomail.com with SMTPS id 1509397387527544.6361921667201; Mon, 30 Oct 2017 14:03:07 -0700 (PDT) Received: from localhost ([::1]:42583 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1e9HD3-0004lQ-2W for importer@patchew.org; Mon, 30 Oct 2017 17:03:01 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:50500) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1e9H79-0008Mi-Oj for qemu-devel@nongnu.org; Mon, 30 Oct 2017 16:56:59 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1e9H78-00012i-Dw for qemu-devel@nongnu.org; Mon, 30 Oct 2017 16:56:55 -0400 Received: from mx1.redhat.com ([209.132.183.28]:59660) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1e9H75-0000yg-49; Mon, 30 Oct 2017 16:56:51 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 19F7CC05686E; Mon, 30 Oct 2017 20:56:50 +0000 (UTC) Received: from red.redhat.com (ovpn-123-123.rdu2.redhat.com [10.10.123.123]) by smtp.corp.redhat.com (Postfix) with ESMTP id 6DF7E5C1A1; Mon, 30 Oct 2017 20:56:48 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 19F7CC05686E Authentication-Results: ext-mx08.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx08.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=eblake@redhat.com From: Eric Blake To: qemu-devel@nongnu.org Date: Mon, 30 Oct 2017 21:56:27 +0100 Message-Id: <20171030205636.14236-4-eblake@redhat.com> In-Reply-To: <20171030205636.14236-1-eblake@redhat.com> References: <20171030205636.14236-1-eblake@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.32]); Mon, 30 Oct 2017 20:56:50 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL 03/12] nbd: Expose constants and structs for structured read X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , Paolo Bonzini , "open list:Network Block Dev..." , Max Reitz Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Upcoming patches will implement the NBD structured reply extension [1] for both client and server roles. Declare the constants, structs, and lookup routines that will be valuable whether the server or client code is backported in isolation. This includes moving one constant from an internal header to the public header, as part of the structured read processing will be done in block/nbd-client.c rather than nbd/client.c. [1]https://github.com/NetworkBlockDevice/nbd/blob/extension-structured-repl= y/doc/proto.md Based on patches from Vladimir Sementsov-Ogievskiy. Signed-off-by: Eric Blake Reviewed-by: Vladimir Sementsov-Ogievskiy Message-Id: <20171027104037.8319-4-eblake@redhat.com> --- include/block/nbd.h | 41 +++++++++++++++++++++++++++++++++++++++++ nbd/nbd-internal.h | 2 +- nbd/common.c | 27 +++++++++++++++++++++++++++ nbd/server.c | 2 ++ 4 files changed, 71 insertions(+), 1 deletion(-) diff --git a/include/block/nbd.h b/include/block/nbd.h index dc62b5cd19..225e9575e4 100644 --- a/include/block/nbd.h +++ b/include/block/nbd.h @@ -69,6 +69,28 @@ typedef struct NBDSimpleReply { uint64_t handle; } QEMU_PACKED NBDSimpleReply; +/* Header of all structured replies */ +typedef struct NBDStructuredReplyChunk { + uint32_t magic; /* NBD_STRUCTURED_REPLY_MAGIC */ + uint16_t flags; /* combination of NBD_REPLY_FLAG_* */ + uint16_t type; /* NBD_REPLY_TYPE_* */ + uint64_t handle; /* request handle */ + uint32_t length; /* length of payload */ +} QEMU_PACKED NBDStructuredReplyChunk; + +/* Header of NBD_REPLY_TYPE_OFFSET_DATA, complete NBD_REPLY_TYPE_OFFSET_HO= LE */ +typedef struct NBDStructuredRead { + NBDStructuredReplyChunk h; + uint64_t offset; +} QEMU_PACKED NBDStructuredRead; + +/* Header of all NBD_REPLY_TYPE_ERROR* errors */ +typedef struct NBDStructuredError { + NBDStructuredReplyChunk h; + uint32_t error; + uint16_t message_length; +} QEMU_PACKED NBDStructuredError; + /* Transmission (export) flags: sent from server to client during handshak= e, but describe what will happen during transmission */ #define NBD_FLAG_HAS_FLAGS (1 << 0) /* Flags are there */ @@ -79,6 +101,7 @@ typedef struct NBDSimpleReply { rotational media */ #define NBD_FLAG_SEND_TRIM (1 << 5) /* Send TRIM (discard) */ #define NBD_FLAG_SEND_WRITE_ZEROES (1 << 6) /* Send WRITE_ZEROES */ +#define NBD_FLAG_SEND_DF (1 << 7) /* Send DF (Do not Fragment) */ /* New-style handshake (global) flags, sent from server to client, and control what will happen during handshake phase. */ @@ -125,6 +148,7 @@ typedef struct NBDSimpleReply { /* Request flags, sent from client to server during transmission phase */ #define NBD_CMD_FLAG_FUA (1 << 0) /* 'force unit access' during wri= te */ #define NBD_CMD_FLAG_NO_HOLE (1 << 1) /* don't punch hole on zero run */ +#define NBD_CMD_FLAG_DF (1 << 2) /* don't fragment structured read= */ /* Supported request types */ enum { @@ -149,6 +173,22 @@ enum { * aren't overflowing some other buffer. */ #define NBD_MAX_NAME_SIZE 256 +/* Two types of reply structures */ +#define NBD_SIMPLE_REPLY_MAGIC 0x67446698 +#define NBD_STRUCTURED_REPLY_MAGIC 0x668e33ef + +/* Structured reply flags */ +#define NBD_REPLY_FLAG_DONE (1 << 0) /* This reply-chunk is last = */ + +/* Structured reply types */ +#define NBD_REPLY_ERR(value) ((1 << 15) | (value)) + +#define NBD_REPLY_TYPE_NONE 0 +#define NBD_REPLY_TYPE_OFFSET_DATA 1 +#define NBD_REPLY_TYPE_OFFSET_HOLE 2 +#define NBD_REPLY_TYPE_ERROR NBD_REPLY_ERR(1) +#define NBD_REPLY_TYPE_ERROR_OFFSET NBD_REPLY_ERR(2) + /* 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. * Everything else is squashed to EINVAL. @@ -159,6 +199,7 @@ enum { #define NBD_ENOMEM 12 #define NBD_EINVAL 22 #define NBD_ENOSPC 28 +#define NBD_EOVERFLOW 75 #define NBD_ESHUTDOWN 108 /* Details collected by NBD_OPT_EXPORT_NAME and NBD_OPT_GO */ diff --git a/nbd/nbd-internal.h b/nbd/nbd-internal.h index df6c8b2f24..4f24d6e57d 100644 --- a/nbd/nbd-internal.h +++ b/nbd/nbd-internal.h @@ -47,7 +47,6 @@ #define NBD_OLDSTYLE_NEGOTIATE_SIZE (8 + 8 + 8 + 4 + 124) #define NBD_REQUEST_MAGIC 0x25609513 -#define NBD_SIMPLE_REPLY_MAGIC 0x67446698 #define NBD_OPTS_MAGIC 0x49484156454F5054LL #define NBD_CLIENT_MAGIC 0x0000420281861253LL #define NBD_REP_MAGIC 0x0003e889045565a9LL @@ -114,6 +113,7 @@ const char *nbd_opt_lookup(uint32_t opt); const char *nbd_rep_lookup(uint32_t rep); const char *nbd_info_lookup(uint16_t info); const char *nbd_cmd_lookup(uint16_t info); +const char *nbd_reply_type_lookup(uint16_t type); const char *nbd_err_lookup(int err); int nbd_drop(QIOChannel *ioc, size_t size, Error **errp); diff --git a/nbd/common.c b/nbd/common.c index 593904f148..6047d71748 100644 --- a/nbd/common.c +++ b/nbd/common.c @@ -151,6 +151,28 @@ const char *nbd_cmd_lookup(uint16_t cmd) } +const char *nbd_reply_type_lookup(uint16_t type) +{ + switch (type) { + case NBD_REPLY_TYPE_NONE: + return "none"; + case NBD_REPLY_TYPE_OFFSET_DATA: + return "data"; + case NBD_REPLY_TYPE_OFFSET_HOLE: + return "hole"; + case NBD_REPLY_TYPE_ERROR: + return "generic error"; + case NBD_REPLY_TYPE_ERROR_OFFSET: + return "error at offset"; + default: + if (type & (1 << 15)) { + return ""; + } + return ""; + } +} + + const char *nbd_err_lookup(int err) { switch (err) { @@ -166,6 +188,8 @@ const char *nbd_err_lookup(int err) return "EINVAL"; case NBD_ENOSPC: return "ENOSPC"; + case NBD_EOVERFLOW: + return "EOVERFLOW"; case NBD_ESHUTDOWN: return "ESHUTDOWN"; default: @@ -193,6 +217,9 @@ int nbd_errno_to_system_errno(int err) case NBD_ENOSPC: ret =3D ENOSPC; break; + case NBD_EOVERFLOW: + ret =3D EOVERFLOW; + break; case NBD_ESHUTDOWN: ret =3D ESHUTDOWN; break; diff --git a/nbd/server.c b/nbd/server.c index 459e00c553..efb6003364 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -40,6 +40,8 @@ static int system_errno_to_nbd_errno(int err) case EFBIG: case ENOSPC: return NBD_ENOSPC; + case EOVERFLOW: + return NBD_EOVERFLOW; case ESHUTDOWN: return NBD_ESHUTDOWN; case EINVAL: --=20 2.13.6 From nobody Mon May 6 21:04:14 2024 Delivered-To: importer@patchew.org Received-SPF: temperror (zoho.com: Error in retrieving data from DNS) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=temperror (zoho.com: Error in retrieving data from DNS) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (208.118.235.17 [208.118.235.17]) by mx.zohomail.com with SMTPS id 1509397519691729.951754578379; Mon, 30 Oct 2017 14:05:19 -0700 (PDT) Received: from localhost ([::1]:42594 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1e9HF3-0006Hb-DR for importer@patchew.org; Mon, 30 Oct 2017 17:05:05 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:50512) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1e9H7A-0008NY-LH for qemu-devel@nongnu.org; Mon, 30 Oct 2017 16:57:00 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1e9H79-000159-Q0 for qemu-devel@nongnu.org; Mon, 30 Oct 2017 16:56:56 -0400 Received: from mx1.redhat.com ([209.132.183.28]:57842) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1e9H77-00011M-Kd; Mon, 30 Oct 2017 16:56:53 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 9DA0A267E0; Mon, 30 Oct 2017 20:56:52 +0000 (UTC) Received: from red.redhat.com (ovpn-123-123.rdu2.redhat.com [10.10.123.123]) by smtp.corp.redhat.com (Postfix) with ESMTP id 83A515C1A1; Mon, 30 Oct 2017 20:56:50 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 9DA0A267E0 Authentication-Results: ext-mx06.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx06.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=eblake@redhat.com From: Eric Blake To: qemu-devel@nongnu.org Date: Mon, 30 Oct 2017 21:56:28 +0100 Message-Id: <20171030205636.14236-5-eblake@redhat.com> In-Reply-To: <20171030205636.14236-1-eblake@redhat.com> References: <20171030205636.14236-1-eblake@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.30]); Mon, 30 Oct 2017 20:56:52 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL 04/12] nbd/server: Report error for write to read-only export X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Paolo Bonzini , "open list:Network Block Dev..." Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_6 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" When the server is read-only, we were already reporting an error message for NBD_CMD_WRITE_ZEROES, but failed to set errp for a similar NBD_CMD_WRITE. This will matter more once structured replies allow the server to propagate the errp information back to the client. While at it, use an error message that makes a bit more sense if viewed on the client side. Note that when using qemu-io to test qemu-nbd behavior, it is rather difficult to convince qemu-io to send protocol violations (such as a read beyond bounds), because we have a lot of active checking on the client side that a qemu-io request makes sense before it ever goes over the wire to the server. The case of a client attempting a write when the server is started as 'qemu-nbd -r' is one of the few places where we can easily test error path handling, without having to resort to hacking in known temporary bugs to either the server or client. [Maybe we want a future patch to the client to do up-front checking on writes to a read-only export, the way it does up-front bounds checking; but I don't see anything in the NBD spec that points to a protocol violation in our current behavior.] Signed-off-by: Eric Blake Reviewed-by: Vladimir Sementsov-Ogievskiy Message-Id: <20171027104037.8319-5-eblake@redhat.com> --- nbd/server.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nbd/server.c b/nbd/server.c index efb6003364..05ff7470d5 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -1381,6 +1381,7 @@ static coroutine_fn void nbd_trip(void *opaque) break; case NBD_CMD_WRITE: if (exp->nbdflags & NBD_FLAG_READ_ONLY) { + error_setg(&local_err, "Export is read-only"); ret =3D -EROFS; break; } @@ -1398,7 +1399,7 @@ static coroutine_fn void nbd_trip(void *opaque) break; case NBD_CMD_WRITE_ZEROES: if (exp->nbdflags & NBD_FLAG_READ_ONLY) { - error_setg(&local_err, "Server is read-only, return error"); + error_setg(&local_err, "Export is read-only"); ret =3D -EROFS; break; } --=20 2.13.6 From nobody Mon May 6 21:04:14 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (208.118.235.17 [208.118.235.17]) by mx.zohomail.com with SMTPS id 1509397269696296.21295563582544; Mon, 30 Oct 2017 14:01:09 -0700 (PDT) Received: from localhost ([::1]:42573 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1e9HB4-00032W-Ph for importer@patchew.org; Mon, 30 Oct 2017 17:00:58 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:50591) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1e9H7G-0008To-V4 for qemu-devel@nongnu.org; Mon, 30 Oct 2017 16:57:04 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1e9H7G-0001FB-28 for qemu-devel@nongnu.org; Mon, 30 Oct 2017 16:57:03 -0400 Received: from mx1.redhat.com ([209.132.183.28]:50034) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1e9H7B-00016X-SB; Mon, 30 Oct 2017 16:56:58 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id CBCBD80C08; Mon, 30 Oct 2017 20:56:56 +0000 (UTC) Received: from red.redhat.com (ovpn-123-123.rdu2.redhat.com [10.10.123.123]) by smtp.corp.redhat.com (Postfix) with ESMTP id 3D2275C1A1; Mon, 30 Oct 2017 20:56:52 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com CBCBD80C08 Authentication-Results: ext-mx02.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx02.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=eblake@redhat.com From: Eric Blake To: qemu-devel@nongnu.org Date: Mon, 30 Oct 2017 21:56:29 +0100 Message-Id: <20171030205636.14236-6-eblake@redhat.com> In-Reply-To: <20171030205636.14236-1-eblake@redhat.com> References: <20171030205636.14236-1-eblake@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.26]); Mon, 30 Oct 2017 20:56:56 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL 05/12] nbd/server: Simplify nbd_negotiate_options loop X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Paolo Bonzini , "open list:Network Block Dev..." Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Instead of making each caller check whether a transmission error occurred, we can sink a common error check to the end of the loop. Signed-off-by: Eric Blake Message-Id: <20171027104037.8319-6-eblake@redhat.com> [eblake: squash in compiler warning fix] Reviewed-by: Vladimir Sementsov-Ogievskiy --- nbd/server.c | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/nbd/server.c b/nbd/server.c index 05ff7470d5..2f03059b4c 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -678,6 +678,7 @@ static int nbd_negotiate_options(NBDClient *client, uin= t16_t myflags, if (!tioc) { return -EIO; } + ret =3D 0; object_unref(OBJECT(client->ioc)); client->ioc =3D QIO_CHANNEL(tioc); break; @@ -698,9 +699,6 @@ static int nbd_negotiate_options(NBDClient *client, uin= t16_t myflags, "Option 0x%" PRIx32 "not permitted before TLS= ", option); - if (ret < 0) { - return ret; - } /* Let the client keep trying, unless they asked to * quit. In this mode, we've already sent an error, so * we can't ack the abort. */ @@ -713,9 +711,6 @@ static int nbd_negotiate_options(NBDClient *client, uin= t16_t myflags, switch (option) { case NBD_OPT_LIST: ret =3D nbd_negotiate_handle_list(client, length, errp); - if (ret < 0) { - return ret; - } break; case NBD_OPT_ABORT: @@ -738,9 +733,6 @@ static int nbd_negotiate_options(NBDClient *client, uin= t16_t myflags, assert(option =3D=3D NBD_OPT_GO); return 0; } - if (ret) { - return ret; - } break; case NBD_OPT_STARTTLS: @@ -758,9 +750,6 @@ static int nbd_negotiate_options(NBDClient *client, uin= t16_t myflags, option, errp, "TLS not configured"); } - if (ret < 0) { - return ret; - } break; default: if (nbd_drop(client->ioc, length, errp) < 0) { @@ -772,9 +761,6 @@ static int nbd_negotiate_options(NBDClient *client, uin= t16_t myflags, "Unsupported option 0x%" PRIx32 " (%s)", option, nbd_opt_lookup(option)); - if (ret < 0) { - return ret; - } break; } } else { @@ -794,6 +780,9 @@ static int nbd_negotiate_options(NBDClient *client, uin= t16_t myflags, return -EINVAL; } } + if (ret < 0) { + return ret; + } } } --=20 2.13.6 From nobody Mon May 6 21:04:14 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (208.118.235.17 [208.118.235.17]) by mx.zohomail.com with SMTPS id 1509397400406928.6019734583184; Mon, 30 Oct 2017 14:03:20 -0700 (PDT) Received: from localhost ([::1]:42584 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1e9HDE-0004vB-IF for importer@patchew.org; Mon, 30 Oct 2017 17:03:12 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:50605) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1e9H7H-0008UW-JD for qemu-devel@nongnu.org; Mon, 30 Oct 2017 16:57:04 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1e9H7G-0001Fv-HJ for qemu-devel@nongnu.org; Mon, 30 Oct 2017 16:57:03 -0400 Received: from mx1.redhat.com ([209.132.183.28]:58158) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1e9H7D-00019S-LK; Mon, 30 Oct 2017 16:56:59 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 96D171B5E58; Mon, 30 Oct 2017 20:56:58 +0000 (UTC) Received: from red.redhat.com (ovpn-123-123.rdu2.redhat.com [10.10.123.123]) by smtp.corp.redhat.com (Postfix) with ESMTP id 3BD5A5C1A1; Mon, 30 Oct 2017 20:56:57 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 96D171B5E58 Authentication-Results: ext-mx06.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx06.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=eblake@redhat.com From: Eric Blake To: qemu-devel@nongnu.org Date: Mon, 30 Oct 2017 21:56:30 +0100 Message-Id: <20171030205636.14236-7-eblake@redhat.com> In-Reply-To: <20171030205636.14236-1-eblake@redhat.com> References: <20171030205636.14236-1-eblake@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.30]); Mon, 30 Oct 2017 20:56:58 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL 06/12] nbd/server: Refactor zero-length option check X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Paolo Bonzini , "open list:Network Block Dev..." Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Consolidate the response for a non-zero-length option payload into a new function, nbd_reject_length(). This check will also be used when introducing support for structured replies. Note that STARTTLS response differs based on time: if the connection is still unencrypted, we set fatal to true (a client that can't request TLS correctly may still think that we are ready to start the TLS handshake, so we must disconnect); while if the connection is already encrypted, the client is sending a bogus request but is no longer at risk of being confused by continuing the connection. Signed-off-by: Eric Blake Message-Id: <20171027104037.8319-7-eblake@redhat.com> [eblake: correct return value on STARTTLS] Reviewed-by: Vladimir Sementsov-Ogievskiy --- nbd/server.c | 74 +++++++++++++++++++++++++++++++++++++-------------------= ---- 1 file changed, 46 insertions(+), 28 deletions(-) diff --git a/nbd/server.c b/nbd/server.c index 2f03059b4c..cf815603a6 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -253,21 +253,10 @@ static int nbd_negotiate_send_rep_list(QIOChannel *io= c, NBDExport *exp, /* Process the NBD_OPT_LIST command, with a potential series of replies. * Return -errno on error, 0 on success. */ -static int nbd_negotiate_handle_list(NBDClient *client, uint32_t length, - Error **errp) +static int nbd_negotiate_handle_list(NBDClient *client, Error **errp) { NBDExport *exp; - if (length) { - if (nbd_drop(client->ioc, length, errp) < 0) { - return -EIO; - } - return nbd_negotiate_send_rep_err(client->ioc, - NBD_REP_ERR_INVALID, NBD_OPT_LIS= T, - errp, - "OPT_LIST should not have length= "); - } - /* For each export, send a NBD_REP_SERVER reply. */ QTAILQ_FOREACH(exp, &exports, next) { if (nbd_negotiate_send_rep_list(client->ioc, exp, errp)) { @@ -531,7 +520,6 @@ static int nbd_negotiate_handle_info(NBDClient *client,= uint32_t length, /* Handle NBD_OPT_STARTTLS. Return NULL to drop connection, or else the * new channel for all further (now-encrypted) communication. */ static QIOChannel *nbd_negotiate_handle_starttls(NBDClient *client, - uint32_t length, Error **errp) { QIOChannel *ioc; @@ -540,15 +528,6 @@ static QIOChannel *nbd_negotiate_handle_starttls(NBDCl= ient *client, trace_nbd_negotiate_handle_starttls(); ioc =3D client->ioc; - if (length) { - if (nbd_drop(ioc, length, errp) < 0) { - return NULL; - } - nbd_negotiate_send_rep_err(ioc, NBD_REP_ERR_INVALID, NBD_OPT_START= TLS, - errp, - "OPT_STARTTLS should not have length"); - return NULL; - } if (nbd_negotiate_send_rep(client->ioc, NBD_REP_ACK, NBD_OPT_STARTTLS, errp) < 0) { @@ -584,6 +563,34 @@ static QIOChannel *nbd_negotiate_handle_starttls(NBDCl= ient *client, return QIO_CHANNEL(tioc); } +/* nbd_reject_length: Handle any unexpected payload. + * @fatal requests that we quit talking to the client, even if we are able + * to successfully send an error to the guest. + * Return: + * -errno transmission error occurred or @fatal was requested, errp is set + * 0 error message successfully sent to client, errp is not set + */ +static int nbd_reject_length(NBDClient *client, uint32_t length, + uint32_t option, bool fatal, Error **errp) +{ + int ret; + + assert(length); + if (nbd_drop(client->ioc, length, errp) < 0) { + return -EIO; + } + ret =3D nbd_negotiate_send_rep_err(client->ioc, NBD_REP_ERR_INVALID, + option, errp, + "option '%s' should have zero length", + nbd_opt_lookup(option)); + if (fatal && !ret) { + error_setg(errp, "option '%s' should have zero length", + nbd_opt_lookup(option)); + return -EINVAL; + } + return ret; +} + /* nbd_negotiate_options * Process all NBD_OPT_* client option commands, during fixed newstyle * negotiation. @@ -674,7 +681,13 @@ static int nbd_negotiate_options(NBDClient *client, ui= nt16_t myflags, } switch (option) { case NBD_OPT_STARTTLS: - tioc =3D nbd_negotiate_handle_starttls(client, length, err= p); + if (length) { + /* Unconditionally drop the connection if the client + * can't start a TLS negotiation correctly */ + return nbd_reject_length(client, length, option, true, + errp); + } + tioc =3D nbd_negotiate_handle_starttls(client, errp); if (!tioc) { return -EIO; } @@ -710,7 +723,12 @@ static int nbd_negotiate_options(NBDClient *client, ui= nt16_t myflags, } else if (fixedNewstyle) { switch (option) { case NBD_OPT_LIST: - ret =3D nbd_negotiate_handle_list(client, length, errp); + if (length) { + ret =3D nbd_reject_length(client, length, option, fals= e, + errp); + } else { + ret =3D nbd_negotiate_handle_list(client, errp); + } break; case NBD_OPT_ABORT: @@ -736,10 +754,10 @@ static int nbd_negotiate_options(NBDClient *client, u= int16_t myflags, break; case NBD_OPT_STARTTLS: - if (nbd_drop(client->ioc, length, errp) < 0) { - return -EIO; - } - if (client->tlscreds) { + if (length) { + ret =3D nbd_reject_length(client, length, option, fals= e, + errp); + } else if (client->tlscreds) { ret =3D nbd_negotiate_send_rep_err(client->ioc, NBD_REP_ERR_INVALID, option, errp, --=20 2.13.6 From nobody Mon May 6 21:04:14 2024 Delivered-To: importer@patchew.org Received-SPF: temperror (zoho.com: Error in retrieving data from DNS) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=temperror (zoho.com: Error in retrieving data from DNS) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (208.118.235.17 [208.118.235.17]) by mx.zohomail.com with SMTPS id 1509397542664588.9672119142112; Mon, 30 Oct 2017 14:05:42 -0700 (PDT) Received: from localhost ([::1]:42595 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1e9HFH-0006O4-Jx for importer@patchew.org; Mon, 30 Oct 2017 17:05:19 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:50671) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1e9H7K-00005s-Ol for qemu-devel@nongnu.org; Mon, 30 Oct 2017 16:57:11 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1e9H7J-0001Ki-Fs for qemu-devel@nongnu.org; Mon, 30 Oct 2017 16:57:06 -0400 Received: from mx1.redhat.com ([209.132.183.28]:37102) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1e9H7F-0001DD-NP; Mon, 30 Oct 2017 16:57:01 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id AF71D83F44; Mon, 30 Oct 2017 20:57:00 +0000 (UTC) Received: from red.redhat.com (ovpn-123-123.rdu2.redhat.com [10.10.123.123]) by smtp.corp.redhat.com (Postfix) with ESMTP id 0B0045C1A1; Mon, 30 Oct 2017 20:56:58 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com AF71D83F44 Authentication-Results: ext-mx03.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx03.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=eblake@redhat.com From: Eric Blake To: qemu-devel@nongnu.org Date: Mon, 30 Oct 2017 21:56:31 +0100 Message-Id: <20171030205636.14236-8-eblake@redhat.com> In-Reply-To: <20171030205636.14236-1-eblake@redhat.com> References: <20171030205636.14236-1-eblake@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.27]); Mon, 30 Oct 2017 20:57:00 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL 07/12] nbd: Minimal structured read for server X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Paolo Bonzini , Vladimir Sementsov-Ogievskiy , "open list:Network Block Dev..." Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_6 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" From: Vladimir Sementsov-Ogievskiy Minimal implementation of structured read: one structured reply chunk, no segmentation. Minimal structured error implementation: no text message. Support DF flag, but just ignore it, as there is no segmentation any way. Signed-off-by: Vladimir Sementsov-Ogievskiy Signed-off-by: Eric Blake Message-Id: <20171027104037.8319-8-eblake@redhat.com> --- nbd/server.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++++--= ---- nbd/trace-events | 2 ++ 2 files changed, 99 insertions(+), 10 deletions(-) diff --git a/nbd/server.c b/nbd/server.c index cf815603a6..3261fd1bd7 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -100,6 +100,8 @@ struct NBDClient { QTAILQ_ENTRY(NBDClient) next; int nb_requests; bool closing; + + bool structured_reply; }; /* That's all folks */ @@ -769,6 +771,23 @@ static int nbd_negotiate_options(NBDClient *client, ui= nt16_t myflags, "TLS not configured"); } break; + + case NBD_OPT_STRUCTURED_REPLY: + if (length) { + ret =3D nbd_reject_length(client, length, option, fals= e, + errp); + } else if (client->structured_reply) { + ret =3D nbd_negotiate_send_rep_err( + client->ioc, NBD_REP_ERR_INVALID, option, errp, + "structured reply already negotiated"); + } else { + ret =3D nbd_negotiate_send_rep(client->ioc, NBD_REP_AC= K, + option, errp); + client->structured_reply =3D true; + myflags |=3D NBD_FLAG_SEND_DF; + } + break; + default: if (nbd_drop(client->ioc, length, errp) < 0) { return -EIO; @@ -1243,6 +1262,60 @@ static int nbd_co_send_simple_reply(NBDClient *clien= t, return nbd_co_send_iov(client, iov, len ? 2 : 1, errp); } +static inline void set_be_chunk(NBDStructuredReplyChunk *chunk, uint16_t f= lags, + uint16_t type, uint64_t handle, uint32_t l= ength) +{ + stl_be_p(&chunk->magic, NBD_STRUCTURED_REPLY_MAGIC); + stw_be_p(&chunk->flags, flags); + stw_be_p(&chunk->type, type); + stq_be_p(&chunk->handle, handle); + stl_be_p(&chunk->length, length); +} + +static int coroutine_fn nbd_co_send_structured_read(NBDClient *client, + uint64_t handle, + uint64_t offset, + void *data, + size_t size, + Error **errp) +{ + NBDStructuredRead chunk; + struct iovec iov[] =3D { + {.iov_base =3D &chunk, .iov_len =3D sizeof(chunk)}, + {.iov_base =3D data, .iov_len =3D size} + }; + + trace_nbd_co_send_structured_read(handle, offset, data, size); + set_be_chunk(&chunk.h, NBD_REPLY_FLAG_DONE, NBD_REPLY_TYPE_OFFSET_DATA, + handle, sizeof(chunk) - sizeof(chunk.h) + size); + stq_be_p(&chunk.offset, offset); + + return nbd_co_send_iov(client, iov, 2, errp); +} + +static int coroutine_fn nbd_co_send_structured_error(NBDClient *client, + uint64_t handle, + uint32_t error, + Error **errp) +{ + NBDStructuredError chunk; + int nbd_err =3D system_errno_to_nbd_errno(error); + struct iovec iov[] =3D { + {.iov_base =3D &chunk, .iov_len =3D sizeof(chunk)}, + /* FIXME: Support human-readable error message */ + }; + + assert(nbd_err); + trace_nbd_co_send_structured_error(handle, nbd_err, + nbd_err_lookup(nbd_err)); + set_be_chunk(&chunk.h, NBD_REPLY_FLAG_DONE, NBD_REPLY_TYPE_ERROR, hand= le, + sizeof(chunk) - sizeof(chunk.h)); + stl_be_p(&chunk.error, nbd_err); + stw_be_p(&chunk.message_length, 0); + + return nbd_co_send_iov(client, iov, 1, errp); +} + /* nbd_co_receive_request * Collect a client request. Return 0 if request looks valid, -EIO to drop * connection right away, and any other negative value to report an error = to @@ -1253,6 +1326,7 @@ static int nbd_co_receive_request(NBDRequestData *req= , NBDRequest *request, Error **errp) { NBDClient *client =3D req->client; + int valid_flags; g_assert(qemu_in_coroutine()); assert(client->recv_coroutine =3D=3D qemu_coroutine_self()); @@ -1314,13 +1388,15 @@ static int nbd_co_receive_request(NBDRequestData *r= eq, NBDRequest *request, (uint64_t)client->exp->size); return request->type =3D=3D NBD_CMD_WRITE ? -ENOSPC : -EINVAL; } - if (request->flags & ~(NBD_CMD_FLAG_FUA | NBD_CMD_FLAG_NO_HOLE)) { - error_setg(errp, "unsupported flags (got 0x%x)", request->flags); - return -EINVAL; + valid_flags =3D NBD_CMD_FLAG_FUA; + if (request->type =3D=3D NBD_CMD_READ && client->structured_reply) { + valid_flags |=3D NBD_CMD_FLAG_DF; + } else if (request->type =3D=3D NBD_CMD_WRITE_ZEROES) { + valid_flags |=3D NBD_CMD_FLAG_NO_HOLE; } - if (request->type !=3D NBD_CMD_WRITE_ZEROES && - (request->flags & NBD_CMD_FLAG_NO_HOLE)) { - error_setg(errp, "unexpected flags (got 0x%x)", request->flags); + if (request->flags & ~valid_flags) { + error_setg(errp, "unsupported flags for command %s (got 0x%x)", + nbd_cmd_lookup(request->type), request->flags); return -EINVAL; } @@ -1458,10 +1534,21 @@ reply: local_err =3D NULL; } - if (nbd_co_send_simple_reply(req->client, request.handle, - ret < 0 ? -ret : 0, - req->data, reply_data_len, &local_err) < = 0) - { + if (client->structured_reply && request.type =3D=3D NBD_CMD_READ) { + if (ret < 0) { + ret =3D nbd_co_send_structured_error(req->client, request.hand= le, + -ret, &local_err); + } else { + ret =3D nbd_co_send_structured_read(req->client, request.handl= e, + request.from, req->data, + reply_data_len, &local_err); + } + } else { + ret =3D nbd_co_send_simple_reply(req->client, request.handle, + ret < 0 ? -ret : 0, + req->data, reply_data_len, &local_e= rr); + } + if (ret < 0) { error_prepend(&local_err, "Failed to send reply: "); goto disconnect; } diff --git a/nbd/trace-events b/nbd/trace-events index ab3d7dad4f..6894f8bbb4 100644 --- a/nbd/trace-events +++ b/nbd/trace-events @@ -56,6 +56,8 @@ nbd_receive_request(uint32_t magic, uint16_t flags, uint1= 6_t type, uint64_t from nbd_blk_aio_attached(const char *name, void *ctx) "Export %s: Attaching cl= ients to AIO context %p\n" nbd_blk_aio_detach(const char *name, void *ctx) "Export %s: Detaching clie= nts from AIO context %p\n" nbd_co_send_simple_reply(uint64_t handle, uint32_t error, const char *errn= ame, int len) "Send simple reply: handle =3D %" PRIu64 ", error =3D %" PRIu= 32 " (%s), len =3D %d" +nbd_co_send_structured_read(uint64_t handle, uint64_t offset, void *data, = size_t size) "Send structured read data reply: handle =3D %" PRIu64 ", offs= et =3D %" PRIu64 ", data =3D %p, len =3D %zu" +nbd_co_send_structured_error(uint64_t handle, int err, const char *errname= ) "Send structured error reply: handle =3D %" PRIu64 ", error =3D %d (%s)" nbd_co_receive_request_decode_type(uint64_t handle, uint16_t type, const c= har *name) "Decoding type: handle =3D %" PRIu64 ", type =3D %" PRIu16 " (%s= )" nbd_co_receive_request_payload_received(uint64_t handle, uint32_t len) "Pa= yload received: handle =3D %" PRIu64 ", len =3D %" PRIu32 nbd_co_receive_request_cmd_write(uint32_t len) "Reading %" PRIu32 " byte(s= )" --=20 2.13.6 From nobody Mon May 6 21:04:14 2024 Delivered-To: importer@patchew.org Received-SPF: temperror (zoho.com: Error in retrieving data from DNS) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=temperror (zoho.com: Error in retrieving data from DNS) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (208.118.235.17 [208.118.235.17]) by mx.zohomail.com with SMTPS id 1509397626361769.0411177499545; Mon, 30 Oct 2017 14:07:06 -0700 (PDT) Received: from localhost ([::1]:42611 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1e9HGf-0007aC-I9 for importer@patchew.org; Mon, 30 Oct 2017 17:06:45 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:50754) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1e9H7P-0000Bo-RD for qemu-devel@nongnu.org; Mon, 30 Oct 2017 16:57:12 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1e9H7L-0001MQ-1n for qemu-devel@nongnu.org; Mon, 30 Oct 2017 16:57:11 -0400 Received: from mx1.redhat.com ([209.132.183.28]:44898) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1e9H7I-0001Hg-5G; Mon, 30 Oct 2017 16:57:04 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 1CE4DC1871E7; Mon, 30 Oct 2017 20:57:03 +0000 (UTC) Received: from red.redhat.com (ovpn-123-123.rdu2.redhat.com [10.10.123.123]) by smtp.corp.redhat.com (Postfix) with ESMTP id 242305C1A1; Mon, 30 Oct 2017 20:57:00 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 1CE4DC1871E7 Authentication-Results: ext-mx07.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx07.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=eblake@redhat.com From: Eric Blake To: qemu-devel@nongnu.org Date: Mon, 30 Oct 2017 21:56:32 +0100 Message-Id: <20171030205636.14236-9-eblake@redhat.com> In-Reply-To: <20171030205636.14236-1-eblake@redhat.com> References: <20171030205636.14236-1-eblake@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.31]); Mon, 30 Oct 2017 20:57:03 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL 08/12] nbd/server: Include human-readable message in structured errors X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Paolo Bonzini , "open list:Network Block Dev..." Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_6 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" The NBD spec permits including a human-readable error string if structured replies are in force, so we might as well send the client the message that we logged on any error. Signed-off-by: Eric Blake Reviewed-by: Vladimir Sementsov-Ogievskiy Message-Id: <20171027104037.8319-9-eblake@redhat.com> --- nbd/server.c | 20 +++++++++++++------- nbd/trace-events | 2 +- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/nbd/server.c b/nbd/server.c index 3261fd1bd7..70b40ed27e 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -1296,24 +1296,25 @@ static int coroutine_fn nbd_co_send_structured_read= (NBDClient *client, static int coroutine_fn nbd_co_send_structured_error(NBDClient *client, uint64_t handle, uint32_t error, + const char *msg, Error **errp) { NBDStructuredError chunk; int nbd_err =3D system_errno_to_nbd_errno(error); struct iovec iov[] =3D { {.iov_base =3D &chunk, .iov_len =3D sizeof(chunk)}, - /* FIXME: Support human-readable error message */ + {.iov_base =3D (char *)msg, .iov_len =3D msg ? strlen(msg) : 0}, }; assert(nbd_err); trace_nbd_co_send_structured_error(handle, nbd_err, - nbd_err_lookup(nbd_err)); + nbd_err_lookup(nbd_err), msg ? msg = : ""); set_be_chunk(&chunk.h, NBD_REPLY_FLAG_DONE, NBD_REPLY_TYPE_ERROR, hand= le, - sizeof(chunk) - sizeof(chunk.h)); + sizeof(chunk) - sizeof(chunk.h) + iov[1].iov_len); stl_be_p(&chunk.error, nbd_err); - stw_be_p(&chunk.message_length, 0); + stw_be_p(&chunk.message_length, iov[1].iov_len); - return nbd_co_send_iov(client, iov, 1, errp); + return nbd_co_send_iov(client, iov, 1 + !!iov[1].iov_len, errp); } /* nbd_co_receive_request @@ -1414,6 +1415,7 @@ static coroutine_fn void nbd_trip(void *opaque) int flags; int reply_data_len =3D 0; Error *local_err =3D NULL; + char *msg =3D NULL; trace_nbd_trip(); if (client->closing) { @@ -1530,14 +1532,17 @@ reply: if (local_err) { /* If we get here, local_err was not a fatal error, and should be = sent * to the client. */ + assert(ret < 0); + msg =3D g_strdup(error_get_pretty(local_err)); error_report_err(local_err); local_err =3D NULL; } - if (client->structured_reply && request.type =3D=3D NBD_CMD_READ) { + if (client->structured_reply && + (ret < 0 || request.type =3D=3D NBD_CMD_READ)) { if (ret < 0) { ret =3D nbd_co_send_structured_error(req->client, request.hand= le, - -ret, &local_err); + -ret, msg, &local_err); } else { ret =3D nbd_co_send_structured_read(req->client, request.handl= e, request.from, req->data, @@ -1548,6 +1553,7 @@ reply: ret < 0 ? -ret : 0, req->data, reply_data_len, &local_e= rr); } + g_free(msg); if (ret < 0) { error_prepend(&local_err, "Failed to send reply: "); goto disconnect; diff --git a/nbd/trace-events b/nbd/trace-events index 6894f8bbb4..52150bd738 100644 --- a/nbd/trace-events +++ b/nbd/trace-events @@ -57,7 +57,7 @@ nbd_blk_aio_attached(const char *name, void *ctx) "Export= %s: Attaching clients nbd_blk_aio_detach(const char *name, void *ctx) "Export %s: Detaching clie= nts from AIO context %p\n" nbd_co_send_simple_reply(uint64_t handle, uint32_t error, const char *errn= ame, int len) "Send simple reply: handle =3D %" PRIu64 ", error =3D %" PRIu= 32 " (%s), len =3D %d" nbd_co_send_structured_read(uint64_t handle, uint64_t offset, void *data, = size_t size) "Send structured read data reply: handle =3D %" PRIu64 ", offs= et =3D %" PRIu64 ", data =3D %p, len =3D %zu" -nbd_co_send_structured_error(uint64_t handle, int err, const char *errname= ) "Send structured error reply: handle =3D %" PRIu64 ", error =3D %d (%s)" +nbd_co_send_structured_error(uint64_t handle, int err, const char *errname= , const char *msg) "Send structured error reply: handle =3D %" PRIu64 ", er= ror =3D %d (%s), msg =3D '%s'" nbd_co_receive_request_decode_type(uint64_t handle, uint16_t type, const c= har *name) "Decoding type: handle =3D %" PRIu64 ", type =3D %" PRIu16 " (%s= )" nbd_co_receive_request_payload_received(uint64_t handle, uint32_t len) "Pa= yload received: handle =3D %" PRIu64 ", len =3D %" PRIu32 nbd_co_receive_request_cmd_write(uint32_t len) "Reading %" PRIu32 " byte(s= )" --=20 2.13.6 From nobody Mon May 6 21:04:14 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (208.118.235.17 [208.118.235.17]) by mx.zohomail.com with SMTPS id 150939714428235.52716602943906; Mon, 30 Oct 2017 13:59:04 -0700 (PDT) Received: from localhost ([::1]:42561 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1e9H93-0001Nb-Dk for importer@patchew.org; Mon, 30 Oct 2017 16:58:53 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:50814) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1e9H7S-0000EN-GE for qemu-devel@nongnu.org; Mon, 30 Oct 2017 16:57:15 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1e9H7R-0001T1-6d for qemu-devel@nongnu.org; Mon, 30 Oct 2017 16:57:14 -0400 Received: from mx1.redhat.com ([209.132.183.28]:58348) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1e9H7L-0001Lt-55; Mon, 30 Oct 2017 16:57:07 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 22B7C267FF; Mon, 30 Oct 2017 20:57:06 +0000 (UTC) Received: from red.redhat.com (ovpn-123-123.rdu2.redhat.com [10.10.123.123]) by smtp.corp.redhat.com (Postfix) with ESMTP id AEF075C1A1; Mon, 30 Oct 2017 20:57:03 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 22B7C267FF Authentication-Results: ext-mx06.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx06.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=eblake@redhat.com From: Eric Blake To: qemu-devel@nongnu.org Date: Mon, 30 Oct 2017 21:56:33 +0100 Message-Id: <20171030205636.14236-10-eblake@redhat.com> In-Reply-To: <20171030205636.14236-1-eblake@redhat.com> References: <20171030205636.14236-1-eblake@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.30]); Mon, 30 Oct 2017 20:57:06 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL 09/12] nbd/client: refactor nbd_receive_starttls X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Paolo Bonzini , Vladimir Sementsov-Ogievskiy , "open list:Network Block Dev..." Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" From: Vladimir Sementsov-Ogievskiy Split out nbd_request_simple_option to be reused for structured reply option. Signed-off-by: Vladimir Sementsov-Ogievskiy Signed-off-by: Eric Blake Message-Id: <20171027104037.8319-10-eblake@redhat.com> --- nbd/client.c | 70 ++++++++++++++++++++++++++++++++++++++--------------= ---- nbd/trace-events | 4 +--- 2 files changed, 49 insertions(+), 25 deletions(-) diff --git a/nbd/client.c b/nbd/client.c index 50f36b511e..9acf745b79 100644 --- a/nbd/client.c +++ b/nbd/client.c @@ -508,35 +508,61 @@ static int nbd_receive_query_exports(QIOChannel *ioc, } } +/* nbd_request_simple_option: Send an option request, and parse the reply + * 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 **err= p) +{ + nbd_opt_reply reply; + int error; + + if (nbd_send_option_request(ioc, opt, 0, NULL, errp) < 0) { + return -1; + } + + if (nbd_receive_option_reply(ioc, opt, &reply, errp) < 0) { + return -1; + } + error =3D nbd_handle_reply_err(ioc, &reply, errp); + if (error <=3D 0) { + return error; + } + + if (reply.type !=3D NBD_REP_ACK) { + error_setg(errp, "Server answered option %d (%s) with unexpected " + "reply %" PRIx32 " (%s)", opt, nbd_opt_lookup(opt), + reply.type, nbd_rep_lookup(reply.type)); + nbd_send_opt_abort(ioc); + return -1; + } + + if (reply.length !=3D 0) { + error_setg(errp, "Option %d ('%s') response length is %" PRIu32 + " (it should be zero)", opt, nbd_opt_lookup(opt), + reply.length); + nbd_send_opt_abort(ioc); + return -1; + } + + return 1; +} + static QIOChannel *nbd_receive_starttls(QIOChannel *ioc, QCryptoTLSCreds *tlscreds, const char *hostname, Error **errp) { - nbd_opt_reply reply; + int ret; QIOChannelTLS *tioc; struct NBDTLSHandshakeData data =3D { 0 }; - trace_nbd_receive_starttls_request(); - if (nbd_send_option_request(ioc, NBD_OPT_STARTTLS, 0, NULL, errp) < 0)= { - return NULL; - } - - trace_nbd_receive_starttls_reply(); - if (nbd_receive_option_reply(ioc, NBD_OPT_STARTTLS, &reply, errp) < 0)= { - return NULL; - } - - if (reply.type !=3D NBD_REP_ACK) { - error_setg(errp, "Server rejected request to start TLS %" PRIx32, - reply.type); - nbd_send_opt_abort(ioc); - return NULL; - } - - if (reply.length !=3D 0) { - error_setg(errp, "Start TLS response was not zero %" PRIu32, - reply.length); - nbd_send_opt_abort(ioc); + ret =3D nbd_request_simple_option(ioc, NBD_OPT_STARTTLS, errp); + if (ret <=3D 0) { + if (ret =3D=3D 0) { + error_setg(errp, "Server don't support STARTTLS option"); + nbd_send_opt_abort(ioc); + } return NULL; } diff --git a/nbd/trace-events b/nbd/trace-events index 52150bd738..596df96575 100644 --- a/nbd/trace-events +++ b/nbd/trace-events @@ -8,9 +8,7 @@ nbd_opt_go_info_unknown(int info, const char *name) "Ignori= ng unknown info %d (% nbd_opt_go_info_block_size(uint32_t minimum, uint32_t preferred, uint32_t = maximum) "Block sizes are 0x%" PRIx32 ", 0x%" PRIx32 ", 0x%" PRIx32 nbd_receive_query_exports_start(const char *wantname) "Querying export lis= t for '%s'" nbd_receive_query_exports_success(const char *wantname) "Found desired exp= ort name '%s'" -nbd_receive_starttls_request(void) "Requesting TLS from server" -nbd_receive_starttls_reply(void) "Getting TLS reply from server" -nbd_receive_starttls_new_client(void) "TLS request approved, setting up TL= S" +nbd_receive_starttls_new_client(void) "Setting up TLS" nbd_receive_starttls_tls_handshake(void) "Starting TLS handshake" nbd_receive_negotiate(void *tlscreds, const char *hostname) "Receiving neg= otiation tlscreds=3D%p hostname=3D%s" nbd_receive_negotiate_magic(uint64_t magic) "Magic is 0x%" PRIx64 --=20 2.13.6 From nobody Mon May 6 21:04:14 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (208.118.235.17 [208.118.235.17]) by mx.zohomail.com with SMTPS id 1509397721408488.03781844350726; Mon, 30 Oct 2017 14:08:41 -0700 (PDT) Received: from localhost ([::1]:42617 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1e9HIL-0000Ak-TT for importer@patchew.org; Mon, 30 Oct 2017 17:08:29 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:50851) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1e9H7T-0000Fh-RD for qemu-devel@nongnu.org; Mon, 30 Oct 2017 16:57:17 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1e9H7S-0001UE-AK for qemu-devel@nongnu.org; Mon, 30 Oct 2017 16:57:15 -0400 Received: from mx1.redhat.com ([209.132.183.28]:60438) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1e9H7N-0001OC-Cx; Mon, 30 Oct 2017 16:57:09 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 687D58B120; Mon, 30 Oct 2017 20:57:08 +0000 (UTC) Received: from red.redhat.com (ovpn-123-123.rdu2.redhat.com [10.10.123.123]) by smtp.corp.redhat.com (Postfix) with ESMTP id 8E7E95C1A1; Mon, 30 Oct 2017 20:57:06 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 687D58B120 Authentication-Results: ext-mx04.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx04.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=eblake@redhat.com From: Eric Blake To: qemu-devel@nongnu.org Date: Mon, 30 Oct 2017 21:56:34 +0100 Message-Id: <20171030205636.14236-11-eblake@redhat.com> In-Reply-To: <20171030205636.14236-1-eblake@redhat.com> References: <20171030205636.14236-1-eblake@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.28]); Mon, 30 Oct 2017 20:57:08 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL 10/12] nbd/client: prepare nbd_receive_reply for structured reply X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , Paolo Bonzini , Vladimir Sementsov-Ogievskiy , "open list:Network Block Dev..." , Max Reitz Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" From: Vladimir Sementsov-Ogievskiy In following patch nbd_receive_reply will be used both for simple and structured reply header receiving. NBDReply is altered into union of simple reply header and structured reply chunk header, simple error translation moved to block/nbd-client to be consistent with further structured reply error translation. Signed-off-by: Vladimir Sementsov-Ogievskiy Signed-off-by: Eric Blake Message-Id: <20171027104037.8319-11-eblake@redhat.com> --- include/block/nbd.h | 30 ++++++++++++--- block/nbd-client.c | 8 ++-- nbd/client.c | 104 +++++++++++++++++++++++++++++++++++++++++-------= ---- nbd/trace-events | 3 +- 4 files changed, 113 insertions(+), 32 deletions(-) diff --git a/include/block/nbd.h b/include/block/nbd.h index 225e9575e4..2ee1578420 100644 --- a/include/block/nbd.h +++ b/include/block/nbd.h @@ -57,12 +57,6 @@ struct NBDRequest { }; typedef struct NBDRequest NBDRequest; -struct NBDReply { - uint64_t handle; - uint32_t error; -}; -typedef struct NBDReply NBDReply; - typedef struct NBDSimpleReply { uint32_t magic; /* NBD_SIMPLE_REPLY_MAGIC */ uint32_t error; @@ -78,6 +72,20 @@ typedef struct NBDStructuredReplyChunk { uint32_t length; /* length of payload */ } QEMU_PACKED NBDStructuredReplyChunk; +typedef union NBDReply { + NBDSimpleReply simple; + NBDStructuredReplyChunk structured; + struct { + /* @magic and @handle fields have the same offset and size both in + * simple reply and structured reply chunk, so let them be accessi= ble + * without ".simple." or ".structured." specification + */ + uint32_t magic; + uint32_t _skip; + uint64_t handle; + } QEMU_PACKED; +} NBDReply; + /* Header of NBD_REPLY_TYPE_OFFSET_DATA, complete NBD_REPLY_TYPE_OFFSET_HO= LE */ typedef struct NBDStructuredRead { NBDStructuredReplyChunk h; @@ -256,4 +264,14 @@ void nbd_client_put(NBDClient *client); void nbd_server_start(SocketAddress *addr, const char *tls_creds, Error **errp); +static inline bool nbd_reply_is_simple(NBDReply *reply) +{ + return reply->magic =3D=3D NBD_SIMPLE_REPLY_MAGIC; +} + +static inline bool nbd_reply_is_structured(NBDReply *reply) +{ + return reply->magic =3D=3D NBD_STRUCTURED_REPLY_MAGIC; +} + #endif diff --git a/block/nbd-client.c b/block/nbd-client.c index c0683c3c83..58493b7ac4 100644 --- a/block/nbd-client.c +++ b/block/nbd-client.c @@ -92,7 +92,9 @@ static coroutine_fn void nbd_read_reply_entry(void *opaqu= e) i =3D HANDLE_TO_INDEX(s, s->reply.handle); if (i >=3D MAX_NBD_REQUESTS || !s->requests[i].coroutine || - !s->requests[i].receiving) { + !s->requests[i].receiving || + nbd_reply_is_structured(&s->reply)) + { break; } @@ -194,8 +196,8 @@ static int nbd_co_receive_reply(NBDClientSession *s, ret =3D -EIO; } else { assert(s->reply.handle =3D=3D handle); - ret =3D -s->reply.error; - if (qiov && s->reply.error =3D=3D 0) { + ret =3D -nbd_errno_to_system_errno(s->reply.simple.error); + if (qiov && ret =3D=3D 0) { if (qio_channel_readv_all(s->ioc, qiov->iov, qiov->niov, NULL) < 0) { ret =3D -EIO; diff --git a/nbd/client.c b/nbd/client.c index 9acf745b79..4f0745f601 100644 --- a/nbd/client.c +++ b/nbd/client.c @@ -908,6 +908,57 @@ int nbd_send_request(QIOChannel *ioc, NBDRequest *requ= est) return nbd_write(ioc, buf, sizeof(buf), NULL); } +/* nbd_receive_simple_reply + * Read simple reply except magic field (which should be already read). + * Payload is not read (payload is possible for CMD_READ, but here we even + * don't know whether it take place or not). + */ +static int nbd_receive_simple_reply(QIOChannel *ioc, NBDSimpleReply *reply, + Error **errp) +{ + int ret; + + assert(reply->magic =3D=3D NBD_SIMPLE_REPLY_MAGIC); + + ret =3D nbd_read(ioc, (uint8_t *)reply + sizeof(reply->magic), + sizeof(*reply) - sizeof(reply->magic), errp); + if (ret < 0) { + return ret; + } + + be32_to_cpus(&reply->error); + be64_to_cpus(&reply->handle); + + return 0; +} + +/* nbd_receive_structured_reply_chunk + * Read structured reply chunk except magic field (which should be already + * read). + * Payload is not read. + */ +static int nbd_receive_structured_reply_chunk(QIOChannel *ioc, + NBDStructuredReplyChunk *chu= nk, + Error **errp) +{ + int ret; + + assert(chunk->magic =3D=3D NBD_STRUCTURED_REPLY_MAGIC); + + ret =3D nbd_read(ioc, (uint8_t *)chunk + sizeof(chunk->magic), + sizeof(*chunk) - sizeof(chunk->magic), errp); + if (ret < 0) { + return ret; + } + + be16_to_cpus(&chunk->flags); + be16_to_cpus(&chunk->type); + be64_to_cpus(&chunk->handle); + be32_to_cpus(&chunk->length); + + return 0; +} + /* nbd_receive_reply * Returns 1 on success * 0 on eof, when no data was read (errp is not set) @@ -915,38 +966,47 @@ int nbd_send_request(QIOChannel *ioc, NBDRequest *req= uest) */ int nbd_receive_reply(QIOChannel *ioc, NBDReply *reply, Error **errp) { - uint8_t buf[NBD_REPLY_SIZE]; - uint32_t magic; int ret; - ret =3D nbd_read_eof(ioc, buf, sizeof(buf), errp); + ret =3D nbd_read_eof(ioc, &reply->magic, sizeof(reply->magic), errp); if (ret <=3D 0) { return ret; } - /* Reply - [ 0 .. 3] magic (NBD_SIMPLE_REPLY_MAGIC) - [ 4 .. 7] error (0 =3D=3D no error) - [ 7 .. 15] handle - */ + be32_to_cpus(&reply->magic); - magic =3D ldl_be_p(buf); - reply->error =3D ldl_be_p(buf + 4); - reply->handle =3D ldq_be_p(buf + 8); + switch (reply->magic) { + case NBD_SIMPLE_REPLY_MAGIC: + ret =3D nbd_receive_simple_reply(ioc, &reply->simple, errp); + if (ret < 0) { + break; + } - trace_nbd_receive_reply(magic, reply->error, nbd_err_lookup(reply->err= or), - reply->handle); - reply->error =3D nbd_errno_to_system_errno(reply->error); - - if (reply->error =3D=3D ESHUTDOWN) { - /* This works even on mingw which lacks a native ESHUTDOWN */ - error_setg(errp, "server shutting down"); + trace_nbd_receive_simple_reply(reply->simple.error, + nbd_err_lookup(reply->simple.error), + reply->handle); + if (reply->simple.error =3D=3D NBD_ESHUTDOWN) { + /* This works even on mingw which lacks a native ESHUTDOWN */ + error_setg(errp, "server shutting down"); + return -EINVAL; + } + break; + case NBD_STRUCTURED_REPLY_MAGIC: + ret =3D nbd_receive_structured_reply_chunk(ioc, &reply->structured= , errp); + if (ret < 0) { + break; + } + trace_nbd_receive_structured_reply_chunk(reply->structured.flags, + reply->structured.type, + reply->structured.handle, + reply->structured.length); + break; + default: + error_setg(errp, "invalid magic (got 0x%" PRIx32 ")", reply->magic= ); return -EINVAL; } - - if (magic !=3D NBD_SIMPLE_REPLY_MAGIC) { - error_setg(errp, "invalid magic (got 0x%" PRIx32 ")", magic); - return -EINVAL; + if (ret < 0) { + return ret; } return 1; diff --git a/nbd/trace-events b/nbd/trace-events index 596df96575..4a13757524 100644 --- a/nbd/trace-events +++ b/nbd/trace-events @@ -26,7 +26,8 @@ nbd_client_loop_ret(int ret, const char *error) "NBD loop= returned %d: %s" nbd_client_clear_queue(void) "Clearing NBD queue" nbd_client_clear_socket(void) "Clearing NBD socket" nbd_send_request(uint64_t from, uint32_t len, uint64_t handle, uint16_t fl= ags, uint16_t type, const char *name) "Sending request to server: { .from = =3D %" PRIu64", .len =3D %" PRIu32 ", .handle =3D %" PRIu64 ", .flags =3D 0= x%" PRIx16 ", .type =3D %" PRIu16 " (%s) }" -nbd_receive_reply(uint32_t magic, int32_t error, const char *errname, uint= 64_t handle) "Got reply: { magic =3D 0x%" PRIx32 ", .error =3D %" PRId32 " = (%s), handle =3D %" PRIu64" }" +nbd_receive_simple_reply(int32_t error, const char *errname, uint64_t hand= le) "Got simple reply: { .error =3D %" PRId32 " (%s), handle =3D %" PRIu64"= }" +nbd_receive_structured_reply_chunk(uint16_t flags, uint16_t type, uint64_t= handle, uint32_t length) "Got structured reply chunk: { flags =3D 0x%" PRI= x16 ", type =3D %d, handle =3D %" PRIu64 ", length =3D %" PRIu32 " }" # nbd/common.c nbd_unknown_error(int err) "Squashing unexpected error %d to EINVAL" --=20 2.13.6 From nobody Mon May 6 21:04:14 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (208.118.235.17 [208.118.235.17]) by mx.zohomail.com with SMTPS id 1509397271304952.4742332686751; Mon, 30 Oct 2017 14:01:11 -0700 (PDT) Received: from localhost ([::1]:42574 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1e9HBB-00037r-Gc for importer@patchew.org; Mon, 30 Oct 2017 17:01:05 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:50823) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1e9H7S-0000Ep-Sh for qemu-devel@nongnu.org; Mon, 30 Oct 2017 16:57:15 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1e9H7S-0001U1-2l for qemu-devel@nongnu.org; Mon, 30 Oct 2017 16:57:14 -0400 Received: from mx1.redhat.com ([209.132.183.28]:60158) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1e9H7P-0001Qs-Bw; Mon, 30 Oct 2017 16:57:11 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 5C56CC0568F9; Mon, 30 Oct 2017 20:57:10 +0000 (UTC) Received: from red.redhat.com (ovpn-123-123.rdu2.redhat.com [10.10.123.123]) by smtp.corp.redhat.com (Postfix) with ESMTP id D12185C1A1; Mon, 30 Oct 2017 20:57:08 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 5C56CC0568F9 Authentication-Results: ext-mx08.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx08.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=eblake@redhat.com From: Eric Blake To: qemu-devel@nongnu.org Date: Mon, 30 Oct 2017 21:56:35 +0100 Message-Id: <20171030205636.14236-12-eblake@redhat.com> In-Reply-To: <20171030205636.14236-1-eblake@redhat.com> References: <20171030205636.14236-1-eblake@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.32]); Mon, 30 Oct 2017 20:57:10 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL 11/12] nbd: Move nbd_read() to common header X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , Paolo Bonzini , "open list:Network Block Dev..." , Max Reitz Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" An upcoming change to block/nbd-client.c will want to read the tail of a structured reply chunk directly from the wire. Move this function to make it easier. Based on a patch from Vladimir Sementsov-Ogievskiy. Signed-off-by: Eric Blake Reviewed-by: Vladimir Sementsov-Ogievskiy Message-Id: <20171027104037.8319-12-eblake@redhat.com> --- include/block/nbd.h | 10 ++++++++++ nbd/nbd-internal.h | 9 --------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/include/block/nbd.h b/include/block/nbd.h index 2ee1578420..da6e305dd5 100644 --- a/include/block/nbd.h +++ b/include/block/nbd.h @@ -264,6 +264,16 @@ void nbd_client_put(NBDClient *client); void nbd_server_start(SocketAddress *addr, const char *tls_creds, Error **errp); + +/* nbd_read + * Reads @size bytes from @ioc. Returns 0 on success. + */ +static inline int nbd_read(QIOChannel *ioc, void *buffer, size_t size, + Error **errp) +{ + return qio_channel_read_all(ioc, buffer, size, errp) < 0 ? -EIO : 0; +} + static inline bool nbd_reply_is_simple(NBDReply *reply) { return reply->magic =3D=3D NBD_SIMPLE_REPLY_MAGIC; diff --git a/nbd/nbd-internal.h b/nbd/nbd-internal.h index 4f24d6e57d..b64eb1cc9b 100644 --- a/nbd/nbd-internal.h +++ b/nbd/nbd-internal.h @@ -82,15 +82,6 @@ static inline int nbd_read_eof(QIOChannel *ioc, void *bu= ffer, size_t size, return ret; } -/* nbd_read - * Reads @size bytes from @ioc. Returns 0 on success. - */ -static inline int nbd_read(QIOChannel *ioc, void *buffer, size_t size, - Error **errp) -{ - return qio_channel_read_all(ioc, buffer, size, errp) < 0 ? -EIO : 0; -} - /* nbd_write * Writes @size bytes to @ioc. Returns 0 on success. */ --=20 2.13.6 From nobody Mon May 6 21:04:14 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (208.118.235.17 [208.118.235.17]) by mx.zohomail.com with SMTPS id 1509397408764114.69177162010226; Mon, 30 Oct 2017 14:03:28 -0700 (PDT) Received: from localhost ([::1]:42585 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1e9HDO-000529-LL for importer@patchew.org; Mon, 30 Oct 2017 17:03:22 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:50949) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1e9H7d-0000Nx-Ds for qemu-devel@nongnu.org; Mon, 30 Oct 2017 16:57:28 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1e9H7b-0001bc-0p for qemu-devel@nongnu.org; Mon, 30 Oct 2017 16:57:25 -0400 Received: from mx1.redhat.com ([209.132.183.28]:58624) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1e9H7S-0001To-LJ; Mon, 30 Oct 2017 16:57:14 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 64C5F37E70; Mon, 30 Oct 2017 20:57:13 +0000 (UTC) Received: from red.redhat.com (ovpn-123-123.rdu2.redhat.com [10.10.123.123]) by smtp.corp.redhat.com (Postfix) with ESMTP id 1CD0A5C1A1; Mon, 30 Oct 2017 20:57:10 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 64C5F37E70 Authentication-Results: ext-mx05.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx05.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=eblake@redhat.com From: Eric Blake To: qemu-devel@nongnu.org Date: Mon, 30 Oct 2017 21:56:36 +0100 Message-Id: <20171030205636.14236-13-eblake@redhat.com> In-Reply-To: <20171030205636.14236-1-eblake@redhat.com> References: <20171030205636.14236-1-eblake@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.29]); Mon, 30 Oct 2017 20:57:13 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL 12/12] nbd: Minimal structured read for client X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , Paolo Bonzini , Vladimir Sementsov-Ogievskiy , "open list:Network Block Dev..." , Max Reitz Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" From: Vladimir Sementsov-Ogievskiy Minimal implementation: for structured error only error_report error message. Note that test 83 is now more verbose, because the implementation prints more warnings about unexpected communication errors; perhaps future patches should tone things down by using trace messages instead of traces, but the common case of successful communication is no noisier than before. Signed-off-by: Vladimir Sementsov-Ogievskiy Signed-off-by: Eric Blake Message-Id: <20171027104037.8319-13-eblake@redhat.com> --- block/nbd-client.h | 1 + include/block/nbd.h | 12 ++ nbd/nbd-internal.h | 1 - block/nbd-client.c | 490 +++++++++++++++++++++++++++++++++++++++++= +--- nbd/client.c | 12 ++ tests/qemu-iotests/083.out | 15 ++ 6 files changed, 498 insertions(+), 33 deletions(-) diff --git a/block/nbd-client.h b/block/nbd-client.h index b435754b82..612c4c21a0 100644 --- a/block/nbd-client.h +++ b/block/nbd-client.h @@ -19,6 +19,7 @@ typedef struct { Coroutine *coroutine; + uint64_t offset; /* original offset of the request */ bool receiving; /* waiting for read_reply_co? */ } NBDClientRequest; diff --git a/include/block/nbd.h b/include/block/nbd.h index da6e305dd5..92d1723d7c 100644 --- a/include/block/nbd.h +++ b/include/block/nbd.h @@ -197,6 +197,11 @@ enum { #define NBD_REPLY_TYPE_ERROR NBD_REPLY_ERR(1) #define NBD_REPLY_TYPE_ERROR_OFFSET NBD_REPLY_ERR(2) +static inline bool nbd_reply_type_is_error(int type) +{ + return type & (1 << 15); +} + /* 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. * Everything else is squashed to EINVAL. @@ -214,6 +219,11 @@ enum { struct NBDExportInfo { /* Set by client before nbd_receive_negotiate() */ bool request_sizes; + + /* In-out fields, set by client before nbd_receive_negotiate() and + * updated by server results during nbd_receive_negotiate() */ + bool structured_reply; + /* Set by server results during nbd_receive_negotiate() */ uint64_t size; uint16_t flags; @@ -284,4 +294,6 @@ static inline bool nbd_reply_is_structured(NBDReply *re= ply) return reply->magic =3D=3D NBD_STRUCTURED_REPLY_MAGIC; } +const char *nbd_reply_type_lookup(uint16_t type); + #endif diff --git a/nbd/nbd-internal.h b/nbd/nbd-internal.h index b64eb1cc9b..eeff78d3c9 100644 --- a/nbd/nbd-internal.h +++ b/nbd/nbd-internal.h @@ -104,7 +104,6 @@ const char *nbd_opt_lookup(uint32_t opt); const char *nbd_rep_lookup(uint32_t rep); const char *nbd_info_lookup(uint16_t info); const char *nbd_cmd_lookup(uint16_t info); -const char *nbd_reply_type_lookup(uint16_t type); const char *nbd_err_lookup(int err); int nbd_drop(QIOChannel *ioc, size_t size, Error **errp); diff --git a/block/nbd-client.c b/block/nbd-client.c index 58493b7ac4..b44d4d4a01 100644 --- a/block/nbd-client.c +++ b/block/nbd-client.c @@ -93,7 +93,7 @@ static coroutine_fn void nbd_read_reply_entry(void *opaqu= e) if (i >=3D MAX_NBD_REQUESTS || !s->requests[i].coroutine || !s->requests[i].receiving || - nbd_reply_is_structured(&s->reply)) + (nbd_reply_is_structured(&s->reply) && !s->info.structured_rep= ly)) { break; } @@ -141,6 +141,7 @@ static int nbd_co_send_request(BlockDriverState *bs, assert(i < MAX_NBD_REQUESTS); s->requests[i].coroutine =3D qemu_coroutine_self(); + s->requests[i].offset =3D request->from; s->requests[i].receiving =3D false; request->handle =3D INDEX_TO_HANDLE(s, i); @@ -181,75 +182,489 @@ err: return rc; } -static int nbd_co_receive_reply(NBDClientSession *s, - uint64_t handle, - QEMUIOVector *qiov) +static inline uint16_t payload_advance16(uint8_t **payload) +{ + *payload +=3D 2; + return lduw_be_p(*payload - 2); +} + +static inline uint32_t payload_advance32(uint8_t **payload) +{ + *payload +=3D 4; + return ldl_be_p(*payload - 4); +} + +static inline uint64_t payload_advance64(uint8_t **payload) +{ + *payload +=3D 8; + return ldq_be_p(*payload - 8); +} + +static int nbd_parse_offset_hole_payload(NBDStructuredReplyChunk *chunk, + uint8_t *payload, uint64_t orig_o= ffset, + QEMUIOVector *qiov, Error **errp) +{ + uint64_t offset; + uint32_t hole_size; + + if (chunk->length !=3D sizeof(offset) + sizeof(hole_size)) { + error_setg(errp, "Protocol error: invalid payload for " + "NBD_REPLY_TYPE_OFFSET_HOLE"); + return -EINVAL; + } + + offset =3D payload_advance64(&payload); + hole_size =3D payload_advance32(&payload); + + if (offset < orig_offset || hole_size > qiov->size || + offset > orig_offset + qiov->size - hole_size) { + error_setg(errp, "Protocol error: server sent chunk exceeding requ= ested" + " region"); + return -EINVAL; + } + + qemu_iovec_memset(qiov, offset - orig_offset, 0, hole_size); + + return 0; +} + +/* nbd_parse_error_payload + * on success @errp contains message describing nbd error reply + */ +static int nbd_parse_error_payload(NBDStructuredReplyChunk *chunk, + uint8_t *payload, int *request_ret, + Error **errp) +{ + uint32_t error; + uint16_t message_size; + + assert(chunk->type & (1 << 15)); + + if (chunk->length < sizeof(error) + sizeof(message_size)) { + error_setg(errp, + "Protocol error: invalid payload for structured error"); + return -EINVAL; + } + + error =3D nbd_errno_to_system_errno(payload_advance32(&payload)); + if (error =3D=3D 0) { + error_setg(errp, "Protocol error: server sent structured error chu= nk" + "with error =3D 0"); + return -EINVAL; + } + + *request_ret =3D -error; + message_size =3D payload_advance16(&payload); + + if (message_size > chunk->length - sizeof(error) - sizeof(message_size= )) { + error_setg(errp, "Protocol error: server sent structured error chu= nk" + "with incorrect message size"); + return -EINVAL; + } + + /* TODO: Add a trace point to mention the server complaint */ + + /* TODO handle ERROR_OFFSET */ + + return 0; +} + +static int nbd_co_receive_offset_data_payload(NBDClientSession *s, + uint64_t orig_offset, + QEMUIOVector *qiov, Error **= errp) +{ + QEMUIOVector sub_qiov; + uint64_t offset; + size_t data_size; + int ret; + NBDStructuredReplyChunk *chunk =3D &s->reply.structured; + + assert(nbd_reply_is_structured(&s->reply)); + + if (chunk->length < sizeof(offset)) { + error_setg(errp, "Protocol error: invalid payload for " + "NBD_REPLY_TYPE_OFFSET_DATA"); + return -EINVAL; + } + + if (nbd_read(s->ioc, &offset, sizeof(offset), errp) < 0) { + return -EIO; + } + be64_to_cpus(&offset); + + data_size =3D chunk->length - sizeof(offset); + if (offset < orig_offset || data_size > qiov->size || + offset > orig_offset + qiov->size - data_size) { + error_setg(errp, "Protocol error: server sent chunk exceeding requ= ested" + " region"); + return -EINVAL; + } + + qemu_iovec_init(&sub_qiov, qiov->niov); + qemu_iovec_concat(&sub_qiov, qiov, offset - orig_offset, data_size); + ret =3D qio_channel_readv_all(s->ioc, sub_qiov.iov, sub_qiov.niov, err= p); + qemu_iovec_destroy(&sub_qiov); + + return ret < 0 ? -EIO : 0; +} + +#define NBD_MAX_MALLOC_PAYLOAD 1000 +/* nbd_co_receive_structured_payload + */ +static coroutine_fn int nbd_co_receive_structured_payload( + NBDClientSession *s, void **payload, Error **errp) +{ + int ret; + uint32_t len; + + assert(nbd_reply_is_structured(&s->reply)); + + len =3D s->reply.structured.length; + + if (len =3D=3D 0) { + return 0; + } + + if (payload =3D=3D NULL) { + error_setg(errp, "Unexpected structured payload"); + return -EINVAL; + } + + if (len > NBD_MAX_MALLOC_PAYLOAD) { + error_setg(errp, "Payload too large"); + return -EINVAL; + } + + *payload =3D g_new(char, len); + ret =3D nbd_read(s->ioc, *payload, len, errp); + if (ret < 0) { + g_free(*payload); + *payload =3D NULL; + return ret; + } + + return 0; +} + +/* nbd_co_do_receive_one_chunk + * for simple reply: + * set request_ret to received reply error + * if qiov is not NULL: read payload to @qiov + * for structured reply chunk: + * if error chunk: read payload, set @request_ret, do not set @payload + * else if offset_data chunk: read payload data to @qiov, do not set @pa= yload + * else: read payload to @payload + * + * If function fails, @errp contains corresponding error message, and the + * connection with the server is suspect. If it returns 0, then the + * transaction succeeded (although @request_ret may be a negative errno + * corresponding to the server's error reply), and errp is unchanged. + */ +static coroutine_fn int nbd_co_do_receive_one_chunk( + NBDClientSession *s, uint64_t handle, bool only_structured, + int *request_ret, QEMUIOVector *qiov, void **payload, Error **errp) { int ret; int i =3D HANDLE_TO_INDEX(s, handle); + void *local_payload =3D NULL; + NBDStructuredReplyChunk *chunk; + + if (payload) { + *payload =3D NULL; + } + *request_ret =3D 0; /* Wait until we're woken up by nbd_read_reply_entry. */ s->requests[i].receiving =3D true; qemu_coroutine_yield(); s->requests[i].receiving =3D false; if (!s->ioc || s->quit) { - ret =3D -EIO; + error_setg(errp, "Connection closed"); + return -EIO; + } + + assert(s->reply.handle =3D=3D handle); + + if (nbd_reply_is_simple(&s->reply)) { + if (only_structured) { + error_setg(errp, "Protocol error: simple reply when structured= " + "reply chunk was expected"); + return -EINVAL; + } + + *request_ret =3D -nbd_errno_to_system_errno(s->reply.simple.error); + if (*request_ret < 0 || !qiov) { + return 0; + } + + return qio_channel_readv_all(s->ioc, qiov->iov, qiov->niov, + errp) < 0 ? -EIO : 0; + } + + /* handle structured reply chunk */ + assert(s->info.structured_reply); + chunk =3D &s->reply.structured; + + if (chunk->type =3D=3D NBD_REPLY_TYPE_NONE) { + if (!(chunk->flags & NBD_REPLY_FLAG_DONE)) { + error_setg(errp, "Protocol error: NBD_REPLY_TYPE_NONE chunk wi= thout" + "NBD_REPLY_FLAG_DONE flag set"); + return -EINVAL; + } + return 0; + } + + if (chunk->type =3D=3D NBD_REPLY_TYPE_OFFSET_DATA) { + if (!qiov) { + error_setg(errp, "Unexpected NBD_REPLY_TYPE_OFFSET_DATA chunk"= ); + return -EINVAL; + } + + return nbd_co_receive_offset_data_payload(s, s->requests[i].offset, + qiov, errp); + } + + if (nbd_reply_type_is_error(chunk->type)) { + payload =3D &local_payload; + } + + ret =3D nbd_co_receive_structured_payload(s, payload, errp); + if (ret < 0) { + return ret; + } + + if (nbd_reply_type_is_error(chunk->type)) { + ret =3D nbd_parse_error_payload(chunk, local_payload, request_ret,= errp); + g_free(local_payload); + return ret; + } + + return 0; +} + +/* nbd_co_receive_one_chunk + * Read reply, wake up read_reply_co and set s->quit if needed. + * Return value is a fatal error code or normal nbd reply error code + */ +static coroutine_fn int nbd_co_receive_one_chunk( + NBDClientSession *s, uint64_t handle, bool only_structured, + QEMUIOVector *qiov, NBDReply *reply, void **payload, Error **errp) +{ + int request_ret; + int ret =3D nbd_co_do_receive_one_chunk(s, handle, only_structured, + &request_ret, qiov, payload, err= p); + + if (ret < 0) { + s->quit =3D true; } else { - assert(s->reply.handle =3D=3D handle); - ret =3D -nbd_errno_to_system_errno(s->reply.simple.error); - if (qiov && ret =3D=3D 0) { - if (qio_channel_readv_all(s->ioc, qiov->iov, qiov->niov, - NULL) < 0) { - ret =3D -EIO; - s->quit =3D true; - } + /* For assert at loop start in nbd_read_reply_entry */ + if (reply) { + *reply =3D s->reply; } - - /* Tell the read handler to read another header. */ s->reply.handle =3D 0; + ret =3D request_ret; } - s->requests[i].coroutine =3D NULL; - - /* Kick the read_reply_co to get the next reply. */ if (s->read_reply_co) { aio_co_wake(s->read_reply_co); } + return ret; +} + +typedef struct NBDReplyChunkIter { + int ret; + Error *err; + bool done, only_structured; +} NBDReplyChunkIter; + +static void nbd_iter_error(NBDReplyChunkIter *iter, bool fatal, + int ret, Error **local_err) +{ + assert(ret < 0); + + if (fatal || iter->ret =3D=3D 0) { + if (iter->ret !=3D 0) { + error_free(iter->err); + iter->err =3D NULL; + } + iter->ret =3D ret; + error_propagate(&iter->err, *local_err); + } else { + error_free(*local_err); + } + + *local_err =3D NULL; +} + +/* NBD_FOREACH_REPLY_CHUNK + */ +#define NBD_FOREACH_REPLY_CHUNK(s, iter, handle, structured, \ + qiov, reply, payload) \ + for (iter =3D (NBDReplyChunkIter) { .only_structured =3D structured };= \ + nbd_reply_chunk_iter_receive(s, &iter, handle, qiov, reply, paylo= ad);) + +/* nbd_reply_chunk_iter_receive + */ +static bool nbd_reply_chunk_iter_receive(NBDClientSession *s, + NBDReplyChunkIter *iter, + uint64_t handle, + QEMUIOVector *qiov, NBDReply *rep= ly, + void **payload) +{ + int ret; + NBDReply local_reply; + NBDStructuredReplyChunk *chunk; + Error *local_err =3D NULL; + if (s->quit) { + error_setg(&local_err, "Connection closed"); + nbd_iter_error(iter, true, -EIO, &local_err); + goto break_loop; + } + + if (iter->done) { + /* Previous iteration was last. */ + goto break_loop; + } + + if (reply =3D=3D NULL) { + reply =3D &local_reply; + } + + ret =3D nbd_co_receive_one_chunk(s, handle, iter->only_structured, + qiov, reply, payload, &local_err); + if (ret < 0) { + /* If it is a fatal error s->quit is set by nbd_co_receive_one_chu= nk */ + nbd_iter_error(iter, s->quit, ret, &local_err); + } + + /* Do not execute the body of NBD_FOREACH_REPLY_CHUNK for simple reply= . */ + if (nbd_reply_is_simple(&s->reply) || s->quit) { + goto break_loop; + } + + chunk =3D &reply->structured; + iter->only_structured =3D true; + + if (chunk->type =3D=3D NBD_REPLY_TYPE_NONE) { + /* NBD_REPLY_FLAG_DONE is already checked in nbd_co_receive_one_ch= unk */ + assert(chunk->flags & NBD_REPLY_FLAG_DONE); + goto break_loop; + } + + if (chunk->flags & NBD_REPLY_FLAG_DONE) { + /* This iteration is last. */ + iter->done =3D true; + } + + /* Execute the loop body */ + return true; + +break_loop: + s->requests[HANDLE_TO_INDEX(s, handle)].coroutine =3D NULL; + qemu_co_mutex_lock(&s->send_mutex); s->in_flight--; qemu_co_queue_next(&s->free_sema); qemu_co_mutex_unlock(&s->send_mutex); - return ret; + return false; } -static int nbd_co_request(BlockDriverState *bs, - NBDRequest *request, - QEMUIOVector *qiov) +static int nbd_co_receive_return_code(NBDClientSession *s, uint64_t handle, + Error **errp) +{ + NBDReplyChunkIter iter; + + NBD_FOREACH_REPLY_CHUNK(s, iter, handle, false, NULL, NULL, NULL) { + /* nbd_reply_chunk_iter_receive does all the work */ + } + + error_propagate(errp, iter.err); + return iter.ret; +} + +static int nbd_co_receive_cmdread_reply(NBDClientSession *s, uint64_t hand= le, + uint64_t offset, QEMUIOVector *qio= v, + Error **errp) +{ + NBDReplyChunkIter iter; + NBDReply reply; + void *payload =3D NULL; + Error *local_err =3D NULL; + + NBD_FOREACH_REPLY_CHUNK(s, iter, handle, s->info.structured_reply, + qiov, &reply, &payload) + { + int ret; + NBDStructuredReplyChunk *chunk =3D &reply.structured; + + assert(nbd_reply_is_structured(&reply)); + + switch (chunk->type) { + case NBD_REPLY_TYPE_OFFSET_DATA: + /* special cased in nbd_co_receive_one_chunk, data is already + * in qiov */ + break; + case NBD_REPLY_TYPE_OFFSET_HOLE: + ret =3D nbd_parse_offset_hole_payload(&reply.structured, paylo= ad, + offset, qiov, &local_err); + if (ret < 0) { + s->quit =3D true; + nbd_iter_error(&iter, true, ret, &local_err); + } + break; + default: + if (!nbd_reply_type_is_error(chunk->type)) { + /* not allowed reply type */ + s->quit =3D true; + error_setg(&local_err, + "Unexpected reply type: %d (%s) for CMD_READ", + chunk->type, nbd_reply_type_lookup(chunk->type)= ); + nbd_iter_error(&iter, true, -EINVAL, &local_err); + } + } + + g_free(payload); + payload =3D NULL; + } + + error_propagate(errp, iter.err); + return iter.ret; +} + +static int nbd_co_request(BlockDriverState *bs, NBDRequest *request, + QEMUIOVector *write_qiov) { - NBDClientSession *client =3D nbd_get_client_session(bs); int ret; + Error *local_err =3D NULL; + NBDClientSession *client =3D nbd_get_client_session(bs); - if (qiov) { - assert(request->type =3D=3D NBD_CMD_WRITE || request->type =3D=3D = NBD_CMD_READ); - assert(request->len =3D=3D iov_size(qiov->iov, qiov->niov)); + assert(request->type !=3D NBD_CMD_READ); + if (write_qiov) { + assert(request->type =3D=3D NBD_CMD_WRITE); + assert(request->len =3D=3D iov_size(write_qiov->iov, write_qiov->n= iov)); } else { - assert(request->type !=3D NBD_CMD_WRITE && request->type !=3D NBD_= CMD_READ); + assert(request->type !=3D NBD_CMD_WRITE); } - ret =3D nbd_co_send_request(bs, request, - request->type =3D=3D NBD_CMD_WRITE ? qiov : = NULL); + ret =3D nbd_co_send_request(bs, request, write_qiov); if (ret < 0) { return ret; } - return nbd_co_receive_reply(client, request->handle, - request->type =3D=3D NBD_CMD_READ ? qiov := NULL); + ret =3D nbd_co_receive_return_code(client, request->handle, &local_err= ); + if (local_err) { + error_report_err(local_err); + } + return ret; } int nbd_client_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int flags) { + int ret; + Error *local_err =3D NULL; + NBDClientSession *client =3D nbd_get_client_session(bs); NBDRequest request =3D { .type =3D NBD_CMD_READ, .from =3D offset, @@ -259,7 +674,17 @@ int nbd_client_co_preadv(BlockDriverState *bs, uint64_= t offset, assert(bytes <=3D NBD_MAX_BUFFER_SIZE); assert(!flags); - return nbd_co_request(bs, &request, qiov); + ret =3D nbd_co_send_request(bs, &request, NULL); + if (ret < 0) { + return ret; + } + + ret =3D nbd_co_receive_cmdread_reply(client, request.handle, offset, q= iov, + &local_err); + if (ret < 0) { + error_report_err(local_err); + } + return ret; } int nbd_client_co_pwritev(BlockDriverState *bs, uint64_t offset, @@ -381,6 +806,7 @@ int nbd_client_init(BlockDriverState *bs, qio_channel_set_blocking(QIO_CHANNEL(sioc), true, NULL); client->info.request_sizes =3D true; + client->info.structured_reply =3D true; ret =3D nbd_receive_negotiate(QIO_CHANNEL(sioc), export, tlscreds, hostname, &client->ioc, &client->info, errp); diff --git a/nbd/client.c b/nbd/client.c index 4f0745f601..3d680e63e1 100644 --- a/nbd/client.c +++ b/nbd/client.c @@ -602,9 +602,11 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char = *name, uint64_t magic; int rc; bool zeroes =3D true; + bool structured_reply =3D info->structured_reply; trace_nbd_receive_negotiate(tlscreds, hostname ? hostname : ""); + info->structured_reply =3D false; rc =3D -EINVAL; if (outioc) { @@ -685,6 +687,16 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char = *name, if (fixedNewStyle) { int result; + if (structured_reply) { + result =3D nbd_request_simple_option(ioc, + NBD_OPT_STRUCTURED_REPL= Y, + errp); + if (result < 0) { + goto fail; + } + info->structured_reply =3D result =3D=3D 1; + } + /* 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 diff --git a/tests/qemu-iotests/083.out b/tests/qemu-iotests/083.out index 25dde519e3..be6079d27e 100644 --- a/tests/qemu-iotests/083.out +++ b/tests/qemu-iotests/083.out @@ -41,6 +41,7 @@ can't open device nbd+tcp://127.0.0.1:PORT/foo =3D=3D=3D Check disconnect after neg2 =3D=3D=3D +Connection closed read failed: Input/output error =3D=3D=3D Check disconnect 8 neg2 =3D=3D=3D @@ -53,32 +54,39 @@ can't open device nbd+tcp://127.0.0.1:PORT/foo =3D=3D=3D Check disconnect before request =3D=3D=3D +Connection closed read failed: Input/output error =3D=3D=3D Check disconnect after request =3D=3D=3D +Connection closed read failed: Input/output error =3D=3D=3D Check disconnect before reply =3D=3D=3D +Connection closed read failed: Input/output error =3D=3D=3D Check disconnect after reply =3D=3D=3D +Unexpected end-of-file before all bytes were read read failed: Input/output error =3D=3D=3D Check disconnect 4 reply =3D=3D=3D Unexpected end-of-file before all bytes were read +Connection closed read failed: Input/output error =3D=3D=3D Check disconnect 8 reply =3D=3D=3D Unexpected end-of-file before all bytes were read +Connection closed read failed: Input/output error =3D=3D=3D Check disconnect before data =3D=3D=3D +Unexpected end-of-file before all bytes were read read failed: Input/output error =3D=3D=3D Check disconnect after data =3D=3D=3D @@ -108,6 +116,7 @@ can't open device nbd+tcp://127.0.0.1:PORT/ =3D=3D=3D Check disconnect after neg-classic =3D=3D=3D +Connection closed read failed: Input/output error =3D=3D=3D Check disconnect before neg1 =3D=3D=3D @@ -168,28 +177,34 @@ read failed: Input/output error =3D=3D=3D Check disconnect after request =3D=3D=3D +Connection closed read failed: Input/output error =3D=3D=3D Check disconnect before reply =3D=3D=3D +Connection closed read failed: Input/output error =3D=3D=3D Check disconnect after reply =3D=3D=3D +Unexpected end-of-file before all bytes were read read failed: Input/output error =3D=3D=3D Check disconnect 4 reply =3D=3D=3D Unexpected end-of-file before all bytes were read +Connection closed read failed: Input/output error =3D=3D=3D Check disconnect 8 reply =3D=3D=3D Unexpected end-of-file before all bytes were read +Connection closed read failed: Input/output error =3D=3D=3D Check disconnect before data =3D=3D=3D +Unexpected end-of-file before all bytes were read read failed: Input/output error =3D=3D=3D Check disconnect after data =3D=3D=3D --=20 2.13.6