Skip to content

Commit

Permalink
nbd: accept URIs
Browse files Browse the repository at this point in the history
The URI syntax is consistent with the Gluster syntax.  Export names
are specified in the path, preceded by one or more (otherwise unused)
slashes.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
  • Loading branch information
bonzini committed Nov 12, 2012
1 parent d04b0bb commit 1d7d2a9
Show file tree
Hide file tree
Showing 2 changed files with 114 additions and 9 deletions.
98 changes: 97 additions & 1 deletion block/nbd.c
Expand Up @@ -28,6 +28,7 @@

#include "qemu-common.h"
#include "nbd.h"
#include "uri.h"
#include "block_int.h"
#include "module.h"
#include "qemu_socket.h"
Expand Down Expand Up @@ -69,6 +70,69 @@ typedef struct BDRVNBDState {
char *export_name; /* An NBD server may export several devices */
} BDRVNBDState;

static int nbd_parse_uri(BDRVNBDState *s, const char *filename)
{
URI *uri;
const char *p;
QueryParams *qp = NULL;
int ret = 0;

uri = uri_parse(filename);
if (!uri) {
return -EINVAL;
}

/* transport */
if (!strcmp(uri->scheme, "nbd")) {
s->is_unix = false;
} else if (!strcmp(uri->scheme, "nbd+tcp")) {
s->is_unix = false;
} else if (!strcmp(uri->scheme, "nbd+unix")) {
s->is_unix = true;
} else {
ret = -EINVAL;
goto out;
}

p = uri->path ? uri->path : "/";
p += strspn(p, "/");
if (p[0]) {
s->export_name = g_strdup(p);
}

qp = query_params_parse(uri->query);
if (qp->n > 1 || (s->is_unix && !qp->n) || (!s->is_unix && qp->n)) {
ret = -EINVAL;
goto out;
}

if (s->is_unix) {
/* nbd+unix:///export?socket=path */
if (uri->server || uri->port || strcmp(qp->p[0].name, "socket")) {
ret = -EINVAL;
goto out;
}
s->host_spec = g_strdup(qp->p[0].value);
} else {
/* nbd[+tcp]://host:port/export */
if (!uri->server) {
ret = -EINVAL;
goto out;
}
if (!uri->port) {
uri->port = NBD_DEFAULT_PORT;
}
s->host_spec = g_strdup_printf("%s:%d", uri->server, uri->port);
}

out:
if (qp) {
query_params_free(qp);
}
uri_free(uri);
return ret;
}

static int nbd_config(BDRVNBDState *s, const char *filename)
{
char *file;
Expand All @@ -77,6 +141,10 @@ static int nbd_config(BDRVNBDState *s, const char *filename)
const char *unixpath;
int err = -EINVAL;

if (strstr(filename, "://")) {
return nbd_parse_uri(s, filename);
}

file = g_strdup(filename);

export_name = strstr(file, EN_OPTSTR);
Expand Down Expand Up @@ -495,6 +563,33 @@ static int64_t nbd_getlength(BlockDriverState *bs)

static BlockDriver bdrv_nbd = {
.format_name = "nbd",
.protocol_name = "nbd",
.instance_size = sizeof(BDRVNBDState),
.bdrv_file_open = nbd_open,
.bdrv_co_readv = nbd_co_readv,
.bdrv_co_writev = nbd_co_writev,
.bdrv_close = nbd_close,
.bdrv_co_flush_to_os = nbd_co_flush,
.bdrv_co_discard = nbd_co_discard,
.bdrv_getlength = nbd_getlength,
};

static BlockDriver bdrv_nbd_tcp = {
.format_name = "nbd",
.protocol_name = "nbd+tcp",
.instance_size = sizeof(BDRVNBDState),
.bdrv_file_open = nbd_open,
.bdrv_co_readv = nbd_co_readv,
.bdrv_co_writev = nbd_co_writev,
.bdrv_close = nbd_close,
.bdrv_co_flush_to_os = nbd_co_flush,
.bdrv_co_discard = nbd_co_discard,
.bdrv_getlength = nbd_getlength,
};

static BlockDriver bdrv_nbd_unix = {
.format_name = "nbd",
.protocol_name = "nbd+unix",
.instance_size = sizeof(BDRVNBDState),
.bdrv_file_open = nbd_open,
.bdrv_co_readv = nbd_co_readv,
Expand All @@ -503,12 +598,13 @@ static BlockDriver bdrv_nbd = {
.bdrv_co_flush_to_os = nbd_co_flush,
.bdrv_co_discard = nbd_co_discard,
.bdrv_getlength = nbd_getlength,
.protocol_name = "nbd",
};

static void bdrv_nbd_init(void)
{
bdrv_register(&bdrv_nbd);
bdrv_register(&bdrv_nbd_tcp);
bdrv_register(&bdrv_nbd_unix);
}

block_init(bdrv_nbd_init);
25 changes: 17 additions & 8 deletions qemu-doc.texi
Expand Up @@ -610,14 +610,14 @@ QEMU can access directly to block device exported using the Network Block Device
protocol.

@example
qemu-system-i386 linux.img -hdb nbd:my_nbd_server.mydomain.org:1024
qemu-system-i386 linux.img -hdb nbd://my_nbd_server.mydomain.org:1024/
@end example

If the NBD server is located on the same host, you can use an unix socket instead
of an inet socket:

@example
qemu-system-i386 linux.img -hdb nbd:unix:/tmp/my_socket
qemu-system-i386 linux.img -hdb nbd+unix://?socket=/tmp/my_socket
@end example

In this case, the block device must be exported using qemu-nbd:
Expand All @@ -631,17 +631,26 @@ The use of qemu-nbd allows to share a disk between several guests:
qemu-nbd --socket=/tmp/my_socket --share=2 my_disk.qcow2
@end example

@noindent
and then you can use it with two guests:
@example
qemu-system-i386 linux1.img -hdb nbd:unix:/tmp/my_socket
qemu-system-i386 linux2.img -hdb nbd:unix:/tmp/my_socket
qemu-system-i386 linux1.img -hdb nbd+unix://?socket=/tmp/my_socket
qemu-system-i386 linux2.img -hdb nbd+unix://?socket=/tmp/my_socket
@end example

If the nbd-server uses named exports (since NBD 2.9.18), you must use the
"exportname" option:
If the nbd-server uses named exports (supported since NBD 2.9.18, or with QEMU's
own embedded NBD server), you must specify an export name in the URI:
@example
qemu-system-i386 -cdrom nbd:localhost:exportname=debian-500-ppc-netinst
qemu-system-i386 -cdrom nbd:localhost:exportname=openSUSE-11.1-ppc-netinst
qemu-system-i386 -cdrom nbd://localhost/debian-500-ppc-netinst
qemu-system-i386 -cdrom nbd://localhost/openSUSE-11.1-ppc-netinst
@end example

The URI syntax for NBD is supported since QEMU 1.3. An alternative syntax is
also available. Here are some example of the older syntax:
@example
qemu-system-i386 linux.img -hdb nbd:my_nbd_server.mydomain.org:1024
qemu-system-i386 linux2.img -hdb nbd:unix:/tmp/my_socket
qemu-system-i386 -cdrom nbd:localhost:10809:exportname=debian-500-ppc-netinst
@end example

@node disk_images_sheepdog
Expand Down

0 comments on commit 1d7d2a9

Please sign in to comment.