Skip to content

Commit

Permalink
Merge remote-tracking branch 'remotes/ericb/tags/pull-nbd-2019-09-05-…
Browse files Browse the repository at this point in the history
…v2' into staging

nbd patches for 2019-09-05

- Advertise NBD_FLAG_CAN_MULTI_CONN on readonly images
- Tolerate larger set of server error responses during handshake
- More precision on handling fallocate() failures due to alignment
- Better documentation of NBD connection URIs
- Implement new extension NBD_CMD_FLAG_FAST_ZERO to benefit qemu-img convert

# gpg: Signature made Thu 05 Sep 2019 22:08:17 BST
# gpg:                using RSA key 71C2CC22B1C4602927D2F3AAA7A16B4A2527436A
# gpg: Good signature from "Eric Blake <eblake@redhat.com>" [full]
# gpg:                 aka "Eric Blake (Free Software Programmer) <ebb9@byu.net>" [full]
# gpg:                 aka "[jpeg image of size 6874]" [full]
# Primary key fingerprint: 71C2 CC22 B1C4 6029 27D2  F3AA A7A1 6B4A 2527 436A

* remotes/ericb/tags/pull-nbd-2019-09-05-v2:
  nbd: Implement server use of NBD FAST_ZERO
  nbd: Implement client use of NBD FAST_ZERO
  nbd: Prepare for NBD_CMD_FLAG_FAST_ZERO
  nbd: Improve per-export flag handling in server
  docs: Update preferred NBD device syntax
  block: workaround for unaligned byte range in fallocate()
  nbd: Tolerate more errors to structured reply request
  nbd: Use g_autofree in a few places
  nbd: Advertise multi-conn for shared read-only connections

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
  • Loading branch information
pm215 committed Sep 6, 2019
2 parents 90b1e3a + b491dbb commit 019217c
Show file tree
Hide file tree
Showing 14 changed files with 141 additions and 104 deletions.
7 changes: 7 additions & 0 deletions block/file-posix.c
Expand Up @@ -1588,6 +1588,13 @@ static int handle_aiocb_write_zeroes(void *opaque)
if (s->has_write_zeroes) {
int ret = do_fallocate(s->fd, FALLOC_FL_ZERO_RANGE,
aiocb->aio_offset, aiocb->aio_nbytes);
if (ret == -EINVAL) {
/*
* Allow falling back to pwrite for file systems that
* do not support fallocate() for an unaligned byte range.
*/
return -ENOTSUP;
}
if (ret == 0 || ret != -ENOTSUP) {
return ret;
}
Expand Down
2 changes: 1 addition & 1 deletion block/io.c
Expand Up @@ -1746,7 +1746,7 @@ static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
assert(!bs->supported_zero_flags);
}

