nbd: correctly propagate errors

Before:
    $ ./qemu-io-old
    qemu-io-old> open -r -o file.driver=nbd
    one of path and host must be specified.
    qemu-io-old: can't open device (null): Could not open image: Invalid argument
    $ ./qemu-io-old
    qemu-io-old> open -r -o file.driver=nbd,file.host=foo,file.path=bar
    path and host may not be used at the same time.
    qemu-io-old: can't open device (null): Could not open image: Invalid argument

After:
    $ ./qemu-io
    qemu-io> open -r -o file.driver=nbd
    qemu-io: can't open device (null): one of path and host must be specified.
    $ ./qemu-io
    qemu-io> open -r -o file.driver=nbd,file.host=foo,file.path=bar
    qemu-io: can't open device (null): path and host may not be used at the same time.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Reviewed-by: Fam Zheng <famz@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
Paolo Bonzini 2014-02-17 14:43:49 +01:00 committed by Kevin Wolf
parent a69d9af449
commit 77e8b9ca64
4 changed files with 18 additions and 35 deletions

View File

@ -188,19 +188,18 @@ out:
g_free(file); g_free(file);
} }
static int nbd_config(BDRVNBDState *s, QDict *options, char **export) static void nbd_config(BDRVNBDState *s, QDict *options, char **export,
Error **errp)
{ {
Error *local_err = NULL; Error *local_err = NULL;
if (qdict_haskey(options, "path") == qdict_haskey(options, "host")) { if (qdict_haskey(options, "path") == qdict_haskey(options, "host")) {
if (qdict_haskey(options, "path")) { if (qdict_haskey(options, "path")) {
qerror_report(ERROR_CLASS_GENERIC_ERROR, "path and host may not " error_setg(errp, "path and host may not be used at the same time.");
"be used at the same time.");
} else { } else {
qerror_report(ERROR_CLASS_GENERIC_ERROR, "one of path and host " error_setg(errp, "one of path and host must be specified.");
"must be specified.");
} }
return -EINVAL; return;
} }
s->client.is_unix = qdict_haskey(options, "path"); s->client.is_unix = qdict_haskey(options, "path");
@ -209,9 +208,8 @@ static int nbd_config(BDRVNBDState *s, QDict *options, char **export)
qemu_opts_absorb_qdict(s->socket_opts, options, &local_err); qemu_opts_absorb_qdict(s->socket_opts, options, &local_err);
if (local_err) { if (local_err) {
qerror_report_err(local_err); error_propagate(errp, local_err);
error_free(local_err); return;
return -EINVAL;
} }
if (!qemu_opt_get(s->socket_opts, "port")) { if (!qemu_opt_get(s->socket_opts, "port")) {
@ -222,19 +220,17 @@ static int nbd_config(BDRVNBDState *s, QDict *options, char **export)
if (*export) { if (*export) {
qdict_del(options, "export"); qdict_del(options, "export");
} }
return 0;
} }
static int nbd_establish_connection(BlockDriverState *bs) static int nbd_establish_connection(BlockDriverState *bs, Error **errp)
{ {
BDRVNBDState *s = bs->opaque; BDRVNBDState *s = bs->opaque;
int sock; int sock;
if (s->client.is_unix) { if (s->client.is_unix) {
sock = unix_socket_outgoing(qemu_opt_get(s->socket_opts, "path")); sock = unix_connect_opts(s->socket_opts, errp, NULL, NULL);
} else { } else {
sock = tcp_socket_outgoing_opts(s->socket_opts); sock = inet_connect_opts(s->socket_opts, errp, NULL, NULL);
if (sock >= 0) { if (sock >= 0) {
socket_set_nodelay(sock); socket_set_nodelay(sock);
} }
@ -255,17 +251,19 @@ static int nbd_open(BlockDriverState *bs, QDict *options, int flags,
BDRVNBDState *s = bs->opaque; BDRVNBDState *s = bs->opaque;
char *export = NULL; char *export = NULL;
int result, sock; int result, sock;
Error *local_err = NULL;
/* Pop the config into our state object. Exit if invalid. */ /* Pop the config into our state object. Exit if invalid. */
result = nbd_config(s, options, &export); nbd_config(s, options, &export, &local_err);
if (result != 0) { if (local_err) {
return result; error_propagate(errp, local_err);
return -EINVAL;
} }
/* establish TCP connection, return error if it fails /* establish TCP connection, return error if it fails
* TODO: Configurable retry-until-timeout behaviour. * TODO: Configurable retry-until-timeout behaviour.
*/ */
sock = nbd_establish_connection(bs); sock = nbd_establish_connection(bs, errp);
if (sock < 0) { if (sock < 0) {
return sock; return sock;
} }

View File

@ -64,7 +64,6 @@ enum {
ssize_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read); ssize_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read);
int tcp_socket_incoming(const char *address, uint16_t port); int tcp_socket_incoming(const char *address, uint16_t port);
int tcp_socket_incoming_spec(const char *address_and_port); int tcp_socket_incoming_spec(const char *address_and_port);
int tcp_socket_outgoing_opts(QemuOpts *opts);
int unix_socket_outgoing(const char *path); int unix_socket_outgoing(const char *path);
int unix_socket_incoming(const char *path); int unix_socket_incoming(const char *path);

12
nbd.c
View File

@ -199,18 +199,6 @@ static void combine_addr(char *buf, size_t len, const char* address,
} }
} }
int tcp_socket_outgoing_opts(QemuOpts *opts)
{
Error *local_err = NULL;
int fd = inet_connect_opts(opts, &local_err, NULL, NULL);
if (local_err != NULL) {
qerror_report_err(local_err);
error_free(local_err);
}
return fd;
}
int tcp_socket_incoming(const char *address, uint16_t port) int tcp_socket_incoming(const char *address, uint16_t port)
{ {
char address_and_port[128]; char address_and_port[128];

View File

@ -231,8 +231,7 @@ Testing: -drive driver=file
QEMU_PROG: -drive driver=file: could not open disk image ide0-hd0: The 'file' block driver requires a file name QEMU_PROG: -drive driver=file: could not open disk image ide0-hd0: The 'file' block driver requires a file name
Testing: -drive driver=nbd Testing: -drive driver=nbd
QEMU_PROG: -drive driver=nbd: one of path and host must be specified. QEMU_PROG: -drive driver=nbd: could not open disk image ide0-hd0: one of path and host must be specified.
QEMU_PROG: -drive driver=nbd: could not open disk image ide0-hd0: Could not open image: Invalid argument
Testing: -drive driver=raw Testing: -drive driver=raw
QEMU_PROG: -drive driver=raw: could not open disk image ide0-hd0: Can't use 'raw' as a block driver for the protocol level QEMU_PROG: -drive driver=raw: could not open disk image ide0-hd0: Can't use 'raw' as a block driver for the protocol level
@ -241,8 +240,7 @@ Testing: -drive file.driver=file
QEMU_PROG: -drive file.driver=file: could not open disk image ide0-hd0: The 'file' block driver requires a file name QEMU_PROG: -drive file.driver=file: could not open disk image ide0-hd0: The 'file' block driver requires a file name
Testing: -drive file.driver=nbd Testing: -drive file.driver=nbd
QEMU_PROG: -drive file.driver=nbd: one of path and host must be specified. QEMU_PROG: -drive file.driver=nbd: could not open disk image ide0-hd0: one of path and host must be specified.
QEMU_PROG: -drive file.driver=nbd: could not open disk image ide0-hd0: Could not open image: Invalid argument
Testing: -drive file.driver=raw Testing: -drive file.driver=raw
QEMU_PROG: -drive file.driver=raw: could not open disk image ide0-hd0: Can't use 'raw' as a block driver for the protocol level QEMU_PROG: -drive file.driver=raw: could not open disk image ide0-hd0: Can't use 'raw' as a block driver for the protocol level