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 -----BEGIN PGP SIGNATURE----- iQEzBAABCAAdFiEEccLMIrHEYCkn0vOqp6FrSiUnQ2oFAl1xeUEACgkQp6FrSiUn Q2qCTQgAh0Q8HM6qDhDCTtNZ/HxxNTZ7n1O9ZB7bTQ+S6miFPh77+qsI/Gk81rJR iwPKv1k8JZBnWtciwl2uynBCVlxHmBtxmVlzc66BVg3TMyOx3Eedsbel9Dl5QUgp JREwPUN0uyly+zDL8X/7WB+Xmldz2u6cbnfl8JeszCscnhJ4cFNMzW5b4gaCpi73 OYt8AU2vg8c9yDK6lb/Xcc7dGSAba1vbcTSc6GPaGGlY5nPM/JKsWjlU8Abg2krM m/mGpQzsb72xcL/9/vY17xarFi8uz4uU+U0Ohpe5XYl+IO/RiEgjokitlgrUtMWi LNVKWj+5E0lIsNVSwhIWLEQxQACbjw== =P3mc -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/ericb/tags/pull-nbd-2019-09-05-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>
This commit is contained in:
commit
019217c3b3
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
18
block/nbd.c
18
block/nbd.c
@ -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;
|
||||
@ -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;
|
||||
@ -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;
|
||||
@ -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);
|
||||
@ -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? */
|
||||
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
@ -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. */
|
||||
@ -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 {
|
||||
@ -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 */
|
||||
@ -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);
|
||||
|
83
nbd/client.c
83
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
|
||||
@ -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;
|
||||
@ -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));
|
||||
@ -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) {
|
||||
err:
|
||||
nbd_send_opt_abort(ioc);
|
||||
}
|
||||
return result;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* nbd_receive_list:
|
||||
@ -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;
|
||||
}
|
||||
@ -298,7 +297,7 @@ 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;
|
||||
@ -306,24 +305,17 @@ static int nbd_receive_list(QIOChannel *ioc, char **name, char **description,
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
@ -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;
|
||||
@ -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;
|
||||
}
|
||||
@ -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");
|
||||
@ -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;
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
|
@ -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:
|
||||
@ -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;
|
||||
|
83
nbd/server.c
83
nbd/server.c
@ -55,6 +55,11 @@ static int system_errno_to_nbd_errno(int err)
|
||||
return NBD_ENOSPC;
|
||||
case EOVERFLOW:
|
||||
return NBD_EOVERFLOW;
|
||||
case ENOTSUP:
|
||||
#if ENOTSUP != EOPNOTSUPP
|
||||
case EOPNOTSUPP:
|
||||
#endif
|
||||
return NBD_ENOTSUP;
|
||||
case ESHUTDOWN:
|
||||
return NBD_ESHUTDOWN;
|
||||
case EINVAL:
|
||||
@ -206,7 +211,7 @@ static int GCC_FMT_ATTR(4, 0)
|
||||
nbd_negotiate_send_rep_verr(NBDClient *client, uint32_t type,
|
||||
Error **errp, const char *fmt, va_list va)
|
||||
{
|
||||
char *msg;
|
||||
g_autofree char *msg = NULL;
|
||||
int ret;
|
||||
size_t len;
|
||||
|
||||
@ -216,18 +221,14 @@ nbd_negotiate_send_rep_verr(NBDClient *client, uint32_t type,
|
||||
trace_nbd_negotiate_send_rep_err(msg);
|
||||
ret = nbd_negotiate_send_rep_len(client, type, len, errp);
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
return ret;
|
||||
}
|
||||
if (nbd_write(client->ioc, msg, len, errp) < 0) {
|
||||
error_prepend(errp, "write failed (error message): ");
|
||||
ret = -EIO;
|
||||
} else {
|
||||
ret = 0;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
out:
|
||||
g_free(msg);
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Send an error reply.
|
||||
@ -423,14 +424,14 @@ static void nbd_check_meta_export(NBDClient *client)
|
||||
|
||||
/* Send a reply to NBD_OPT_EXPORT_NAME.
|
||||
* Return -errno on error, 0 on success. */
|
||||
static int nbd_negotiate_handle_export_name(NBDClient *client,
|
||||
uint16_t myflags, bool no_zeroes,
|
||||
static int nbd_negotiate_handle_export_name(NBDClient *client, bool no_zeroes,
|
||||
Error **errp)
|
||||
{
|
||||
char name[NBD_MAX_NAME_SIZE + 1];
|
||||
char buf[NBD_REPLY_EXPORT_NAME_SIZE] = "";
|
||||
size_t len;
|
||||
int ret;
|
||||
uint16_t myflags;
|
||||
|
||||
/* Client sends:
|
||||
[20 .. xx] export name (length bytes)
|
||||
@ -458,10 +459,13 @@ static int nbd_negotiate_handle_export_name(NBDClient *client,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
trace_nbd_negotiate_new_style_size_flags(client->exp->size,
|
||||
client->exp->nbdflags | myflags);
|
||||
myflags = client->exp->nbdflags;
|
||||
if (client->structured_reply) {
|
||||
myflags |= NBD_FLAG_SEND_DF;
|
||||
}
|
||||
trace_nbd_negotiate_new_style_size_flags(client->exp->size, myflags);
|
||||
stq_be_p(buf, client->exp->size);
|
||||
stw_be_p(buf + 8, client->exp->nbdflags | myflags);
|
||||
stw_be_p(buf + 8, myflags);
|
||||
len = no_zeroes ? 10 : sizeof(buf);
|
||||
ret = nbd_write(client->ioc, buf, len, errp);
|
||||
if (ret < 0) {
|
||||
@ -526,8 +530,7 @@ static int nbd_reject_length(NBDClient *client, bool fatal, Error **errp)
|
||||
/* Handle NBD_OPT_INFO and NBD_OPT_GO.
|
||||
* Return -errno on error, 0 if ready for next option, and 1 to move
|
||||
* into transmission phase. */
|
||||
static int nbd_negotiate_handle_info(NBDClient *client, uint16_t myflags,
|
||||
Error **errp)
|
||||
static int nbd_negotiate_handle_info(NBDClient *client, Error **errp)
|
||||
{
|
||||
int rc;
|
||||
char name[NBD_MAX_NAME_SIZE + 1];
|
||||
@ -540,6 +543,7 @@ static int nbd_negotiate_handle_info(NBDClient *client, uint16_t myflags,
|
||||
uint32_t sizes[3];
|
||||
char buf[sizeof(uint64_t) + sizeof(uint16_t)];
|
||||
uint32_t check_align = 0;
|
||||
uint16_t myflags;
|
||||
|
||||
/* Client sends:
|
||||
4 bytes: L, name length (can be 0)
|
||||
@ -637,10 +641,13 @@ static int nbd_negotiate_handle_info(NBDClient *client, uint16_t myflags,
|
||||
}
|
||||
|
||||
/* Send NBD_INFO_EXPORT always */
|
||||
trace_nbd_negotiate_new_style_size_flags(exp->size,
|
||||
exp->nbdflags | myflags);
|
||||
myflags = exp->nbdflags;
|
||||
if (client->structured_reply) {
|
||||
myflags |= NBD_FLAG_SEND_DF;
|
||||
}
|
||||
trace_nbd_negotiate_new_style_size_flags(exp->size, myflags);
|
||||
stq_be_p(buf, exp->size);
|
||||
stw_be_p(buf + 8, exp->nbdflags | myflags);
|
||||
stw_be_p(buf + 8, myflags);
|
||||
rc = nbd_negotiate_send_info(client, NBD_INFO_EXPORT,
|
||||
sizeof(buf), buf, errp);
|
||||
if (rc < 0) {
|
||||
@ -1037,8 +1044,7 @@ static int nbd_negotiate_meta_queries(NBDClient *client,
|
||||
* 1 if client sent NBD_OPT_ABORT, i.e. on valid disconnect,
|
||||
* errp is not set
|
||||
*/
|
||||
static int nbd_negotiate_options(NBDClient *client, uint16_t myflags,
|
||||
Error **errp)
|
||||
static int nbd_negotiate_options(NBDClient *client, Error **errp)
|
||||
{
|
||||
uint32_t flags;
|
||||
bool fixedNewstyle = false;
|
||||
@ -1172,13 +1178,12 @@ static int nbd_negotiate_options(NBDClient *client, uint16_t myflags,
|
||||
return 1;
|
||||
|
||||
case NBD_OPT_EXPORT_NAME:
|
||||
return nbd_negotiate_handle_export_name(client,
|
||||
myflags, no_zeroes,
|
||||
return nbd_negotiate_handle_export_name(client, no_zeroes,
|
||||
errp);
|
||||
|
||||
case NBD_OPT_INFO:
|
||||
case NBD_OPT_GO:
|
||||
ret = nbd_negotiate_handle_info(client, myflags, errp);
|
||||
ret = nbd_negotiate_handle_info(client, errp);
|
||||
if (ret == 1) {
|
||||
assert(option == NBD_OPT_GO);
|
||||
return 0;
|
||||
@ -1209,7 +1214,6 @@ static int nbd_negotiate_options(NBDClient *client, uint16_t myflags,
|
||||
} else {
|
||||
ret = nbd_negotiate_send_rep(client, NBD_REP_ACK, errp);
|
||||
client->structured_reply = true;
|
||||
myflags |= NBD_FLAG_SEND_DF;
|
||||
}
|
||||
break;
|
||||
|
||||
@ -1232,8 +1236,7 @@ static int nbd_negotiate_options(NBDClient *client, uint16_t myflags,
|
||||
*/
|
||||
switch (option) {
|
||||
case NBD_OPT_EXPORT_NAME:
|
||||
return nbd_negotiate_handle_export_name(client,
|
||||
myflags, no_zeroes,
|
||||
return nbd_negotiate_handle_export_name(client, no_zeroes,
|
||||
errp);
|
||||
|
||||
default:
|
||||
@ -1259,9 +1262,6 @@ static coroutine_fn int nbd_negotiate(NBDClient *client, Error **errp)
|
||||
{
|
||||
char buf[NBD_OLDSTYLE_NEGOTIATE_SIZE] = "";
|
||||
int ret;
|
||||
const uint16_t myflags = (NBD_FLAG_HAS_FLAGS | NBD_FLAG_SEND_TRIM |
|
||||
NBD_FLAG_SEND_FLUSH | NBD_FLAG_SEND_FUA |
|
||||
NBD_FLAG_SEND_WRITE_ZEROES | NBD_FLAG_SEND_CACHE);
|
||||
|
||||
/* Old style negotiation header, no room for options
|
||||
[ 0 .. 7] passwd ("NBDMAGIC")
|
||||
@ -1289,7 +1289,7 @@ static coroutine_fn int nbd_negotiate(NBDClient *client, Error **errp)
|
||||
error_prepend(errp, "write failed: ");
|
||||
return -EINVAL;
|
||||
}
|
||||
ret = nbd_negotiate_options(client, myflags, errp);
|
||||
ret = nbd_negotiate_options(client, errp);
|
||||
if (ret != 0) {
|
||||
if (ret < 0) {
|
||||
error_prepend(errp, "option negotiation failed: ");
|
||||
@ -1461,7 +1461,7 @@ static void nbd_eject_notifier(Notifier *n, void *data)
|
||||
|
||||
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)
|
||||
{
|
||||
@ -1485,7 +1485,7 @@ NBDExport *nbd_export_new(BlockDriverState *bs, uint64_t dev_offset,
|
||||
/* Don't allow resize while the NBD server is running, otherwise we don't
|
||||
* care what happens with the node. */
|
||||
perm = BLK_PERM_CONSISTENT_READ;
|
||||
if ((nbdflags & NBD_FLAG_READ_ONLY) == 0) {
|
||||
if (!readonly) {
|
||||
perm |= BLK_PERM_WRITE;
|
||||
}
|
||||
blk = blk_new(bdrv_get_aio_context(bs), perm,
|
||||
@ -1505,7 +1505,17 @@ NBDExport *nbd_export_new(BlockDriverState *bs, uint64_t dev_offset,
|
||||
exp->dev_offset = dev_offset;
|
||||
exp->name = g_strdup(name);
|
||||
exp->description = g_strdup(desc);
|
||||
exp->nbdflags = nbdflags;
|
||||
exp->nbdflags = (NBD_FLAG_HAS_FLAGS | NBD_FLAG_SEND_FLUSH |
|
||||
NBD_FLAG_SEND_FUA | NBD_FLAG_SEND_CACHE);
|
||||
if (readonly) {
|
||||
exp->nbdflags |= NBD_FLAG_READ_ONLY;
|
||||
if (shared) {
|
||||
exp->nbdflags |= NBD_FLAG_CAN_MULTI_CONN;
|
||||
}
|
||||
} else {
|
||||
exp->nbdflags |= (NBD_FLAG_SEND_TRIM | NBD_FLAG_SEND_WRITE_ZEROES |
|
||||
NBD_FLAG_SEND_FAST_ZERO);
|
||||
}
|
||||
assert(size <= INT64_MAX - dev_offset);
|
||||
exp->size = QEMU_ALIGN_DOWN(size, BDRV_SECTOR_SIZE);
|
||||
|
||||
@ -1530,7 +1540,7 @@ NBDExport *nbd_export_new(BlockDriverState *bs, uint64_t dev_offset,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if ((nbdflags & NBD_FLAG_READ_ONLY) && bdrv_is_writable(bs) &&
|
||||
if (readonly && bdrv_is_writable(bs) &&
|
||||
bdrv_dirty_bitmap_enabled(bm)) {
|
||||
error_setg(errp,
|
||||
"Enabled bitmap '%s' incompatible with readonly export",
|
||||
@ -2157,7 +2167,7 @@ static int nbd_co_receive_request(NBDRequestData *req, NBDRequest *request,
|
||||
if (request->type == NBD_CMD_READ && client->structured_reply) {
|
||||
valid_flags |= NBD_CMD_FLAG_DF;
|
||||
} else if (request->type == NBD_CMD_WRITE_ZEROES) {
|
||||
valid_flags |= NBD_CMD_FLAG_NO_HOLE;
|
||||
valid_flags |= NBD_CMD_FLAG_NO_HOLE | NBD_CMD_FLAG_FAST_ZERO;
|
||||
} else if (request->type == NBD_CMD_BLOCK_STATUS) {
|
||||
valid_flags |= NBD_CMD_FLAG_REQ_ONE;
|
||||
}
|
||||
@ -2296,6 +2306,9 @@ static coroutine_fn int nbd_handle_request(NBDClient *client,
|
||||
if (!(request->flags & NBD_CMD_FLAG_NO_HOLE)) {
|
||||
flags |= BDRV_REQ_MAY_UNMAP;
|
||||
}
|
||||
if (request->flags & NBD_CMD_FLAG_FAST_ZERO) {
|
||||
flags |= BDRV_REQ_NO_FALLBACK;
|
||||
}
|
||||
ret = blk_pwrite_zeroes(exp->blk, request->from + exp->dev_offset,
|
||||
request->len, flags);
|
||||
return nbd_send_generic_reply(client, request->handle, ret,
|
||||
|
@ -4,7 +4,7 @@
|
||||
nbd_send_option_request(uint32_t opt, const char *name, uint32_t len) "Sending option request %" PRIu32" (%s), len %" PRIu32
|
||||
nbd_receive_option_reply(uint32_t option, const char *optname, uint32_t type, const char *typename, uint32_t length) "Received option reply %" PRIu32" (%s), type %" PRIu32" (%s), len %" PRIu32
|
||||
nbd_server_error_msg(uint32_t err, const char *type, const char *msg) "server reported error 0x%" PRIx32 " (%s) with additional message: %s"
|
||||
nbd_reply_err_unsup(uint32_t option, const char *name) "server doesn't understand request %" PRIu32 " (%s), attempting fallback"
|
||||
nbd_reply_err_ignored(uint32_t option, const char *name, uint32_t reply, const char *reply_name) "server failed request %" PRIu32 " (%s) with error 0x%" PRIx32 " (%s), attempting fallback"
|
||||
nbd_receive_list(const char *name, const char *desc) "export list includes '%s', description '%s'"
|
||||
nbd_opt_info_go_start(const char *opt, const char *name) "Attempting %s for export '%s'"
|
||||
nbd_opt_info_go_success(const char *opt) "Export is ready after %s request"
|
||||
|
@ -301,9 +301,16 @@ LIBISCSI_CHAP_PASSWORD="password" \
|
||||
|
||||
@item NBD
|
||||
QEMU supports NBD (Network Block Devices) both using TCP protocol as well
|
||||
as Unix Domain Sockets.
|
||||
as Unix Domain Sockets. With TCP, the default port is 10809.
|
||||
|
||||
Syntax for specifying a NBD device using TCP
|
||||
Syntax for specifying a NBD device using TCP, in preferred URI form:
|
||||
``nbd://<server-ip>[:<port>]/[<export>]''
|
||||
|
||||
Syntax for specifying a NBD device using Unix Domain Sockets; remember
|
||||
that '?' is a shell glob character and may need quoting:
|
||||
``nbd+unix:///[<export>]?socket=<domain-socket>''
|
||||
|
||||
Older syntax that is also recognized:
|
||||
``nbd:<server-ip>:<port>[:exportname=<export>]''
|
||||
|
||||
Syntax for specifying a NBD device using Unix Domain Sockets
|
||||
|
@ -294,6 +294,7 @@ static int qemu_nbd_client_list(SocketAddress *saddr, QCryptoTLSCreds *tls,
|
||||
[NBD_FLAG_CAN_MULTI_CONN_BIT] = "multi",
|
||||
[NBD_FLAG_SEND_RESIZE_BIT] = "resize",
|
||||
[NBD_FLAG_SEND_CACHE_BIT] = "cache",
|
||||
[NBD_FLAG_SEND_FAST_ZERO_BIT] = "fast-zero",
|
||||
};
|
||||
|
||||
printf(" size: %" PRIu64 "\n", list[i].size);
|
||||
@ -600,7 +601,7 @@ int main(int argc, char **argv)
|
||||
BlockBackend *blk;
|
||||
BlockDriverState *bs;
|
||||
uint64_t dev_offset = 0;
|
||||
uint16_t nbdflags = 0;
|
||||
bool readonly = false;
|
||||
bool disconnect = false;
|
||||
const char *bindto = NULL;
|
||||
const char *port = NULL;
|
||||
@ -782,7 +783,7 @@ int main(int argc, char **argv)
|
||||
}
|
||||
/* fall through */
|
||||
case 'r':
|
||||
nbdflags |= NBD_FLAG_READ_ONLY;
|
||||
readonly = true;
|
||||
flags &= ~BDRV_O_RDWR;
|
||||
break;
|
||||
case 'P':
|
||||
@ -1173,7 +1174,7 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
export = nbd_export_new(bs, dev_offset, fd_size, export_name,
|
||||
export_description, bitmap, nbdflags,
|
||||
export_description, bitmap, readonly, shared > 1,
|
||||
nbd_export_closed, writethrough, NULL,
|
||||
&error_fatal);
|
||||
|
||||
|
@ -40,7 +40,7 @@ exports available: 0
|
||||
exports available: 2
|
||||
export: 'n'
|
||||
size: 4194304
|
||||
flags: 0x4ef ( readonly flush fua trim zeroes df cache )
|
||||
flags: 0x58f ( readonly flush fua df multi cache )
|
||||
min block: 1
|
||||
opt block: 4096
|
||||
max block: 33554432
|
||||
@ -49,7 +49,7 @@ exports available: 2
|
||||
qemu:dirty-bitmap:b
|
||||
export: 'n2'
|
||||
size: 4194304
|
||||
flags: 0x4ed ( flush fua trim zeroes df cache )
|
||||
flags: 0xced ( flush fua trim zeroes df cache fast-zero )
|
||||
min block: 1
|
||||
opt block: 4096
|
||||
max block: 33554432
|
||||
|
@ -20,10 +20,10 @@ qemu-nbd: Denied by server for option 5 (starttls)
|
||||
server reported: TLS not configured
|
||||
|
||||
== check plain client to TLS server fails ==
|
||||
qemu-img: Could not open 'nbd://localhost:PORT': TLS negotiation required before option 8 (structured reply)
|
||||
server reported: Option 0x8 not permitted before TLS
|
||||
qemu-nbd: TLS negotiation required before option 8 (structured reply)
|
||||
server reported: Option 0x8 not permitted before TLS
|
||||
qemu-img: Could not open 'nbd://localhost:PORT': TLS negotiation required before option 7 (go)
|
||||
server reported: Option 0x7 not permitted before TLS
|
||||
qemu-nbd: TLS negotiation required before option 3 (list)
|
||||
server reported: Option 0x3 not permitted before TLS
|
||||
|
||||
== check TLS works ==
|
||||
image: nbd://127.0.0.1:PORT
|
||||
@ -37,7 +37,7 @@ disk size: unavailable
|
||||
exports available: 1
|
||||
export: ''
|
||||
size: 67108864
|
||||
flags: 0x4ed ( flush fua trim zeroes df cache )
|
||||
flags: 0xced ( flush fua trim zeroes df cache fast-zero )
|
||||
min block: 1
|
||||
opt block: 4096
|
||||
max block: 33554432
|
||||
|
Loading…
Reference in New Issue
Block a user