From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
To: qemu-block@nongnu.org, qemu-devel@nongnu.org
Cc: pbonzini@redhat.com, eblake@redhat.com, mreitz@redhat.com,
kwolf@redhat.com, den@openvz.org
Subject: Re: [Qemu-devel] [PATCH v1.1 DRAFT] nbd: Minimal structured read for client
Date: Tue, 3 Oct 2017 12:59:31 +0300 [thread overview]
Message-ID: <153ee259-26fb-f42f-1ea6-ce00e6869b6e@virtuozzo.com> (raw)
In-Reply-To: <20170927151008.53763-1-vsementsov@virtuozzo.com>
Eric?
27.09.2017 18:10, Vladimir Sementsov-Ogievskiy wrote:
> Minimal implementation: drop most of additional error information.
>
> Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
> ---
>
> Hi!
>
> Here is a draft of how to refactor reply-payload receiving if you don't
> like my previous simple (but not flexible) try. Ofcourse, if we agree on this
> approach this patch should be splitted into several ones and many things
> (error handling) should be improved.
>
> The idea is:
>
> nbd_read_reply_entry reads only reply header through nbd/client.c code.
>
> Then, the payload is read through block/nbd-client-cmds.c:
> simple payload: generic per-command handler, however it should only exist
> for CMD_READ
> structured NONE: no payload, handle in nbd_co_receive_one_chunk
> structured error: read by nbd_handle_structured_error_payload
> defined in block/nbd-client-cmds.c
> structured success: read by per-[command X reply-type] handler
> defined in block/nbd-client-cmds.c
>
> For now nbd-client-cmds.c looks more like nbd-payload.c, but, may be, we
> should move command sending special-casing (CMD_WRITE) to it too..
>
> Don't waste time on careful reviewing this patch, let's consider first
> the concept of nbd-client-cmds.c,
>
> block/nbd-client.h | 10 +++
> include/block/nbd.h | 82 ++++++++++++++++--
> nbd/nbd-internal.h | 25 ------
> block/nbd-client-cmds.c | 220 ++++++++++++++++++++++++++++++++++++++++++++++++
> block/nbd-client.c | 118 ++++++++++++++++++++------
> nbd/client.c | 128 ++++++++++++++++------------
> block/Makefile.objs | 2 +-
> 7 files changed, 475 insertions(+), 110 deletions(-)
> create mode 100644 block/nbd-client-cmds.c
>
> diff --git a/block/nbd-client.h b/block/nbd-client.h
> index b435754b82..abb88e4ea5 100644
> --- a/block/nbd-client.h
> +++ b/block/nbd-client.h
> @@ -35,6 +35,8 @@ typedef struct NBDClientSession {
> NBDClientRequest requests[MAX_NBD_REQUESTS];
> NBDReply reply;
> bool quit;
> +
> + bool structured_reply;
> } NBDClientSession;
>
> NBDClientSession *nbd_get_client_session(BlockDriverState *bs);
> @@ -60,4 +62,12 @@ void nbd_client_detach_aio_context(BlockDriverState *bs);
> void nbd_client_attach_aio_context(BlockDriverState *bs,
> AioContext *new_context);
>
> +int nbd_handle_structured_payload(QIOChannel *ioc, int cmd,
> + NBDStructuredReplyChunk *reply, void *opaque);
> +int nbd_handle_simple_payload(QIOChannel *ioc, int cmd, void *opaque);
> +
> +int nbd_handle_structured_error_payload(QIOChannel *ioc,
> + NBDStructuredReplyChunk *reply,
> + int *request_ret);
> +
> #endif /* NBD_CLIENT_H */
> diff --git a/include/block/nbd.h b/include/block/nbd.h
> index 314f2f9bbc..b9a4e1dfa9 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;
> @@ -77,6 +71,24 @@ typedef struct NBDStructuredReplyChunk {
> uint32_t length; /* length of payload */
> } QEMU_PACKED NBDStructuredReplyChunk;
>
> +typedef union NBDReply {
> + NBDSimpleReply simple;
> + NBDStructuredReplyChunk structured;
> + struct {
> + uint32_t magic;
> + uint32_t _skip;
> + uint64_t handle;
> + } QEMU_PACKED;
> +} NBDReply;
> +
> +#define NBD_SIMPLE_REPLY_MAGIC 0x67446698
> +#define NBD_STRUCTURED_REPLY_MAGIC 0x668e33ef
> +
> +static inline bool nbd_reply_is_simple(NBDReply *reply)
> +{
> + return reply->magic == NBD_SIMPLE_REPLY_MAGIC;
> +}
> +
> typedef struct NBDStructuredRead {
> NBDStructuredReplyChunk h;
> uint64_t offset;
> @@ -88,6 +100,11 @@ typedef struct NBDStructuredError {
> uint16_t message_length;
> } QEMU_PACKED NBDStructuredError;
>
> +typedef struct NBDPayloadOffsetHole {
> + uint64_t offset;
> + uint32_t hole_size;
> +} QEMU_PACKED NBDPayloadOffsetHole;
> +
> /* Transmission (export) flags: sent from server to client during handshake,
> but describe what will happen during transmission */
> #define NBD_FLAG_HAS_FLAGS (1 << 0) /* Flags are there */
> @@ -178,12 +195,54 @@ enum {
>
> #define NBD_SREP_TYPE_NONE 0
> #define NBD_SREP_TYPE_OFFSET_DATA 1
> +#define NBD_SREP_TYPE_OFFSET_HOLE 2
> #define NBD_SREP_TYPE_ERROR NBD_SREP_ERR(1)
> +#define NBD_SREP_TYPE_ERROR_OFFSET NBD_SREP_ERR(2)
> +
> +static inline bool nbd_srep_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.
> + */
> +#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
> +
> +static inline int nbd_errno_to_system_errno(int err)
> +{
> + switch (err) {
> + case NBD_SUCCESS:
> + return 0;
> + case NBD_EPERM:
> + return EPERM;
> + case NBD_EIO:
> + return EIO;
> + case NBD_ENOMEM:
> + return ENOMEM;
> + case NBD_ENOSPC:
> + return ENOSPC;
> + case NBD_ESHUTDOWN:
> + return ESHUTDOWN;
> + case NBD_EINVAL:
> + return EINVAL;
> + }
> +
> + return EINVAL;
> +}
>
> /* Details collected by NBD_OPT_EXPORT_NAME and NBD_OPT_GO */
> struct NBDExportInfo {
> /* Set by client before nbd_receive_negotiate() */
> bool request_sizes;
> + bool structured_reply;
> /* Set by server results during nbd_receive_negotiate() */
> uint64_t size;
> uint16_t flags;
> @@ -233,4 +292,15 @@ 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;
> +}
> +
> +int nbd_drop(QIOChannel *ioc, size_t size, Error **errp);
> +
> #endif
> diff --git a/nbd/nbd-internal.h b/nbd/nbd-internal.h
> index 6b0d1183ba..9f7b6b68e8 100644
> --- a/nbd/nbd-internal.h
> +++ b/nbd/nbd-internal.h
> @@ -47,8 +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_STRUCTURED_REPLY_MAGIC 0x668e33ef
> #define NBD_OPTS_MAGIC 0x49484156454F5054LL
> #define NBD_CLIENT_MAGIC 0x0000420281861253LL
> #define NBD_REP_MAGIC 0x0003e889045565a9LL
> @@ -65,18 +63,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
> @@ -96,15 +82,6 @@ static inline int nbd_read_eof(QIOChannel *ioc, void *buffer, 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.
> */
> @@ -137,6 +114,4 @@ const char *nbd_rep_lookup(uint32_t rep);
> const char *nbd_info_lookup(uint16_t info);
> const char *nbd_cmd_lookup(uint16_t info);
>
> -int nbd_drop(QIOChannel *ioc, size_t size, Error **errp);
> -
> #endif
> diff --git a/block/nbd-client-cmds.c b/block/nbd-client-cmds.c
> new file mode 100644
> index 0000000000..488a3dc267
> --- /dev/null
> +++ b/block/nbd-client-cmds.c
> @@ -0,0 +1,220 @@
> +/*
> + * QEMU Block driver for NBD
> + *
> + * Copyright (c) 2017 Parallels International GmbH
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a copy
> + * of this software and associated documentation files (the "Software"), to deal
> + * in the Software without restriction, including without limitation the rights
> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> + * copies of the Software, and to permit persons to whom the Software is
> + * furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> + * THE SOFTWARE.
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qapi/error.h"
> +#include "nbd-client.h"
> +
> +
> +typedef int (*NBDCommandFn)(QIOChannel *ioc,
> + NBDStructuredReplyChunk *chunk,
> + void *opaque);
> +typedef struct NBDCommand {
> + int (*read_simple_payload)(QIOChannel *ioc, void *opaque);
> + NBDCommandFn read_offset_data;
> + NBDCommandFn read_offset_hole;
> +} NBDCommand;
> +
> +static int nbd_cmd_read__siple_payload(QIOChannel *ioc, void *opaque)
> +{
> + QEMUIOVector *qiov = (QEMUIOVector *)opaque;
> + return qio_channel_readv_all(ioc, qiov->iov, qiov->niov, NULL);
> +}
> +
> +static int nbd_cmd_read__offset_data(QIOChannel *ioc,
> + NBDStructuredReplyChunk *chunk,
> + void *opaque)
> +{
> + QEMUIOVector *qiov = (QEMUIOVector *)opaque;
> + QEMUIOVector sub_qiov;
> + uint64_t offset;
> + size_t data_size;
> + int ret;
> +
> + if (chunk->length < sizeof(offset)) {
> + return -1;
> + }
> +
> + if (nbd_read(ioc, &offset, sizeof(offset), NULL) < 0) {
> + return -1;
> + }
> + be64_to_cpus(&offset);
> +
> + data_size = chunk->length - sizeof(offset);
> + if (offset + data_size > qiov->size) {
> + return -1;
> + }
> +
> + qemu_iovec_init(&sub_qiov, qiov->niov);
> + qemu_iovec_concat(&sub_qiov, qiov, offset, data_size);
> + ret = qio_channel_readv_all(ioc, sub_qiov.iov, sub_qiov.niov, NULL);
> + qemu_iovec_destroy(&sub_qiov);
> +
> + return ret;
> +}
> +
> +static int nbd_cmd_read__offset_hole(QIOChannel *ioc,
> + NBDStructuredReplyChunk *chunk,
> + void *opaque)
> +{
> + QEMUIOVector *qiov = (QEMUIOVector *)opaque;
> + NBDPayloadOffsetHole pl;
> +
> + if (chunk->length != sizeof(pl)) {
> + return -1;
> + }
> +
> + if (nbd_read(ioc, &pl, sizeof(pl), NULL) < 0) {
> + return -1;
> + }
> +
> + be64_to_cpus(&pl.offset);
> + be32_to_cpus(&pl.hole_size);
> +
> + if (pl.offset + pl.hole_size > qiov->size) {
> + return -1;
> + }
> +
> + qemu_iovec_memset(qiov, pl.offset, 0, pl.hole_size);
> +
> + return 0;
> +}
> +
> +NBDCommand nbd_cmd_read = {
> + .read_simple_payload = nbd_cmd_read__siple_payload,
> + .read_offset_data = nbd_cmd_read__offset_data,
> + .read_offset_hole = nbd_cmd_read__offset_hole,
> +};
> +
> +static NBDCommand *nbd_get_cmd(int cmd)
> +{
> + switch (cmd) {
> + case NBD_CMD_READ:
> + return &nbd_cmd_read;
> + }
> +
> + return NULL;
> +}
> +
> +static NBDCommandFn nbd_cmd_get_handler(int cmd, int reply_type)
> +{
> + NBDCommand *command = nbd_get_cmd(cmd);
> +
> + if (command == NULL) {
> + return NULL;
> + }
> +
> + switch (reply_type) {
> + case NBD_SREP_TYPE_OFFSET_DATA:
> + return command->read_offset_data;
> + case NBD_SREP_TYPE_OFFSET_HOLE:
> + return command->read_offset_hole;
> + }
> +
> + return NULL;
> +}
> +
> +/* nbd_handle_structured_payload
> + * Find corresponding handler and call it.
> + * If not found return -1 (fail)
> + */
> +int nbd_handle_structured_payload(QIOChannel *ioc, int cmd, NBDStructuredReplyChunk *chunk,
> + void *opaque)
> +{
> + NBDCommandFn fn = nbd_cmd_get_handler(cmd, chunk->type);
> +
> + if (fn == NULL) {
> + return -1;
> + }
> +
> + return fn(ioc, chunk, opaque);
> +}
> +
> +/* nbd_handle_simple_payload
> + * Find corresponding handler and call it.
> + * If not found return 0 (success)
> + */
> +int nbd_handle_simple_payload(QIOChannel *ioc, int cmd, void *opaque)
> +{
> + NBDCommand *command = nbd_get_cmd(cmd);
> +
> + if (command == NULL || command->read_simple_payload == NULL) {
> + return 0;
> + }
> +
> + return command->read_simple_payload(ioc, opaque);
> +}
> +
> +int nbd_handle_structured_error_payload(QIOChannel *ioc, NBDStructuredReplyChunk *chunk,
> + int *request_ret)
> +{
> + uint32_t error;
> + uint16_t message_size;
> + int ret;
> + assert(chunk->type & (1 << 15));
> +
> + switch (chunk->type) {
> + case NBD_SREP_TYPE_ERROR:
> + case NBD_SREP_TYPE_ERROR_OFFSET:
> + ret = nbd_read(ioc, &error, sizeof(error), NULL);
> + if (ret < 0) {
> + return ret;
> + }
> + be32_to_cpus(&error);
> +
> + ret = nbd_read(ioc, &message_size, sizeof(message_size), NULL);
> + if (ret < 0) {
> + return ret;
> + }
> + be16_to_cpus(&message_size);
> +
> + if (message_size > 0) {
> + /* TODO: provide error message to user */
> + ret = nbd_drop(ioc, message_size, NULL);
> + if (ret < 0) {
> + return ret;
> + }
> + }
> +
> + if (chunk->type == NBD_SREP_TYPE_ERROR_OFFSET) {
> + /* drop 64bit offset */
> + ret = nbd_drop(ioc, 8, NULL);
> + if (ret < 0) {
> + return ret;
> + }
> + }
> + break;
> + default:
> + /* unknown error */
> + ret = nbd_drop(ioc, chunk->length, NULL);
> + if (ret < 0) {
> + return ret;
> + }
> +
> + error = NBD_EINVAL;
> + }
> +
> + *request_ret = nbd_errno_to_system_errno(error);
> + return 0;
> +}
> diff --git a/block/nbd-client.c b/block/nbd-client.c
> index e4f0c789f4..cf80564a83 100644
> --- a/block/nbd-client.c
> +++ b/block/nbd-client.c
> @@ -179,9 +179,9 @@ err:
> return rc;
> }
>
> -static int nbd_co_receive_reply(NBDClientSession *s,
> - uint64_t handle,
> - QEMUIOVector *qiov)
> +static int nbd_co_receive_one_chunk(NBDClientSession *s, uint64_t handle,
> + int request_cmd, void *request_opaque,
> + bool *cont)
> {
> int ret;
> int i = HANDLE_TO_INDEX(s, handle);
> @@ -191,29 +191,93 @@ static int nbd_co_receive_reply(NBDClientSession *s,
> qemu_coroutine_yield();
> s->requests[i].receiving = false;
> if (!s->ioc || s->quit) {
> - ret = -EIO;
> - } else {
> - assert(s->reply.handle == handle);
> - ret = -s->reply.error;
> - if (qiov && s->reply.error == 0) {
> - if (qio_channel_readv_all(s->ioc, qiov->iov, qiov->niov,
> - NULL) < 0) {
> - ret = -EIO;
> - s->quit = true;
> + *cont = false;
> + return -EIO;
> + }
> +
> + assert(s->reply.handle == handle);
> +
> + if (nbd_reply_is_simple(&s->reply)) {
> + *cont = false;
> + ret = -s->reply.simple.error;
> + if (s->structured_reply && request_cmd == NBD_CMD_READ) {
> + goto fatal;
> + }
> + if (ret == 0) {
> + if (nbd_handle_simple_payload(s->ioc, request_cmd,
> + request_opaque) < 0)
> + {
> + goto fatal;
> }
> }
> + goto out;
> + }
> +
> + /* handle structured reply chunk */
> +
> + *cont = !(s->reply.structured.flags & NBD_SREP_FLAG_DONE);
>
> - /* Tell the read handler to read another header. */
> - s->reply.handle = 0;
> + if (s->reply.structured.type == NBD_SREP_TYPE_NONE) {
> + goto out;
> }
>
> - s->requests[i].coroutine = NULL;
> + if (nbd_srep_type_is_error(s->reply.structured.type)) {
> + if (nbd_handle_structured_error_payload(s->ioc, &s->reply.structured,
> + &ret) < 0)
> + {
> + goto fatal;
> + }
> + goto out;
> + }
> +
> + /* here we deal with successful not-NONE structured reply */
> + if (nbd_handle_structured_payload(s->ioc, request_cmd,
> + &s->reply.structured,
> + request_opaque) < 0)
> + {
> + goto fatal;
> + }
> +
> +out:
> + /* For assert at loop start in nbd_read_reply_entry */
> + s->reply.handle = 0;
>
> - /* Kick the read_reply_co to get the next reply. */
> if (s->read_reply_co) {
> aio_co_wake(s->read_reply_co);
> }
>
> + return ret;
> +
> +fatal:
> + /* protocol or ioc failure */
> + *cont = false;
> + s->quit = true;
> + if (s->read_reply_co) {
> + aio_co_wake(s->read_reply_co);
> + }
> +
> + return -EIO;
> +}
> +
> +static int nbd_co_receive_reply(NBDClientSession *s,
> + uint64_t handle,
> + int request_cmd,
> + void *request_opaque)
> +{
> + int ret = 0;
> + int i = HANDLE_TO_INDEX(s, handle);
> + bool cont = true;
> +
> + while (cont) {
> + int rc = nbd_co_receive_one_chunk(s, handle, request_cmd,
> + request_opaque, &cont);
> + if (rc < 0 && ret == 0) {
> + ret = rc;
> + }
> + }
> +
> + s->requests[i].coroutine = NULL;
> +
> qemu_co_mutex_lock(&s->send_mutex);
> s->in_flight--;
> qemu_co_queue_next(&s->free_sema);
> @@ -224,22 +288,28 @@ static int nbd_co_receive_reply(NBDClientSession *s,
>
> static int nbd_co_request(BlockDriverState *bs,
> NBDRequest *request,
> - QEMUIOVector *qiov)
> + void *request_opaque)
> {
> NBDClientSession *client = nbd_get_client_session(bs);
> int ret;
> + QEMUIOVector *send_qiov = NULL;
> +
> + if (request->type == NBD_CMD_WRITE) {
> + /* TODO: move request sending special casing to nbd-client-cmds.c like
> + * receiving part. */
> + send_qiov = request_opaque;
> + request_opaque = NULL;
> + assert(send_qiov &&
> + request->len == iov_size(send_qiov->iov, send_qiov->niov));
> + }
>
> - assert(!qiov || request->type == NBD_CMD_WRITE ||
> - request->type == NBD_CMD_READ);
> - assert(!qiov || request->len == iov_size(qiov->iov, qiov->niov));
> - ret = nbd_co_send_request(bs, request,
> - request->type == NBD_CMD_WRITE ? qiov : NULL);
> + ret = nbd_co_send_request(bs, request, send_qiov);
> if (ret < 0) {
> return ret;
> }
>
> - return nbd_co_receive_reply(client, request->handle,
> - request->type == NBD_CMD_READ ? qiov : NULL);
> + return nbd_co_receive_reply(client, request->handle, request->type,
> + request_opaque);
> }
>
> int nbd_client_co_preadv(BlockDriverState *bs, uint64_t offset,
> diff --git a/nbd/client.c b/nbd/client.c
> index 51ae492e92..d0e9b8f138 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 = 0;
> - break;
> - case NBD_EPERM:
> - ret = EPERM;
> - break;
> - case NBD_EIO:
> - ret = EIO;
> - break;
> - case NBD_ENOMEM:
> - ret = ENOMEM;
> - break;
> - case NBD_ENOSPC:
> - ret = ENOSPC;
> - break;
> - case NBD_ESHUTDOWN:
> - ret = ESHUTDOWN;
> - break;
> - default:
> - trace_nbd_unknown_error(err);
> - /* fallthrough */
> - case NBD_EINVAL:
> - ret = EINVAL;
> - break;
> - }
> - return ret;
> -}
> -
> /* Definitions for opaque data types */
>
> static QTAILQ_HEAD(, NBDExport) exports = QTAILQ_HEAD_INITIALIZER(exports);
> @@ -719,6 +687,13 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name,
> if (fixedNewStyle) {
> int result;
>
> + result = nbd_request_simple_option(ioc, NBD_OPT_STRUCTURED_REPLY,
> + errp);
> + if (result < 0) {
> + goto fail;
> + }
> + info->structured_reply = result > 0;
> +
> /* 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
> @@ -759,6 +734,12 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name,
> goto fail;
> }
> be16_to_cpus(&info->flags);
> +
> + if (info->structured_reply && !(info->flags & NBD_CMD_FLAG_DF)) {
> + error_setg(errp, "Structured reply is negotiated, "
> + "but DF flag is not.");
> + goto fail;
> + }
> } else if (magic == NBD_CLIENT_MAGIC) {
> uint32_t oldflags;
>
> @@ -942,6 +923,46 @@ int nbd_send_request(QIOChannel *ioc, NBDRequest *request)
> return nbd_write(ioc, buf, sizeof(buf), NULL);
> }
>
> +/* nbd_receive_simple_reply
> + * Read simple reply except magic field (which should be already read)
> + */
> +static int nbd_receive_simple_reply(QIOChannel *ioc, NBDSimpleReply *reply,
> + Error **errp)
> +{
> + int ret = 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 *chunk,
> + Error **errp)
> +{
> + int ret = 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)
> @@ -949,39 +970,38 @@ int nbd_send_request(QIOChannel *ioc, NBDRequest *request)
> */
> int nbd_receive_reply(QIOChannel *ioc, NBDReply *reply, Error **errp)
> {
> - uint8_t buf[NBD_REPLY_SIZE];
> - uint32_t magic;
> int ret;
>
> - ret = nbd_read_eof(ioc, buf, sizeof(buf), errp);
> + ret = nbd_read_eof(ioc, &reply->magic, sizeof(reply->magic), errp);
> if (ret <= 0) {
> return ret;
> }
>
> - /* Reply
> - [ 0 .. 3] magic (NBD_SIMPLE_REPLY_MAGIC)
> - [ 4 .. 7] error (0 == no error)
> - [ 7 .. 15] handle
> - */
> + be32_to_cpus(&reply->magic);
>
> - magic = ldl_be_p(buf);
> - reply->error = ldl_be_p(buf + 4);
> - reply->handle = ldq_be_p(buf + 8);
> + switch (reply->magic) {
> + case NBD_SIMPLE_REPLY_MAGIC:
> + ret = nbd_receive_simple_reply(ioc, &reply->simple, errp);
> + reply->simple.error = nbd_errno_to_system_errno(reply->simple.error);
>
> - reply->error = nbd_errno_to_system_errno(reply->error);
> -
> - if (reply->error == ESHUTDOWN) {
> - /* This works even on mingw which lacks a native ESHUTDOWN */
> - error_setg(errp, "server shutting down");
> + if (reply->simple.error == ESHUTDOWN) {
> + /* This works even on mingw which lacks a native ESHUTDOWN */
> + error_setg(errp, "server shutting down");
> + return -EINVAL;
> + }
> + trace_nbd_receive_reply(reply->magic, reply->simple.error,
> + reply->simple.handle);
> + break;
> + case NBD_STRUCTURED_REPLY_MAGIC:
> + ret = nbd_receive_structured_reply_chunk(ioc, &reply->structured, errp);
> + break;
> + default:
> + error_setg(errp, "invalid magic (got 0x%" PRIx32 ")", reply->magic);
> return -EINVAL;
> }
> - trace_nbd_receive_reply(magic, reply->error, reply->handle);
> -
> - if (magic != 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/block/Makefile.objs b/block/Makefile.objs
> index 6eaf78a046..c99420f42b 100644
> --- a/block/Makefile.objs
> +++ b/block/Makefile.objs
> @@ -12,7 +12,7 @@ block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
> block-obj-y += null.o mirror.o commit.o io.o
> block-obj-y += throttle-groups.o
>
> -block-obj-y += nbd.o nbd-client.o sheepdog.o
> +block-obj-y += nbd.o nbd-client.o nbd-client-cmds.o sheepdog.o
> block-obj-$(CONFIG_LIBISCSI) += iscsi.o
> block-obj-$(if $(CONFIG_LIBISCSI),y,n) += iscsi-opts.o
> block-obj-$(CONFIG_LIBNFS) += nfs.o
--
Best regards,
Vladimir
next prev parent reply other threads:[~2017-10-03 9:59 UTC|newest]
Thread overview: 31+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-09-25 13:57 [Qemu-devel] [PATCH 0/8] nbd minimal structured read Vladimir Sementsov-Ogievskiy
2017-09-25 13:57 ` [Qemu-devel] [PATCH 1/8] block/nbd-client: assert qiov len once in nbd_co_request Vladimir Sementsov-Ogievskiy
2017-09-25 21:58 ` Eric Blake
2017-09-25 13:57 ` [Qemu-devel] [PATCH 2/8] block/nbd-client: refactor nbd_co_receive_reply Vladimir Sementsov-Ogievskiy
2017-09-25 21:59 ` Eric Blake
2017-09-25 13:57 ` [Qemu-devel] [PATCH 3/8] nbd: rename NBD_REPLY_MAGIC to NBD_SIMPLE_REPLY_MAGIC Vladimir Sementsov-Ogievskiy
2017-09-25 13:57 ` [Qemu-devel] [PATCH 4/8] nbd-server: refactor simple reply sending Vladimir Sementsov-Ogievskiy
2017-09-25 13:57 ` [Qemu-devel] [PATCH 5/8] nbd: header constants indenting Vladimir Sementsov-Ogievskiy
2017-09-25 13:57 ` [Qemu-devel] [PATCH 6/8] nbd: Minimal structured read for server Vladimir Sementsov-Ogievskiy
2017-09-25 13:58 ` [Qemu-devel] [PATCH 7/8] nbd/client: refactor nbd_receive_starttls Vladimir Sementsov-Ogievskiy
2017-09-25 13:58 ` [Qemu-devel] [PATCH 8/8] nbd: Minimal structured read for client Vladimir Sementsov-Ogievskiy
2017-09-25 22:19 ` Eric Blake
2017-09-27 10:05 ` Vladimir Sementsov-Ogievskiy
2017-09-27 12:32 ` Vladimir Sementsov-Ogievskiy
2017-09-27 15:10 ` [Qemu-devel] [PATCH v1.1 DRAFT] " Vladimir Sementsov-Ogievskiy
2017-10-03 9:59 ` Vladimir Sementsov-Ogievskiy [this message]
2017-10-03 10:07 ` [Qemu-devel] [Qemu-block] [PATCH 8/8] " Paolo Bonzini
2017-10-03 12:26 ` Vladimir Sementsov-Ogievskiy
2017-10-03 14:05 ` Paolo Bonzini
2017-10-03 12:58 ` Vladimir Sementsov-Ogievskiy
2017-10-03 13:35 ` Vladimir Sementsov-Ogievskiy
2017-10-03 14:06 ` Paolo Bonzini
2017-10-05 9:59 ` Vladimir Sementsov-Ogievskiy
2017-10-05 10:02 ` Vladimir Sementsov-Ogievskiy
2017-10-05 10:36 ` Paolo Bonzini
2017-10-05 22:12 ` Eric Blake
2017-10-06 7:09 ` Vladimir Sementsov-Ogievskiy
2017-10-06 7:23 ` Vladimir Sementsov-Ogievskiy
2017-10-06 7:34 ` Vladimir Sementsov-Ogievskiy
2017-10-06 13:44 ` Eric Blake
2017-09-25 14:06 ` [Qemu-devel] [PATCH 0/8] nbd minimal structured read Vladimir Sementsov-Ogievskiy
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=153ee259-26fb-f42f-1ea6-ce00e6869b6e@virtuozzo.com \
--to=vsementsov@virtuozzo.com \
--cc=den@openvz.org \
--cc=eblake@redhat.com \
--cc=kwolf@redhat.com \
--cc=mreitz@redhat.com \
--cc=pbonzini@redhat.com \
--cc=qemu-block@nongnu.org \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).