mirror of https://github.com/xqemu/xqemu.git
nbd patches for 2019-01-21
Add 'qemu-nbd --list' for probing a remote NBD server's advertisements. - Eric Blake: 0/21 nbd: add qemu-nbd --list -----BEGIN PGP SIGNATURE----- iQEcBAABCAAGBQJcRktLAAoJEKeha0olJ0NqY8cIAJqcHDAuk1GwcDE/NIAASY9E 2PsaEL2pM65bEWUwsnVkFyRb4y4S4QX9VtAR/c9G6jR0YHuDvCCz7VGjiHh3eGso 9AWKzuh5C4mayAN5dTOlbjryOx7hlcz8wDDjP5OQNqIlBvmWVAnLeh5Kkqlc7KDk f1SH8kJfqegDAhKDeDhi/HGlL1UVzMr5A2sR6I1wbb5IbBru5JtAKzgqAmdBH893 lWZ9EDXqajwPCo8ASwZNyawmtmjx+VBeFjO2juA3qTWvf262roiB3XT5W/3n/CCb Er5CBwQQvSFBUfF9bRYDziyjwQwTXoIQJ6nuJLzPGx2cUpQbJ/svphoRQ6rBOjY= =gywW -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/ericb/tags/pull-nbd-2019-01-21' into staging nbd patches for 2019-01-21 Add 'qemu-nbd --list' for probing a remote NBD server's advertisements. - Eric Blake: 0/21 nbd: add qemu-nbd --list # gpg: Signature made Mon 21 Jan 2019 22:44:27 GMT # gpg: using RSA key A7A16B4A2527436A # gpg: Good signature from "Eric Blake <eblake@redhat.com>" # gpg: aka "Eric Blake (Free Software Programmer) <ebb9@byu.net>" # gpg: aka "[jpeg image of size 6874]" # Primary key fingerprint: 71C2 CC22 B1C4 6029 27D2 F3AA A7A1 6B4A 2527 436A * remotes/ericb/tags/pull-nbd-2019-01-21: (21 commits) iotests: Enhance 223, 233 to cover 'qemu-nbd --list' nbd/client: Work around 3.0 bug for listing meta contexts qemu-nbd: Add --list option nbd/client: Add meta contexts to nbd_receive_export_list() nbd/client: Add nbd_receive_export_list() nbd/client: Refactor nbd_opt_go() to support NBD_OPT_INFO nbd/client: Pull out oldstyle size determination nbd/client: Split handshake into two functions nbd/client: Refactor return of nbd_receive_negotiate() nbd/client: Split out nbd_receive_one_meta_context() nbd/client: Split out nbd_send_meta_query() nbd/client: Change signature of nbd_negotiate_simple_meta_context() nbd/client: Move export name into NBDExportInfo nbd/client: Refactor nbd_receive_list() qemu-nbd: Avoid strtol open-coding nbd/server: Favor [u]int64_t over off_t nbd/server: Hoist length check to qmp_nbd_server_add qemu-nbd: Sanity check partition bounds qemu-nbd: Enhance man page maint: Allow for EXAMPLES in texi2pod ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
952bc8b3c2
2
Makefile
2
Makefile
|
@ -860,6 +860,8 @@ docs/interop/qemu-qmp-ref.dvi docs/interop/qemu-qmp-ref.html \
|
||||||
docs/interop/qemu-qmp-ref.txt docs/interop/qemu-qmp-ref.7: \
|
docs/interop/qemu-qmp-ref.txt docs/interop/qemu-qmp-ref.7: \
|
||||||
docs/interop/qemu-qmp-ref.texi docs/interop/qemu-qmp-qapi.texi
|
docs/interop/qemu-qmp-ref.texi docs/interop/qemu-qmp-qapi.texi
|
||||||
|
|
||||||
|
$(filter %.1 %.7 %.8,$(DOCS)): scripts/texi2pod.pl
|
||||||
|
|
||||||
# Reports/Analysis
|
# Reports/Analysis
|
||||||
|
|
||||||
%/coverage-report.html:
|
%/coverage-report.html:
|
||||||
|
|
|
@ -249,11 +249,11 @@ static int nbd_parse_blockstatus_payload(NBDClientSession *client,
|
||||||
}
|
}
|
||||||
|
|
||||||
context_id = payload_advance32(&payload);
|
context_id = payload_advance32(&payload);
|
||||||
if (client->info.meta_base_allocation_id != context_id) {
|
if (client->info.context_id != context_id) {
|
||||||
error_setg(errp, "Protocol error: unexpected context id %d for "
|
error_setg(errp, "Protocol error: unexpected context id %d for "
|
||||||
"NBD_REPLY_TYPE_BLOCK_STATUS, when negotiated context "
|
"NBD_REPLY_TYPE_BLOCK_STATUS, when negotiated context "
|
||||||
"id is %d", context_id,
|
"id is %d", context_id,
|
||||||
client->info.meta_base_allocation_id);
|
client->info.context_id);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -999,10 +999,11 @@ int nbd_client_init(BlockDriverState *bs,
|
||||||
client->info.structured_reply = true;
|
client->info.structured_reply = true;
|
||||||
client->info.base_allocation = true;
|
client->info.base_allocation = true;
|
||||||
client->info.x_dirty_bitmap = g_strdup(x_dirty_bitmap);
|
client->info.x_dirty_bitmap = g_strdup(x_dirty_bitmap);
|
||||||
ret = nbd_receive_negotiate(QIO_CHANNEL(sioc), export,
|
client->info.name = g_strdup(export ?: "");
|
||||||
tlscreds, hostname,
|
ret = nbd_receive_negotiate(QIO_CHANNEL(sioc), tlscreds, hostname,
|
||||||
&client->ioc, &client->info, errp);
|
&client->ioc, &client->info, errp);
|
||||||
g_free(client->info.x_dirty_bitmap);
|
g_free(client->info.x_dirty_bitmap);
|
||||||
|
g_free(client->info.name);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
logout("Failed to negotiate with the NBD server\n");
|
logout("Failed to negotiate with the NBD server\n");
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -146,6 +146,7 @@ void qmp_nbd_server_add(const char *device, bool has_name, const char *name,
|
||||||
BlockDriverState *bs = NULL;
|
BlockDriverState *bs = NULL;
|
||||||
BlockBackend *on_eject_blk;
|
BlockBackend *on_eject_blk;
|
||||||
NBDExport *exp;
|
NBDExport *exp;
|
||||||
|
int64_t len;
|
||||||
|
|
||||||
if (!nbd_server) {
|
if (!nbd_server) {
|
||||||
error_setg(errp, "NBD server not running");
|
error_setg(errp, "NBD server not running");
|
||||||
|
@ -168,6 +169,13 @@ void qmp_nbd_server_add(const char *device, bool has_name, const char *name,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
len = bdrv_getlength(bs);
|
||||||
|
if (len < 0) {
|
||||||
|
error_setg_errno(errp, -len,
|
||||||
|
"Failed to determine the NBD export's length");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!has_writable) {
|
if (!has_writable) {
|
||||||
writable = false;
|
writable = false;
|
||||||
}
|
}
|
||||||
|
@ -175,7 +183,7 @@ void qmp_nbd_server_add(const char *device, bool has_name, const char *name,
|
||||||
writable = false;
|
writable = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
exp = nbd_export_new(bs, 0, -1, name, NULL, bitmap,
|
exp = nbd_export_new(bs, 0, len, name, NULL, bitmap,
|
||||||
writable ? 0 : NBD_FLAG_READ_ONLY,
|
writable ? 0 : NBD_FLAG_READ_ONLY,
|
||||||
NULL, false, on_eject_blk, errp);
|
NULL, false, on_eject_blk, errp);
|
||||||
if (!exp) {
|
if (!exp) {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2016-2017 Red Hat, Inc.
|
* Copyright (C) 2016-2019 Red Hat, Inc.
|
||||||
* Copyright (C) 2005 Anthony Liguori <anthony@codemonkey.ws>
|
* Copyright (C) 2005 Anthony Liguori <anthony@codemonkey.ws>
|
||||||
*
|
*
|
||||||
* Network Block Device
|
* Network Block Device
|
||||||
|
@ -263,26 +263,39 @@ struct NBDExportInfo {
|
||||||
bool request_sizes;
|
bool request_sizes;
|
||||||
char *x_dirty_bitmap;
|
char *x_dirty_bitmap;
|
||||||
|
|
||||||
|
/* Set by client before nbd_receive_negotiate(), or by server results
|
||||||
|
* during nbd_receive_export_list() */
|
||||||
|
char *name; /* must be non-NULL */
|
||||||
|
|
||||||
/* In-out fields, set by client before nbd_receive_negotiate() and
|
/* In-out fields, set by client before nbd_receive_negotiate() and
|
||||||
* updated by server results during nbd_receive_negotiate() */
|
* updated by server results during nbd_receive_negotiate() */
|
||||||
bool structured_reply;
|
bool structured_reply;
|
||||||
bool base_allocation; /* base:allocation context for NBD_CMD_BLOCK_STATUS */
|
bool base_allocation; /* base:allocation context for NBD_CMD_BLOCK_STATUS */
|
||||||
|
|
||||||
/* Set by server results during nbd_receive_negotiate() */
|
/* Set by server results during nbd_receive_negotiate() and
|
||||||
|
* nbd_receive_export_list() */
|
||||||
uint64_t size;
|
uint64_t size;
|
||||||
uint16_t flags;
|
uint16_t flags;
|
||||||
uint32_t min_block;
|
uint32_t min_block;
|
||||||
uint32_t opt_block;
|
uint32_t opt_block;
|
||||||
uint32_t max_block;
|
uint32_t max_block;
|
||||||
|
|
||||||
uint32_t meta_base_allocation_id;
|
uint32_t context_id;
|
||||||
|
|
||||||
|
/* Set by server results during nbd_receive_export_list() */
|
||||||
|
char *description;
|
||||||
|
int n_contexts;
|
||||||
|
char **contexts;
|
||||||
};
|
};
|
||||||
typedef struct NBDExportInfo NBDExportInfo;
|
typedef struct NBDExportInfo NBDExportInfo;
|
||||||
|
|
||||||
int nbd_receive_negotiate(QIOChannel *ioc, const char *name,
|
int nbd_receive_negotiate(QIOChannel *ioc, QCryptoTLSCreds *tlscreds,
|
||||||
QCryptoTLSCreds *tlscreds, const char *hostname,
|
const char *hostname, QIOChannel **outioc,
|
||||||
QIOChannel **outioc, NBDExportInfo *info,
|
NBDExportInfo *info, Error **errp);
|
||||||
Error **errp);
|
void nbd_free_export_list(NBDExportInfo *info, int count);
|
||||||
|
int nbd_receive_export_list(QIOChannel *ioc, QCryptoTLSCreds *tlscreds,
|
||||||
|
const char *hostname, NBDExportInfo **info,
|
||||||
|
Error **errp);
|
||||||
int nbd_init(int fd, QIOChannelSocket *sioc, NBDExportInfo *info,
|
int nbd_init(int fd, QIOChannelSocket *sioc, NBDExportInfo *info,
|
||||||
Error **errp);
|
Error **errp);
|
||||||
int nbd_send_request(QIOChannel *ioc, NBDRequest *request);
|
int nbd_send_request(QIOChannel *ioc, NBDRequest *request);
|
||||||
|
@ -294,8 +307,8 @@ int nbd_errno_to_system_errno(int err);
|
||||||
typedef struct NBDExport NBDExport;
|
typedef struct NBDExport NBDExport;
|
||||||
typedef struct NBDClient NBDClient;
|
typedef struct NBDClient NBDClient;
|
||||||
|
|
||||||
NBDExport *nbd_export_new(BlockDriverState *bs, off_t dev_offset, off_t size,
|
NBDExport *nbd_export_new(BlockDriverState *bs, uint64_t dev_offset,
|
||||||
const char *name, const char *description,
|
uint64_t size, const char *name, const char *desc,
|
||||||
const char *bitmap, uint16_t nbdflags,
|
const char *bitmap, uint16_t nbdflags,
|
||||||
void (*close)(NBDExport *), bool writethrough,
|
void (*close)(NBDExport *), bool writethrough,
|
||||||
BlockBackend *on_eject_blk, Error **errp);
|
BlockBackend *on_eject_blk, Error **errp);
|
||||||
|
|
787
nbd/client.c
787
nbd/client.c
File diff suppressed because it is too large
Load Diff
24
nbd/server.c
24
nbd/server.c
|
@ -77,8 +77,8 @@ struct NBDExport {
|
||||||
BlockBackend *blk;
|
BlockBackend *blk;
|
||||||
char *name;
|
char *name;
|
||||||
char *description;
|
char *description;
|
||||||
off_t dev_offset;
|
uint64_t dev_offset;
|
||||||
off_t size;
|
uint64_t size;
|
||||||
uint16_t nbdflags;
|
uint16_t nbdflags;
|
||||||
QTAILQ_HEAD(, NBDClient) clients;
|
QTAILQ_HEAD(, NBDClient) clients;
|
||||||
QTAILQ_ENTRY(NBDExport) next;
|
QTAILQ_ENTRY(NBDExport) next;
|
||||||
|
@ -1455,8 +1455,8 @@ static void nbd_eject_notifier(Notifier *n, void *data)
|
||||||
nbd_export_close(exp);
|
nbd_export_close(exp);
|
||||||
}
|
}
|
||||||
|
|
||||||
NBDExport *nbd_export_new(BlockDriverState *bs, off_t dev_offset, off_t size,
|
NBDExport *nbd_export_new(BlockDriverState *bs, uint64_t dev_offset,
|
||||||
const char *name, const char *description,
|
uint64_t size, const char *name, const char *desc,
|
||||||
const char *bitmap, uint16_t nbdflags,
|
const char *bitmap, uint16_t nbdflags,
|
||||||
void (*close)(NBDExport *), bool writethrough,
|
void (*close)(NBDExport *), bool writethrough,
|
||||||
BlockBackend *on_eject_blk, Error **errp)
|
BlockBackend *on_eject_blk, Error **errp)
|
||||||
|
@ -1495,17 +1495,13 @@ NBDExport *nbd_export_new(BlockDriverState *bs, off_t dev_offset, off_t size,
|
||||||
exp->refcount = 1;
|
exp->refcount = 1;
|
||||||
QTAILQ_INIT(&exp->clients);
|
QTAILQ_INIT(&exp->clients);
|
||||||
exp->blk = blk;
|
exp->blk = blk;
|
||||||
|
assert(dev_offset <= INT64_MAX);
|
||||||
exp->dev_offset = dev_offset;
|
exp->dev_offset = dev_offset;
|
||||||
exp->name = g_strdup(name);
|
exp->name = g_strdup(name);
|
||||||
exp->description = g_strdup(description);
|
exp->description = g_strdup(desc);
|
||||||
exp->nbdflags = nbdflags;
|
exp->nbdflags = nbdflags;
|
||||||
exp->size = size < 0 ? blk_getlength(blk) : size;
|
assert(size <= INT64_MAX - dev_offset);
|
||||||
if (exp->size < 0) {
|
exp->size = QEMU_ALIGN_DOWN(size, BDRV_SECTOR_SIZE);
|
||||||
error_setg_errno(errp, -exp->size,
|
|
||||||
"Failed to determine the NBD export's length");
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
exp->size -= exp->size % BDRV_SECTOR_SIZE;
|
|
||||||
|
|
||||||
if (bitmap) {
|
if (bitmap) {
|
||||||
BdrvDirtyBitmap *bm = NULL;
|
BdrvDirtyBitmap *bm = NULL;
|
||||||
|
@ -2134,10 +2130,10 @@ static int nbd_co_receive_request(NBDRequestData *req, NBDRequest *request,
|
||||||
return -EROFS;
|
return -EROFS;
|
||||||
}
|
}
|
||||||
if (request->from > client->exp->size ||
|
if (request->from > client->exp->size ||
|
||||||
request->from + request->len > client->exp->size) {
|
request->len > client->exp->size - request->from) {
|
||||||
error_setg(errp, "operation past EOF; From: %" PRIu64 ", Len: %" PRIu32
|
error_setg(errp, "operation past EOF; From: %" PRIu64 ", Len: %" PRIu32
|
||||||
", Size: %" PRIu64, request->from, request->len,
|
", Size: %" PRIu64, request->from, request->len,
|
||||||
(uint64_t)client->exp->size);
|
client->exp->size);
|
||||||
return (request->type == NBD_CMD_WRITE ||
|
return (request->type == NBD_CMD_WRITE ||
|
||||||
request->type == NBD_CMD_WRITE_ZEROES) ? -ENOSPC : -EINVAL;
|
request->type == NBD_CMD_WRITE_ZEROES) ? -ENOSPC : -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,20 +3,21 @@ nbd_send_option_request(uint32_t opt, const char *name, uint32_t len) "Sending o
|
||||||
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_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_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_unsup(uint32_t option, const char *name) "server doesn't understand request %" PRIu32 " (%s), attempting fallback"
|
||||||
nbd_opt_go_start(const char *name) "Attempting NBD_OPT_GO for export '%s'"
|
nbd_receive_list(const char *name, const char *desc) "export list includes '%s', description '%s'"
|
||||||
nbd_opt_go_success(void) "Export is good to go"
|
nbd_opt_info_go_start(const char *opt, const char *name) "Attempting %s for export '%s'"
|
||||||
nbd_opt_go_info_unknown(int info, const char *name) "Ignoring unknown info %d (%s)"
|
nbd_opt_info_go_success(const char *opt) "Export is ready after %s request"
|
||||||
nbd_opt_go_info_block_size(uint32_t minimum, uint32_t preferred, uint32_t maximum) "Block sizes are 0x%" PRIx32 ", 0x%" PRIx32 ", 0x%" PRIx32
|
nbd_opt_info_unknown(int info, const char *name) "Ignoring unknown info %d (%s)"
|
||||||
|
nbd_opt_info_block_size(uint32_t minimum, uint32_t preferred, uint32_t maximum) "Block sizes are 0x%" PRIx32 ", 0x%" PRIx32 ", 0x%" PRIx32
|
||||||
nbd_receive_query_exports_start(const char *wantname) "Querying export list for '%s'"
|
nbd_receive_query_exports_start(const char *wantname) "Querying export list for '%s'"
|
||||||
nbd_receive_query_exports_success(const char *wantname) "Found desired export name '%s'"
|
nbd_receive_query_exports_success(const char *wantname) "Found desired export name '%s'"
|
||||||
nbd_receive_starttls_new_client(void) "Setting up TLS"
|
nbd_receive_starttls_new_client(void) "Setting up TLS"
|
||||||
nbd_receive_starttls_tls_handshake(void) "Starting TLS handshake"
|
nbd_receive_starttls_tls_handshake(void) "Starting TLS handshake"
|
||||||
nbd_opt_meta_request(const char *context, const char *export) "Requesting to set meta context %s for export %s"
|
nbd_opt_meta_request(const char *optname, const char *context, const char *export) "Requesting %s %s for export %s"
|
||||||
nbd_opt_meta_reply(const char *context, uint32_t id) "Received mapping of context %s to id %" PRIu32
|
nbd_opt_meta_reply(const char *optname, const char *context, uint32_t id) "Received %s mapping of %s to id %" PRIu32
|
||||||
nbd_receive_negotiate(void *tlscreds, const char *hostname) "Receiving negotiation tlscreds=%p hostname=%s"
|
nbd_start_negotiate(void *tlscreds, const char *hostname) "Receiving negotiation tlscreds=%p hostname=%s"
|
||||||
nbd_receive_negotiate_magic(uint64_t magic) "Magic is 0x%" PRIx64
|
nbd_receive_negotiate_magic(uint64_t magic) "Magic is 0x%" PRIx64
|
||||||
nbd_receive_negotiate_server_flags(uint32_t globalflags) "Global flags are 0x%" PRIx32
|
nbd_receive_negotiate_server_flags(uint32_t globalflags) "Global flags are 0x%" PRIx32
|
||||||
nbd_receive_negotiate_default_name(void) "Using default NBD export name \"\""
|
nbd_receive_negotiate_name(const char *name) "Requesting NBD export name '%s'"
|
||||||
nbd_receive_negotiate_size_flags(uint64_t size, uint16_t flags) "Size is %" PRIu64 ", export flags 0x%" PRIx16
|
nbd_receive_negotiate_size_flags(uint64_t size, uint16_t flags) "Size is %" PRIu64 ", export flags 0x%" PRIx16
|
||||||
nbd_init_set_socket(void) "Setting NBD socket"
|
nbd_init_set_socket(void) "Setting NBD socket"
|
||||||
nbd_init_set_block_size(unsigned long block_size) "Setting block size to %lu"
|
nbd_init_set_block_size(unsigned long block_size) "Setting block size to %lu"
|
||||||
|
|
224
qemu-nbd.c
224
qemu-nbd.c
|
@ -76,7 +76,8 @@ static void usage(const char *name)
|
||||||
{
|
{
|
||||||
(printf) (
|
(printf) (
|
||||||
"Usage: %s [OPTIONS] FILE\n"
|
"Usage: %s [OPTIONS] FILE\n"
|
||||||
"QEMU Disk Network Block Device Server\n"
|
" or: %s -L [OPTIONS]\n"
|
||||||
|
"QEMU Disk Network Block Device Utility\n"
|
||||||
"\n"
|
"\n"
|
||||||
" -h, --help display this help and exit\n"
|
" -h, --help display this help and exit\n"
|
||||||
" -V, --version output version information and exit\n"
|
" -V, --version output version information and exit\n"
|
||||||
|
@ -98,6 +99,7 @@ static void usage(const char *name)
|
||||||
" -B, --bitmap=NAME expose a persistent dirty bitmap\n"
|
" -B, --bitmap=NAME expose a persistent dirty bitmap\n"
|
||||||
"\n"
|
"\n"
|
||||||
"General purpose options:\n"
|
"General purpose options:\n"
|
||||||
|
" -L, --list list exports available from another NBD server\n"
|
||||||
" --object type,id=ID,... define an object such as 'secret' for providing\n"
|
" --object type,id=ID,... define an object such as 'secret' for providing\n"
|
||||||
" passwords and/or encryption keys\n"
|
" passwords and/or encryption keys\n"
|
||||||
" --tls-creds=ID use id of an earlier --object to provide TLS\n"
|
" --tls-creds=ID use id of an earlier --object to provide TLS\n"
|
||||||
|
@ -131,7 +133,7 @@ static void usage(const char *name)
|
||||||
" --image-opts treat FILE as a full set of image options\n"
|
" --image-opts treat FILE as a full set of image options\n"
|
||||||
"\n"
|
"\n"
|
||||||
QEMU_HELP_BOTTOM "\n"
|
QEMU_HELP_BOTTOM "\n"
|
||||||
, name, NBD_DEFAULT_PORT, "DEVICE");
|
, name, name, NBD_DEFAULT_PORT, "DEVICE");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void version(const char *name)
|
static void version(const char *name)
|
||||||
|
@ -176,7 +178,7 @@ static void read_partition(uint8_t *p, struct partition_record *r)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int find_partition(BlockBackend *blk, int partition,
|
static int find_partition(BlockBackend *blk, int partition,
|
||||||
off_t *offset, off_t *size)
|
uint64_t *offset, uint64_t *size)
|
||||||
{
|
{
|
||||||
struct partition_record mbr[4];
|
struct partition_record mbr[4];
|
||||||
uint8_t data[MBR_SIZE];
|
uint8_t data[MBR_SIZE];
|
||||||
|
@ -243,6 +245,91 @@ static void termsig_handler(int signum)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int qemu_nbd_client_list(SocketAddress *saddr, QCryptoTLSCreds *tls,
|
||||||
|
const char *hostname)
|
||||||
|
{
|
||||||
|
int ret = EXIT_FAILURE;
|
||||||
|
int rc;
|
||||||
|
Error *err = NULL;
|
||||||
|
QIOChannelSocket *sioc;
|
||||||
|
NBDExportInfo *list;
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
sioc = qio_channel_socket_new();
|
||||||
|
if (qio_channel_socket_connect_sync(sioc, saddr, &err) < 0) {
|
||||||
|
error_report_err(err);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
rc = nbd_receive_export_list(QIO_CHANNEL(sioc), tls, hostname, &list,
|
||||||
|
&err);
|
||||||
|
if (rc < 0) {
|
||||||
|
if (err) {
|
||||||
|
error_report_err(err);
|
||||||
|
}
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
printf("exports available: %d\n", rc);
|
||||||
|
for (i = 0; i < rc; i++) {
|
||||||
|
printf(" export: '%s'\n", list[i].name);
|
||||||
|
if (list[i].description && *list[i].description) {
|
||||||
|
printf(" description: %s\n", list[i].description);
|
||||||
|
}
|
||||||
|
if (list[i].flags & NBD_FLAG_HAS_FLAGS) {
|
||||||
|
printf(" size: %" PRIu64 "\n", list[i].size);
|
||||||
|
printf(" flags: 0x%x (", list[i].flags);
|
||||||
|
if (list[i].flags & NBD_FLAG_READ_ONLY) {
|
||||||
|
printf(" readonly");
|
||||||
|
}
|
||||||
|
if (list[i].flags & NBD_FLAG_SEND_FLUSH) {
|
||||||
|
printf(" flush");
|
||||||
|
}
|
||||||
|
if (list[i].flags & NBD_FLAG_SEND_FUA) {
|
||||||
|
printf(" fua");
|
||||||
|
}
|
||||||
|
if (list[i].flags & NBD_FLAG_ROTATIONAL) {
|
||||||
|
printf(" rotational");
|
||||||
|
}
|
||||||
|
if (list[i].flags & NBD_FLAG_SEND_TRIM) {
|
||||||
|
printf(" trim");
|
||||||
|
}
|
||||||
|
if (list[i].flags & NBD_FLAG_SEND_WRITE_ZEROES) {
|
||||||
|
printf(" zeroes");
|
||||||
|
}
|
||||||
|
if (list[i].flags & NBD_FLAG_SEND_DF) {
|
||||||
|
printf(" df");
|
||||||
|
}
|
||||||
|
if (list[i].flags & NBD_FLAG_CAN_MULTI_CONN) {
|
||||||
|
printf(" multi");
|
||||||
|
}
|
||||||
|
if (list[i].flags & NBD_FLAG_SEND_RESIZE) {
|
||||||
|
printf(" resize");
|
||||||
|
}
|
||||||
|
if (list[i].flags & NBD_FLAG_SEND_CACHE) {
|
||||||
|
printf(" cache");
|
||||||
|
}
|
||||||
|
printf(" )\n");
|
||||||
|
}
|
||||||
|
if (list[i].min_block) {
|
||||||
|
printf(" min block: %u\n", list[i].min_block);
|
||||||
|
printf(" opt block: %u\n", list[i].opt_block);
|
||||||
|
printf(" max block: %u\n", list[i].max_block);
|
||||||
|
}
|
||||||
|
if (list[i].n_contexts) {
|
||||||
|
printf(" available meta contexts: %d\n", list[i].n_contexts);
|
||||||
|
for (j = 0; j < list[i].n_contexts; j++) {
|
||||||
|
printf(" %s\n", list[i].contexts[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nbd_free_export_list(list, rc);
|
||||||
|
|
||||||
|
ret = EXIT_SUCCESS;
|
||||||
|
out:
|
||||||
|
object_unref(OBJECT(sioc));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#if HAVE_NBD_DEVICE
|
#if HAVE_NBD_DEVICE
|
||||||
static void *show_parts(void *arg)
|
static void *show_parts(void *arg)
|
||||||
{
|
{
|
||||||
|
@ -264,7 +351,7 @@ static void *show_parts(void *arg)
|
||||||
static void *nbd_client_thread(void *arg)
|
static void *nbd_client_thread(void *arg)
|
||||||
{
|
{
|
||||||
char *device = arg;
|
char *device = arg;
|
||||||
NBDExportInfo info = { .request_sizes = false, };
|
NBDExportInfo info = { .request_sizes = false, .name = g_strdup("") };
|
||||||
QIOChannelSocket *sioc;
|
QIOChannelSocket *sioc;
|
||||||
int fd;
|
int fd;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -279,7 +366,7 @@ static void *nbd_client_thread(void *arg)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = nbd_receive_negotiate(QIO_CHANNEL(sioc), NULL,
|
ret = nbd_receive_negotiate(QIO_CHANNEL(sioc),
|
||||||
NULL, NULL, NULL, &info, &local_error);
|
NULL, NULL, NULL, &info, &local_error);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
if (local_error) {
|
if (local_error) {
|
||||||
|
@ -318,6 +405,7 @@ static void *nbd_client_thread(void *arg)
|
||||||
}
|
}
|
||||||
close(fd);
|
close(fd);
|
||||||
object_unref(OBJECT(sioc));
|
object_unref(OBJECT(sioc));
|
||||||
|
g_free(info.name);
|
||||||
kill(getpid(), SIGTERM);
|
kill(getpid(), SIGTERM);
|
||||||
return (void *) EXIT_SUCCESS;
|
return (void *) EXIT_SUCCESS;
|
||||||
|
|
||||||
|
@ -326,6 +414,7 @@ out_fd:
|
||||||
out_socket:
|
out_socket:
|
||||||
object_unref(OBJECT(sioc));
|
object_unref(OBJECT(sioc));
|
||||||
out:
|
out:
|
||||||
|
g_free(info.name);
|
||||||
kill(getpid(), SIGTERM);
|
kill(getpid(), SIGTERM);
|
||||||
return (void *) EXIT_FAILURE;
|
return (void *) EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
@ -423,7 +512,8 @@ static QemuOptsList qemu_object_opts = {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static QCryptoTLSCreds *nbd_get_tls_creds(const char *id, Error **errp)
|
static QCryptoTLSCreds *nbd_get_tls_creds(const char *id, bool list,
|
||||||
|
Error **errp)
|
||||||
{
|
{
|
||||||
Object *obj;
|
Object *obj;
|
||||||
QCryptoTLSCreds *creds;
|
QCryptoTLSCreds *creds;
|
||||||
|
@ -443,10 +533,18 @@ static QCryptoTLSCreds *nbd_get_tls_creds(const char *id, Error **errp)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (creds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
|
if (list) {
|
||||||
error_setg(errp,
|
if (creds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT) {
|
||||||
"Expecting TLS credentials with a server endpoint");
|
error_setg(errp,
|
||||||
return NULL;
|
"Expecting TLS credentials with a client endpoint");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (creds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
|
||||||
|
error_setg(errp,
|
||||||
|
"Expecting TLS credentials with a server endpoint");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
object_ref(obj);
|
object_ref(obj);
|
||||||
return creds;
|
return creds;
|
||||||
|
@ -469,7 +567,8 @@ static void setup_address_and_port(const char **address, const char **port)
|
||||||
static const char *socket_activation_validate_opts(const char *device,
|
static const char *socket_activation_validate_opts(const char *device,
|
||||||
const char *sockpath,
|
const char *sockpath,
|
||||||
const char *address,
|
const char *address,
|
||||||
const char *port)
|
const char *port,
|
||||||
|
bool list)
|
||||||
{
|
{
|
||||||
if (device != NULL) {
|
if (device != NULL) {
|
||||||
return "NBD device can't be set when using socket activation";
|
return "NBD device can't be set when using socket activation";
|
||||||
|
@ -487,6 +586,10 @@ static const char *socket_activation_validate_opts(const char *device,
|
||||||
return "TCP port number can't be set when using socket activation";
|
return "TCP port number can't be set when using socket activation";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (list) {
|
||||||
|
return "List mode is incompatible with socket activation";
|
||||||
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -500,17 +603,17 @@ int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
BlockBackend *blk;
|
BlockBackend *blk;
|
||||||
BlockDriverState *bs;
|
BlockDriverState *bs;
|
||||||
off_t dev_offset = 0;
|
uint64_t dev_offset = 0;
|
||||||
uint16_t nbdflags = 0;
|
uint16_t nbdflags = 0;
|
||||||
bool disconnect = false;
|
bool disconnect = false;
|
||||||
const char *bindto = NULL;
|
const char *bindto = NULL;
|
||||||
const char *port = NULL;
|
const char *port = NULL;
|
||||||
char *sockpath = NULL;
|
char *sockpath = NULL;
|
||||||
char *device = NULL;
|
char *device = NULL;
|
||||||
off_t fd_size;
|
int64_t fd_size;
|
||||||
QemuOpts *sn_opts = NULL;
|
QemuOpts *sn_opts = NULL;
|
||||||
const char *sn_id_or_name = NULL;
|
const char *sn_id_or_name = NULL;
|
||||||
const char *sopt = "hVb:o:p:rsnP:c:dvk:e:f:tl:x:T:D:B:";
|
const char *sopt = "hVb:o:p:rsnP:c:dvk:e:f:tl:x:T:D:B:L";
|
||||||
struct option lopt[] = {
|
struct option lopt[] = {
|
||||||
{ "help", no_argument, NULL, 'h' },
|
{ "help", no_argument, NULL, 'h' },
|
||||||
{ "version", no_argument, NULL, 'V' },
|
{ "version", no_argument, NULL, 'V' },
|
||||||
|
@ -523,6 +626,7 @@ int main(int argc, char **argv)
|
||||||
{ "bitmap", required_argument, NULL, 'B' },
|
{ "bitmap", required_argument, NULL, 'B' },
|
||||||
{ "connect", required_argument, NULL, 'c' },
|
{ "connect", required_argument, NULL, 'c' },
|
||||||
{ "disconnect", no_argument, NULL, 'd' },
|
{ "disconnect", no_argument, NULL, 'd' },
|
||||||
|
{ "list", no_argument, NULL, 'L' },
|
||||||
{ "snapshot", no_argument, NULL, 's' },
|
{ "snapshot", no_argument, NULL, 's' },
|
||||||
{ "load-snapshot", required_argument, NULL, 'l' },
|
{ "load-snapshot", required_argument, NULL, 'l' },
|
||||||
{ "nocache", no_argument, NULL, 'n' },
|
{ "nocache", no_argument, NULL, 'n' },
|
||||||
|
@ -546,9 +650,8 @@ int main(int argc, char **argv)
|
||||||
};
|
};
|
||||||
int ch;
|
int ch;
|
||||||
int opt_ind = 0;
|
int opt_ind = 0;
|
||||||
char *end;
|
|
||||||
int flags = BDRV_O_RDWR;
|
int flags = BDRV_O_RDWR;
|
||||||
int partition = -1;
|
int partition = 0;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
bool seen_cache = false;
|
bool seen_cache = false;
|
||||||
bool seen_discard = false;
|
bool seen_discard = false;
|
||||||
|
@ -558,7 +661,7 @@ int main(int argc, char **argv)
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
BlockdevDetectZeroesOptions detect_zeroes = BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF;
|
BlockdevDetectZeroesOptions detect_zeroes = BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF;
|
||||||
QDict *options = NULL;
|
QDict *options = NULL;
|
||||||
const char *export_name = ""; /* Default export name */
|
const char *export_name = NULL; /* defaults to "" later for server mode */
|
||||||
const char *export_description = NULL;
|
const char *export_description = NULL;
|
||||||
const char *bitmap = NULL;
|
const char *bitmap = NULL;
|
||||||
const char *tlscredsid = NULL;
|
const char *tlscredsid = NULL;
|
||||||
|
@ -566,6 +669,7 @@ int main(int argc, char **argv)
|
||||||
bool writethrough = true;
|
bool writethrough = true;
|
||||||
char *trace_file = NULL;
|
char *trace_file = NULL;
|
||||||
bool fork_process = false;
|
bool fork_process = false;
|
||||||
|
bool list = false;
|
||||||
int old_stderr = -1;
|
int old_stderr = -1;
|
||||||
unsigned socket_activation;
|
unsigned socket_activation;
|
||||||
|
|
||||||
|
@ -660,13 +764,8 @@ int main(int argc, char **argv)
|
||||||
port = optarg;
|
port = optarg;
|
||||||
break;
|
break;
|
||||||
case 'o':
|
case 'o':
|
||||||
dev_offset = strtoll (optarg, &end, 0);
|
if (qemu_strtou64(optarg, NULL, 0, &dev_offset) < 0) {
|
||||||
if (*end) {
|
error_report("Invalid offset '%s'", optarg);
|
||||||
error_report("Invalid offset `%s'", optarg);
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
if (dev_offset < 0) {
|
|
||||||
error_report("Offset must be positive `%s'", optarg);
|
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -688,13 +787,9 @@ int main(int argc, char **argv)
|
||||||
flags &= ~BDRV_O_RDWR;
|
flags &= ~BDRV_O_RDWR;
|
||||||
break;
|
break;
|
||||||
case 'P':
|
case 'P':
|
||||||
partition = strtol(optarg, &end, 0);
|
if (qemu_strtoi(optarg, NULL, 0, &partition) < 0 ||
|
||||||
if (*end) {
|
partition < 1 || partition > 8) {
|
||||||
error_report("Invalid partition `%s'", optarg);
|
error_report("Invalid partition '%s'", optarg);
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
if (partition < 1 || partition > 8) {
|
|
||||||
error_report("Invalid partition %d", partition);
|
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -715,15 +810,11 @@ int main(int argc, char **argv)
|
||||||
device = optarg;
|
device = optarg;
|
||||||
break;
|
break;
|
||||||
case 'e':
|
case 'e':
|
||||||
shared = strtol(optarg, &end, 0);
|
if (qemu_strtoi(optarg, NULL, 0, &shared) < 0 ||
|
||||||
if (*end) {
|
shared < 1) {
|
||||||
error_report("Invalid shared device number '%s'", optarg);
|
error_report("Invalid shared device number '%s'", optarg);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
if (shared < 1) {
|
|
||||||
error_report("Shared device number must be greater than 0");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case 'f':
|
case 'f':
|
||||||
fmt = optarg;
|
fmt = optarg;
|
||||||
|
@ -772,13 +863,33 @@ int main(int argc, char **argv)
|
||||||
case QEMU_NBD_OPT_FORK:
|
case QEMU_NBD_OPT_FORK:
|
||||||
fork_process = true;
|
fork_process = true;
|
||||||
break;
|
break;
|
||||||
|
case 'L':
|
||||||
|
list = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((argc - optind) != 1) {
|
if (list) {
|
||||||
|
if (argc != optind) {
|
||||||
|
error_report("List mode is incompatible with a file name");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
if (export_name || export_description || dev_offset || partition ||
|
||||||
|
device || disconnect || fmt || sn_id_or_name || bitmap ||
|
||||||
|
seen_aio || seen_discard || seen_cache) {
|
||||||
|
error_report("List mode is incompatible with per-device settings");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
if (fork_process) {
|
||||||
|
error_report("List mode is incompatible with forking");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
} else if ((argc - optind) != 1) {
|
||||||
error_report("Invalid number of arguments");
|
error_report("Invalid number of arguments");
|
||||||
error_printf("Try `%s --help' for more information.\n", argv[0]);
|
error_printf("Try `%s --help' for more information.\n", argv[0]);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
|
} else if (!export_name) {
|
||||||
|
export_name = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
qemu_opts_foreach(&qemu_object_opts,
|
qemu_opts_foreach(&qemu_object_opts,
|
||||||
|
@ -797,7 +908,8 @@ int main(int argc, char **argv)
|
||||||
} else {
|
} else {
|
||||||
/* Using socket activation - check user didn't use -p etc. */
|
/* Using socket activation - check user didn't use -p etc. */
|
||||||
const char *err_msg = socket_activation_validate_opts(device, sockpath,
|
const char *err_msg = socket_activation_validate_opts(device, sockpath,
|
||||||
bindto, port);
|
bindto, port,
|
||||||
|
list);
|
||||||
if (err_msg != NULL) {
|
if (err_msg != NULL) {
|
||||||
error_report("%s", err_msg);
|
error_report("%s", err_msg);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
|
@ -820,7 +932,7 @@ int main(int argc, char **argv)
|
||||||
error_report("TLS is not supported with a host device");
|
error_report("TLS is not supported with a host device");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
tlscreds = nbd_get_tls_creds(tlscredsid, &local_err);
|
tlscreds = nbd_get_tls_creds(tlscredsid, list, &local_err);
|
||||||
if (local_err) {
|
if (local_err) {
|
||||||
error_report("Failed to get TLS creds %s",
|
error_report("Failed to get TLS creds %s",
|
||||||
error_get_pretty(local_err));
|
error_get_pretty(local_err));
|
||||||
|
@ -828,6 +940,11 @@ int main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (list) {
|
||||||
|
saddr = nbd_build_socket_address(sockpath, bindto, port);
|
||||||
|
return qemu_nbd_client_list(saddr, tlscreds, bindto);
|
||||||
|
}
|
||||||
|
|
||||||
#if !HAVE_NBD_DEVICE
|
#if !HAVE_NBD_DEVICE
|
||||||
if (disconnect || device) {
|
if (disconnect || device) {
|
||||||
error_report("Kernel /dev/nbdN support not available");
|
error_report("Kernel /dev/nbdN support not available");
|
||||||
|
@ -1005,20 +1122,37 @@ int main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dev_offset >= fd_size) {
|
if (dev_offset >= fd_size) {
|
||||||
error_report("Offset (%lld) has to be smaller than the image size "
|
error_report("Offset (%" PRIu64 ") has to be smaller than the image "
|
||||||
"(%lld)",
|
"size (%" PRId64 ")", dev_offset, fd_size);
|
||||||
(long long int)dev_offset, (long long int)fd_size);
|
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
fd_size -= dev_offset;
|
fd_size -= dev_offset;
|
||||||
|
|
||||||
if (partition != -1) {
|
if (partition) {
|
||||||
ret = find_partition(blk, partition, &dev_offset, &fd_size);
|
uint64_t limit;
|
||||||
|
|
||||||
|
if (dev_offset) {
|
||||||
|
error_report("Cannot request partition and offset together");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
ret = find_partition(blk, partition, &dev_offset, &limit);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_report("Could not find partition %d: %s", partition,
|
error_report("Could not find partition %d: %s", partition,
|
||||||
strerror(-ret));
|
strerror(-ret));
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
* MBR partition limits are (32-bit << 9); this assert lets
|
||||||
|
* the compiler know that we can't overflow 64 bits.
|
||||||
|
*/
|
||||||
|
assert(dev_offset + limit >= dev_offset);
|
||||||
|
if (dev_offset + limit > fd_size) {
|
||||||
|
error_report("Discovered partition %d at offset %" PRIu64
|
||||||
|
" size %" PRIu64 ", but size exceeds file length %"
|
||||||
|
PRId64, partition, dev_offset, limit, fd_size);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
fd_size = limit;
|
||||||
}
|
}
|
||||||
|
|
||||||
export = nbd_export_new(bs, dev_offset, fd_size, export_name,
|
export = nbd_export_new(bs, dev_offset, fd_size, export_name,
|
||||||
|
|
119
qemu-nbd.texi
119
qemu-nbd.texi
|
@ -2,6 +2,8 @@
|
||||||
@c man begin SYNOPSIS
|
@c man begin SYNOPSIS
|
||||||
@command{qemu-nbd} [OPTION]... @var{filename}
|
@command{qemu-nbd} [OPTION]... @var{filename}
|
||||||
|
|
||||||
|
@command{qemu-nbd} @option{-L} [OPTION]...
|
||||||
|
|
||||||
@command{qemu-nbd} @option{-d} @var{dev}
|
@command{qemu-nbd} @option{-d} @var{dev}
|
||||||
@c man end
|
@c man end
|
||||||
@end example
|
@end example
|
||||||
|
@ -10,11 +12,19 @@
|
||||||
|
|
||||||
Export a QEMU disk image using the NBD protocol.
|
Export a QEMU disk image using the NBD protocol.
|
||||||
|
|
||||||
|
Other uses:
|
||||||
|
@itemize
|
||||||
|
@item
|
||||||
|
Bind a /dev/nbdX block device to a QEMU server (on Linux).
|
||||||
|
@item
|
||||||
|
As a client to query exports of a remote NBD server.
|
||||||
|
@end itemize
|
||||||
|
|
||||||
@c man end
|
@c man end
|
||||||
|
|
||||||
@c man begin OPTIONS
|
@c man begin OPTIONS
|
||||||
@var{filename} is a disk image filename, or a set of block
|
@var{filename} is a disk image filename, or a set of block
|
||||||
driver options if @var{--image-opts} is specified.
|
driver options if @option{--image-opts} is specified.
|
||||||
|
|
||||||
@var{dev} is an NBD device.
|
@var{dev} is an NBD device.
|
||||||
|
|
||||||
|
@ -25,26 +35,29 @@ See the @code{qemu(1)} manual page for full details of the properties
|
||||||
supported. The common object types that it makes sense to define are the
|
supported. The common object types that it makes sense to define are the
|
||||||
@code{secret} object, which is used to supply passwords and/or encryption
|
@code{secret} object, which is used to supply passwords and/or encryption
|
||||||
keys, and the @code{tls-creds} object, which is used to supply TLS
|
keys, and the @code{tls-creds} object, which is used to supply TLS
|
||||||
credentials for the qemu-nbd server.
|
credentials for the qemu-nbd server or client.
|
||||||
@item -p, --port=@var{port}
|
@item -p, --port=@var{port}
|
||||||
The TCP port to listen on (default @samp{10809})
|
The TCP port to listen on as a server, or connect to as a client
|
||||||
|
(default @samp{10809}).
|
||||||
@item -o, --offset=@var{offset}
|
@item -o, --offset=@var{offset}
|
||||||
The offset into the image
|
The offset into the image.
|
||||||
@item -b, --bind=@var{iface}
|
@item -b, --bind=@var{iface}
|
||||||
The interface to bind to (default @samp{0.0.0.0})
|
The interface to bind to as a server, or connect to as a client
|
||||||
|
(default @samp{0.0.0.0}).
|
||||||
@item -k, --socket=@var{path}
|
@item -k, --socket=@var{path}
|
||||||
Use a unix socket with path @var{path}
|
Use a unix socket with path @var{path}.
|
||||||
@item --image-opts
|
@item --image-opts
|
||||||
Treat @var{filename} as a set of image options, instead of a plain
|
Treat @var{filename} as a set of image options, instead of a plain
|
||||||
filename. If this flag is specified, the @var{-f} flag should
|
filename. If this flag is specified, the @var{-f} flag should
|
||||||
not be used, instead the '@code{format=}' option should be set.
|
not be used, instead the '@code{format=}' option should be set.
|
||||||
@item -f, --format=@var{fmt}
|
@item -f, --format=@var{fmt}
|
||||||
Force the use of the block driver for format @var{fmt} instead of
|
Force the use of the block driver for format @var{fmt} instead of
|
||||||
auto-detecting
|
auto-detecting.
|
||||||
@item -r, --read-only
|
@item -r, --read-only
|
||||||
Export the disk as read-only
|
Export the disk as read-only.
|
||||||
@item -P, --partition=@var{num}
|
@item -P, --partition=@var{num}
|
||||||
Only expose partition @var{num}
|
Only expose MBR partition @var{num}. Understands physical partitions
|
||||||
|
1-4 and logical partitions 5-8.
|
||||||
@item -B, --bitmap=@var{name}
|
@item -B, --bitmap=@var{name}
|
||||||
If @var{filename} has a qcow2 persistent bitmap @var{name}, expose
|
If @var{filename} has a qcow2 persistent bitmap @var{name}, expose
|
||||||
that bitmap via the ``qemu:dirty-bitmap:@var{name}'' context
|
that bitmap via the ``qemu:dirty-bitmap:@var{name}'' context
|
||||||
|
@ -52,7 +65,7 @@ accessible through NBD_OPT_SET_META_CONTEXT.
|
||||||
@item -s, --snapshot
|
@item -s, --snapshot
|
||||||
Use @var{filename} as an external snapshot, create a temporary
|
Use @var{filename} as an external snapshot, create a temporary
|
||||||
file with backing_file=@var{filename}, redirect the write to
|
file with backing_file=@var{filename}, redirect the write to
|
||||||
the temporary one
|
the temporary one.
|
||||||
@item -l, --load-snapshot=@var{snapshot_param}
|
@item -l, --load-snapshot=@var{snapshot_param}
|
||||||
Load an internal snapshot inside @var{filename} and export it
|
Load an internal snapshot inside @var{filename} and export it
|
||||||
as an read-only device, @var{snapshot_param} format is
|
as an read-only device, @var{snapshot_param} format is
|
||||||
|
@ -76,31 +89,38 @@ driver-specific optimized zero write commands. @var{detect-zeroes} is one of
|
||||||
converts a zero write to an unmap operation and can only be used if
|
converts a zero write to an unmap operation and can only be used if
|
||||||
@var{discard} is set to @samp{unmap}. The default is @samp{off}.
|
@var{discard} is set to @samp{unmap}. The default is @samp{off}.
|
||||||
@item -c, --connect=@var{dev}
|
@item -c, --connect=@var{dev}
|
||||||
Connect @var{filename} to NBD device @var{dev}
|
Connect @var{filename} to NBD device @var{dev} (Linux only).
|
||||||
@item -d, --disconnect
|
@item -d, --disconnect
|
||||||
Disconnect the device @var{dev}
|
Disconnect the device @var{dev} (Linux only).
|
||||||
@item -e, --shared=@var{num}
|
@item -e, --shared=@var{num}
|
||||||
Allow up to @var{num} clients to share the device (default @samp{1})
|
Allow up to @var{num} clients to share the device (default
|
||||||
|
@samp{1}). Safe for readers, but for now, consistency is not
|
||||||
|
guaranteed between multiple writers.
|
||||||
@item -t, --persistent
|
@item -t, --persistent
|
||||||
Don't exit on the last connection
|
Don't exit on the last connection.
|
||||||
@item -x, --export-name=@var{name}
|
@item -x, --export-name=@var{name}
|
||||||
Set the NBD volume export name. This switches the server to use
|
Set the NBD volume export name (default of a zero-length string).
|
||||||
the new style NBD protocol negotiation
|
|
||||||
@item -D, --description=@var{description}
|
@item -D, --description=@var{description}
|
||||||
Set the NBD volume export description, as a human-readable
|
Set the NBD volume export description, as a human-readable
|
||||||
string. Requires the use of @option{-x}
|
string.
|
||||||
|
@item -L, --list
|
||||||
|
Connect as a client and list all details about the exports exposed by
|
||||||
|
a remote NBD server. This enables list mode, and is incompatible
|
||||||
|
with options that change behavior related to a specific export (such as
|
||||||
|
@option{--export-name}, @option{--offset}, ...).
|
||||||
@item --tls-creds=ID
|
@item --tls-creds=ID
|
||||||
Enable mandatory TLS encryption for the server by setting the ID
|
Enable mandatory TLS encryption for the server by setting the ID
|
||||||
of the TLS credentials object previously created with the --object
|
of the TLS credentials object previously created with the --object
|
||||||
option.
|
option; or provide the credentials needed for connecting as a client
|
||||||
|
in list mode.
|
||||||
@item --fork
|
@item --fork
|
||||||
Fork off the server process and exit the parent once the server is running.
|
Fork off the server process and exit the parent once the server is running.
|
||||||
@item -v, --verbose
|
@item -v, --verbose
|
||||||
Display extra debugging information
|
Display extra debugging information.
|
||||||
@item -h, --help
|
@item -h, --help
|
||||||
Display this help and exit
|
Display this help and exit.
|
||||||
@item -V, --version
|
@item -V, --version
|
||||||
Display version information and exit
|
Display version information and exit.
|
||||||
@item -T, --trace [[enable=]@var{pattern}][,events=@var{file}][,file=@var{file}]
|
@item -T, --trace [[enable=]@var{pattern}][,events=@var{file}][,file=@var{file}]
|
||||||
@findex --trace
|
@findex --trace
|
||||||
@include qemu-option-trace.texi
|
@include qemu-option-trace.texi
|
||||||
|
@ -108,6 +128,63 @@ Display version information and exit
|
||||||
|
|
||||||
@c man end
|
@c man end
|
||||||
|
|
||||||
|
@c man begin EXAMPLES
|
||||||
|
Start a server listening on port 10809 that exposes only the
|
||||||
|
guest-visible contents of a qcow2 file, with no TLS encryption, and
|
||||||
|
with the default export name (an empty string). The command is
|
||||||
|
one-shot, and will block until the first successful client
|
||||||
|
disconnects:
|
||||||
|
|
||||||
|
@example
|
||||||
|
qemu-nbd -f qcow2 file.qcow2
|
||||||
|
@end example
|
||||||
|
|
||||||
|
Start a long-running server listening with encryption on port 10810,
|
||||||
|
and require clients to have a correct X.509 certificate to connect to
|
||||||
|
a 1 megabyte subset of a raw file, using the export name 'subset':
|
||||||
|
|
||||||
|
@example
|
||||||
|
qemu-nbd \
|
||||||
|
--object tls-creds-x509,id=tls0,endpoint=server,dir=/path/to/qemutls \
|
||||||
|
--tls-creds tls0 -t -x subset -p 10810 \
|
||||||
|
--image-opts driver=raw,offset=1M,size=1M,file.driver=file,file.filename=file.raw
|
||||||
|
@end example
|
||||||
|
|
||||||
|
Serve a read-only copy of just the first MBR partition of a guest
|
||||||
|
image over a Unix socket with as many as 5 simultaneous readers, with
|
||||||
|
a persistent process forked as a daemon:
|
||||||
|
|
||||||
|
@example
|
||||||
|
qemu-nbd --fork --persistent --shared=5 --socket=/path/to/sock \
|
||||||
|
--partition=1 --read-only --format=qcow2 file.qcow2
|
||||||
|
@end example
|
||||||
|
|
||||||
|
Expose the guest-visible contents of a qcow2 file via a block device
|
||||||
|
/dev/nbd0 (and possibly creating /dev/nbd0p1 and friends for
|
||||||
|
partitions found within), then disconnect the device when done.
|
||||||
|
Access to bind qemu-nbd to an /dev/nbd device generally requires root
|
||||||
|
privileges, and may also require the execution of @code{modprobe nbd}
|
||||||
|
to enable the kernel NBD client module. @emph{CAUTION}: Do not use
|
||||||
|
this method to mount filesystems from an untrusted guest image - a
|
||||||
|
malicious guest may have prepared the image to attempt to trigger
|
||||||
|
kernel bugs in partition probing or file system mounting.
|
||||||
|
|
||||||
|
@example
|
||||||
|
qemu-nbd -c /dev/nbd0 -f qcow2 file.qcow2
|
||||||
|
qemu-nbd -d /dev/nbd0
|
||||||
|
@end example
|
||||||
|
|
||||||
|
Query a remote server to see details about what export(s) it is
|
||||||
|
serving on port 10809, and authenticating via PSK:
|
||||||
|
|
||||||
|
@example
|
||||||
|
qemu-nbd \
|
||||||
|
--object tls-creds-psk,id=tls0,dir=/tmp/keys,username=eblake,endpoint=client \
|
||||||
|
--tls-creds tls0 -L -b remote.example.com
|
||||||
|
@end example
|
||||||
|
|
||||||
|
@c man end
|
||||||
|
|
||||||
@ignore
|
@ignore
|
||||||
|
|
||||||
@setfilename qemu-nbd
|
@setfilename qemu-nbd
|
||||||
|
|
|
@ -398,7 +398,7 @@ $sects{NAME} = "$fn \- $tl\n";
|
||||||
$sects{FOOTNOTES} .= "=back\n" if exists $sects{FOOTNOTES};
|
$sects{FOOTNOTES} .= "=back\n" if exists $sects{FOOTNOTES};
|
||||||
|
|
||||||
for $sect (qw(NAME SYNOPSIS DESCRIPTION OPTIONS ENVIRONMENT FILES
|
for $sect (qw(NAME SYNOPSIS DESCRIPTION OPTIONS ENVIRONMENT FILES
|
||||||
BUGS NOTES FOOTNOTES SEEALSO AUTHOR COPYRIGHT)) {
|
BUGS NOTES FOOTNOTES EXAMPLES SEEALSO AUTHOR COPYRIGHT)) {
|
||||||
if(exists $sects{$sect}) {
|
if(exists $sects{$sect}) {
|
||||||
$head = $sect;
|
$head = $sect;
|
||||||
$head =~ s/SEEALSO/SEE ALSO/;
|
$head =~ s/SEEALSO/SEE ALSO/;
|
||||||
|
|
|
@ -127,6 +127,7 @@ _send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-start",
|
||||||
_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-start",
|
_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-start",
|
||||||
"arguments":{"addr":{"type":"unix",
|
"arguments":{"addr":{"type":"unix",
|
||||||
"data":{"path":"'"$TEST_DIR/nbd"1'"}}}}' "error" # Attempt second server
|
"data":{"path":"'"$TEST_DIR/nbd"1'"}}}}' "error" # Attempt second server
|
||||||
|
$QEMU_NBD_PROG -L -k "$TEST_DIR/nbd"
|
||||||
_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-add",
|
_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-add",
|
||||||
"arguments":{"device":"n", "bitmap":"b"}}' "return"
|
"arguments":{"device":"n", "bitmap":"b"}}' "return"
|
||||||
_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-add",
|
_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-add",
|
||||||
|
@ -142,6 +143,7 @@ _send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-add",
|
||||||
_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-add",
|
_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-add",
|
||||||
"arguments":{"device":"n", "name":"n2", "writable":true,
|
"arguments":{"device":"n", "name":"n2", "writable":true,
|
||||||
"bitmap":"b2"}}' "return"
|
"bitmap":"b2"}}' "return"
|
||||||
|
$QEMU_NBD_PROG -L -k "$TEST_DIR/nbd"
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo "=== Contrast normal status to large granularity dirty-bitmap ==="
|
echo "=== Contrast normal status to large granularity dirty-bitmap ==="
|
||||||
|
|
|
@ -30,12 +30,32 @@ wrote 2097152/2097152 bytes at offset 2097152
|
||||||
{"error": {"class": "GenericError", "desc": "NBD server not running"}}
|
{"error": {"class": "GenericError", "desc": "NBD server not running"}}
|
||||||
{"return": {}}
|
{"return": {}}
|
||||||
{"error": {"class": "GenericError", "desc": "NBD server already running"}}
|
{"error": {"class": "GenericError", "desc": "NBD server already running"}}
|
||||||
|
exports available: 0
|
||||||
{"return": {}}
|
{"return": {}}
|
||||||
{"error": {"class": "GenericError", "desc": "Cannot find device=nosuch nor node_name=nosuch"}}
|
{"error": {"class": "GenericError", "desc": "Cannot find device=nosuch nor node_name=nosuch"}}
|
||||||
{"error": {"class": "GenericError", "desc": "NBD server already has export named 'n'"}}
|
{"error": {"class": "GenericError", "desc": "NBD server already has export named 'n'"}}
|
||||||
{"error": {"class": "GenericError", "desc": "Enabled bitmap 'b2' incompatible with readonly export"}}
|
{"error": {"class": "GenericError", "desc": "Enabled bitmap 'b2' incompatible with readonly export"}}
|
||||||
{"error": {"class": "GenericError", "desc": "Bitmap 'b3' is not found"}}
|
{"error": {"class": "GenericError", "desc": "Bitmap 'b3' is not found"}}
|
||||||
{"return": {}}
|
{"return": {}}
|
||||||
|
exports available: 2
|
||||||
|
export: 'n'
|
||||||
|
size: 4194304
|
||||||
|
flags: 0x4ef ( readonly flush fua trim zeroes df cache )
|
||||||
|
min block: 512
|
||||||
|
opt block: 4096
|
||||||
|
max block: 33554432
|
||||||
|
available meta contexts: 2
|
||||||
|
base:allocation
|
||||||
|
qemu:dirty-bitmap:b
|
||||||
|
export: 'n2'
|
||||||
|
size: 4194304
|
||||||
|
flags: 0x4ed ( flush fua trim zeroes df cache )
|
||||||
|
min block: 512
|
||||||
|
opt block: 4096
|
||||||
|
max block: 33554432
|
||||||
|
available meta contexts: 2
|
||||||
|
base:allocation
|
||||||
|
qemu:dirty-bitmap:b2
|
||||||
|
|
||||||
=== Contrast normal status to large granularity dirty-bitmap ===
|
=== Contrast normal status to large granularity dirty-bitmap ===
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
#
|
#
|
||||||
# Test NBD TLS certificate / authorization integration
|
# Test NBD TLS certificate / authorization integration
|
||||||
#
|
#
|
||||||
# Copyright (C) 2018 Red Hat, Inc.
|
# Copyright (C) 2018-2019 Red Hat, Inc.
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify
|
# This program is free software; you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
@ -30,6 +30,7 @@ _cleanup()
|
||||||
{
|
{
|
||||||
nbd_server_stop
|
nbd_server_stop
|
||||||
_cleanup_test_img
|
_cleanup_test_img
|
||||||
|
rm -f "$TEST_DIR/server.log"
|
||||||
tls_x509_cleanup
|
tls_x509_cleanup
|
||||||
}
|
}
|
||||||
trap "_cleanup; exit \$status" 0 1 2 3 15
|
trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||||
|
@ -66,12 +67,14 @@ $QEMU_IO -c 'w -P 0x11 1m 1m' "$TEST_IMG" | _filter_qemu_io
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo "== check TLS client to plain server fails =="
|
echo "== check TLS client to plain server fails =="
|
||||||
nbd_server_start_tcp_socket -f $IMGFMT "$TEST_IMG"
|
nbd_server_start_tcp_socket -f $IMGFMT "$TEST_IMG" 2> "$TEST_DIR/server.log"
|
||||||
|
|
||||||
$QEMU_IMG info --image-opts \
|
obj=tls-creds-x509,dir=${tls_dir}/client1,endpoint=client,id=tls0
|
||||||
--object tls-creds-x509,dir=${tls_dir}/client1,endpoint=client,id=tls0 \
|
$QEMU_IMG info --image-opts --object $obj \
|
||||||
driver=nbd,host=$nbd_tcp_addr,port=$nbd_tcp_port,tls-creds=tls0 \
|
driver=nbd,host=$nbd_tcp_addr,port=$nbd_tcp_port,tls-creds=tls0 \
|
||||||
2>&1 | sed "s/$nbd_tcp_port/PORT/g"
|
2>&1 | sed "s/$nbd_tcp_port/PORT/g"
|
||||||
|
$QEMU_NBD_PROG -L -b $nbd_tcp_addr -p $nbd_tcp_port --object $obj \
|
||||||
|
--tls-creds=tls0
|
||||||
|
|
||||||
nbd_server_stop
|
nbd_server_stop
|
||||||
|
|
||||||
|
@ -81,23 +84,28 @@ echo "== check plain client to TLS server fails =="
|
||||||
nbd_server_start_tcp_socket \
|
nbd_server_start_tcp_socket \
|
||||||
--object tls-creds-x509,dir=${tls_dir}/server1,endpoint=server,id=tls0,verify-peer=yes \
|
--object tls-creds-x509,dir=${tls_dir}/server1,endpoint=server,id=tls0,verify-peer=yes \
|
||||||
--tls-creds tls0 \
|
--tls-creds tls0 \
|
||||||
-f $IMGFMT "$TEST_IMG"
|
-f $IMGFMT "$TEST_IMG" 2>> "$TEST_DIR/server.log"
|
||||||
|
|
||||||
$QEMU_IMG info nbd://localhost:$nbd_tcp_port 2>&1 | sed "s/$nbd_tcp_port/PORT/g"
|
$QEMU_IMG info nbd://localhost:$nbd_tcp_port 2>&1 | sed "s/$nbd_tcp_port/PORT/g"
|
||||||
|
$QEMU_NBD_PROG -L -b $nbd_tcp_addr -p $nbd_tcp_port
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo "== check TLS works =="
|
echo "== check TLS works =="
|
||||||
$QEMU_IMG info --image-opts \
|
obj=tls-creds-x509,dir=${tls_dir}/client1,endpoint=client,id=tls0
|
||||||
--object tls-creds-x509,dir=${tls_dir}/client1,endpoint=client,id=tls0 \
|
$QEMU_IMG info --image-opts --object $obj \
|
||||||
driver=nbd,host=$nbd_tcp_addr,port=$nbd_tcp_port,tls-creds=tls0 \
|
driver=nbd,host=$nbd_tcp_addr,port=$nbd_tcp_port,tls-creds=tls0 \
|
||||||
2>&1 | sed "s/$nbd_tcp_port/PORT/g"
|
2>&1 | sed "s/$nbd_tcp_port/PORT/g"
|
||||||
|
$QEMU_NBD_PROG -L -b $nbd_tcp_addr -p $nbd_tcp_port --object $obj \
|
||||||
|
--tls-creds=tls0
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo "== check TLS with different CA fails =="
|
echo "== check TLS with different CA fails =="
|
||||||
$QEMU_IMG info --image-opts \
|
obj=tls-creds-x509,dir=${tls_dir}/client2,endpoint=client,id=tls0
|
||||||
--object tls-creds-x509,dir=${tls_dir}/client2,endpoint=client,id=tls0 \
|
$QEMU_IMG info --image-opts --object $obj \
|
||||||
driver=nbd,host=$nbd_tcp_addr,port=$nbd_tcp_port,tls-creds=tls0 \
|
driver=nbd,host=$nbd_tcp_addr,port=$nbd_tcp_port,tls-creds=tls0 \
|
||||||
2>&1 | sed "s/$nbd_tcp_port/PORT/g"
|
2>&1 | sed "s/$nbd_tcp_port/PORT/g"
|
||||||
|
$QEMU_NBD_PROG -L -b $nbd_tcp_addr -p $nbd_tcp_port --object $obj \
|
||||||
|
--tls-creds=tls0
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo "== perform I/O over TLS =="
|
echo "== perform I/O over TLS =="
|
||||||
|
@ -109,6 +117,10 @@ $QEMU_IO -c 'r -P 0x11 1m 1m' -c 'w -P 0x22 1m 1m' --image-opts \
|
||||||
|
|
||||||
$QEMU_IO -f $IMGFMT -r -U -c 'r -P 0x22 1m 1m' "$TEST_IMG" | _filter_qemu_io
|
$QEMU_IO -f $IMGFMT -r -U -c 'r -P 0x22 1m 1m' "$TEST_IMG" | _filter_qemu_io
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "== final server log =="
|
||||||
|
cat "$TEST_DIR/server.log"
|
||||||
|
|
||||||
# success, all done
|
# success, all done
|
||||||
echo "*** done"
|
echo "*** done"
|
||||||
rm -f $seq.full
|
rm -f $seq.full
|
||||||
|
|
|
@ -15,20 +15,33 @@ wrote 1048576/1048576 bytes at offset 1048576
|
||||||
== check TLS client to plain server fails ==
|
== check TLS client to plain server fails ==
|
||||||
qemu-img: Could not open 'driver=nbd,host=127.0.0.1,port=PORT,tls-creds=tls0': Denied by server for option 5 (starttls)
|
qemu-img: Could not open 'driver=nbd,host=127.0.0.1,port=PORT,tls-creds=tls0': Denied by server for option 5 (starttls)
|
||||||
server reported: TLS not configured
|
server reported: TLS not configured
|
||||||
|
qemu-nbd: Denied by server for option 5 (starttls)
|
||||||
|
server reported: TLS not configured
|
||||||
|
|
||||||
== check plain client to TLS server fails ==
|
== check plain client to TLS server fails ==
|
||||||
qemu-img: Could not open 'nbd://localhost:PORT': TLS negotiation required before option 8 (structured reply)
|
qemu-img: Could not open 'nbd://localhost:PORT': TLS negotiation required before option 8 (structured reply)
|
||||||
server reported: Option 0x8 not permitted before TLS
|
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
|
||||||
|
|
||||||
== check TLS works ==
|
== check TLS works ==
|
||||||
image: nbd://127.0.0.1:PORT
|
image: nbd://127.0.0.1:PORT
|
||||||
file format: nbd
|
file format: nbd
|
||||||
virtual size: 64M (67108864 bytes)
|
virtual size: 64M (67108864 bytes)
|
||||||
disk size: unavailable
|
disk size: unavailable
|
||||||
|
exports available: 1
|
||||||
|
export: ''
|
||||||
|
size: 67108864
|
||||||
|
flags: 0x4ed ( flush fua trim zeroes df cache )
|
||||||
|
min block: 512
|
||||||
|
opt block: 4096
|
||||||
|
max block: 33554432
|
||||||
|
available meta contexts: 1
|
||||||
|
base:allocation
|
||||||
|
|
||||||
== check TLS with different CA fails ==
|
== check TLS with different CA fails ==
|
||||||
qemu-nbd: option negotiation failed: Verify failed: No certificate was found.
|
|
||||||
qemu-img: Could not open 'driver=nbd,host=127.0.0.1,port=PORT,tls-creds=tls0': The certificate hasn't got a known issuer
|
qemu-img: Could not open 'driver=nbd,host=127.0.0.1,port=PORT,tls-creds=tls0': The certificate hasn't got a known issuer
|
||||||
|
qemu-nbd: The certificate hasn't got a known issuer
|
||||||
|
|
||||||
== perform I/O over TLS ==
|
== perform I/O over TLS ==
|
||||||
read 1048576/1048576 bytes at offset 1048576
|
read 1048576/1048576 bytes at offset 1048576
|
||||||
|
@ -37,4 +50,8 @@ wrote 1048576/1048576 bytes at offset 1048576
|
||||||
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
read 1048576/1048576 bytes at offset 1048576
|
read 1048576/1048576 bytes at offset 1048576
|
||||||
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
|
||||||
|
== final server log ==
|
||||||
|
qemu-nbd: option negotiation failed: Verify failed: No certificate was found.
|
||||||
|
qemu-nbd: option negotiation failed: Verify failed: No certificate was found.
|
||||||
*** done
|
*** done
|
||||||
|
|
Loading…
Reference in New Issue