diff options
Diffstat (limited to 'nbd')
-rw-r--r-- | nbd/client.c | 104 | ||||
-rw-r--r-- | nbd/trace-events | 3 |
2 files changed, 84 insertions, 23 deletions
diff --git a/nbd/client.c b/nbd/client.c index 9acf745b79..4f0745f601 100644 --- a/nbd/client.c +++ b/nbd/client.c @@ -908,6 +908,57 @@ int nbd_send_request(QIOChannel *ioc, NBDRequest *request) return nbd_write(ioc, buf, sizeof(buf), NULL); } +/* nbd_receive_simple_reply + * Read simple reply except magic field (which should be already read). + * Payload is not read (payload is possible for CMD_READ, but here we even + * don't know whether it take place or not). + */ +static int nbd_receive_simple_reply(QIOChannel *ioc, NBDSimpleReply *reply, + Error **errp) +{ + int ret; + + assert(reply->magic == NBD_SIMPLE_REPLY_MAGIC); + + ret = nbd_read(ioc, (uint8_t *)reply + sizeof(reply->magic), + sizeof(*reply) - sizeof(reply->magic), errp); + if (ret < 0) { + return ret; + } + + be32_to_cpus(&reply->error); + be64_to_cpus(&reply->handle); + + return 0; +} + +/* nbd_receive_structured_reply_chunk + * Read structured reply chunk except magic field (which should be already + * read). + * Payload is not read. + */ +static int nbd_receive_structured_reply_chunk(QIOChannel *ioc, + NBDStructuredReplyChunk *chunk, + Error **errp) +{ + int ret; + + assert(chunk->magic == NBD_STRUCTURED_REPLY_MAGIC); + + ret = nbd_read(ioc, (uint8_t *)chunk + sizeof(chunk->magic), + sizeof(*chunk) - sizeof(chunk->magic), errp); + if (ret < 0) { + return ret; + } + + be16_to_cpus(&chunk->flags); + be16_to_cpus(&chunk->type); + be64_to_cpus(&chunk->handle); + be32_to_cpus(&chunk->length); + + return 0; +} + /* nbd_receive_reply * Returns 1 on success * 0 on eof, when no data was read (errp is not set) @@ -915,38 +966,47 @@ int nbd_send_request(QIOChannel *ioc, NBDRequest *request) */ int nbd_receive_reply(QIOChannel *ioc, NBDReply *reply, Error **errp) { - uint8_t buf[NBD_REPLY_SIZE]; - uint32_t magic; int ret; - ret = nbd_read_eof(ioc, buf, sizeof(buf), errp); + ret = nbd_read_eof(ioc, &reply->magic, sizeof(reply->magic), errp); if (ret <= 0) { return ret; } - /* Reply - [ 0 .. 3] magic (NBD_SIMPLE_REPLY_MAGIC) - [ 4 .. 7] error (0 == no error) - [ 7 .. 15] handle - */ + be32_to_cpus(&reply->magic); - magic = ldl_be_p(buf); - reply->error = ldl_be_p(buf + 4); - reply->handle = ldq_be_p(buf + 8); - - trace_nbd_receive_reply(magic, reply->error, nbd_err_lookup(reply->error), - reply->handle); - reply->error = nbd_errno_to_system_errno(reply->error); + switch (reply->magic) { + case NBD_SIMPLE_REPLY_MAGIC: + ret = nbd_receive_simple_reply(ioc, &reply->simple, errp); + if (ret < 0) { + break; + } - if (reply->error == ESHUTDOWN) { - /* This works even on mingw which lacks a native ESHUTDOWN */ - error_setg(errp, "server shutting down"); + trace_nbd_receive_simple_reply(reply->simple.error, + nbd_err_lookup(reply->simple.error), + reply->handle); + if (reply->simple.error == NBD_ESHUTDOWN) { + /* This works even on mingw which lacks a native ESHUTDOWN */ + error_setg(errp, "server shutting down"); + return -EINVAL; + } + break; + case NBD_STRUCTURED_REPLY_MAGIC: + ret = nbd_receive_structured_reply_chunk(ioc, &reply->structured, errp); + if (ret < 0) { + break; + } + trace_nbd_receive_structured_reply_chunk(reply->structured.flags, + reply->structured.type, + reply->structured.handle, + reply->structured.length); + break; + default: + error_setg(errp, "invalid magic (got 0x%" PRIx32 ")", reply->magic); return -EINVAL; } - - if (magic != NBD_SIMPLE_REPLY_MAGIC) { - error_setg(errp, "invalid magic (got 0x%" PRIx32 ")", magic); - return -EINVAL; + if (ret < 0) { + return ret; } return 1; diff --git a/nbd/trace-events b/nbd/trace-events index 596df96575..4a13757524 100644 --- a/nbd/trace-events +++ b/nbd/trace-events @@ -26,7 +26,8 @@ nbd_client_loop_ret(int ret, const char *error) "NBD loop returned %d: %s" nbd_client_clear_queue(void) "Clearing NBD queue" nbd_client_clear_socket(void) "Clearing NBD socket" nbd_send_request(uint64_t from, uint32_t len, uint64_t handle, uint16_t flags, uint16_t type, const char *name) "Sending request to server: { .from = %" PRIu64", .len = %" PRIu32 ", .handle = %" PRIu64 ", .flags = 0x%" PRIx16 ", .type = %" PRIu16 " (%s) }" -nbd_receive_reply(uint32_t magic, int32_t error, const char *errname, uint64_t handle) "Got reply: { magic = 0x%" PRIx32 ", .error = %" PRId32 " (%s), handle = %" PRIu64" }" +nbd_receive_simple_reply(int32_t error, const char *errname, uint64_t handle) "Got simple reply: { .error = %" PRId32 " (%s), handle = %" PRIu64" }" +nbd_receive_structured_reply_chunk(uint16_t flags, uint16_t type, uint64_t handle, uint32_t length) "Got structured reply chunk: { flags = 0x%" PRIx16 ", type = %d, handle = %" PRIu64 ", length = %" PRIu32 " }" # nbd/common.c nbd_unknown_error(int err) "Squashing unexpected error %d to EINVAL" |