nbd: Improve error messages
This patch makes use of the Error object for nbd_receive_negotiate() so that errors during negotiation look nicer. Furthermore, this patch adds an additional error message if the received magic was wrong, but would be correct for the other protocol version, respectively: So if an export name was specified, but the NBD server magic corresponds to an old handshake, this condition is explicitly signaled to the user, and vice versa. As these messages are now part of the "Could not open image" error message, additional filtering has to be employed in iotest 083, which this patch does as well. Signed-off-by: Max Reitz <mreitz@redhat.com> Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
parent
a231cb2726
commit
1ce52846d3
@ -373,7 +373,7 @@ void nbd_client_session_close(NbdClientSession *client)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int nbd_client_session_init(NbdClientSession *client, BlockDriverState *bs,
|
int nbd_client_session_init(NbdClientSession *client, BlockDriverState *bs,
|
||||||
int sock, const char *export)
|
int sock, const char *export, Error **errp)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@ -382,7 +382,7 @@ int nbd_client_session_init(NbdClientSession *client, BlockDriverState *bs,
|
|||||||
qemu_set_block(sock);
|
qemu_set_block(sock);
|
||||||
ret = nbd_receive_negotiate(sock, export,
|
ret = nbd_receive_negotiate(sock, export,
|
||||||
&client->nbdflags, &client->size,
|
&client->nbdflags, &client->size,
|
||||||
&client->blocksize);
|
&client->blocksize, errp);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
logout("Failed to negotiate with the NBD server\n");
|
logout("Failed to negotiate with the NBD server\n");
|
||||||
closesocket(sock);
|
closesocket(sock);
|
||||||
|
@ -36,7 +36,7 @@ typedef struct NbdClientSession {
|
|||||||
} NbdClientSession;
|
} NbdClientSession;
|
||||||
|
|
||||||
int nbd_client_session_init(NbdClientSession *client, BlockDriverState *bs,
|
int nbd_client_session_init(NbdClientSession *client, BlockDriverState *bs,
|
||||||
int sock, const char *export_name);
|
int sock, const char *export_name, Error **errp);
|
||||||
void nbd_client_session_close(NbdClientSession *client);
|
void nbd_client_session_close(NbdClientSession *client);
|
||||||
|
|
||||||
int nbd_client_session_co_discard(NbdClientSession *client, int64_t sector_num,
|
int nbd_client_session_co_discard(NbdClientSession *client, int64_t sector_num,
|
||||||
|
@ -271,7 +271,7 @@ static int nbd_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* NBD handshake */
|
/* NBD handshake */
|
||||||
result = nbd_client_session_init(&s->client, bs, sock, export);
|
result = nbd_client_session_init(&s->client, bs, sock, export, errp);
|
||||||
g_free(export);
|
g_free(export);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -75,7 +75,7 @@ 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 nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
|
int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
|
||||||
off_t *size, size_t *blocksize);
|
off_t *size, size_t *blocksize, Error **errp);
|
||||||
int nbd_init(int fd, int csock, uint32_t flags, off_t size, size_t blocksize);
|
int nbd_init(int fd, int csock, uint32_t flags, off_t size, size_t blocksize);
|
||||||
ssize_t nbd_send_request(int csock, struct nbd_request *request);
|
ssize_t nbd_send_request(int csock, struct nbd_request *request);
|
||||||
ssize_t nbd_receive_reply(int csock, struct nbd_reply *reply);
|
ssize_t nbd_receive_reply(int csock, struct nbd_reply *reply);
|
||||||
|
42
nbd.c
42
nbd.c
@ -494,7 +494,7 @@ fail:
|
|||||||
}
|
}
|
||||||
|
|
||||||
int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
|
int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
|
||||||
off_t *size, size_t *blocksize)
|
off_t *size, size_t *blocksize, Error **errp)
|
||||||
{
|
{
|
||||||
char buf[256];
|
char buf[256];
|
||||||
uint64_t magic, s;
|
uint64_t magic, s;
|
||||||
@ -506,13 +506,13 @@ int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
|
|||||||
rc = -EINVAL;
|
rc = -EINVAL;
|
||||||
|
|
||||||
if (read_sync(csock, buf, 8) != 8) {
|
if (read_sync(csock, buf, 8) != 8) {
|
||||||
LOG("read failed");
|
error_setg(errp, "Failed to read data");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
buf[8] = '\0';
|
buf[8] = '\0';
|
||||||
if (strlen(buf) == 0) {
|
if (strlen(buf) == 0) {
|
||||||
LOG("server connection closed");
|
error_setg(errp, "Server connection closed unexpectedly");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -527,12 +527,12 @@ int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
|
|||||||
qemu_isprint(buf[7]) ? buf[7] : '.');
|
qemu_isprint(buf[7]) ? buf[7] : '.');
|
||||||
|
|
||||||
if (memcmp(buf, "NBDMAGIC", 8) != 0) {
|
if (memcmp(buf, "NBDMAGIC", 8) != 0) {
|
||||||
LOG("Invalid magic received");
|
error_setg(errp, "Invalid magic received");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (read_sync(csock, &magic, sizeof(magic)) != sizeof(magic)) {
|
if (read_sync(csock, &magic, sizeof(magic)) != sizeof(magic)) {
|
||||||
LOG("read failed");
|
error_setg(errp, "Failed to read magic");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
magic = be64_to_cpu(magic);
|
magic = be64_to_cpu(magic);
|
||||||
@ -545,52 +545,60 @@ int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
|
|||||||
|
|
||||||
TRACE("Checking magic (opts_magic)");
|
TRACE("Checking magic (opts_magic)");
|
||||||
if (magic != NBD_OPTS_MAGIC) {
|
if (magic != NBD_OPTS_MAGIC) {
|
||||||
LOG("Bad magic received");
|
if (magic == NBD_CLIENT_MAGIC) {
|
||||||
|
error_setg(errp, "Server does not support export names");
|
||||||
|
} else {
|
||||||
|
error_setg(errp, "Bad magic received");
|
||||||
|
}
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
if (read_sync(csock, &tmp, sizeof(tmp)) != sizeof(tmp)) {
|
if (read_sync(csock, &tmp, sizeof(tmp)) != sizeof(tmp)) {
|
||||||
LOG("flags read failed");
|
error_setg(errp, "Failed to read server flags");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
*flags = be16_to_cpu(tmp) << 16;
|
*flags = be16_to_cpu(tmp) << 16;
|
||||||
/* reserved for future use */
|
/* reserved for future use */
|
||||||
if (write_sync(csock, &reserved, sizeof(reserved)) !=
|
if (write_sync(csock, &reserved, sizeof(reserved)) !=
|
||||||
sizeof(reserved)) {
|
sizeof(reserved)) {
|
||||||
LOG("write failed (reserved)");
|
error_setg(errp, "Failed to read reserved field");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
/* write the export name */
|
/* write the export name */
|
||||||
magic = cpu_to_be64(magic);
|
magic = cpu_to_be64(magic);
|
||||||
if (write_sync(csock, &magic, sizeof(magic)) != sizeof(magic)) {
|
if (write_sync(csock, &magic, sizeof(magic)) != sizeof(magic)) {
|
||||||
LOG("write failed (magic)");
|
error_setg(errp, "Failed to send export name magic");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
opt = cpu_to_be32(NBD_OPT_EXPORT_NAME);
|
opt = cpu_to_be32(NBD_OPT_EXPORT_NAME);
|
||||||
if (write_sync(csock, &opt, sizeof(opt)) != sizeof(opt)) {
|
if (write_sync(csock, &opt, sizeof(opt)) != sizeof(opt)) {
|
||||||
LOG("write failed (opt)");
|
error_setg(errp, "Failed to send export name option number");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
namesize = cpu_to_be32(strlen(name));
|
namesize = cpu_to_be32(strlen(name));
|
||||||
if (write_sync(csock, &namesize, sizeof(namesize)) !=
|
if (write_sync(csock, &namesize, sizeof(namesize)) !=
|
||||||
sizeof(namesize)) {
|
sizeof(namesize)) {
|
||||||
LOG("write failed (namesize)");
|
error_setg(errp, "Failed to send export name length");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
if (write_sync(csock, (char*)name, strlen(name)) != strlen(name)) {
|
if (write_sync(csock, (char*)name, strlen(name)) != strlen(name)) {
|
||||||
LOG("write failed (name)");
|
error_setg(errp, "Failed to send export name");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
TRACE("Checking magic (cli_magic)");
|
TRACE("Checking magic (cli_magic)");
|
||||||
|
|
||||||
if (magic != NBD_CLIENT_MAGIC) {
|
if (magic != NBD_CLIENT_MAGIC) {
|
||||||
LOG("Bad magic received");
|
if (magic == NBD_OPTS_MAGIC) {
|
||||||
|
error_setg(errp, "Server requires an export name");
|
||||||
|
} else {
|
||||||
|
error_setg(errp, "Bad magic received");
|
||||||
|
}
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (read_sync(csock, &s, sizeof(s)) != sizeof(s)) {
|
if (read_sync(csock, &s, sizeof(s)) != sizeof(s)) {
|
||||||
LOG("read failed");
|
error_setg(errp, "Failed to read export length");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
*size = be64_to_cpu(s);
|
*size = be64_to_cpu(s);
|
||||||
@ -599,19 +607,19 @@ int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
|
|||||||
|
|
||||||
if (!name) {
|
if (!name) {
|
||||||
if (read_sync(csock, flags, sizeof(*flags)) != sizeof(*flags)) {
|
if (read_sync(csock, flags, sizeof(*flags)) != sizeof(*flags)) {
|
||||||
LOG("read failed (flags)");
|
error_setg(errp, "Failed to read export flags");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
*flags = be32_to_cpup(flags);
|
*flags = be32_to_cpup(flags);
|
||||||
} else {
|
} else {
|
||||||
if (read_sync(csock, &tmp, sizeof(tmp)) != sizeof(tmp)) {
|
if (read_sync(csock, &tmp, sizeof(tmp)) != sizeof(tmp)) {
|
||||||
LOG("read failed (tmp)");
|
error_setg(errp, "Failed to read export flags");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
*flags |= be32_to_cpu(tmp);
|
*flags |= be32_to_cpu(tmp);
|
||||||
}
|
}
|
||||||
if (read_sync(csock, &buf, 124) != 124) {
|
if (read_sync(csock, &buf, 124) != 124) {
|
||||||
LOG("read failed (buf)");
|
error_setg(errp, "Failed to read reserved block");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
rc = 0;
|
rc = 0;
|
||||||
|
@ -284,6 +284,7 @@ static void *nbd_client_thread(void *arg)
|
|||||||
int fd, sock;
|
int fd, sock;
|
||||||
int ret;
|
int ret;
|
||||||
pthread_t show_parts_thread;
|
pthread_t show_parts_thread;
|
||||||
|
Error *local_error = NULL;
|
||||||
|
|
||||||
sock = unix_socket_outgoing(sockpath);
|
sock = unix_socket_outgoing(sockpath);
|
||||||
if (sock < 0) {
|
if (sock < 0) {
|
||||||
@ -291,8 +292,12 @@ static void *nbd_client_thread(void *arg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ret = nbd_receive_negotiate(sock, NULL, &nbdflags,
|
ret = nbd_receive_negotiate(sock, NULL, &nbdflags,
|
||||||
&size, &blocksize);
|
&size, &blocksize, &local_error);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
if (local_error) {
|
||||||
|
fprintf(stderr, "%s\n", error_get_pretty(local_error));
|
||||||
|
error_free(local_error);
|
||||||
|
}
|
||||||
goto out_socket;
|
goto out_socket;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,7 +56,8 @@ filter_nbd() {
|
|||||||
#
|
#
|
||||||
# Filter out the TCP port number since this changes between runs.
|
# Filter out the TCP port number since this changes between runs.
|
||||||
sed -e 's#^.*nbd\.c:.*##g' \
|
sed -e 's#^.*nbd\.c:.*##g' \
|
||||||
-e 's#nbd:127\.0\.0\.1:[^:]*:#nbd:127\.0\.0\.1:PORT:#g'
|
-e 's#nbd:127\.0\.0\.1:[^:]*:#nbd:127\.0\.0\.1:PORT:#g' \
|
||||||
|
-e 's#\(exportname=foo\|PORT\): Failed to .*$#\1#'
|
||||||
}
|
}
|
||||||
|
|
||||||
check_disconnect() {
|
check_disconnect() {
|
||||||
|
@ -1,62 +1,52 @@
|
|||||||
QA output created by 083
|
QA output created by 083
|
||||||
=== Check disconnect before neg1 ===
|
=== Check disconnect before neg1 ===
|
||||||
|
|
||||||
|
qemu-io: can't open device nbd:127.0.0.1:PORT:exportname=foo
|
||||||
qemu-io: can't open device nbd:127.0.0.1:PORT:exportname=foo: Could not open image: Invalid argument
|
|
||||||
no file open, try 'help open'
|
no file open, try 'help open'
|
||||||
|
|
||||||
=== Check disconnect after neg1 ===
|
=== Check disconnect after neg1 ===
|
||||||
|
|
||||||
|
qemu-io: can't open device nbd:127.0.0.1:PORT:exportname=foo
|
||||||
qemu-io: can't open device nbd:127.0.0.1:PORT:exportname=foo: Could not open image: Invalid argument
|
|
||||||
no file open, try 'help open'
|
no file open, try 'help open'
|
||||||
|
|
||||||
=== Check disconnect 8 neg1 ===
|
=== Check disconnect 8 neg1 ===
|
||||||
|
|
||||||
|
qemu-io: can't open device nbd:127.0.0.1:PORT:exportname=foo
|
||||||
qemu-io: can't open device nbd:127.0.0.1:PORT:exportname=foo: Could not open image: Invalid argument
|
|
||||||
no file open, try 'help open'
|
no file open, try 'help open'
|
||||||
|
|
||||||
=== Check disconnect 16 neg1 ===
|
=== Check disconnect 16 neg1 ===
|
||||||
|
|
||||||
|
qemu-io: can't open device nbd:127.0.0.1:PORT:exportname=foo
|
||||||
qemu-io: can't open device nbd:127.0.0.1:PORT:exportname=foo: Could not open image: Invalid argument
|
|
||||||
no file open, try 'help open'
|
no file open, try 'help open'
|
||||||
|
|
||||||
=== Check disconnect before export ===
|
=== Check disconnect before export ===
|
||||||
|
|
||||||
|
qemu-io: can't open device nbd:127.0.0.1:PORT:exportname=foo
|
||||||
qemu-io: can't open device nbd:127.0.0.1:PORT:exportname=foo: Could not open image: Invalid argument
|
|
||||||
no file open, try 'help open'
|
no file open, try 'help open'
|
||||||
|
|
||||||
=== Check disconnect after export ===
|
=== Check disconnect after export ===
|
||||||
|
|
||||||
|
qemu-io: can't open device nbd:127.0.0.1:PORT:exportname=foo
|
||||||
qemu-io: can't open device nbd:127.0.0.1:PORT:exportname=foo: Could not open image: Invalid argument
|
|
||||||
no file open, try 'help open'
|
no file open, try 'help open'
|
||||||
|
|
||||||
=== Check disconnect 4 export ===
|
=== Check disconnect 4 export ===
|
||||||
|
|
||||||
|
qemu-io: can't open device nbd:127.0.0.1:PORT:exportname=foo
|
||||||
qemu-io: can't open device nbd:127.0.0.1:PORT:exportname=foo: Could not open image: Invalid argument
|
|
||||||
no file open, try 'help open'
|
no file open, try 'help open'
|
||||||
|
|
||||||
=== Check disconnect 12 export ===
|
=== Check disconnect 12 export ===
|
||||||
|
|
||||||
|
qemu-io: can't open device nbd:127.0.0.1:PORT:exportname=foo
|
||||||
qemu-io: can't open device nbd:127.0.0.1:PORT:exportname=foo: Could not open image: Invalid argument
|
|
||||||
no file open, try 'help open'
|
no file open, try 'help open'
|
||||||
|
|
||||||
=== Check disconnect 16 export ===
|
=== Check disconnect 16 export ===
|
||||||
|
|
||||||
|
qemu-io: can't open device nbd:127.0.0.1:PORT:exportname=foo
|
||||||
qemu-io: can't open device nbd:127.0.0.1:PORT:exportname=foo: Could not open image: Invalid argument
|
|
||||||
no file open, try 'help open'
|
no file open, try 'help open'
|
||||||
|
|
||||||
=== Check disconnect before neg2 ===
|
=== Check disconnect before neg2 ===
|
||||||
|
|
||||||
|
qemu-io: can't open device nbd:127.0.0.1:PORT:exportname=foo
|
||||||
qemu-io: can't open device nbd:127.0.0.1:PORT:exportname=foo: Could not open image: Invalid argument
|
|
||||||
no file open, try 'help open'
|
no file open, try 'help open'
|
||||||
|
|
||||||
=== Check disconnect after neg2 ===
|
=== Check disconnect after neg2 ===
|
||||||
@ -66,14 +56,12 @@ read failed: Input/output error
|
|||||||
|
|
||||||
=== Check disconnect 8 neg2 ===
|
=== Check disconnect 8 neg2 ===
|
||||||
|
|
||||||
|
qemu-io: can't open device nbd:127.0.0.1:PORT:exportname=foo
|
||||||
qemu-io: can't open device nbd:127.0.0.1:PORT:exportname=foo: Could not open image: Invalid argument
|
|
||||||
no file open, try 'help open'
|
no file open, try 'help open'
|
||||||
|
|
||||||
=== Check disconnect 10 neg2 ===
|
=== Check disconnect 10 neg2 ===
|
||||||
|
|
||||||
|
qemu-io: can't open device nbd:127.0.0.1:PORT:exportname=foo
|
||||||
qemu-io: can't open device nbd:127.0.0.1:PORT:exportname=foo: Could not open image: Invalid argument
|
|
||||||
no file open, try 'help open'
|
no file open, try 'help open'
|
||||||
|
|
||||||
=== Check disconnect before request ===
|
=== Check disconnect before request ===
|
||||||
@ -119,32 +107,27 @@ read 512/512 bytes at offset 0
|
|||||||
|
|
||||||
=== Check disconnect before neg-classic ===
|
=== Check disconnect before neg-classic ===
|
||||||
|
|
||||||
|
qemu-io: can't open device nbd:127.0.0.1:PORT
|
||||||
qemu-io: can't open device nbd:127.0.0.1:PORT: Could not open image: Invalid argument
|
|
||||||
no file open, try 'help open'
|
no file open, try 'help open'
|
||||||
|
|
||||||
=== Check disconnect 8 neg-classic ===
|
=== Check disconnect 8 neg-classic ===
|
||||||
|
|
||||||
|
qemu-io: can't open device nbd:127.0.0.1:PORT
|
||||||
qemu-io: can't open device nbd:127.0.0.1:PORT: Could not open image: Invalid argument
|
|
||||||
no file open, try 'help open'
|
no file open, try 'help open'
|
||||||
|
|
||||||
=== Check disconnect 16 neg-classic ===
|
=== Check disconnect 16 neg-classic ===
|
||||||
|
|
||||||
|
qemu-io: can't open device nbd:127.0.0.1:PORT
|
||||||
qemu-io: can't open device nbd:127.0.0.1:PORT: Could not open image: Invalid argument
|
|
||||||
no file open, try 'help open'
|
no file open, try 'help open'
|
||||||
|
|
||||||
=== Check disconnect 24 neg-classic ===
|
=== Check disconnect 24 neg-classic ===
|
||||||
|
|
||||||
|
qemu-io: can't open device nbd:127.0.0.1:PORT
|
||||||
qemu-io: can't open device nbd:127.0.0.1:PORT: Could not open image: Invalid argument
|
|
||||||
no file open, try 'help open'
|
no file open, try 'help open'
|
||||||
|
|
||||||
=== Check disconnect 28 neg-classic ===
|
=== Check disconnect 28 neg-classic ===
|
||||||
|
|
||||||
|
qemu-io: can't open device nbd:127.0.0.1:PORT
|
||||||
qemu-io: can't open device nbd:127.0.0.1:PORT: Could not open image: Invalid argument
|
|
||||||
no file open, try 'help open'
|
no file open, try 'help open'
|
||||||
|
|
||||||
=== Check disconnect after neg-classic ===
|
=== Check disconnect after neg-classic ===
|
||||||
|
Loading…
Reference in New Issue
Block a user