Skip to content
This repository has been archived by the owner on Nov 5, 2019. It is now read-only.

Commit

Permalink
nbd: Add qemu-nbd -D for human-readable description
Browse files Browse the repository at this point in the history
The NBD protocol allows servers to advertise a human-readable
description alongside an export name during NBD_OPT_LIST.  Add
an option to pass through the user's string to the NBD client.

Doing this also makes it easier to test commit 200650d, which
is the client counterpart of receiving the description.

Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1476469998-28592-2-git-send-email-eblake@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
  • Loading branch information
ebblake authored and bonzini committed Nov 2, 2016
1 parent 1775f11 commit b1a75b3
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 12 deletions.
1 change: 1 addition & 0 deletions include/block/nbd.h
Expand Up @@ -115,6 +115,7 @@ BlockBackend *nbd_export_get_blockdev(NBDExport *exp);

NBDExport *nbd_export_find(const char *name);
void nbd_export_set_name(NBDExport *exp, const char *name);
void nbd_export_set_description(NBDExport *exp, const char *description);
void nbd_export_close_all(void);

void nbd_client_new(NBDExport *exp,
Expand Down
5 changes: 3 additions & 2 deletions nbd/nbd-internal.h
Expand Up @@ -104,9 +104,10 @@ static inline ssize_t read_sync(QIOChannel *ioc, void *buffer, size_t size)
return nbd_wr_syncv(ioc, &iov, 1, size, true);
}

static inline ssize_t write_sync(QIOChannel *ioc, void *buffer, size_t size)
static inline ssize_t write_sync(QIOChannel *ioc, const void *buffer,
size_t size)
{
struct iovec iov = { .iov_base = buffer, .iov_len = size };
struct iovec iov = { .iov_base = (void *) buffer, .iov_len = size };

return nbd_wr_syncv(ioc, &iov, 1, size, false);
}
Expand Down
34 changes: 26 additions & 8 deletions nbd/server.c
Expand Up @@ -61,6 +61,7 @@ struct NBDExport {

BlockBackend *blk;
char *name;
char *description;
off_t dev_offset;
off_t size;
uint16_t nbdflags;
Expand Down Expand Up @@ -129,7 +130,8 @@ static ssize_t nbd_negotiate_read(QIOChannel *ioc, void *buffer, size_t size)

}