if (ret < 0 && !(flags & BDRV_REQ_NO_FALLBACK)) {
if (ret == -ENOTSUP && !(flags & BDRV_REQ_NO_FALLBACK)) {
/* Fall back to bounce buffer if write zeroes is unsupported */
BdrvRequestFlags write_flags = flags & ~BDRV_REQ_ZERO_WRITE;

Expand Down
18 changes: 11 additions & 7 deletions block/nbd.c
Expand Up @@ -1044,6 +1044,10 @@ static int nbd_client_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset,
if (!(flags & BDRV_REQ_MAY_UNMAP)) {
request.flags |= NBD_CMD_FLAG_NO_HOLE;
}
if (flags & BDRV_REQ_NO_FALLBACK) {
assert(s->info.flags & NBD_FLAG_SEND_FAST_ZERO);
request.flags |= NBD_CMD_FLAG_FAST_ZERO;
}

if (!bytes) {
return 0;
Expand Down Expand Up @@ -1239,6 +1243,9 @@ static int nbd_client_connect(BlockDriverState *bs, Error **errp)
}
if (s->info.flags & NBD_FLAG_SEND_WRITE_ZEROES) {
bs->supported_zero_flags |= BDRV_REQ_MAY_UNMAP;
if (s->info.flags & NBD_FLAG_SEND_FAST_ZERO) {
bs->supported_zero_flags |= BDRV_REQ_NO_FALLBACK;
}
}

s->sioc = sioc;
Expand Down Expand Up @@ -1374,7 +1381,7 @@ static bool nbd_has_filename_options_conflict(QDict *options, Error **errp)
static void nbd_parse_filename(const char *filename, QDict *options,
Error **errp)
{
char *file;
g_autofree char *file = NULL;
char *export_name;
const char *host_spec;
const char *unixpath;
Expand All @@ -1396,7 +1403,7 @@ static void nbd_parse_filename(const char *filename, QDict *options,
export_name = strstr(file, EN_OPTSTR);
if (export_name) {
if (export_name[strlen(EN_OPTSTR)] == 0) {
goto out;
return;
}
export_name[0] = 0; /* truncate 'file' */
export_name += strlen(EN_OPTSTR);
Expand All @@ -1407,11 +1414,11 @@ static void nbd_parse_filename(const char *filename, QDict *options,
/* extract the host_spec - fail if it's not nbd:... */
if (!strstart(file, "nbd:", &host_spec)) {
error_setg(errp, "File name string for NBD must start with 'nbd:'");
goto out;
return;
}

if (!*host_spec) {
goto out;
return;
}

/* are we a UNIX or TCP socket? */
Expand All @@ -1431,9 +1438,6 @@ static void nbd_parse_filename(const char *filename, QDict *options,
out_inet:
qapi_free_InetSocketAddress(addr);
}

out:
g_free(file);
}

static bool nbd_process_legacy_socket_options(QDict *output_options,
Expand Down
3 changes: 1 addition & 2 deletions blockdev-nbd.c
Expand Up @@ -187,8 +187,7 @@ void qmp_nbd_server_add(const char *device, bool has_name, const char *name,
writable = false;
}

exp = nbd_export_new(bs, 0, len, name, NULL, bitmap,
writable ? 0 : NBD_FLAG_READ_ONLY,
exp = nbd_export_new(bs, 0, len, name, NULL, bitmap, !writable, !writable,
NULL, false, on_eject_blk, errp);
if (!exp) {
return;
Expand Down
2 changes: 2 additions & 0 deletions docs/interop/nbd.txt
Expand Up @@ -53,3 +53,5 @@ the operation of that feature.
* 2.12: NBD_CMD_BLOCK_STATUS for "base:allocation"
* 3.0: NBD_OPT_STARTTLS with TLS Pre-Shared Keys (PSK),
NBD_CMD_BLOCK_STATUS for "qemu:dirty-bitmap:", NBD_CMD_CACHE
* 4.2: NBD_FLAG_CAN_MULTI_CONN for sharable read-only exports,
NBD_CMD_FLAG_FAST_ZERO
6 changes: 5 additions & 1 deletion include/block/nbd.h
Expand Up @@ -140,6 +140,7 @@ enum {
NBD_FLAG_CAN_MULTI_CONN_BIT = 8, /* Multi-client cache consistent */
NBD_FLAG_SEND_RESIZE_BIT = 9, /* Send resize */
NBD_FLAG_SEND_CACHE_BIT = 10, /* Send CACHE (prefetch) */
NBD_FLAG_SEND_FAST_ZERO_BIT = 11, /* FAST_ZERO flag for WRITE_ZEROES */
};

#define NBD_FLAG_HAS_FLAGS (1 << NBD_FLAG_HAS_FLAGS_BIT)
Expand All @@ -153,6 +154,7 @@ enum {
#define NBD_FLAG_CAN_MULTI_CONN (1 << NBD_FLAG_CAN_MULTI_CONN_BIT)
#define NBD_FLAG_SEND_RESIZE (1 << NBD_FLAG_SEND_RESIZE_BIT)
#define NBD_FLAG_SEND_CACHE (1 << NBD_FLAG_SEND_CACHE_BIT)
#define NBD_FLAG_SEND_FAST_ZERO (1 << NBD_FLAG_SEND_FAST_ZERO_BIT)

/* New-style handshake (global) flags, sent from server to client, and
control what will happen during handshake phase. */
Expand Down Expand Up @@ -205,6 +207,7 @@ enum {
#define NBD_CMD_FLAG_DF (1 << 2) /* don't fragment structured read */
#define NBD_CMD_FLAG_REQ_ONE (1 << 3) /* only one extent in BLOCK_STATUS
* reply chunk */
#define NBD_CMD_FLAG_FAST_ZERO (1 << 4) /* fail if WRITE_ZEROES is not fast */

/* Supported request types */
enum {
Expand Down Expand Up @@ -270,6 +273,7 @@ static inline bool nbd_reply_type_is_error(int type)
#define NBD_EINVAL 22
#define NBD_ENOSPC 28
#define NBD_EOVERFLOW 75
#define NBD_ENOTSUP 95
#define NBD_ESHUTDOWN 108

/* Details collected by NBD_OPT_EXPORT_NAME and NBD_OPT_GO */
Expand Down Expand Up @@ -326,7 +330,7 @@ typedef struct NBDClient NBDClient;

NBDExport *nbd_export_new(BlockDriverState *bs, uint64_t dev_offset,
uint64_t size, const char *name, const char *desc,
const char *bitmap, uint16_t nbdflags,
const char *bitmap, bool readonly, bool shared,
void (*close)(NBDExport *), bool writethrough,
BlockBackend *on_eject_blk, Error **errp);
void nbd_export_close(NBDExport *exp);
Expand Down
85 changes: 40 additions & 45 deletions nbd/client.c
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2016-2018 Red Hat, Inc.
* Copyright (C) 2016-2019 Red Hat, Inc.
* Copyright (C) 2005 Anthony Liguori <anthony@codemonkey.ws>
*
* Network Block Device Client Side
Expand Down Expand Up @@ -142,17 +142,18 @@ static int nbd_receive_option_reply(QIOChannel *ioc, uint32_t opt,
return 0;
}

/* If reply represents success, return 1 without further action.
* If reply represents an error, consume the optional payload of
* the packet on ioc. Then return 0 for unsupported (so the client
* can fall back to other approaches), or -1 with errp set for other
* errors.
/*
* If reply represents success, return 1 without further action. If
* reply represents an error, consume the optional payload of the
* packet on ioc. Then return 0 for unsupported (so the client can
* fall back to other approaches), where @strict determines if only
* ERR_UNSUP or all errors fit that category, or -1 with errp set for
* other errors.
*/
static int nbd_handle_reply_err(QIOChannel *ioc, NBDOptionReply *reply,
Error **errp)
bool strict, Error **errp)
{
char *msg = NULL;
int result = -1;
g_autofree char *msg = NULL;

if (!(reply->type & (1 << 31))) {
return 1;
Expand All @@ -163,26 +164,28 @@ static int nbd_handle_reply_err(QIOChannel *ioc, NBDOptionReply *reply,
error_setg(errp, "server error %" PRIu32
" (%s) message is too long",
reply->type, nbd_rep_lookup(reply->type));
goto cleanup;
goto err;
}
msg = g_malloc(reply->length + 1);
if (nbd_read(ioc, msg, reply->length, NULL, errp) < 0) {
error_prepend(errp, "Failed to read option error %" PRIu32
" (%s) message: ",
reply->type, nbd_rep_lookup(reply->type));
goto cleanup;
goto err;
}
msg[reply->length] = '\0';
trace_nbd_server_error_msg(reply->type,
nbd_reply_type_lookup(reply->type), msg);
}

switch (reply->type) {
case NBD_REP_ERR_UNSUP:
trace_nbd_reply_err_unsup(reply->option, nbd_opt_lookup(reply->option));
result = 0;
goto cleanup;
if (reply->type == NBD_REP_ERR_UNSUP || !strict) {
trace_nbd_reply_err_ignored(reply->option,
nbd_opt_lookup(reply->option),
reply->type, nbd_rep_lookup(reply->type));
return 0;
}

switch (reply->type) {
case NBD_REP_ERR_POLICY:
error_setg(errp, "Denied by server for option %" PRIu32 " (%s)",
reply->option, nbd_opt_lookup(reply->option));
Expand Down Expand Up @@ -227,12 +230,9 @@ static int nbd_handle_reply_err(QIOChannel *ioc, NBDOptionReply *reply,
error_append_hint(errp, "server reported: %s\n", msg);
}

cleanup:
g_free(msg);
if (result < 0) {
nbd_send_opt_abort(ioc);
}
return result;
err:
nbd_send_opt_abort(ioc);
return -1;
}

/* nbd_receive_list:
Expand All @@ -247,18 +247,17 @@ static int nbd_handle_reply_err(QIOChannel *ioc, NBDOptionReply *reply,
static int nbd_receive_list(QIOChannel *ioc, char **name, char **description,
Error **errp)
{
int ret = -1;
NBDOptionReply reply;
uint32_t len;
uint32_t namelen;
char *local_name = NULL;
char *local_desc = NULL;
g_autofree char *local_name = NULL;
g_autofree char *local_desc = NULL;
int error;

if (nbd_receive_option_reply(ioc, NBD_OPT_LIST, &reply, errp) < 0) {
return -1;
}
error = nbd_handle_reply_err(ioc, &reply, errp);
error = nbd_handle_reply_err(ioc, &reply, true, errp);
if (error <= 0) {
return error;
}
Expand Down Expand Up @@ -298,32 +297,25 @@ static int nbd_receive_list(QIOChannel *ioc, char **name, char **description,
local_name = g_malloc(namelen + 1);
if (nbd_read(ioc, local_name, namelen, "export name", errp) < 0) {
nbd_send_opt_abort(ioc);
goto out;
return -1;
}
local_name[namelen] = '\0';
len -= namelen;
if (len) {
local_desc = g_malloc(len + 1);
if (nbd_read(ioc, local_desc, len, "export description", errp) < 0) {
nbd_send_opt_abort(ioc);
goto out;
return -1;
}
local_desc[len] = '\0';
}

trace_nbd_receive_list(local_name, local_desc ?: "");
*name = local_name;
local_name = NULL;
*name = g_steal_pointer(&local_name);
if (description) {
*description = local_desc;
local_desc = NULL;
*description = g_steal_pointer(&local_desc);
}
ret = 1;

out:
g_free(local_name);
g_free(local_desc);
return ret;
return 1;
}


Expand Down Expand Up @@ -371,7 +363,7 @@ static int nbd_opt_info_or_go(QIOChannel *ioc, uint32_t opt,
if (nbd_receive_option_reply(ioc, opt, &reply, errp) < 0) {
return -1;
}
error = nbd_handle_reply_err(ioc, &reply, errp);
error = nbd_handle_reply_err(ioc, &reply, true, errp);
if (error <= 0) {
return error;
}
Expand Down Expand Up @@ -546,12 +538,15 @@ static int nbd_receive_query_exports(QIOChannel *ioc,
}
}

/* nbd_request_simple_option: Send an option request, and parse the reply
/*
* nbd_request_simple_option: Send an option request, and parse the reply.
* @strict controls whether ERR_UNSUP or all errors produce 0 status.
* return 1 for successful negotiation,
* 0 if operation is unsupported,
* -1 with errp set for any other error
*/
static int nbd_request_simple_option(QIOChannel *ioc, int opt, Error **errp)
static int nbd_request_simple_option(QIOChannel *ioc, int opt, bool strict,
Error **errp)
{
NBDOptionReply reply;
int error;
Expand All @@ -563,7 +558,7 @@ static int nbd_request_simple_option(QIOChannel *ioc, int opt, Error **errp)
if (nbd_receive_option_reply(ioc, opt, &reply, errp) < 0) {
return -1;
}
error = nbd_handle_reply_err(ioc, &reply, errp);
error = nbd_handle_reply_err(ioc, &reply, strict, errp);
if (error <= 0) {
return error;
}
Expand Down Expand Up @@ -595,7 +590,7 @@ static QIOChannel *nbd_receive_starttls(QIOChannel *ioc,
QIOChannelTLS *tioc;
struct NBDTLSHandshakeData data = { 0 };

ret = nbd_request_simple_option(ioc, NBD_OPT_STARTTLS, errp);
ret = nbd_request_simple_option(ioc, NBD_OPT_STARTTLS, true, errp);
if (ret <= 0) {
if (ret == 0) {
error_setg(errp, "Server don't support STARTTLS option");
Expand Down Expand Up @@ -695,7 +690,7 @@ static int nbd_receive_one_meta_context(QIOChannel *ioc,
return -1;
}

ret = nbd_handle_reply_err(ioc, &reply, errp);
ret = nbd_handle_reply_err(ioc, &reply, false, errp);
if (ret <= 0) {
return ret;
}
Expand Down Expand Up @@ -951,7 +946,7 @@ static int nbd_start_negotiate(AioContext *aio_context, QIOChannel *ioc,
if (structured_reply) {
result = nbd_request_simple_option(ioc,
NBD_OPT_STRUCTURED_REPLY,
errp);
false, errp);
if (result < 0) {
return -EINVAL;
}
Expand Down
5 changes: 5 additions & 0 deletions nbd/common.c
Expand Up @@ -201,6 +201,8 @@ const char *nbd_err_lookup(int err)
return "ENOSPC";
case NBD_EOVERFLOW:
return "EOVERFLOW";
case NBD_ENOTSUP:
return "ENOTSUP";
case NBD_ESHUTDOWN:
return "ESHUTDOWN";
default:
Expand Down Expand Up @@ -231,6 +233,9 @@ int nbd_errno_to_system_errno(int err)
case NBD_EOVERFLOW:
ret = EOVERFLOW;
break;
case NBD_ENOTSUP:
ret = ENOTSUP;
break;
case NBD_ESHUTDOWN:
ret = ESHUTDOWN;
break;
Expand Down

0 comments on commit 019217c

Please sign in to comment.