From nobody Thu Dec 18 00:30:37 2025 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 (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1508452571420892.5381506960189; Thu, 19 Oct 2017 15:36:11 -0700 (PDT) Received: from localhost ([::1]:51465 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1e5JQ3-0004BY-TR for importer@patchew.org; Thu, 19 Oct 2017 18:36:03 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:36138) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1e5JHH-0005Fo-N8 for qemu-devel@nongnu.org; Thu, 19 Oct 2017 18:27:01 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1e5JHG-0004Kp-6j for qemu-devel@nongnu.org; Thu, 19 Oct 2017 18:26:59 -0400 Received: from mx1.redhat.com ([209.132.183.28]:58914) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1e5JH9-00045K-2M; Thu, 19 Oct 2017 18:26:51 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 1738B883D8; Thu, 19 Oct 2017 22:26:50 +0000 (UTC) Received: from red.redhat.com (ovpn-121-90.rdu2.redhat.com [10.10.121.90]) by smtp.corp.redhat.com (Postfix) with ESMTP id 4D02317AA7; Thu, 19 Oct 2017 22:26:49 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 1738B883D8 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: Thu, 19 Oct 2017 17:26:32 -0500 Message-Id: <20171019222637.17890-7-eblake@redhat.com> In-Reply-To: <20171019222637.17890-1-eblake@redhat.com> References: <20171019222637.17890-1-eblake@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.26]); Thu, 19 Oct 2017 22:26: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] [PATCH v5 06/11] 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: pbonzini@redhat.com, vsementsov@virtuozzo.com, qemu-block@nongnu.org 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 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 Reviewed-by: Vladimir Sementsov-Ogievskiy --- v5: correct DF flag spelling, include errname in trace, handle any bogus payload from option v4: better _DF flag handling, convert errno to wire format, add comments and tracing, rework structured error for less churn when adding text message later, don't kill connection on redundant client option --- nbd/server.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++++--= ---- nbd/trace-events | 2 ++ 2 files changed, 98 insertions(+), 10 deletions(-) diff --git a/nbd/server.c b/nbd/server.c index b3f7e0b18e..9be93c4a52 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 */ @@ -754,6 +756,22 @@ 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_check_zero_length(client, length, option, = 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; @@ -1228,6 +1246,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 @@ -1238,6 +1310,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()); @@ -1299,13 +1372,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; } @@ -1443,10 +1518,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