From nobody Mon Feb 9 08:56:28 2026 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.zoho.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 148613832371453.02353477198483; Fri, 3 Feb 2017 08:12:03 -0800 (PST) Received: from localhost ([::1]:35530 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cZgSu-0002fR-OE for importer@patchew.org; Fri, 03 Feb 2017 11:12:00 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:36728) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cZg5o-0007oz-4w for qemu-devel@nongnu.org; Fri, 03 Feb 2017 10:48:13 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cZg5j-00081b-2Z for qemu-devel@nongnu.org; Fri, 03 Feb 2017 10:48:08 -0500 Received: from mailhub.sw.ru ([195.214.232.25]:2837 helo=relay.sw.ru) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1cZg5i-0007xZ-J4 for qemu-devel@nongnu.org; Fri, 03 Feb 2017 10:48:03 -0500 Received: from kvm.qa.sw.ru. (msk-vpn.virtuozzo.com [195.214.232.6]) by relay.sw.ru (8.13.4/8.13.4) with ESMTP id v13Flv7i011039; Fri, 3 Feb 2017 18:47:57 +0300 (MSK) From: Vladimir Sementsov-Ogievskiy To: qemu-block@nongnu.org, qemu-devel@nongnu.org Date: Fri, 3 Feb 2017 18:47:42 +0300 Message-Id: <20170203154757.36140-4-vsementsov@virtuozzo.com> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20170203154757.36140-1-vsementsov@virtuozzo.com> References: <20170203154757.36140-1-vsementsov@virtuozzo.com> X-detected-operating-system: by eggs.gnu.org: OpenBSD 3.x [fuzzy] X-Received-From: 195.214.232.25 Subject: [Qemu-devel] [PATCH 03/18] 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: kwolf@redhat.com, famz@redhat.com, den@virtuozzo.com, armbru@redhat.com, mreitz@redhat.com, stefanha@redhat.com, pbonzini@redhat.com, jsnow@redhat.com 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" Minimal implementation of structured read: one data chunk + finishing none 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 --- include/block/nbd.h | 31 +++++++++++++ nbd/nbd-internal.h | 2 + nbd/server.c | 125 ++++++++++++++++++++++++++++++++++++++++++++++++= ++-- 3 files changed, 154 insertions(+), 4 deletions(-) diff --git a/include/block/nbd.h b/include/block/nbd.h index 3c65cf8d87..58b864f145 100644 --- a/include/block/nbd.h +++ b/include/block/nbd.h @@ -70,6 +70,25 @@ struct NBDSimpleReply { }; typedef struct NBDSimpleReply NBDSimpleReply; =20 +typedef struct NBDStructuredReplyChunk { + uint32_t magic; + uint16_t flags; + uint16_t type; + uint64_t handle; + uint32_t length; +} QEMU_PACKED NBDStructuredReplyChunk; + +typedef struct NBDStructuredRead { + NBDStructuredReplyChunk h; + uint64_t offset; +} QEMU_PACKED NBDStructuredRead; + +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 +98,7 @@ typedef struct NBDSimpleReply NBDSimpleReply; #define NBD_FLAG_ROTATIONAL (1 << 4) /* Use elevator algorithm = - 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 Fragmen= t) */ =20 /* New-style handshake (global) flags, sent from server to client, and control what will happen during handshake phase. */ @@ -106,6 +126,7 @@ typedef struct NBDSimpleReply 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= */ =20 /* Supported request types */ enum { @@ -130,6 +151,16 @@ enum { * aren't overflowing some other buffer. */ #define NBD_MAX_NAME_SIZE 256 =20 +/* Structured reply flags */ +#define NBD_REPLY_FLAG_DONE 1 + +/* Structured reply types */ +#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 ((1 << 15) + 1) +#define NBD_REPLY_TYPE_ERROR_OFFSET ((1 << 15) + 2) + ssize_t nbd_wr_syncv(QIOChannel *ioc, struct iovec *iov, size_t niov, diff --git a/nbd/nbd-internal.h b/nbd/nbd-internal.h index 49b66b6896..489eeaf887 100644 --- a/nbd/nbd-internal.h +++ b/nbd/nbd-internal.h @@ -60,6 +60,7 @@ #define NBD_REPLY_SIZE (4 + 4 + 8) #define NBD_REQUEST_MAGIC 0x25609513 #define NBD_SIMPLE_REPLY_MAGIC 0x67446698 +#define NBD_STRUCTURED_REPLY_MAGIC 0x668e33ef #define NBD_OPTS_MAGIC 0x49484156454F5054LL #define NBD_CLIENT_MAGIC 0x0000420281861253LL #define NBD_REP_MAGIC 0x0003e889045565a9LL @@ -81,6 +82,7 @@ #define NBD_OPT_LIST (3) #define NBD_OPT_PEEK_EXPORT (4) #define NBD_OPT_STARTTLS (5) +#define NBD_OPT_STRUCTURED_REPLY (8) =20 /* 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. diff --git a/nbd/server.c b/nbd/server.c index 4cfc02123b..cb79a93c87 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; }; =20 /* That's all folks */ @@ -573,6 +575,16 @@ static int nbd_negotiate_options(NBDClient *client) return ret; } break; + + case NBD_OPT_STRUCTURED_REPLY: + client->structured_reply =3D true; + ret =3D nbd_negotiate_send_rep(client->ioc, NBD_REP_ACK, + clientflags); + if (ret < 0) { + return ret; + } + break; + default: if (nbd_negotiate_drop_sync(client->ioc, length) !=3D leng= th) { return -EIO; @@ -1067,6 +1079,86 @@ static ssize_t nbd_co_send_simple_reply(NBDRequestDa= ta *req, return rc; } =20 +static void set_be_chunk(NBDStructuredReplyChunk *chunk, uint16_t flags, + uint16_t type, uint64_t handle, uint32_t length) +{ + 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 nbd_co_send_iov(NBDClient *client, struct iovec *iov, unsigned = niov) +{ + ssize_t ret; + size_t size =3D iov_size(iov, niov); + + g_assert(qemu_in_coroutine()); + qemu_co_mutex_lock(&client->send_lock); + client->send_coroutine =3D qemu_coroutine_self(); + nbd_set_handlers(client); + + ret =3D nbd_wr_syncv(client->ioc, iov, niov, size, false); + if (ret >=3D 0 && ret !=3D size) { + ret =3D -EIO; + } + + client->send_coroutine =3D NULL; + nbd_set_handlers(client); + qemu_co_mutex_unlock(&client->send_lock); + + return ret; +} + +static inline int nbd_co_send_buf(NBDClient *client, void *buf, size_t siz= e) +{ + struct iovec iov[] =3D { + {.iov_base =3D buf, .iov_len =3D size} + }; + + return nbd_co_send_iov(client, iov, 1); +} + +static int nbd_co_send_structured_read(NBDClient *client, uint64_t handle, + uint64_t offset, void *data, size_t= size) +{ + NBDStructuredRead chunk; + + struct iovec iov[] =3D { + {.iov_base =3D &chunk, .iov_len =3D sizeof(chunk)}, + {.iov_base =3D data, .iov_len =3D size} + }; + + set_be_chunk(&chunk.h, 0, 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); +} + +static int nbd_co_send_structured_error(NBDClient *client, uint64_t handle, + uint32_t error) +{ + NBDStructuredError chunk; + + 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, error); + stw_be_p(&chunk.message_length, 0); + + return nbd_co_send_buf(client, &chunk, sizeof(chunk)); +} + +static int nbd_co_send_structured_none(NBDClient *client, uint64_t handle) +{ + NBDStructuredReplyChunk chunk; + + set_be_chunk(&chunk, NBD_REPLY_FLAG_DONE, NBD_REPLY_TYPE_NONE, handle,= 0); + + return nbd_co_send_buf(client, &chunk, sizeof(chunk)); +} + /* Collect a client request. Return 0 if request looks valid, -EAGAIN * to keep trying the collection, -EIO to drop connection right away, * and any other negative value to report an error to the client @@ -1147,7 +1239,8 @@ static ssize_t nbd_co_receive_request(NBDRequestData = *req, rc =3D request->type =3D=3D NBD_CMD_WRITE ? -ENOSPC : -EINVAL; goto out; } - if (request->flags & ~(NBD_CMD_FLAG_FUA | NBD_CMD_FLAG_NO_HOLE)) { + if (request->flags & ~(NBD_CMD_FLAG_FUA | NBD_CMD_FLAG_NO_HOLE | + NBD_CMD_FLAG_DF)) { LOG("unsupported flags (got 0x%x)", request->flags); rc =3D -EINVAL; goto out; @@ -1226,12 +1319,34 @@ static void nbd_trip(void *opaque) req->data, request.len); if (ret < 0) { LOG("reading from file failed"); - reply.error =3D -ret; - goto error_reply; + if (client->structured_reply) { + ret =3D nbd_co_send_structured_error(req->client, request.= handle, + -ret); + if (ret < 0) { + goto out; + } else { + break; + } + } else { + reply.error =3D -ret; + goto error_reply; + } } =20 TRACE("Read %" PRIu32" byte(s)", request.len); - if (nbd_co_send_simple_reply(req, &reply, request.len) < 0) { + if (client->structured_reply) { + ret =3D nbd_co_send_structured_read(req->client, request.handl= e, + request.from, req->data, + request.len); + if (ret < 0) { + goto out; + } + + ret =3D nbd_co_send_structured_none(req->client, request.handl= e); + } else { + ret =3D nbd_co_send_simple_reply(req, &reply, request.len); + } + if (ret < 0) { goto out; } break; @@ -1444,6 +1559,8 @@ void nbd_client_new(NBDExport *exp, client->can_read =3D true; client->close =3D close_fn; =20 + client->structured_reply =3D false; + data->client =3D client; data->co =3D qemu_coroutine_create(nbd_co_client_start, data); qemu_coroutine_enter(data->co); --=20 2.11.0