diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2019-01-07 11:55:52 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2019-01-07 11:55:52 +0000 |
commit | a29644590f95166c8a13e5797f8e7701134b31d0 (patch) | |
tree | 408c948f7f8b1ddd720cf0b9b714d564b3529f69 | |
parent | e59dbbac0364344a3ad84c3497a98c56003d3fb8 (diff) | |
parent | ef2e35fcc8e14bcc9366df5fdf53f65d679f8dca (diff) |
Merge remote-tracking branch 'remotes/ericb/tags/pull-nbd-2019-01-05' into staging
nbd patches for 2019-01-05
Error and trace improvements in NBD code, such as less noise for
common disconnect scenarios.
- Vladimir Sementsov-Ogievskiy: 0/3 nbd-client: drop extra error noise
- Eric Blake: portions of 0/22 nbd: add qemu-nbd --list
# gpg: Signature made Sat 05 Jan 2019 13:58:54 GMT
# gpg: using RSA key A7A16B4A2527436A
# gpg: Good signature from "Eric Blake <eblake@redhat.com>"
# gpg: aka "Eric Blake (Free Software Programmer) <ebb9@byu.net>"
# gpg: aka "[jpeg image of size 6874]"
# Primary key fingerprint: 71C2 CC22 B1C4 6029 27D2 F3AA A7A1 6B4A 2527 436A
* remotes/ericb/tags/pull-nbd-2019-01-05:
nbd/client: Drop pointless buf variable
qemu-nbd: Fail earlier for -c/-d on non-linux
nbd/client: More consistent error messages
nbd: Document timeline of various features
qemu-nbd: Use program name in error messages
block/nbd-client: use traces instead of noisy error_report_err
nbd/client: Trace all server option error messages
nbd: publish _lookup functions
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r-- | block/nbd-client.c | 23 | ||||
-rw-r--r-- | block/trace-events | 4 | ||||
-rw-r--r-- | docs/interop/nbd.txt | 19 | ||||
-rw-r--r-- | include/block/nbd.h | 5 | ||||
-rw-r--r-- | nbd/client.c | 63 | ||||
-rw-r--r-- | nbd/nbd-internal.h | 8 | ||||
-rw-r--r-- | nbd/trace-events | 1 | ||||
-rw-r--r-- | qemu-nbd.c | 22 | ||||
-rw-r--r-- | tests/qemu-iotests/083.out | 28 | ||||
-rw-r--r-- | tests/qemu-iotests/233.out | 2 |
10 files changed, 92 insertions, 83 deletions
diff --git a/block/nbd-client.c b/block/nbd-client.c index fc5b7eda8e..ef32075971 100644 --- a/block/nbd-client.c +++ b/block/nbd-client.c @@ -28,6 +28,8 @@ */ #include "qemu/osdep.h" + +#include "trace.h" #include "qapi/error.h" #include "nbd-client.h" @@ -79,7 +81,8 @@ static coroutine_fn void nbd_read_reply_entry(void *opaque) assert(s->reply.handle == 0); ret = nbd_receive_reply(s->ioc, &s->reply, &local_err); if (local_err) { - error_report_err(local_err); + trace_nbd_read_reply_entry_fail(ret, error_get_pretty(local_err)); + error_free(local_err); } if (ret <= 0) { break; @@ -771,7 +774,11 @@ static int nbd_co_request(BlockDriverState *bs, NBDRequest *request, ret = nbd_co_receive_return_code(client, request->handle, &local_err); if (local_err) { - error_report_err(local_err); + trace_nbd_co_request_fail(request->from, request->len, request->handle, + request->flags, request->type, + nbd_cmd_lookup(request->type), + ret, error_get_pretty(local_err)); + error_free(local_err); } return ret; } @@ -802,7 +809,11 @@ int nbd_client_co_preadv(BlockDriverState *bs, uint64_t offset, ret = nbd_co_receive_cmdread_reply(client, request.handle, offset, qiov, &local_err); if (local_err) { - error_report_err(local_err); + trace_nbd_co_request_fail(request.from, request.len, request.handle, + request.flags, request.type, + nbd_cmd_lookup(request.type), + ret, error_get_pretty(local_err)); + error_free(local_err); } return ret; } @@ -925,7 +936,11 @@ int coroutine_fn nbd_client_co_block_status(BlockDriverState *bs, ret = nbd_co_receive_blockstatus_reply(client, request.handle, bytes, &extent, &local_err); if (local_err) { - error_report_err(local_err); + trace_nbd_co_request_fail(request.from, request.len, request.handle, + request.flags, request.type, + nbd_cmd_lookup(request.type), + ret, error_get_pretty(local_err)); + error_free(local_err); } if (ret < 0) { return ret; diff --git a/block/trace-events b/block/trace-events index 3e8c47bb24..693c14c443 100644 --- a/block/trace-events +++ b/block/trace-events @@ -156,3 +156,7 @@ nvme_cmd_map_qiov_iov(void *s, int i, void *page, int pages) "s %p iov[%d] %p pa # block/iscsi.c iscsi_xcopy(void *src_lun, uint64_t src_off, void *dst_lun, uint64_t dst_off, uint64_t bytes, int ret) "src_lun %p offset %"PRIu64" dst_lun %p offset %"PRIu64" bytes %"PRIu64" ret %d" + +# block/nbd-client.c +nbd_read_reply_entry_fail(int ret, const char *err) "ret = %d, err: %s" +nbd_co_request_fail(uint64_t from, uint32_t len, uint64_t handle, uint16_t flags, uint16_t type, const char *name, int ret, const char *err) "Request failed { .from = %" PRIu64", .len = %" PRIu32 ", .handle = %" PRIu64 ", .flags = 0x%" PRIx16 ", .type = %" PRIu16 " (%s) } ret = %d, err: %s" diff --git a/docs/interop/nbd.txt b/docs/interop/nbd.txt index 77b5f45911..fc64473e02 100644 --- a/docs/interop/nbd.txt +++ b/docs/interop/nbd.txt @@ -15,7 +15,6 @@ Qemu supports the "base:allocation" metadata context as defined in the NBD protocol specification, and also defines an additional metadata namespace "qemu". - == "qemu" namespace == The "qemu" namespace currently contains only one type of context, @@ -36,3 +35,21 @@ in addition to "qemu:dirty-bitmap:<dirty-bitmap-export-name>": namespace. * "qemu:dirty-bitmap:" - returns list of all available dirty-bitmap metadata contexts. + += Features by version = + +The following list documents which qemu version first implemented +various features (both as a server exposing the feature, and as a +client taking advantage of the feature when present), to make it +easier to plan for cross-version interoperability. Note that in +several cases, the initial release containing a feature may require +additional patches from the corresponding stable branch to fix bugs in +the operation of that feature. + +* 2.6: NBD_OPT_STARTTLS with TLS X.509 Certificates +* 2.8: NBD_CMD_WRITE_ZEROES +* 2.10: NBD_OPT_GO, NBD_INFO_BLOCK +* 2.11: NBD_OPT_STRUCTURED_REPLY +* 2.12: NBD_CMD_BLOCK_STATUS for "base:allocation" +* 3.0: NBD_OPT_STARTTLS with TLS Pre-Shared Keys (PSK), +NBD_CMD_BLOCK_STATUS for "qemu:dirty-bitmap:", NBD_CMD_CACHE diff --git a/include/block/nbd.h b/include/block/nbd.h index 6a5bfe5d55..65402d3396 100644 --- a/include/block/nbd.h +++ b/include/block/nbd.h @@ -343,5 +343,10 @@ static inline bool nbd_reply_is_structured(NBDReply *reply) } const char *nbd_reply_type_lookup(uint16_t type); +const char *nbd_opt_lookup(uint32_t opt); +const char *nbd_rep_lookup(uint32_t rep); +const char *nbd_info_lookup(uint16_t info); +const char *nbd_cmd_lookup(uint16_t info); +const char *nbd_err_lookup(int err); #endif diff --git a/nbd/client.c b/nbd/client.c index b4d457a19a..f625c207c5 100644 --- a/nbd/client.c +++ b/nbd/client.c @@ -132,8 +132,9 @@ static int nbd_receive_option_reply(QIOChannel *ioc, uint32_t opt, return -1; } if (reply->option != opt) { - error_setg(errp, "Unexpected option type %x expected %x", - reply->option, opt); + error_setg(errp, "Unexpected option type %u (%s), expected %u (%s)", + reply->option, nbd_opt_lookup(reply->option), + opt, nbd_opt_lookup(opt)); nbd_send_opt_abort(ioc); return -1; } @@ -171,6 +172,8 @@ static int nbd_handle_reply_err(QIOChannel *ioc, NBDOptionReply *reply, goto cleanup; } msg[reply->length] = '\0'; + trace_nbd_server_error_msg(reply->type, + nbd_reply_type_lookup(reply->type), msg); } switch (reply->type) { @@ -265,8 +268,9 @@ static int nbd_receive_list(QIOChannel *ioc, const char *want, bool *match, } return 0; } else if (reply.type != NBD_REP_SERVER) { - error_setg(errp, "Unexpected reply type %" PRIx32 " expected %x", - reply.type, NBD_REP_SERVER); + error_setg(errp, "Unexpected reply type %u (%s), expected %u (%s)", + reply.type, nbd_rep_lookup(reply.type), + NBD_REP_SERVER, nbd_rep_lookup(NBD_REP_SERVER)); nbd_send_opt_abort(ioc); return -1; } @@ -378,9 +382,9 @@ static int nbd_opt_go(QIOChannel *ioc, const char *wantname, return 1; } if (reply.type != NBD_REP_INFO) { - error_setg(errp, "unexpected reply type %" PRIu32 - " (%s), expected %u", - reply.type, nbd_rep_lookup(reply.type), NBD_REP_INFO); + error_setg(errp, "unexpected reply type %u (%s), expected %u (%s)", + reply.type, nbd_rep_lookup(reply.type), + NBD_REP_INFO, nbd_rep_lookup(NBD_REP_INFO)); nbd_send_opt_abort(ioc); return -1; } @@ -704,8 +708,9 @@ static int nbd_negotiate_simple_meta_context(QIOChannel *ioc, } if (reply.type != NBD_REP_ACK) { - error_setg(errp, "Unexpected reply type %" PRIx32 " expected %x", - reply.type, NBD_REP_ACK); + error_setg(errp, "Unexpected reply type %u (%s), expected %u (%s)", + reply.type, nbd_rep_lookup(reply.type), + NBD_REP_ACK, nbd_rep_lookup(NBD_REP_ACK)); nbd_send_opt_abort(ioc); return -1; } @@ -728,7 +733,6 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, QIOChannel **outioc, NBDExportInfo *info, Error **errp) { - char buf[256]; uint64_t magic; int rc; bool zeroes = true; @@ -749,27 +753,20 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, goto fail; } - if (nbd_read(ioc, buf, 8, errp) < 0) { - error_prepend(errp, "Failed to read data: "); - goto fail; - } - - buf[8] = '\0'; - if (strlen(buf) == 0) { - error_setg(errp, "Server connection closed unexpectedly"); + if (nbd_read(ioc, &magic, sizeof(magic), errp) < 0) { + error_prepend(errp, "Failed to read initial magic: "); goto fail; } - - magic = ldq_be_p(buf); + magic = be64_to_cpu(magic); trace_nbd_receive_negotiate_magic(magic); - if (memcmp(buf, "NBDMAGIC", 8) != 0) { - error_setg(errp, "Invalid magic received"); + if (magic != NBD_INIT_MAGIC) { + error_setg(errp, "Bad initial magic received: 0x%" PRIx64, magic); goto fail; } if (nbd_read(ioc, &magic, sizeof(magic), errp) < 0) { - error_prepend(errp, "Failed to read magic: "); + error_prepend(errp, "Failed to read server magic: "); goto fail; } magic = be64_to_cpu(magic); @@ -908,7 +905,7 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, } info->flags = oldflags; } else { - error_setg(errp, "Bad magic received"); + error_setg(errp, "Bad server magic received: 0x%" PRIx64, magic); goto fail; } @@ -1026,23 +1023,7 @@ int nbd_disconnect(int fd) return 0; } -#else -int nbd_init(int fd, QIOChannelSocket *ioc, NBDExportInfo *info, - Error **errp) -{ - error_setg(errp, "nbd_init is only supported on Linux"); - return -ENOTSUP; -} - -int nbd_client(int fd) -{ - return -ENOTSUP; -} -int nbd_disconnect(int fd) -{ - return -ENOTSUP; -} -#endif +#endif /* __linux__ */ int nbd_send_request(QIOChannel *ioc, NBDRequest *request) { diff --git a/nbd/nbd-internal.h b/nbd/nbd-internal.h index eeff78d3c9..82aa221227 100644 --- a/nbd/nbd-internal.h +++ b/nbd/nbd-internal.h @@ -46,8 +46,9 @@ /* Size of oldstyle negotiation */ #define NBD_OLDSTYLE_NEGOTIATE_SIZE (8 + 8 + 8 + 4 + 124) +#define NBD_INIT_MAGIC 0x4e42444d41474943LL /* ASCII "NBDMAGIC" */ #define NBD_REQUEST_MAGIC 0x25609513 -#define NBD_OPTS_MAGIC 0x49484156454F5054LL +#define NBD_OPTS_MAGIC 0x49484156454F5054LL /* ASCII "IHAVEOPT" */ #define NBD_CLIENT_MAGIC 0x0000420281861253LL #define NBD_REP_MAGIC 0x0003e889045565a9LL @@ -100,11 +101,6 @@ struct NBDTLSHandshakeData { void nbd_tls_handshake(QIOTask *task, void *opaque); -const char *nbd_opt_lookup(uint32_t opt); -const char *nbd_rep_lookup(uint32_t rep); -const char *nbd_info_lookup(uint16_t info); -const char *nbd_cmd_lookup(uint16_t info); -const char *nbd_err_lookup(int err); int nbd_drop(QIOChannel *ioc, size_t size, Error **errp); diff --git a/nbd/trace-events b/nbd/trace-events index 5e1d4afe8e..5492042acb 100644 --- a/nbd/trace-events +++ b/nbd/trace-events @@ -1,6 +1,7 @@ # nbd/client.c nbd_send_option_request(uint32_t opt, const char *name, uint32_t len) "Sending option request %" PRIu32" (%s), len %" PRIu32 nbd_receive_option_reply(uint32_t option, const char *optname, uint32_t type, const char *typename, uint32_t length) "Received option reply %" PRIu32" (%s), type %" PRIu32" (%s), len %" PRIu32 +nbd_server_error_msg(uint32_t err, const char *type, const char *msg) "server reported error 0x%" PRIx32 " (%s) with additional message: %s" nbd_reply_err_unsup(uint32_t option, const char *name) "server doesn't understand request %" PRIu32 " (%s), attempting fallback" nbd_opt_go_start(const char *name) "Attempting NBD_OPT_GO for export '%s'" nbd_opt_go_success(void) "Export is good to go" diff --git a/qemu-nbd.c b/qemu-nbd.c index ca7109652e..2807e13239 100644 --- a/qemu-nbd.c +++ b/qemu-nbd.c @@ -43,6 +43,12 @@ #include "trace/control.h" #include "qemu-version.h" +#ifdef __linux__ +#define HAVE_NBD_DEVICE 1 +#else +#define HAVE_NBD_DEVICE 0 +#endif + #define SOCKET_PATH "/var/lock/qemu-nbd-%s" #define QEMU_NBD_OPT_CACHE 256 #define QEMU_NBD_OPT_AIO 257 @@ -98,11 +104,11 @@ static void usage(const char *name) " specify tracing options\n" " --fork fork off the server process and exit the parent\n" " once the server is running\n" -#ifdef __linux__ +#if HAVE_NBD_DEVICE +"\n" "Kernel NBD client support:\n" " -c, --connect=DEV connect FILE to the local NBD device DEV\n" " -d, --disconnect disconnect the specified device\n" -"\n" #endif "\n" "Block device options:\n" @@ -236,6 +242,7 @@ static void termsig_handler(int signum) } +#if HAVE_NBD_DEVICE static void *show_parts(void *arg) { char *device = arg; @@ -321,6 +328,7 @@ out: kill(getpid(), SIGTERM); return (void *) EXIT_FAILURE; } +#endif /* HAVE_NBD_DEVICE */ static int nbd_can_accept(void) { @@ -571,6 +579,7 @@ int main(int argc, char **argv) #endif module_call_init(MODULE_INIT_TRACE); + error_set_progname(argv[0]); qcrypto_init(&error_fatal); module_call_init(MODULE_INIT_QOM); @@ -813,6 +822,12 @@ int main(int argc, char **argv) } } +#if !HAVE_NBD_DEVICE + if (disconnect || device) { + error_report("Kernel /dev/nbdN support not available"); + exit(EXIT_FAILURE); + } +#else /* HAVE_NBD_DEVICE */ if (disconnect) { int nbdfd = open(argv[optind], O_RDWR); if (nbdfd < 0) { @@ -828,6 +843,7 @@ int main(int argc, char **argv) return 0; } +#endif if ((device && !verbose) || fork_process) { int stderr_fd[2]; @@ -1005,6 +1021,7 @@ int main(int argc, char **argv) nbd_export_set_description(exp, export_description); if (device) { +#if HAVE_NBD_DEVICE int ret; ret = pthread_create(&client_thread, NULL, nbd_client_thread, device); @@ -1012,6 +1029,7 @@ int main(int argc, char **argv) error_report("Failed to create client thread: %s", strerror(ret)); exit(EXIT_FAILURE); } +#endif } else { /* Shut up GCC warnings. */ memset(&client_thread, 0, sizeof(client_thread)); diff --git a/tests/qemu-iotests/083.out b/tests/qemu-iotests/083.out index f9af8bb691..7419722cd7 100644 --- a/tests/qemu-iotests/083.out +++ b/tests/qemu-iotests/083.out @@ -41,8 +41,6 @@ can't open device nbd+tcp://127.0.0.1:PORT/foo === Check disconnect after neg2 === -Unable to read from socket: Connection reset by peer -Connection closed read failed: Input/output error === Check disconnect 8 neg2 === @@ -55,40 +53,30 @@ can't open device nbd+tcp://127.0.0.1:PORT/foo === Check disconnect before request === -Unable to read from socket: Connection reset by peer -Connection closed read failed: Input/output error === Check disconnect after request === -Connection closed read failed: Input/output error === Check disconnect before reply === -Connection closed read failed: Input/output error === Check disconnect after reply === -Unexpected end-of-file before all bytes were read read failed: Input/output error === Check disconnect 4 reply === -Unexpected end-of-file before all bytes were read -Connection closed read failed: Input/output error === Check disconnect 8 reply === -Unexpected end-of-file before all bytes were read -Connection closed read failed: Input/output error === Check disconnect before data === -Unexpected end-of-file before all bytes were read read failed: Input/output error === Check disconnect after data === @@ -118,8 +106,6 @@ can't open device nbd+tcp://127.0.0.1:PORT/ === Check disconnect after neg-classic === -Unable to read from socket: Connection reset by peer -Connection closed read failed: Input/output error === Check disconnect before neg1 === @@ -164,8 +150,6 @@ can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock === Check disconnect after neg2 === -Unable to read from socket: Connection reset by peer -Connection closed read failed: Input/output error === Check disconnect 8 neg2 === @@ -178,40 +162,30 @@ can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock === Check disconnect before request === -Unable to read from socket: Connection reset by peer -Connection closed read failed: Input/output error === Check disconnect after request === -Connection closed read failed: Input/output error === Check disconnect before reply === -Connection closed read failed: Input/output error === Check disconnect after reply === -Unexpected end-of-file before all bytes were read read failed: Input/output error === Check disconnect 4 reply === -Unexpected end-of-file before all bytes were read -Connection closed read failed: Input/output error === Check disconnect 8 reply === -Unexpected end-of-file before all bytes were read -Connection closed read failed: Input/output error === Check disconnect before data === -Unexpected end-of-file before all bytes were read read failed: Input/output error === Check disconnect after data === @@ -241,8 +215,6 @@ can't open device nbd+unix:///?socket=TEST_DIR/nbd.sock === Check disconnect after neg-classic === -Unable to read from socket: Connection reset by peer -Connection closed read failed: Input/output error *** done diff --git a/tests/qemu-iotests/233.out b/tests/qemu-iotests/233.out index 94acd9b947..5f416721b0 100644 --- a/tests/qemu-iotests/233.out +++ b/tests/qemu-iotests/233.out @@ -27,7 +27,7 @@ virtual size: 64M (67108864 bytes) disk size: unavailable == check TLS with different CA fails == -option negotiation failed: Verify failed: No certificate was found. +qemu-nbd: option negotiation failed: Verify failed: No certificate was found. qemu-img: Could not open 'driver=nbd,host=127.0.0.1,port=PORT,tls-creds=tls0': The certificate hasn't got a known issuer == perform I/O over TLS == |