static ssize_t nbd_negotiate_write(QIOChannel *ioc, void *buffer, size_t size)
static ssize_t nbd_negotiate_write(QIOChannel *ioc, const void *buffer,
size_t size)
{
ssize_t ret;
guint watch;
Expand Down Expand Up @@ -225,11 +227,15 @@ static int nbd_negotiate_send_rep(QIOChannel *ioc, uint32_t type, uint32_t opt)

static int nbd_negotiate_send_rep_list(QIOChannel *ioc, NBDExport *exp)
{
uint64_t magic, name_len;
uint64_t magic;
size_t name_len, desc_len;
uint32_t opt, type, len;
const char *name = exp->name ? exp->name : "";
const char *desc = exp->description ? exp->description : "";

TRACE("Advertising export name '%s'", exp->name ? exp->name : "");
name_len = strlen(exp->name);
TRACE("Advertising export name '%s' description '%s'", name, desc);
name_len = strlen(name);
desc_len = strlen(desc);
magic = cpu_to_be64(NBD_REP_MAGIC);
if (nbd_negotiate_write(ioc, &magic, sizeof(magic)) != sizeof(magic)) {
LOG("write failed (magic)");
Expand All @@ -245,18 +251,22 @@ static int nbd_negotiate_send_rep_list(QIOChannel *ioc, NBDExport *exp)
LOG("write failed (reply type)");
return -EINVAL;
}
len = cpu_to_be32(name_len + sizeof(len));
len = cpu_to_be32(name_len + desc_len + sizeof(len));
if (nbd_negotiate_write(ioc, &len, sizeof(len)) != sizeof(len)) {
LOG("write failed (length)");
return -EINVAL;
}
len = cpu_to_be32(name_len);
if (nbd_negotiate_write(ioc, &len, sizeof(len)) != sizeof(len)) {
LOG("write failed (length)");
LOG("write failed (name length)");
return -EINVAL;
}
if (nbd_negotiate_write(ioc, name, name_len) != name_len) {
LOG("write failed (name buffer)");
return -EINVAL;
}
if (nbd_negotiate_write(ioc, exp->name, name_len) != name_len) {
LOG("write failed (buffer)");
if (nbd_negotiate_write(ioc, desc, desc_len) != desc_len) {
LOG("write failed (description buffer)");
return -EINVAL;
}
return 0;
Expand Down Expand Up @@ -894,6 +904,12 @@ void nbd_export_set_name(NBDExport *exp, const char *name)
nbd_export_put(exp);
}

void nbd_export_set_description(NBDExport *exp, const char *description)
{
g_free(exp->description);
exp->description = g_strdup(description);
}

void nbd_export_close(NBDExport *exp)
{
NBDClient *client, *next;
Expand All @@ -903,6 +919,7 @@ void nbd_export_close(NBDExport *exp)
client_close(client);
}
nbd_export_set_name(exp, NULL);
nbd_export_set_description(exp, NULL);
nbd_export_put(exp);
}

Expand All @@ -921,6 +938,7 @@ void nbd_export_put(NBDExport *exp)

if (--exp->refcount == 0) {
assert(exp->name == NULL);
assert(exp->description == NULL);

if (exp->close) {
exp->close(exp);
Expand Down
12 changes: 11 additions & 1 deletion qemu-nbd.c
Expand Up @@ -83,6 +83,7 @@ static void usage(const char *name)
" -t, --persistent don't exit on the last connection\n"
" -v, --verbose display extra debugging information\n"
" -x, --export-name=NAME expose export by name\n"
" -D, --description=TEXT with -x, also export a human-readable description\n"
"\n"
"Exposing part of the image:\n"
" -o, --offset=OFFSET offset into the image\n"
Expand Down Expand Up @@ -477,7 +478,7 @@ int main(int argc, char **argv)
off_t fd_size;
QemuOpts *sn_opts = NULL;
const char *sn_id_or_name = NULL;
const char *sopt = "hVb:o:p:rsnP:c:dvk:e:f:tl:x:T:";
const char *sopt = "hVb:o:p:rsnP:c:dvk:e:f:tl:x:T:D:";
struct option lopt[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'V' },
Expand All @@ -503,6 +504,7 @@ int main(int argc, char **argv)
{ "verbose", no_argument, NULL, 'v' },
{ "object", required_argument, NULL, QEMU_NBD_OPT_OBJECT },
{ "export-name", required_argument, NULL, 'x' },
{ "description", required_argument, NULL, 'D' },
{ "tls-creds", required_argument, NULL, QEMU_NBD_OPT_TLSCREDS },
{ "image-opts", no_argument, NULL, QEMU_NBD_OPT_IMAGE_OPTS },
{ "trace", required_argument, NULL, 'T' },
Expand All @@ -524,6 +526,7 @@ int main(int argc, char **argv)
BlockdevDetectZeroesOptions detect_zeroes = BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF;
QDict *options = NULL;
const char *export_name = NULL;
const char *export_description = NULL;
const char *tlscredsid = NULL;
bool imageOpts = false;
bool writethrough = true;
Expand Down Expand Up @@ -689,6 +692,9 @@ int main(int argc, char **argv)
case 'x':
export_name = optarg;
break;
case 'D':
export_description = optarg;
break;
case 'v':
verbose = 1;
break;
Expand Down Expand Up @@ -937,7 +943,11 @@ int main(int argc, char **argv)
}
if (export_name) {
nbd_export_set_name(exp, export_name);
nbd_export_set_description(exp, export_description);
newproto = true;
} else if (export_description) {
error_report("Export description requires an export name");
exit(EXIT_FAILURE);
}

server_ioc = qio_channel_socket_new();
Expand Down
5 changes: 4 additions & 1 deletion qemu-nbd.texi
Expand Up @@ -79,9 +79,12 @@ Disconnect the device @var{dev}
Allow up to @var{num} clients to share the device (default @samp{1})
@item -t, --persistent
Don't exit on the last connection
@item -x NAME, --export-name=NAME
@item -x, --export-name=@var{name}
Set the NBD volume export name. This switches the server to use
the new style NBD protocol negotiation
@item -D, --description=@var{description}
Set the NBD volume export description, as a human-readable
string. Requires the use of @option{-x}
@item --tls-creds=ID
Enable mandatory TLS encryption for the server by setting the ID
of the TLS credentials object previously created with the --object
Expand Down

0 comments on commit b1a75b3

Please sign in to comment.