From: Wolfgang Bumiller Date: Mon, 19 Feb 2018 09:40:26 +0000 (+0100) Subject: merge EPYC and EPYC-IPBP cpu models X-Git-Url: https://git.proxmox.com/?a=commitdiff_plain;h=2b94053508f60e68ee06080398a274731644a852;p=pve-qemu.git merge EPYC and EPYC-IPBP cpu models and a patch format cleanup round Signed-off-by: Wolfgang Bumiller --- diff --git a/debian/patches/extra/0036-kvm-nbd-make-it-thread-safe-fix-qcow2-over-nbd.patch b/debian/patches/extra/0036-kvm-nbd-make-it-thread-safe-fix-qcow2-over-nbd.patch deleted file mode 100644 index e44cec8..0000000 --- a/debian/patches/extra/0036-kvm-nbd-make-it-thread-safe-fix-qcow2-over-nbd.patch +++ /dev/null @@ -1,136 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Eric Blake -Date: Sun, 11 Jun 2017 03:30:07 +0200 -Subject: [PATCH] nbd: make it thread-safe, fix qcow2 over nbd - -RH-Author: Eric Blake -Message-id: <20170611033007.399-1-eblake@redhat.com> -Patchwork-id: 75581 -O-Subject: [RHEV-7.4 qemu-kvm-rhev PATCH] nbd: make it thread-safe, fix qcow2 over nbd -Bugzilla: 1454582 -RH-Acked-by: Laurent Vivier -RH-Acked-by: Max Reitz -RH-Acked-by: Jeffrey Cody - -From: Paolo Bonzini - -NBD is not thread safe, because it accesses s->in_flight without -a CoMutex. Fixing this will be required for multiqueue. -CoQueue doesn't have spurious wakeups but, when another coroutine can -run between qemu_co_queue_next's wakeup and qemu_co_queue_wait's -re-locking of the mutex, the wait condition can become false and -a loop is necessary. - -In fact, it turns out that the loop is necessary even without this -multi-threaded scenario. A particular sequence of coroutine wakeups -is happening ~80% of the time when starting a guest with qcow2 image -served over NBD (i.e. qemu-nbd --format=raw, and QEMU's -drive option -has -format=qcow2). This patch fixes that issue too. - -Signed-off-by: Paolo Bonzini -(cherry picked from commit 6bdcc018a6ed760b9dfe43539124e420aed83092) -Signed-off-by: Eric Blake -Upstream-status: v6 pull request https://lists.gnu.org/archive/html/qemu-devel/2017-06/msg01841.html -Signed-off-by: Miroslav Rezanina ---- - block/nbd-client.c | 30 +++++++++--------------------- - 1 file changed, 9 insertions(+), 21 deletions(-) - -diff --git a/block/nbd-client.c b/block/nbd-client.c -index 1e2952f..43e0292 100644 ---- a/block/nbd-client.c -+++ b/block/nbd-client.c -@@ -114,6 +114,10 @@ static int nbd_co_send_request(BlockDriverState *bs, - int rc, ret, i; - - qemu_co_mutex_lock(&s->send_mutex); -+ while (s->in_flight == MAX_NBD_REQUESTS) { -+ qemu_co_queue_wait(&s->free_sema, &s->send_mutex); -+ } -+ s->in_flight++; - - for (i = 0; i < MAX_NBD_REQUESTS; i++) { - if (s->recv_coroutine[i] == NULL) { -@@ -176,20 +180,6 @@ static void nbd_co_receive_reply(NBDClientSession *s, - } - } - --static void nbd_coroutine_start(NBDClientSession *s, -- NBDRequest *request) --{ -- /* Poor man semaphore. The free_sema is locked when no other request -- * can be accepted, and unlocked after receiving one reply. */ -- if (s->in_flight == MAX_NBD_REQUESTS) { -- qemu_co_queue_wait(&s->free_sema, NULL); -- assert(s->in_flight < MAX_NBD_REQUESTS); -- } -- s->in_flight++; -- -- /* s->recv_coroutine[i] is set as soon as we get the send_lock. */ --} -- - static void nbd_coroutine_end(BlockDriverState *bs, - NBDRequest *request) - { -@@ -197,13 +187,16 @@ static void nbd_coroutine_end(BlockDriverState *bs, - int i = HANDLE_TO_INDEX(s, request->handle); - - s->recv_coroutine[i] = NULL; -- s->in_flight--; -- qemu_co_queue_next(&s->free_sema); - - /* Kick the read_reply_co to get the next reply. */ - if (s->read_reply_co) { - aio_co_wake(s->read_reply_co); - } -+ -+ qemu_co_mutex_lock(&s->send_mutex); -+ s->in_flight--; -+ qemu_co_queue_next(&s->free_sema); -+ qemu_co_mutex_unlock(&s->send_mutex); - } - - int nbd_client_co_preadv(BlockDriverState *bs, uint64_t offset, -@@ -221,7 +214,6 @@ int nbd_client_co_preadv(BlockDriverState *bs, uint64_t offset, - assert(bytes <= NBD_MAX_BUFFER_SIZE); - assert(!flags); - -- nbd_coroutine_start(client, &request); - ret = nbd_co_send_request(bs, &request, NULL); - if (ret < 0) { - reply.error = -ret; -@@ -251,7 +243,6 @@ int nbd_client_co_pwritev(BlockDriverState *bs, uint64_t offset, - - assert(bytes <= NBD_MAX_BUFFER_SIZE); - -- nbd_coroutine_start(client, &request); - ret = nbd_co_send_request(bs, &request, qiov); - if (ret < 0) { - reply.error = -ret; -@@ -286,7 +277,6 @@ int nbd_client_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, - request.flags |= NBD_CMD_FLAG_NO_HOLE; - } - -- nbd_coroutine_start(client, &request); - ret = nbd_co_send_request(bs, &request, NULL); - if (ret < 0) { - reply.error = -ret; -@@ -311,7 +301,6 @@ int nbd_client_co_flush(BlockDriverState *bs) - request.from = 0; - request.len = 0; - -- nbd_coroutine_start(client, &request); - ret = nbd_co_send_request(bs, &request, NULL); - if (ret < 0) { - reply.error = -ret; -@@ -337,7 +326,6 @@ int nbd_client_co_pdiscard(BlockDriverState *bs, int64_t offset, int count) - return 0; - } - -- nbd_coroutine_start(client, &request); - ret = nbd_co_send_request(bs, &request, NULL); - if (ret < 0) { - reply.error = -ret; --- -1.8.3.1 - diff --git a/debian/patches/extra/0036-nbd-make-it-thread-safe-fix-qcow2-over-nbd.patch b/debian/patches/extra/0036-nbd-make-it-thread-safe-fix-qcow2-over-nbd.patch new file mode 100644 index 0000000..b6edf9b --- /dev/null +++ b/debian/patches/extra/0036-nbd-make-it-thread-safe-fix-qcow2-over-nbd.patch @@ -0,0 +1,121 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Thu, 1 Jun 2017 12:44:56 +0200 +Subject: [PATCH] nbd: make it thread-safe, fix qcow2 over nbd + +NBD is not thread safe, because it accesses s->in_flight without +a CoMutex. Fixing this will be required for multiqueue. +CoQueue doesn't have spurious wakeups but, when another coroutine can +run between qemu_co_queue_next's wakeup and qemu_co_queue_wait's +re-locking of the mutex, the wait condition can become false and +a loop is necessary. + +In fact, it turns out that the loop is necessary even without this +multi-threaded scenario. A particular sequence of coroutine wakeups +is happening ~80% of the time when starting a guest with qcow2 image +served over NBD (i.e. qemu-nbd --format=raw, and QEMU's -drive option +has -format=qcow2). This patch fixes that issue too. + +Signed-off-by: Paolo Bonzini +--- + block/nbd-client.c | 30 +++++++++--------------------- + 1 file changed, 9 insertions(+), 21 deletions(-) + +diff --git a/block/nbd-client.c b/block/nbd-client.c +index 56eb0e2e16..282679b4f8 100644 +--- a/block/nbd-client.c ++++ b/block/nbd-client.c +@@ -114,6 +114,10 @@ static int nbd_co_send_request(BlockDriverState *bs, + int rc, ret, i; + + qemu_co_mutex_lock(&s->send_mutex); ++ while (s->in_flight == MAX_NBD_REQUESTS) { ++ qemu_co_queue_wait(&s->free_sema, &s->send_mutex); ++ } ++ s->in_flight++; + + for (i = 0; i < MAX_NBD_REQUESTS; i++) { + if (s->recv_coroutine[i] == NULL) { +@@ -176,20 +180,6 @@ static void nbd_co_receive_reply(NBDClientSession *s, + } + } + +-static void nbd_coroutine_start(NBDClientSession *s, +- NBDRequest *request) +-{ +- /* Poor man semaphore. The free_sema is locked when no other request +- * can be accepted, and unlocked after receiving one reply. */ +- if (s->in_flight == MAX_NBD_REQUESTS) { +- qemu_co_queue_wait(&s->free_sema, NULL); +- assert(s->in_flight < MAX_NBD_REQUESTS); +- } +- s->in_flight++; +- +- /* s->recv_coroutine[i] is set as soon as we get the send_lock. */ +-} +- + static void nbd_coroutine_end(BlockDriverState *bs, + NBDRequest *request) + { +@@ -197,13 +187,16 @@ static void nbd_coroutine_end(BlockDriverState *bs, + int i = HANDLE_TO_INDEX(s, request->handle); + + s->recv_coroutine[i] = NULL; +- s->in_flight--; +- qemu_co_queue_next(&s->free_sema); + + /* Kick the read_reply_co to get the next reply. */ + if (s->read_reply_co) { + aio_co_wake(s->read_reply_co); + } ++ ++ qemu_co_mutex_lock(&s->send_mutex); ++ s->in_flight--; ++ qemu_co_queue_next(&s->free_sema); ++ qemu_co_mutex_unlock(&s->send_mutex); + } + + int nbd_client_co_preadv(BlockDriverState *bs, uint64_t offset, +@@ -221,7 +214,6 @@ int nbd_client_co_preadv(BlockDriverState *bs, uint64_t offset, + assert(bytes <= NBD_MAX_BUFFER_SIZE); + assert(!flags); + +- nbd_coroutine_start(client, &request); + ret = nbd_co_send_request(bs, &request, NULL); + if (ret < 0) { + reply.error = -ret; +@@ -251,7 +243,6 @@ int nbd_client_co_pwritev(BlockDriverState *bs, uint64_t offset, + + assert(bytes <= NBD_MAX_BUFFER_SIZE); + +- nbd_coroutine_start(client, &request); + ret = nbd_co_send_request(bs, &request, qiov); + if (ret < 0) { + reply.error = -ret; +@@ -286,7 +277,6 @@ int nbd_client_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, + request.flags |= NBD_CMD_FLAG_NO_HOLE; + } + +- nbd_coroutine_start(client, &request); + ret = nbd_co_send_request(bs, &request, NULL); + if (ret < 0) { + reply.error = -ret; +@@ -311,7 +301,6 @@ int nbd_client_co_flush(BlockDriverState *bs) + request.from = 0; + request.len = 0; + +- nbd_coroutine_start(client, &request); + ret = nbd_co_send_request(bs, &request, NULL); + if (ret < 0) { + reply.error = -ret; +@@ -337,7 +326,6 @@ int nbd_client_co_pdiscard(BlockDriverState *bs, int64_t offset, int count) + return 0; + } + +- nbd_coroutine_start(client, &request); + ret = nbd_co_send_request(bs, &request, NULL); + if (ret < 0) { + reply.error = -ret; +-- +2.11.0 + diff --git a/debian/patches/extra/0037-kvm-nbd-strict-nbd_wr_syncv.patch b/debian/patches/extra/0037-kvm-nbd-strict-nbd_wr_syncv.patch deleted file mode 100644 index f8245df..0000000 --- a/debian/patches/extra/0037-kvm-nbd-strict-nbd_wr_syncv.patch +++ /dev/null @@ -1,66 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Eric Blake -Date: Wed, 19 Jul 2017 18:01:59 +0200 -Subject: [PATCH] nbd: strict nbd_wr_syncv - -RH-Author: Eric Blake -Message-id: <20170719180202.23329-2-eblake@redhat.com> -Patchwork-id: 75817 -O-Subject: [RHEV-7.4.z qemu-kvm-rhev PATCH 1/4] nbd: strict nbd_wr_syncv -Bugzilla: 1467509 -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Jeffrey Cody - -From: Vladimir Sementsov-Ogievskiy - -nbd_wr_syncv is called either from coroutine or from client negotiation -code, when socket is in blocking mode. So, -EAGAIN is impossible. - -Furthermore, EAGAIN is confusing, as, what to read/write again? With -EAGAIN as a return code we don't know how much data is already -read or written by the function, so in case of EAGAIN the whole -communication is broken. - -Signed-off-by: Vladimir Sementsov-Ogievskiy -Message-Id: <20170516094533.6160-2-vsementsov@virtuozzo.com> -Signed-off-by: Paolo Bonzini -(cherry picked from commit f250a42ddaee042ad2eb02022a3ebd18fcf987de) -Signed-off-by: Eric Blake -Signed-off-by: Miroslav Rezanina ---- - nbd/common.c | 11 ++++++----- - 1 file changed, 6 insertions(+), 5 deletions(-) - -diff --git a/nbd/common.c b/nbd/common.c -index dccbb8e..4db45b3 100644 ---- a/nbd/common.c -+++ b/nbd/common.c -@@ -20,6 +20,10 @@ - #include "qapi/error.h" - #include "nbd-internal.h" - -+/* nbd_wr_syncv -+ * The function may be called from coroutine or from non-coroutine context. -+ * When called from non-coroutine context @ioc must be in blocking mode. -+ */ - ssize_t nbd_wr_syncv(QIOChannel *ioc, - struct iovec *iov, - size_t niov, -@@ -42,11 +46,8 @@ ssize_t nbd_wr_syncv(QIOChannel *ioc, - len = qio_channel_writev(ioc, local_iov, nlocal_iov, &local_err); - } - if (len == QIO_CHANNEL_ERR_BLOCK) { -- if (qemu_in_coroutine()) { -- qio_channel_yield(ioc, do_read ? G_IO_IN : G_IO_OUT); -- } else { -- return -EAGAIN; -- } -+ assert(qemu_in_coroutine()); -+ qio_channel_yield(ioc, do_read ? G_IO_IN : G_IO_OUT); - continue; - } - if (len < 0) { --- -1.8.3.1 - diff --git a/debian/patches/extra/0037-nbd-strict-nbd_wr_syncv.patch b/debian/patches/extra/0037-nbd-strict-nbd_wr_syncv.patch new file mode 100644 index 0000000..c149913 --- /dev/null +++ b/debian/patches/extra/0037-nbd-strict-nbd_wr_syncv.patch @@ -0,0 +1,52 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Vladimir Sementsov-Ogievskiy +Date: Tue, 16 May 2017 12:45:29 +0300 +Subject: [PATCH] nbd: strict nbd_wr_syncv + +nbd_wr_syncv is called either from coroutine or from client negotiation +code, when socket is in blocking mode. So, -EAGAIN is impossible. + +Furthermore, EAGAIN is confusing, as, what to read/write again? With +EAGAIN as a return code we don't know how much data is already +read or written by the function, so in case of EAGAIN the whole +communication is broken. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Message-Id: <20170516094533.6160-2-vsementsov@virtuozzo.com> +Signed-off-by: Paolo Bonzini +--- + nbd/common.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/nbd/common.c b/nbd/common.c +index dccbb8e9de..4db45b3ede 100644 +--- a/nbd/common.c ++++ b/nbd/common.c +@@ -20,6 +20,10 @@ + #include "qapi/error.h" + #include "nbd-internal.h" + ++/* nbd_wr_syncv ++ * The function may be called from coroutine or from non-coroutine context. ++ * When called from non-coroutine context @ioc must be in blocking mode. ++ */ + ssize_t nbd_wr_syncv(QIOChannel *ioc, + struct iovec *iov, + size_t niov, +@@ -42,11 +46,8 @@ ssize_t nbd_wr_syncv(QIOChannel *ioc, + len = qio_channel_writev(ioc, local_iov, nlocal_iov, &local_err); + } + if (len == QIO_CHANNEL_ERR_BLOCK) { +- if (qemu_in_coroutine()) { +- qio_channel_yield(ioc, do_read ? G_IO_IN : G_IO_OUT); +- } else { +- return -EAGAIN; +- } ++ assert(qemu_in_coroutine()); ++ qio_channel_yield(ioc, do_read ? G_IO_IN : G_IO_OUT); + continue; + } + if (len < 0) { +-- +2.11.0 + diff --git a/debian/patches/extra/0038-kvm-nbd-read_sync-and-friends-return-0-on-success.patch b/debian/patches/extra/0038-kvm-nbd-read_sync-and-friends-return-0-on-success.patch deleted file mode 100644 index 3b635b0..0000000 --- a/debian/patches/extra/0038-kvm-nbd-read_sync-and-friends-return-0-on-success.patch +++ /dev/null @@ -1,620 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Eric Blake -Date: Wed, 19 Jul 2017 18:02:00 +0200 -Subject: [PATCH] nbd: read_sync and friends: return 0 on success - -RH-Author: Eric Blake -Message-id: <20170719180202.23329-3-eblake@redhat.com> -Patchwork-id: 75818 -O-Subject: [RHEV-7.4.z qemu-kvm-rhev PATCH 2/4] nbd: read_sync and friends: return 0 on success -Bugzilla: 1467509 -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Jeffrey Cody - -From: Vladimir Sementsov-Ogievskiy - -functions read_sync, drop_sync, write_sync, and also -nbd_negotiate_write, nbd_negotiate_read, nbd_negotiate_drop_sync -returns number of processed bytes. But what this number can be, -except requested number of bytes? - -Actually, underlying nbd_wr_syncv function returns a value >= 0 and -!= requested_bytes only on eof on read operation. So, firstly, it is -impossible on write (let's add an assert) and on read it actually -means, that communication is broken (except nbd_receive_reply, see -below). - -Most of callers operate like this: - if (func(..., size) != size) { - /* error path */ - } -, i.e.: - 1. They are not interested in partial success - 2. Extra duplications in code (especially bad are duplications of - magic numbers) - 3. User doesn't see actual error message, as return code is lost. - (this patch doesn't fix this point, but it makes fixing easier) - -Several callers handles ret >= 0 and != requested-size separately, by -just returning EINVAL in this case. This patch makes read_sync and -friends return EINVAL in this case, so final behavior is the same. - -And only one caller - nbd_receive_reply() does something not so -obvious. It returns EINVAL for ret > 0 and != requested-size, like -previous group, but for ret == 0 it returns 0. The only caller of -nbd_receive_reply() - nbd_read_reply_entry() handles ret == 0 in the -same way as ret < 0, so for now it doesn't matter. However, in -following commits error path handling will be improved and we'll need -to distinguish success from fail in this case too. So, this patch adds -separate helper for this case - read_sync_eof. - -Signed-off-by: Vladimir Sementsov-Ogievskiy -Message-Id: <20170516094533.6160-3-vsementsov@virtuozzo.com> -Signed-off-by: Paolo Bonzini -(cherry picked from commit f5d406fe86bb28da85824b6581e58980cc1a07f3) -Signed-off-by: Eric Blake -Signed-off-by: Miroslav Rezanina ---- - nbd/client.c | 63 ++++++++++++++++------------------------ - nbd/nbd-internal.h | 34 +++++++++++++++++++--- - nbd/server.c | 84 +++++++++++++++++++++--------------------------------- - 3 files changed, 88 insertions(+), 93 deletions(-) - -diff --git a/nbd/client.c b/nbd/client.c -index a58fb02..6b74a62 100644 ---- a/nbd/client.c -+++ b/nbd/client.c -@@ -86,9 +86,9 @@ static QTAILQ_HEAD(, NBDExport) exports = QTAILQ_HEAD_INITIALIZER(exports); - - */ - --/* Discard length bytes from channel. Return -errno on failure, or -- * the amount of bytes consumed. */ --static ssize_t drop_sync(QIOChannel *ioc, size_t size) -+/* Discard length bytes from channel. Return -errno on failure and 0 on -+ * success*/ -+static int drop_sync(QIOChannel *ioc, size_t size) - { - ssize_t ret = 0; - char small[1024]; -@@ -96,14 +96,13 @@ static ssize_t drop_sync(QIOChannel *ioc, size_t size) - - buffer = sizeof(small) >= size ? small : g_malloc(MIN(65536, size)); - while (size > 0) { -- ssize_t count = read_sync(ioc, buffer, MIN(65536, size)); -+ ssize_t count = MIN(65536, size); -+ ret = read_sync(ioc, buffer, MIN(65536, size)); - -- if (count <= 0) { -+ if (ret < 0) { - goto cleanup; - } -- assert(count <= size); - size -= count; -- ret += count; - } - - cleanup: -@@ -136,12 +135,12 @@ static int nbd_send_option_request(QIOChannel *ioc, uint32_t opt, - stl_be_p(&req.option, opt); - stl_be_p(&req.length, len); - -- if (write_sync(ioc, &req, sizeof(req)) != sizeof(req)) { -+ if (write_sync(ioc, &req, sizeof(req)) < 0) { - error_setg(errp, "Failed to send option request header"); - return -1; - } - -- if (len && write_sync(ioc, (char *) data, len) != len) { -+ if (len && write_sync(ioc, (char *) data, len) < 0) { - error_setg(errp, "Failed to send option request data"); - return -1; - } -@@ -170,7 +169,7 @@ static int nbd_receive_option_reply(QIOChannel *ioc, uint32_t opt, - nbd_opt_reply *reply, Error **errp) - { - QEMU_BUILD_BUG_ON(sizeof(*reply) != 20); -- if (read_sync(ioc, reply, sizeof(*reply)) != sizeof(*reply)) { -+ if (read_sync(ioc, reply, sizeof(*reply)) < 0) { - error_setg(errp, "failed to read option reply"); - nbd_send_opt_abort(ioc); - return -1; -@@ -219,7 +218,7 @@ static int nbd_handle_reply_err(QIOChannel *ioc, nbd_opt_reply *reply, - goto cleanup; - } - msg = g_malloc(reply->length + 1); -- if (read_sync(ioc, msg, reply->length) != reply->length) { -+ if (read_sync(ioc, msg, reply->length) < 0) { - error_setg(errp, "failed to read option error message"); - goto cleanup; - } -@@ -321,7 +320,7 @@ static int nbd_receive_list(QIOChannel *ioc, const char *want, bool *match, - nbd_send_opt_abort(ioc); - return -1; - } -- if (read_sync(ioc, &namelen, sizeof(namelen)) != sizeof(namelen)) { -+ if (read_sync(ioc, &namelen, sizeof(namelen)) < 0) { - error_setg(errp, "failed to read option name length"); - nbd_send_opt_abort(ioc); - return -1; -@@ -334,7 +333,7 @@ static int nbd_receive_list(QIOChannel *ioc, const char *want, bool *match, - return -1; - } - if (namelen != strlen(want)) { -- if (drop_sync(ioc, len) != len) { -+ if (drop_sync(ioc, len) < 0) { - error_setg(errp, "failed to skip export name with wrong length"); - nbd_send_opt_abort(ioc); - return -1; -@@ -343,14 +342,14 @@ static int nbd_receive_list(QIOChannel *ioc, const char *want, bool *match, - } - - assert(namelen < sizeof(name)); -- if (read_sync(ioc, name, namelen) != namelen) { -+ if (read_sync(ioc, name, namelen) < 0) { - error_setg(errp, "failed to read export name"); - nbd_send_opt_abort(ioc); - return -1; - } - name[namelen] = '\0'; - len -= namelen; -- if (drop_sync(ioc, len) != len) { -+ if (drop_sync(ioc, len) < 0) { - error_setg(errp, "failed to read export description"); - nbd_send_opt_abort(ioc); - return -1; -@@ -477,7 +476,7 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags, - goto fail; - } - -- if (read_sync(ioc, buf, 8) != 8) { -+ if (read_sync(ioc, buf, 8) < 0) { - error_setg(errp, "Failed to read data"); - goto fail; - } -@@ -503,7 +502,7 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags, - goto fail; - } - -- if (read_sync(ioc, &magic, sizeof(magic)) != sizeof(magic)) { -+ if (read_sync(ioc, &magic, sizeof(magic)) < 0) { - error_setg(errp, "Failed to read magic"); - goto fail; - } -@@ -515,8 +514,7 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags, - uint16_t globalflags; - bool fixedNewStyle = false; - -- if (read_sync(ioc, &globalflags, sizeof(globalflags)) != -- sizeof(globalflags)) { -+ if (read_sync(ioc, &globalflags, sizeof(globalflags)) < 0) { - error_setg(errp, "Failed to read server flags"); - goto fail; - } -@@ -534,8 +532,7 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags, - } - /* client requested flags */ - clientflags = cpu_to_be32(clientflags); -- if (write_sync(ioc, &clientflags, sizeof(clientflags)) != -- sizeof(clientflags)) { -+ if (write_sync(ioc, &clientflags, sizeof(clientflags)) < 0) { - error_setg(errp, "Failed to send clientflags field"); - goto fail; - } -@@ -573,13 +570,13 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags, - } - - /* Read the response */ -- if (read_sync(ioc, &s, sizeof(s)) != sizeof(s)) { -+ if (read_sync(ioc, &s, sizeof(s)) < 0) { - error_setg(errp, "Failed to read export length"); - goto fail; - } - *size = be64_to_cpu(s); - -- if (read_sync(ioc, flags, sizeof(*flags)) != sizeof(*flags)) { -+ if (read_sync(ioc, flags, sizeof(*flags)) < 0) { - error_setg(errp, "Failed to read export flags"); - goto fail; - } -@@ -596,14 +593,14 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags, - goto fail; - } - -- if (read_sync(ioc, &s, sizeof(s)) != sizeof(s)) { -+ if (read_sync(ioc, &s, sizeof(s)) < 0) { - error_setg(errp, "Failed to read export length"); - goto fail; - } - *size = be64_to_cpu(s); - TRACE("Size is %" PRIu64, *size); - -- if (read_sync(ioc, &oldflags, sizeof(oldflags)) != sizeof(oldflags)) { -+ if (read_sync(ioc, &oldflags, sizeof(oldflags)) < 0) { - error_setg(errp, "Failed to read export flags"); - goto fail; - } -@@ -619,7 +616,7 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags, - } - - TRACE("Size is %" PRIu64 ", export flags %" PRIx16, *size, *flags); -- if (zeroes && drop_sync(ioc, 124) != 124) { -+ if (zeroes && drop_sync(ioc, 124) < 0) { - error_setg(errp, "Failed to read reserved block"); - goto fail; - } -@@ -744,7 +741,6 @@ int nbd_disconnect(int fd) - ssize_t nbd_send_request(QIOChannel *ioc, NBDRequest *request) - { - uint8_t buf[NBD_REQUEST_SIZE]; -- ssize_t ret; - - TRACE("Sending request to server: " - "{ .from = %" PRIu64", .len = %" PRIu32 ", .handle = %" PRIu64 -@@ -759,16 +755,7 @@ ssize_t nbd_send_request(QIOChannel *ioc, NBDRequest *request) - stq_be_p(buf + 16, request->from); - stl_be_p(buf + 24, request->len); - -- ret = write_sync(ioc, buf, sizeof(buf)); -- if (ret < 0) { -- return ret; -- } -- -- if (ret != sizeof(buf)) { -- LOG("writing to socket failed"); -- return -EINVAL; -- } -- return 0; -+ return write_sync(ioc, buf, sizeof(buf)); - } - - ssize_t nbd_receive_reply(QIOChannel *ioc, NBDReply *reply) -@@ -777,7 +764,7 @@ ssize_t nbd_receive_reply(QIOChannel *ioc, NBDReply *reply) - uint32_t magic; - ssize_t ret; - -- ret = read_sync(ioc, buf, sizeof(buf)); -+ ret = read_sync_eof(ioc, buf, sizeof(buf)); - if (ret <= 0) { - return ret; - } -diff --git a/nbd/nbd-internal.h b/nbd/nbd-internal.h -index f43d990..e6bbc7c 100644 ---- a/nbd/nbd-internal.h -+++ b/nbd/nbd-internal.h -@@ -94,7 +94,13 @@ - #define NBD_ENOSPC 28 - #define NBD_ESHUTDOWN 108 - --static inline ssize_t read_sync(QIOChannel *ioc, void *buffer, size_t size) -+/* read_sync_eof -+ * Tries to read @size bytes from @ioc. Returns number of bytes actually read. -+ * May return a value >= 0 and < size only on EOF, i.e. when iteratively called -+ * qio_channel_readv() returns 0. So, there are no needs to call read_sync_eof -+ * iteratively. -+ */ -+static inline ssize_t read_sync_eof(QIOChannel *ioc, void *buffer, size_t size) - { - struct iovec iov = { .iov_base = buffer, .iov_len = size }; - /* Sockets are kept in blocking mode in the negotiation phase. After -@@ -105,12 +111,32 @@ static inline ssize_t read_sync(QIOChannel *ioc, void *buffer, size_t size) - return nbd_wr_syncv(ioc, &iov, 1, size, true); - } - --static inline ssize_t write_sync(QIOChannel *ioc, const void *buffer, -- size_t size) -+/* read_sync -+ * Reads @size bytes from @ioc. Returns 0 on success. -+ */ -+static inline int read_sync(QIOChannel *ioc, void *buffer, size_t size) -+{ -+ ssize_t ret = read_sync_eof(ioc, buffer, size); -+ -+ if (ret >= 0 && ret != size) { -+ ret = -EINVAL; -+ } -+ -+ return ret < 0 ? ret : 0; -+} -+ -+/* write_sync -+ * Writes @size bytes to @ioc. Returns 0 on success. -+ */ -+static inline int write_sync(QIOChannel *ioc, const void *buffer, size_t size) - { - struct iovec iov = { .iov_base = (void *) buffer, .iov_len = size }; - -- return nbd_wr_syncv(ioc, &iov, 1, size, false); -+ ssize_t ret = nbd_wr_syncv(ioc, &iov, 1, size, false); -+ -+ assert(ret < 0 || ret == size); -+ -+ return ret < 0 ? ret : 0; - } - - struct NBDTLSHandshakeData { -diff --git a/nbd/server.c b/nbd/server.c -index a98bb21..b44cbe6 100644 ---- a/nbd/server.c -+++ b/nbd/server.c -@@ -112,7 +112,7 @@ static gboolean nbd_negotiate_continue(QIOChannel *ioc, - return TRUE; - } - --static ssize_t nbd_negotiate_read(QIOChannel *ioc, void *buffer, size_t size) -+static int nbd_negotiate_read(QIOChannel *ioc, void *buffer, size_t size) - { - ssize_t ret; - guint watch; -@@ -130,8 +130,7 @@ static ssize_t nbd_negotiate_read(QIOChannel *ioc, void *buffer, size_t size) - - } - --static ssize_t nbd_negotiate_write(QIOChannel *ioc, const void *buffer, -- size_t size) -+static int nbd_negotiate_write(QIOChannel *ioc, const void *buffer, size_t size) - { - ssize_t ret; - guint watch; -@@ -148,24 +147,24 @@ static ssize_t nbd_negotiate_write(QIOChannel *ioc, const void *buffer, - return ret; - } - --static ssize_t nbd_negotiate_drop_sync(QIOChannel *ioc, size_t size) -+static int nbd_negotiate_drop_sync(QIOChannel *ioc, size_t size) - { -- ssize_t ret, dropped = size; -+ ssize_t ret; - uint8_t *buffer = g_malloc(MIN(65536, size)); - - while (size > 0) { -- ret = nbd_negotiate_read(ioc, buffer, MIN(65536, size)); -+ size_t count = MIN(65536, size); -+ ret = nbd_negotiate_read(ioc, buffer, count); - if (ret < 0) { - g_free(buffer); - return ret; - } - -- assert(ret <= size); -- size -= ret; -+ size -= count; - } - - g_free(buffer); -- return dropped; -+ return 0; - } - - /* Basic flow for negotiation -@@ -206,22 +205,22 @@ static int nbd_negotiate_send_rep_len(QIOChannel *ioc, uint32_t type, - type, opt, len); - - magic = cpu_to_be64(NBD_REP_MAGIC); -- if (nbd_negotiate_write(ioc, &magic, sizeof(magic)) != sizeof(magic)) { -+ if (nbd_negotiate_write(ioc, &magic, sizeof(magic)) < 0) { - LOG("write failed (rep magic)"); - return -EINVAL; - } - opt = cpu_to_be32(opt); -- if (nbd_negotiate_write(ioc, &opt, sizeof(opt)) != sizeof(opt)) { -+ if (nbd_negotiate_write(ioc, &opt, sizeof(opt)) < 0) { - LOG("write failed (rep opt)"); - return -EINVAL; - } - type = cpu_to_be32(type); -- if (nbd_negotiate_write(ioc, &type, sizeof(type)) != sizeof(type)) { -+ if (nbd_negotiate_write(ioc, &type, sizeof(type)) < 0) { - LOG("write failed (rep type)"); - return -EINVAL; - } - len = cpu_to_be32(len); -- if (nbd_negotiate_write(ioc, &len, sizeof(len)) != sizeof(len)) { -+ if (nbd_negotiate_write(ioc, &len, sizeof(len)) < 0) { - LOG("write failed (rep data length)"); - return -EINVAL; - } -@@ -256,7 +255,7 @@ nbd_negotiate_send_rep_err(QIOChannel *ioc, uint32_t type, - if (ret < 0) { - goto out; - } -- if (nbd_negotiate_write(ioc, msg, len) != len) { -+ if (nbd_negotiate_write(ioc, msg, len) < 0) { - LOG("write failed (error message)"); - ret = -EIO; - } else { -@@ -287,15 +286,15 @@ static int nbd_negotiate_send_rep_list(QIOChannel *ioc, NBDExport *exp) - } - - len = cpu_to_be32(name_len); -- if (nbd_negotiate_write(ioc, &len, sizeof(len)) != sizeof(len)) { -+ if (nbd_negotiate_write(ioc, &len, sizeof(len)) < 0) { - LOG("write failed (name length)"); - return -EINVAL; - } -- if (nbd_negotiate_write(ioc, name, name_len) != name_len) { -+ if (nbd_negotiate_write(ioc, name, name_len) < 0) { - LOG("write failed (name buffer)"); - return -EINVAL; - } -- if (nbd_negotiate_write(ioc, desc, desc_len) != desc_len) { -+ if (nbd_negotiate_write(ioc, desc, desc_len) < 0) { - LOG("write failed (description buffer)"); - return -EINVAL; - } -@@ -309,7 +308,7 @@ static int nbd_negotiate_handle_list(NBDClient *client, uint32_t length) - NBDExport *exp; - - if (length) { -- if (nbd_negotiate_drop_sync(client->ioc, length) != length) { -+ if (nbd_negotiate_drop_sync(client->ioc, length) < 0) { - return -EIO; - } - return nbd_negotiate_send_rep_err(client->ioc, -@@ -340,7 +339,7 @@ static int nbd_negotiate_handle_export_name(NBDClient *client, uint32_t length) - LOG("Bad length received"); - goto fail; - } -- if (nbd_negotiate_read(client->ioc, name, length) != length) { -+ if (nbd_negotiate_read(client->ioc, name, length) < 0) { - LOG("read failed"); - goto fail; - } -@@ -373,7 +372,7 @@ static QIOChannel *nbd_negotiate_handle_starttls(NBDClient *client, - TRACE("Setting up TLS"); - ioc = client->ioc; - if (length) { -- if (nbd_negotiate_drop_sync(ioc, length) != length) { -+ if (nbd_negotiate_drop_sync(ioc, length) < 0) { - return NULL; - } - nbd_negotiate_send_rep_err(ioc, NBD_REP_ERR_INVALID, NBD_OPT_STARTTLS, -@@ -437,8 +436,7 @@ static int nbd_negotiate_options(NBDClient *client) - ... Rest of request - */ - -- if (nbd_negotiate_read(client->ioc, &flags, sizeof(flags)) != -- sizeof(flags)) { -+ if (nbd_negotiate_read(client->ioc, &flags, sizeof(flags)) < 0) { - LOG("read failed"); - return -EIO; - } -@@ -464,8 +462,7 @@ static int nbd_negotiate_options(NBDClient *client) - uint32_t clientflags, length; - uint64_t magic; - -- if (nbd_negotiate_read(client->ioc, &magic, sizeof(magic)) != -- sizeof(magic)) { -+ if (nbd_negotiate_read(client->ioc, &magic, sizeof(magic)) < 0) { - LOG("read failed"); - return -EINVAL; - } -@@ -476,14 +473,14 @@ static int nbd_negotiate_options(NBDClient *client) - } - - if (nbd_negotiate_read(client->ioc, &clientflags, -- sizeof(clientflags)) != sizeof(clientflags)) { -+ sizeof(clientflags)) < 0) -+ { - LOG("read failed"); - return -EINVAL; - } - clientflags = be32_to_cpu(clientflags); - -- if (nbd_negotiate_read(client->ioc, &length, sizeof(length)) != -- sizeof(length)) { -+ if (nbd_negotiate_read(client->ioc, &length, sizeof(length)) < 0) { - LOG("read failed"); - return -EINVAL; - } -@@ -513,7 +510,7 @@ static int nbd_negotiate_options(NBDClient *client) - return -EINVAL; - - default: -- if (nbd_negotiate_drop_sync(client->ioc, length) != length) { -+ if (nbd_negotiate_drop_sync(client->ioc, length) < 0) { - return -EIO; - } - ret = nbd_negotiate_send_rep_err(client->ioc, -@@ -551,7 +548,7 @@ static int nbd_negotiate_options(NBDClient *client) - return nbd_negotiate_handle_export_name(client, length); - - case NBD_OPT_STARTTLS: -- if (nbd_negotiate_drop_sync(client->ioc, length) != length) { -+ if (nbd_negotiate_drop_sync(client->ioc, length) < 0) { - return -EIO; - } - if (client->tlscreds) { -@@ -570,7 +567,7 @@ static int nbd_negotiate_options(NBDClient *client) - } - break; - default: -- if (nbd_negotiate_drop_sync(client->ioc, length) != length) { -+ if (nbd_negotiate_drop_sync(client->ioc, length) < 0) { - return -EIO; - } - ret = nbd_negotiate_send_rep_err(client->ioc, -@@ -659,12 +656,12 @@ static coroutine_fn int nbd_negotiate(NBDClientNewData *data) - TRACE("TLS cannot be enabled with oldstyle protocol"); - goto fail; - } -- if (nbd_negotiate_write(client->ioc, buf, sizeof(buf)) != sizeof(buf)) { -+ if (nbd_negotiate_write(client->ioc, buf, sizeof(buf)) < 0) { - LOG("write failed"); - goto fail; - } - } else { -- if (nbd_negotiate_write(client->ioc, buf, 18) != 18) { -+ if (nbd_negotiate_write(client->ioc, buf, 18) < 0) { - LOG("write failed"); - goto fail; - } -@@ -679,7 +676,7 @@ static coroutine_fn int nbd_negotiate(NBDClientNewData *data) - stq_be_p(buf + 18, client->exp->size); - stw_be_p(buf + 26, client->exp->nbdflags | myflags); - len = client->no_zeroes ? 10 : sizeof(buf) - 18; -- if (nbd_negotiate_write(client->ioc, buf + 18, len) != len) { -+ if (nbd_negotiate_write(client->ioc, buf + 18, len) < 0) { - LOG("write failed"); - goto fail; - } -@@ -702,11 +699,6 @@ static ssize_t nbd_receive_request(QIOChannel *ioc, NBDRequest *request) - return ret; - } - -- if (ret != sizeof(buf)) { -- LOG("read failed"); -- return -EINVAL; -- } -- - /* Request - [ 0 .. 3] magic (NBD_REQUEST_MAGIC) - [ 4 .. 5] flags (NBD_CMD_FLAG_FUA, ...) -@@ -737,7 +729,6 @@ static ssize_t nbd_receive_request(QIOChannel *ioc, NBDRequest *request) - static ssize_t nbd_send_reply(QIOChannel *ioc, NBDReply *reply) - { - uint8_t buf[NBD_REPLY_SIZE]; -- ssize_t ret; - - reply->error = system_errno_to_nbd_errno(reply->error); - -@@ -754,16 +745,7 @@ static ssize_t nbd_send_reply(QIOChannel *ioc, NBDReply *reply) - stl_be_p(buf + 4, reply->error); - stq_be_p(buf + 8, reply->handle); - -- ret = write_sync(ioc, buf, sizeof(buf)); -- if (ret < 0) { -- return ret; -- } -- -- if (ret != sizeof(buf)) { -- LOG("writing to socket failed"); -- return -EINVAL; -- } -- return 0; -+ return write_sync(ioc, buf, sizeof(buf)); - } - - #define MAX_NBD_REQUESTS 16 -@@ -1067,7 +1049,7 @@ static ssize_t nbd_co_send_reply(NBDRequestData *req, NBDReply *reply, - rc = nbd_send_reply(client->ioc, reply); - if (rc >= 0) { - ret = write_sync(client->ioc, req->data, len); -- if (ret != len) { -+ if (ret < 0) { - rc = -EIO; - } - } -@@ -1141,7 +1123,7 @@ static ssize_t nbd_co_receive_request(NBDRequestData *req, - if (request->type == NBD_CMD_WRITE) { - TRACE("Reading %" PRIu32 " byte(s)", request->len); - -- if (read_sync(client->ioc, req->data, request->len) != request->len) { -+ if (read_sync(client->ioc, req->data, request->len) < 0) { - LOG("reading from socket failed"); - rc = -EIO; - goto out; --- -1.8.3.1 - diff --git a/debian/patches/extra/0038-nbd-read_sync-and-friends-return-0-on-success.patch b/debian/patches/extra/0038-nbd-read_sync-and-friends-return-0-on-success.patch new file mode 100644 index 0000000..91d5205 --- /dev/null +++ b/debian/patches/extra/0038-nbd-read_sync-and-friends-return-0-on-success.patch @@ -0,0 +1,606 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Vladimir Sementsov-Ogievskiy +Date: Tue, 16 May 2017 12:45:30 +0300 +Subject: [PATCH] nbd: read_sync and friends: return 0 on success + +functions read_sync, drop_sync, write_sync, and also +nbd_negotiate_write, nbd_negotiate_read, nbd_negotiate_drop_sync +returns number of processed bytes. But what this number can be, +except requested number of bytes? + +Actually, underlying nbd_wr_syncv function returns a value >= 0 and +!= requested_bytes only on eof on read operation. So, firstly, it is +impossible on write (let's add an assert) and on read it actually +means, that communication is broken (except nbd_receive_reply, see +below). + +Most of callers operate like this: + if (func(..., size) != size) { + /* error path */ + } +, i.e.: + 1. They are not interested in partial success + 2. Extra duplications in code (especially bad are duplications of + magic numbers) + 3. User doesn't see actual error message, as return code is lost. + (this patch doesn't fix this point, but it makes fixing easier) + +Several callers handles ret >= 0 and != requested-size separately, by +just returning EINVAL in this case. This patch makes read_sync and +friends return EINVAL in this case, so final behavior is the same. + +And only one caller - nbd_receive_reply() does something not so +obvious. It returns EINVAL for ret > 0 and != requested-size, like +previous group, but for ret == 0 it returns 0. The only caller of +nbd_receive_reply() - nbd_read_reply_entry() handles ret == 0 in the +same way as ret < 0, so for now it doesn't matter. However, in +following commits error path handling will be improved and we'll need +to distinguish success from fail in this case too. So, this patch adds +separate helper for this case - read_sync_eof. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Message-Id: <20170516094533.6160-3-vsementsov@virtuozzo.com> +Signed-off-by: Paolo Bonzini +--- + nbd/client.c | 63 ++++++++++++++++------------------------ + nbd/nbd-internal.h | 34 +++++++++++++++++++--- + nbd/server.c | 84 +++++++++++++++++++++--------------------------------- + 3 files changed, 88 insertions(+), 93 deletions(-) + +diff --git a/nbd/client.c b/nbd/client.c +index a58fb02cb4..6b74a628f1 100644 +--- a/nbd/client.c ++++ b/nbd/client.c +@@ -86,9 +86,9 @@ static QTAILQ_HEAD(, NBDExport) exports = QTAILQ_HEAD_INITIALIZER(exports); + + */ + +-/* Discard length bytes from channel. Return -errno on failure, or +- * the amount of bytes consumed. */ +-static ssize_t drop_sync(QIOChannel *ioc, size_t size) ++/* Discard length bytes from channel. Return -errno on failure and 0 on ++ * success*/ ++static int drop_sync(QIOChannel *ioc, size_t size) + { + ssize_t ret = 0; + char small[1024]; +@@ -96,14 +96,13 @@ static ssize_t drop_sync(QIOChannel *ioc, size_t size) + + buffer = sizeof(small) >= size ? small : g_malloc(MIN(65536, size)); + while (size > 0) { +- ssize_t count = read_sync(ioc, buffer, MIN(65536, size)); ++ ssize_t count = MIN(65536, size); ++ ret = read_sync(ioc, buffer, MIN(65536, size)); + +- if (count <= 0) { ++ if (ret < 0) { + goto cleanup; + } +- assert(count <= size); + size -= count; +- ret += count; + } + + cleanup: +@@ -136,12 +135,12 @@ static int nbd_send_option_request(QIOChannel *ioc, uint32_t opt, + stl_be_p(&req.option, opt); + stl_be_p(&req.length, len); + +- if (write_sync(ioc, &req, sizeof(req)) != sizeof(req)) { ++ if (write_sync(ioc, &req, sizeof(req)) < 0) { + error_setg(errp, "Failed to send option request header"); + return -1; + } + +- if (len && write_sync(ioc, (char *) data, len) != len) { ++ if (len && write_sync(ioc, (char *) data, len) < 0) { + error_setg(errp, "Failed to send option request data"); + return -1; + } +@@ -170,7 +169,7 @@ static int nbd_receive_option_reply(QIOChannel *ioc, uint32_t opt, + nbd_opt_reply *reply, Error **errp) + { + QEMU_BUILD_BUG_ON(sizeof(*reply) != 20); +- if (read_sync(ioc, reply, sizeof(*reply)) != sizeof(*reply)) { ++ if (read_sync(ioc, reply, sizeof(*reply)) < 0) { + error_setg(errp, "failed to read option reply"); + nbd_send_opt_abort(ioc); + return -1; +@@ -219,7 +218,7 @@ static int nbd_handle_reply_err(QIOChannel *ioc, nbd_opt_reply *reply, + goto cleanup; + } + msg = g_malloc(reply->length + 1); +- if (read_sync(ioc, msg, reply->length) != reply->length) { ++ if (read_sync(ioc, msg, reply->length) < 0) { + error_setg(errp, "failed to read option error message"); + goto cleanup; + } +@@ -321,7 +320,7 @@ static int nbd_receive_list(QIOChannel *ioc, const char *want, bool *match, + nbd_send_opt_abort(ioc); + return -1; + } +- if (read_sync(ioc, &namelen, sizeof(namelen)) != sizeof(namelen)) { ++ if (read_sync(ioc, &namelen, sizeof(namelen)) < 0) { + error_setg(errp, "failed to read option name length"); + nbd_send_opt_abort(ioc); + return -1; +@@ -334,7 +333,7 @@ static int nbd_receive_list(QIOChannel *ioc, const char *want, bool *match, + return -1; + } + if (namelen != strlen(want)) { +- if (drop_sync(ioc, len) != len) { ++ if (drop_sync(ioc, len) < 0) { + error_setg(errp, "failed to skip export name with wrong length"); + nbd_send_opt_abort(ioc); + return -1; +@@ -343,14 +342,14 @@ static int nbd_receive_list(QIOChannel *ioc, const char *want, bool *match, + } + + assert(namelen < sizeof(name)); +- if (read_sync(ioc, name, namelen) != namelen) { ++ if (read_sync(ioc, name, namelen) < 0) { + error_setg(errp, "failed to read export name"); + nbd_send_opt_abort(ioc); + return -1; + } + name[namelen] = '\0'; + len -= namelen; +- if (drop_sync(ioc, len) != len) { ++ if (drop_sync(ioc, len) < 0) { + error_setg(errp, "failed to read export description"); + nbd_send_opt_abort(ioc); + return -1; +@@ -477,7 +476,7 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags, + goto fail; + } + +- if (read_sync(ioc, buf, 8) != 8) { ++ if (read_sync(ioc, buf, 8) < 0) { + error_setg(errp, "Failed to read data"); + goto fail; + } +@@ -503,7 +502,7 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags, + goto fail; + } + +- if (read_sync(ioc, &magic, sizeof(magic)) != sizeof(magic)) { ++ if (read_sync(ioc, &magic, sizeof(magic)) < 0) { + error_setg(errp, "Failed to read magic"); + goto fail; + } +@@ -515,8 +514,7 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags, + uint16_t globalflags; + bool fixedNewStyle = false; + +- if (read_sync(ioc, &globalflags, sizeof(globalflags)) != +- sizeof(globalflags)) { ++ if (read_sync(ioc, &globalflags, sizeof(globalflags)) < 0) { + error_setg(errp, "Failed to read server flags"); + goto fail; + } +@@ -534,8 +532,7 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags, + } + /* client requested flags */ + clientflags = cpu_to_be32(clientflags); +- if (write_sync(ioc, &clientflags, sizeof(clientflags)) != +- sizeof(clientflags)) { ++ if (write_sync(ioc, &clientflags, sizeof(clientflags)) < 0) { + error_setg(errp, "Failed to send clientflags field"); + goto fail; + } +@@ -573,13 +570,13 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags, + } + + /* Read the response */ +- if (read_sync(ioc, &s, sizeof(s)) != sizeof(s)) { ++ if (read_sync(ioc, &s, sizeof(s)) < 0) { + error_setg(errp, "Failed to read export length"); + goto fail; + } + *size = be64_to_cpu(s); + +- if (read_sync(ioc, flags, sizeof(*flags)) != sizeof(*flags)) { ++ if (read_sync(ioc, flags, sizeof(*flags)) < 0) { + error_setg(errp, "Failed to read export flags"); + goto fail; + } +@@ -596,14 +593,14 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags, + goto fail; + } + +- if (read_sync(ioc, &s, sizeof(s)) != sizeof(s)) { ++ if (read_sync(ioc, &s, sizeof(s)) < 0) { + error_setg(errp, "Failed to read export length"); + goto fail; + } + *size = be64_to_cpu(s); + TRACE("Size is %" PRIu64, *size); + +- if (read_sync(ioc, &oldflags, sizeof(oldflags)) != sizeof(oldflags)) { ++ if (read_sync(ioc, &oldflags, sizeof(oldflags)) < 0) { + error_setg(errp, "Failed to read export flags"); + goto fail; + } +@@ -619,7 +616,7 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags, + } + + TRACE("Size is %" PRIu64 ", export flags %" PRIx16, *size, *flags); +- if (zeroes && drop_sync(ioc, 124) != 124) { ++ if (zeroes && drop_sync(ioc, 124) < 0) { + error_setg(errp, "Failed to read reserved block"); + goto fail; + } +@@ -744,7 +741,6 @@ int nbd_disconnect(int fd) + ssize_t nbd_send_request(QIOChannel *ioc, NBDRequest *request) + { + uint8_t buf[NBD_REQUEST_SIZE]; +- ssize_t ret; + + TRACE("Sending request to server: " + "{ .from = %" PRIu64", .len = %" PRIu32 ", .handle = %" PRIu64 +@@ -759,16 +755,7 @@ ssize_t nbd_send_request(QIOChannel *ioc, NBDRequest *request) + stq_be_p(buf + 16, request->from); + stl_be_p(buf + 24, request->len); + +- ret = write_sync(ioc, buf, sizeof(buf)); +- if (ret < 0) { +- return ret; +- } +- +- if (ret != sizeof(buf)) { +- LOG("writing to socket failed"); +- return -EINVAL; +- } +- return 0; ++ return write_sync(ioc, buf, sizeof(buf)); + } + + ssize_t nbd_receive_reply(QIOChannel *ioc, NBDReply *reply) +@@ -777,7 +764,7 @@ ssize_t nbd_receive_reply(QIOChannel *ioc, NBDReply *reply) + uint32_t magic; + ssize_t ret; + +- ret = read_sync(ioc, buf, sizeof(buf)); ++ ret = read_sync_eof(ioc, buf, sizeof(buf)); + if (ret <= 0) { + return ret; + } +diff --git a/nbd/nbd-internal.h b/nbd/nbd-internal.h +index f43d990a05..e6bbc7c4b4 100644 +--- a/nbd/nbd-internal.h ++++ b/nbd/nbd-internal.h +@@ -94,7 +94,13 @@ + #define NBD_ENOSPC 28 + #define NBD_ESHUTDOWN 108 + +-static inline ssize_t read_sync(QIOChannel *ioc, void *buffer, size_t size) ++/* read_sync_eof ++ * Tries to read @size bytes from @ioc. Returns number of bytes actually read. ++ * May return a value >= 0 and < size only on EOF, i.e. when iteratively called ++ * qio_channel_readv() returns 0. So, there are no needs to call read_sync_eof ++ * iteratively. ++ */ ++static inline ssize_t read_sync_eof(QIOChannel *ioc, void *buffer, size_t size) + { + struct iovec iov = { .iov_base = buffer, .iov_len = size }; + /* Sockets are kept in blocking mode in the negotiation phase. After +@@ -105,12 +111,32 @@ static inline ssize_t read_sync(QIOChannel *ioc, void *buffer, size_t size) + return nbd_wr_syncv(ioc, &iov, 1, size, true); + } + +-static inline ssize_t write_sync(QIOChannel *ioc, const void *buffer, +- size_t size) ++/* read_sync ++ * Reads @size bytes from @ioc. Returns 0 on success. ++ */ ++static inline int read_sync(QIOChannel *ioc, void *buffer, size_t size) ++{ ++ ssize_t ret = read_sync_eof(ioc, buffer, size); ++ ++ if (ret >= 0 && ret != size) { ++ ret = -EINVAL; ++ } ++ ++ return ret < 0 ? ret : 0; ++} ++ ++/* write_sync ++ * Writes @size bytes to @ioc. Returns 0 on success. ++ */ ++static inline int write_sync(QIOChannel *ioc, const void *buffer, size_t size) + { + struct iovec iov = { .iov_base = (void *) buffer, .iov_len = size }; + +- return nbd_wr_syncv(ioc, &iov, 1, size, false); ++ ssize_t ret = nbd_wr_syncv(ioc, &iov, 1, size, false); ++ ++ assert(ret < 0 || ret == size); ++ ++ return ret < 0 ? ret : 0; + } + + struct NBDTLSHandshakeData { +diff --git a/nbd/server.c b/nbd/server.c +index 4d6da8ac06..c2a5909ad6 100644 +--- a/nbd/server.c ++++ b/nbd/server.c +@@ -112,7 +112,7 @@ static gboolean nbd_negotiate_continue(QIOChannel *ioc, + return TRUE; + } + +-static ssize_t nbd_negotiate_read(QIOChannel *ioc, void *buffer, size_t size) ++static int nbd_negotiate_read(QIOChannel *ioc, void *buffer, size_t size) + { + ssize_t ret; + guint watch; +@@ -130,8 +130,7 @@ static ssize_t nbd_negotiate_read(QIOChannel *ioc, void *buffer, size_t size) + + } + +-static ssize_t nbd_negotiate_write(QIOChannel *ioc, const void *buffer, +- size_t size) ++static int nbd_negotiate_write(QIOChannel *ioc, const void *buffer, size_t size) + { + ssize_t ret; + guint watch; +@@ -148,24 +147,24 @@ static ssize_t nbd_negotiate_write(QIOChannel *ioc, const void *buffer, + return ret; + } + +-static ssize_t nbd_negotiate_drop_sync(QIOChannel *ioc, size_t size) ++static int nbd_negotiate_drop_sync(QIOChannel *ioc, size_t size) + { +- ssize_t ret, dropped = size; ++ ssize_t ret; + uint8_t *buffer = g_malloc(MIN(65536, size)); + + while (size > 0) { +- ret = nbd_negotiate_read(ioc, buffer, MIN(65536, size)); ++ size_t count = MIN(65536, size); ++ ret = nbd_negotiate_read(ioc, buffer, count); + if (ret < 0) { + g_free(buffer); + return ret; + } + +- assert(ret <= size); +- size -= ret; ++ size -= count; + } + + g_free(buffer); +- return dropped; ++ return 0; + } + + /* Basic flow for negotiation +@@ -206,22 +205,22 @@ static int nbd_negotiate_send_rep_len(QIOChannel *ioc, uint32_t type, + type, opt, len); + + magic = cpu_to_be64(NBD_REP_MAGIC); +- if (nbd_negotiate_write(ioc, &magic, sizeof(magic)) != sizeof(magic)) { ++ if (nbd_negotiate_write(ioc, &magic, sizeof(magic)) < 0) { + LOG("write failed (rep magic)"); + return -EINVAL; + } + opt = cpu_to_be32(opt); +- if (nbd_negotiate_write(ioc, &opt, sizeof(opt)) != sizeof(opt)) { ++ if (nbd_negotiate_write(ioc, &opt, sizeof(opt)) < 0) { + LOG("write failed (rep opt)"); + return -EINVAL; + } + type = cpu_to_be32(type); +- if (nbd_negotiate_write(ioc, &type, sizeof(type)) != sizeof(type)) { ++ if (nbd_negotiate_write(ioc, &type, sizeof(type)) < 0) { + LOG("write failed (rep type)"); + return -EINVAL; + } + len = cpu_to_be32(len); +- if (nbd_negotiate_write(ioc, &len, sizeof(len)) != sizeof(len)) { ++ if (nbd_negotiate_write(ioc, &len, sizeof(len)) < 0) { + LOG("write failed (rep data length)"); + return -EINVAL; + } +@@ -256,7 +255,7 @@ nbd_negotiate_send_rep_err(QIOChannel *ioc, uint32_t type, + if (ret < 0) { + goto out; + } +- if (nbd_negotiate_write(ioc, msg, len) != len) { ++ if (nbd_negotiate_write(ioc, msg, len) < 0) { + LOG("write failed (error message)"); + ret = -EIO; + } else { +@@ -287,15 +286,15 @@ static int nbd_negotiate_send_rep_list(QIOChannel *ioc, NBDExport *exp) + } + + len = cpu_to_be32(name_len); +- if (nbd_negotiate_write(ioc, &len, sizeof(len)) != sizeof(len)) { ++ if (nbd_negotiate_write(ioc, &len, sizeof(len)) < 0) { + LOG("write failed (name length)"); + return -EINVAL; + } +- if (nbd_negotiate_write(ioc, name, name_len) != name_len) { ++ if (nbd_negotiate_write(ioc, name, name_len) < 0) { + LOG("write failed (name buffer)"); + return -EINVAL; + } +- if (nbd_negotiate_write(ioc, desc, desc_len) != desc_len) { ++ if (nbd_negotiate_write(ioc, desc, desc_len) < 0) { + LOG("write failed (description buffer)"); + return -EINVAL; + } +@@ -309,7 +308,7 @@ static int nbd_negotiate_handle_list(NBDClient *client, uint32_t length) + NBDExport *exp; + + if (length) { +- if (nbd_negotiate_drop_sync(client->ioc, length) != length) { ++ if (nbd_negotiate_drop_sync(client->ioc, length) < 0) { + return -EIO; + } + return nbd_negotiate_send_rep_err(client->ioc, +@@ -340,7 +339,7 @@ static int nbd_negotiate_handle_export_name(NBDClient *client, uint32_t length) + LOG("Bad length received"); + goto fail; + } +- if (nbd_negotiate_read(client->ioc, name, length) != length) { ++ if (nbd_negotiate_read(client->ioc, name, length) < 0) { + LOG("read failed"); + goto fail; + } +@@ -373,7 +372,7 @@ static QIOChannel *nbd_negotiate_handle_starttls(NBDClient *client, + TRACE("Setting up TLS"); + ioc = client->ioc; + if (length) { +- if (nbd_negotiate_drop_sync(ioc, length) != length) { ++ if (nbd_negotiate_drop_sync(ioc, length) < 0) { + return NULL; + } + nbd_negotiate_send_rep_err(ioc, NBD_REP_ERR_INVALID, NBD_OPT_STARTTLS, +@@ -437,8 +436,7 @@ static int nbd_negotiate_options(NBDClient *client) + ... Rest of request + */ + +- if (nbd_negotiate_read(client->ioc, &flags, sizeof(flags)) != +- sizeof(flags)) { ++ if (nbd_negotiate_read(client->ioc, &flags, sizeof(flags)) < 0) { + LOG("read failed"); + return -EIO; + } +@@ -464,8 +462,7 @@ static int nbd_negotiate_options(NBDClient *client) + uint32_t clientflags, length; + uint64_t magic; + +- if (nbd_negotiate_read(client->ioc, &magic, sizeof(magic)) != +- sizeof(magic)) { ++ if (nbd_negotiate_read(client->ioc, &magic, sizeof(magic)) < 0) { + LOG("read failed"); + return -EINVAL; + } +@@ -476,14 +473,14 @@ static int nbd_negotiate_options(NBDClient *client) + } + + if (nbd_negotiate_read(client->ioc, &clientflags, +- sizeof(clientflags)) != sizeof(clientflags)) { ++ sizeof(clientflags)) < 0) ++ { + LOG("read failed"); + return -EINVAL; + } + clientflags = be32_to_cpu(clientflags); + +- if (nbd_negotiate_read(client->ioc, &length, sizeof(length)) != +- sizeof(length)) { ++ if (nbd_negotiate_read(client->ioc, &length, sizeof(length)) < 0) { + LOG("read failed"); + return -EINVAL; + } +@@ -519,7 +516,7 @@ static int nbd_negotiate_options(NBDClient *client) + return -EINVAL; + + default: +- if (nbd_negotiate_drop_sync(client->ioc, length) != length) { ++ if (nbd_negotiate_drop_sync(client->ioc, length) < 0) { + return -EIO; + } + ret = nbd_negotiate_send_rep_err(client->ioc, +@@ -557,7 +554,7 @@ static int nbd_negotiate_options(NBDClient *client) + return nbd_negotiate_handle_export_name(client, length); + + case NBD_OPT_STARTTLS: +- if (nbd_negotiate_drop_sync(client->ioc, length) != length) { ++ if (nbd_negotiate_drop_sync(client->ioc, length) < 0) { + return -EIO; + } + if (client->tlscreds) { +@@ -576,7 +573,7 @@ static int nbd_negotiate_options(NBDClient *client) + } + break; + default: +- if (nbd_negotiate_drop_sync(client->ioc, length) != length) { ++ if (nbd_negotiate_drop_sync(client->ioc, length) < 0) { + return -EIO; + } + ret = nbd_negotiate_send_rep_err(client->ioc, +@@ -665,12 +662,12 @@ static coroutine_fn int nbd_negotiate(NBDClientNewData *data) + TRACE("TLS cannot be enabled with oldstyle protocol"); + goto fail; + } +- if (nbd_negotiate_write(client->ioc, buf, sizeof(buf)) != sizeof(buf)) { ++ if (nbd_negotiate_write(client->ioc, buf, sizeof(buf)) < 0) { + LOG("write failed"); + goto fail; + } + } else { +- if (nbd_negotiate_write(client->ioc, buf, 18) != 18) { ++ if (nbd_negotiate_write(client->ioc, buf, 18) < 0) { + LOG("write failed"); + goto fail; + } +@@ -685,7 +682,7 @@ static coroutine_fn int nbd_negotiate(NBDClientNewData *data) + stq_be_p(buf + 18, client->exp->size); + stw_be_p(buf + 26, client->exp->nbdflags | myflags); + len = client->no_zeroes ? 10 : sizeof(buf) - 18; +- if (nbd_negotiate_write(client->ioc, buf + 18, len) != len) { ++ if (nbd_negotiate_write(client->ioc, buf + 18, len) < 0) { + LOG("write failed"); + goto fail; + } +@@ -708,11 +705,6 @@ static ssize_t nbd_receive_request(QIOChannel *ioc, NBDRequest *request) + return ret; + } + +- if (ret != sizeof(buf)) { +- LOG("read failed"); +- return -EINVAL; +- } +- + /* Request + [ 0 .. 3] magic (NBD_REQUEST_MAGIC) + [ 4 .. 5] flags (NBD_CMD_FLAG_FUA, ...) +@@ -743,7 +735,6 @@ static ssize_t nbd_receive_request(QIOChannel *ioc, NBDRequest *request) + static ssize_t nbd_send_reply(QIOChannel *ioc, NBDReply *reply) + { + uint8_t buf[NBD_REPLY_SIZE]; +- ssize_t ret; + + reply->error = system_errno_to_nbd_errno(reply->error); + +@@ -760,16 +751,7 @@ static ssize_t nbd_send_reply(QIOChannel *ioc, NBDReply *reply) + stl_be_p(buf + 4, reply->error); + stq_be_p(buf + 8, reply->handle); + +- ret = write_sync(ioc, buf, sizeof(buf)); +- if (ret < 0) { +- return ret; +- } +- +- if (ret != sizeof(buf)) { +- LOG("writing to socket failed"); +- return -EINVAL; +- } +- return 0; ++ return write_sync(ioc, buf, sizeof(buf)); + } + + #define MAX_NBD_REQUESTS 16 +@@ -1073,7 +1055,7 @@ static ssize_t nbd_co_send_reply(NBDRequestData *req, NBDReply *reply, + rc = nbd_send_reply(client->ioc, reply); + if (rc >= 0) { + ret = write_sync(client->ioc, req->data, len); +- if (ret != len) { ++ if (ret < 0) { + rc = -EIO; + } + } +@@ -1147,7 +1129,7 @@ static ssize_t nbd_co_receive_request(NBDRequestData *req, + if (request->type == NBD_CMD_WRITE) { + TRACE("Reading %" PRIu32 " byte(s)", request->len); + +- if (read_sync(client->ioc, req->data, request->len) != request->len) { ++ if (read_sync(client->ioc, req->data, request->len) < 0) { + LOG("reading from socket failed"); + rc = -EIO; + goto out; +-- +2.11.0 + diff --git a/debian/patches/extra/0039-kvm-nbd-make-nbd_drop-public.patch b/debian/patches/extra/0039-kvm-nbd-make-nbd_drop-public.patch deleted file mode 100644 index 0790170..0000000 --- a/debian/patches/extra/0039-kvm-nbd-make-nbd_drop-public.patch +++ /dev/null @@ -1,151 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Eric Blake -Date: Wed, 19 Jul 2017 18:02:01 +0200 -Subject: [PATCH] nbd: make nbd_drop public - -RH-Author: Eric Blake -Message-id: <20170719180202.23329-4-eblake@redhat.com> -Patchwork-id: 75814 -O-Subject: [RHEV-7.4.z qemu-kvm-rhev PATCH 3/4] nbd: make nbd_drop public -Bugzilla: 1467509 -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Jeffrey Cody - -From: Vladimir Sementsov-Ogievskiy - -Following commit will reuse it for nbd server too. - -Reviewed-by: Eric Blake -Signed-off-by: Vladimir Sementsov-Ogievskiy -Message-Id: <20170602150150.258222-3-vsementsov@virtuozzo.com> -Signed-off-by: Paolo Bonzini -(cherry picked from commit 44298024d30ad36439707b89715a76333f58791b) - - Conflicts: - nbd/client.c, nbd/nbd_internal.h, nbd/common.c - missing errp - addition (e44ed99) and bulk rename (d1fdf25) - -Signed-off-by: Eric Blake -Signed-off-by: Miroslav Rezanina ---- - nbd/client.c | 32 +++----------------------------- - nbd/common.c | 26 ++++++++++++++++++++++++++ - nbd/nbd-internal.h | 2 ++ - 3 files changed, 31 insertions(+), 29 deletions(-) - -diff --git a/nbd/client.c b/nbd/client.c -index 6b74a62..1652f28 100644 ---- a/nbd/client.c -+++ b/nbd/client.c -@@ -86,32 +86,6 @@ static QTAILQ_HEAD(, NBDExport) exports = QTAILQ_HEAD_INITIALIZER(exports); - - */ - --/* Discard length bytes from channel. Return -errno on failure and 0 on -- * success*/ --static int drop_sync(QIOChannel *ioc, size_t size) --{ -- ssize_t ret = 0; -- char small[1024]; -- char *buffer; -- -- buffer = sizeof(small) >= size ? small : g_malloc(MIN(65536, size)); -- while (size > 0) { -- ssize_t count = MIN(65536, size); -- ret = read_sync(ioc, buffer, MIN(65536, size)); -- -- if (ret < 0) { -- goto cleanup; -- } -- size -= count; -- } -- -- cleanup: -- if (buffer != small) { -- g_free(buffer); -- } -- return ret; --} -- - /* Send an option request. - * - * The request is for option @opt, with @data containing @len bytes of -@@ -333,7 +307,7 @@ static int nbd_receive_list(QIOChannel *ioc, const char *want, bool *match, - return -1; - } - if (namelen != strlen(want)) { -- if (drop_sync(ioc, len) < 0) { -+ if (nbd_drop(ioc, len) < 0) { - error_setg(errp, "failed to skip export name with wrong length"); - nbd_send_opt_abort(ioc); - return -1; -@@ -349,7 +323,7 @@ static int nbd_receive_list(QIOChannel *ioc, const char *want, bool *match, - } - name[namelen] = '\0'; - len -= namelen; -- if (drop_sync(ioc, len) < 0) { -+ if (nbd_drop(ioc, len) < 0) { - error_setg(errp, "failed to read export description"); - nbd_send_opt_abort(ioc); - return -1; -@@ -616,7 +590,7 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags, - } - - TRACE("Size is %" PRIu64 ", export flags %" PRIx16, *size, *flags); -- if (zeroes && drop_sync(ioc, 124) < 0) { -+ if (zeroes && nbd_drop(ioc, 124) < 0) { - error_setg(errp, "Failed to read reserved block"); - goto fail; - } -diff --git a/nbd/common.c b/nbd/common.c -index 4db45b3..9a54010 100644 ---- a/nbd/common.c -+++ b/nbd/common.c -@@ -71,6 +71,32 @@ ssize_t nbd_wr_syncv(QIOChannel *ioc, - return done; - } - -+/* Discard length bytes from channel. Return -errno on failure and 0 on -+ * success */ -+int nbd_drop(QIOChannel *ioc, size_t size) -+{ -+ ssize_t ret = 0; -+ char small[1024]; -+ char *buffer; -+ -+ buffer = sizeof(small) >= size ? small : g_malloc(MIN(65536, size)); -+ while (size > 0) { -+ ssize_t count = MIN(65536, size); -+ ret = read_sync(ioc, buffer, MIN(65536, size)); -+ -+ if (ret < 0) { -+ goto cleanup; -+ } -+ size -= count; -+ } -+ -+ cleanup: -+ if (buffer != small) { -+ g_free(buffer); -+ } -+ return ret; -+} -+ - - void nbd_tls_handshake(QIOTask *task, - void *opaque) -diff --git a/nbd/nbd-internal.h b/nbd/nbd-internal.h -index e6bbc7c..c02378c 100644 ---- a/nbd/nbd-internal.h -+++ b/nbd/nbd-internal.h -@@ -149,4 +149,6 @@ struct NBDTLSHandshakeData { - void nbd_tls_handshake(QIOTask *task, - void *opaque); - -+int nbd_drop(QIOChannel *ioc, size_t size); -+ - #endif --- -1.8.3.1 - diff --git a/debian/patches/extra/0039-nbd-make-nbd_drop-public.patch b/debian/patches/extra/0039-nbd-make-nbd_drop-public.patch new file mode 100644 index 0000000..03bc7cf --- /dev/null +++ b/debian/patches/extra/0039-nbd-make-nbd_drop-public.patch @@ -0,0 +1,151 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Eric Blake +Date: Wed, 19 Jul 2017 18:02:01 +0200 +Subject: [PATCH] nbd: make nbd_drop public + +RH-Author: Eric Blake +Message-id: <20170719180202.23329-4-eblake@redhat.com> +Patchwork-id: 75814 +O-Subject: [RHEV-7.4.z qemu-kvm-rhev PATCH 3/4] nbd: make nbd_drop public +Bugzilla: 1467509 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Jeffrey Cody + +From: Vladimir Sementsov-Ogievskiy + +Following commit will reuse it for nbd server too. + +Reviewed-by: Eric Blake +Signed-off-by: Vladimir Sementsov-Ogievskiy +Message-Id: <20170602150150.258222-3-vsementsov@virtuozzo.com> +Signed-off-by: Paolo Bonzini +(cherry picked from commit 44298024d30ad36439707b89715a76333f58791b) + + Conflicts: + nbd/client.c, nbd/nbd_internal.h, nbd/common.c - missing errp + addition (e44ed99) and bulk rename (d1fdf25) + +Signed-off-by: Eric Blake +Signed-off-by: Miroslav Rezanina +--- + nbd/client.c | 32 +++----------------------------- + nbd/common.c | 26 ++++++++++++++++++++++++++ + nbd/nbd-internal.h | 2 ++ + 3 files changed, 31 insertions(+), 29 deletions(-) + +diff --git a/nbd/client.c b/nbd/client.c +index 6b74a628f1..1652f28e9f 100644 +--- a/nbd/client.c ++++ b/nbd/client.c +@@ -86,32 +86,6 @@ static QTAILQ_HEAD(, NBDExport) exports = QTAILQ_HEAD_INITIALIZER(exports); + + */ + +-/* Discard length bytes from channel. Return -errno on failure and 0 on +- * success*/ +-static int drop_sync(QIOChannel *ioc, size_t size) +-{ +- ssize_t ret = 0; +- char small[1024]; +- char *buffer; +- +- buffer = sizeof(small) >= size ? small : g_malloc(MIN(65536, size)); +- while (size > 0) { +- ssize_t count = MIN(65536, size); +- ret = read_sync(ioc, buffer, MIN(65536, size)); +- +- if (ret < 0) { +- goto cleanup; +- } +- size -= count; +- } +- +- cleanup: +- if (buffer != small) { +- g_free(buffer); +- } +- return ret; +-} +- + /* Send an option request. + * + * The request is for option @opt, with @data containing @len bytes of +@@ -333,7 +307,7 @@ static int nbd_receive_list(QIOChannel *ioc, const char *want, bool *match, + return -1; + } + if (namelen != strlen(want)) { +- if (drop_sync(ioc, len) < 0) { ++ if (nbd_drop(ioc, len) < 0) { + error_setg(errp, "failed to skip export name with wrong length"); + nbd_send_opt_abort(ioc); + return -1; +@@ -349,7 +323,7 @@ static int nbd_receive_list(QIOChannel *ioc, const char *want, bool *match, + } + name[namelen] = '\0'; + len -= namelen; +- if (drop_sync(ioc, len) < 0) { ++ if (nbd_drop(ioc, len) < 0) { + error_setg(errp, "failed to read export description"); + nbd_send_opt_abort(ioc); + return -1; +@@ -616,7 +590,7 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags, + } + + TRACE("Size is %" PRIu64 ", export flags %" PRIx16, *size, *flags); +- if (zeroes && drop_sync(ioc, 124) < 0) { ++ if (zeroes && nbd_drop(ioc, 124) < 0) { + error_setg(errp, "Failed to read reserved block"); + goto fail; + } +diff --git a/nbd/common.c b/nbd/common.c +index 4db45b3ede..9a54010c25 100644 +--- a/nbd/common.c ++++ b/nbd/common.c +@@ -71,6 +71,32 @@ ssize_t nbd_wr_syncv(QIOChannel *ioc, + return done; + } + ++/* Discard length bytes from channel. Return -errno on failure and 0 on ++ * success */ ++int nbd_drop(QIOChannel *ioc, size_t size) ++{ ++ ssize_t ret = 0; ++ char small[1024]; ++ char *buffer; ++ ++ buffer = sizeof(small) >= size ? small : g_malloc(MIN(65536, size)); ++ while (size > 0) { ++ ssize_t count = MIN(65536, size); ++ ret = read_sync(ioc, buffer, MIN(65536, size)); ++ ++ if (ret < 0) { ++ goto cleanup; ++ } ++ size -= count; ++ } ++ ++ cleanup: ++ if (buffer != small) { ++ g_free(buffer); ++ } ++ return ret; ++} ++ + + void nbd_tls_handshake(QIOTask *task, + void *opaque) +diff --git a/nbd/nbd-internal.h b/nbd/nbd-internal.h +index e6bbc7c4b4..c02378c553 100644 +--- a/nbd/nbd-internal.h ++++ b/nbd/nbd-internal.h +@@ -149,4 +149,6 @@ struct NBDTLSHandshakeData { + void nbd_tls_handshake(QIOTask *task, + void *opaque); + ++int nbd_drop(QIOChannel *ioc, size_t size); ++ + #endif +-- +2.11.0 + diff --git a/debian/patches/extra/0040-kvm-nbd-server-get-rid-of-nbd_negotiate_read-and-friends.patch b/debian/patches/extra/0040-kvm-nbd-server-get-rid-of-nbd_negotiate_read-and-friends.patch deleted file mode 100644 index 594b020..0000000 --- a/debian/patches/extra/0040-kvm-nbd-server-get-rid-of-nbd_negotiate_read-and-friends.patch +++ /dev/null @@ -1,292 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Eric Blake -Date: Wed, 19 Jul 2017 18:02:02 +0200 -Subject: [PATCH] nbd/server: get rid of nbd_negotiate_read and friends - -RH-Author: Eric Blake -Message-id: <20170719180202.23329-5-eblake@redhat.com> -Patchwork-id: 75816 -O-Subject: [RHEV-7.4.z qemu-kvm-rhev PATCH 4/4] nbd/server: get rid of nbd_negotiate_read and friends -Bugzilla: 1467509 -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Paolo Bonzini -RH-Acked-by: Jeffrey Cody - -From: Vladimir Sementsov-Ogievskiy - -Functions nbd_negotiate_{read,write,drop_sync} were introduced in -1a6245a5b, when nbd_rwv (was nbd_wr_sync) was working through -qemu_co_sendv_recvv (the path is nbd_wr_sync -> qemu_co_{recv/send} -> -qemu_co_send_recv -> qemu_co_sendv_recvv), which just yields, without -setting any handlers. But starting from ff82911cd nbd_rwv (was -nbd_wr_syncv) works through qio_channel_yield() which sets handlers, so -watchers are redundant in nbd_negotiate_{read,write,drop_sync}, then, -let's just use nbd_{read,write,drop} functions. - -Functions nbd_{read,write,drop} has errp parameter, which is unused in -this patch. This will be fixed later. - -Signed-off-by: Vladimir Sementsov-Ogievskiy -Reviewed-by: Eric Blake -Message-Id: <20170602150150.258222-4-vsementsov@virtuozzo.com> -Signed-off-by: Paolo Bonzini -(cherry picked from commit 2b0bbc4f8809c972bad134bc1a2570dbb01dea0b) - -Signed-off-by: Miroslav Rezanina - -Conflicts: - nbd/server.c - missing errp addition (e44ed99) and bulk - rename (d1fdf25) -Fixes CVE-2017-7539 - -Signed-off-by: Eric Blake ---- - nbd/server.c | 106 ++++++++++++----------------------------------------------- - 1 file changed, 21 insertions(+), 85 deletions(-) - -diff --git a/nbd/server.c b/nbd/server.c -index b44cbe6..8e3b8e5 100644 ---- a/nbd/server.c -+++ b/nbd/server.c -@@ -104,69 +104,6 @@ struct NBDClient { - - static void nbd_client_receive_next_request(NBDClient *client); - --static gboolean nbd_negotiate_continue(QIOChannel *ioc, -- GIOCondition condition, -- void *opaque) --{ -- qemu_coroutine_enter(opaque); -- return TRUE; --} -- --static int nbd_negotiate_read(QIOChannel *ioc, void *buffer, size_t size) --{ -- ssize_t ret; -- guint watch; -- -- assert(qemu_in_coroutine()); -- /* Negotiation are always in main loop. */ -- watch = qio_channel_add_watch(ioc, -- G_IO_IN, -- nbd_negotiate_continue, -- qemu_coroutine_self(), -- NULL); -- ret = read_sync(ioc, buffer, size); -- g_source_remove(watch); -- return ret; -- --} -- --static int nbd_negotiate_write(QIOChannel *ioc, const void *buffer, size_t size) --{ -- ssize_t ret; -- guint watch; -- -- assert(qemu_in_coroutine()); -- /* Negotiation are always in main loop. */ -- watch = qio_channel_add_watch(ioc, -- G_IO_OUT, -- nbd_negotiate_continue, -- qemu_coroutine_self(), -- NULL); -- ret = write_sync(ioc, buffer, size); -- g_source_remove(watch); -- return ret; --} -- --static int nbd_negotiate_drop_sync(QIOChannel *ioc, size_t size) --{ -- ssize_t ret; -- uint8_t *buffer = g_malloc(MIN(65536, size)); -- -- while (size > 0) { -- size_t count = MIN(65536, size); -- ret = nbd_negotiate_read(ioc, buffer, count); -- if (ret < 0) { -- g_free(buffer); -- return ret; -- } -- -- size -= count; -- } -- -- g_free(buffer); -- return 0; --} -- - /* Basic flow for negotiation - - Server Client -@@ -205,22 +142,22 @@ static int nbd_negotiate_send_rep_len(QIOChannel *ioc, uint32_t type, - type, opt, len); - - magic = cpu_to_be64(NBD_REP_MAGIC); -- if (nbd_negotiate_write(ioc, &magic, sizeof(magic)) < 0) { -+ if (write_sync(ioc, &magic, sizeof(magic)) < 0) { - LOG("write failed (rep magic)"); - return -EINVAL; - } - opt = cpu_to_be32(opt); -- if (nbd_negotiate_write(ioc, &opt, sizeof(opt)) < 0) { -+ if (write_sync(ioc, &opt, sizeof(opt)) < 0) { - LOG("write failed (rep opt)"); - return -EINVAL; - } - type = cpu_to_be32(type); -- if (nbd_negotiate_write(ioc, &type, sizeof(type)) < 0) { -+ if (write_sync(ioc, &type, sizeof(type)) < 0) { - LOG("write failed (rep type)"); - return -EINVAL; - } - len = cpu_to_be32(len); -- if (nbd_negotiate_write(ioc, &len, sizeof(len)) < 0) { -+ if (write_sync(ioc, &len, sizeof(len)) < 0) { - LOG("write failed (rep data length)"); - return -EINVAL; - } -@@ -255,7 +192,7 @@ nbd_negotiate_send_rep_err(QIOChannel *ioc, uint32_t type, - if (ret < 0) { - goto out; - } -- if (nbd_negotiate_write(ioc, msg, len) < 0) { -+ if (write_sync(ioc, msg, len) < 0) { - LOG("write failed (error message)"); - ret = -EIO; - } else { -@@ -286,15 +223,15 @@ static int nbd_negotiate_send_rep_list(QIOChannel *ioc, NBDExport *exp) - } - - len = cpu_to_be32(name_len); -- if (nbd_negotiate_write(ioc, &len, sizeof(len)) < 0) { -+ if (write_sync(ioc, &len, sizeof(len)) < 0) { - LOG("write failed (name length)"); - return -EINVAL; - } -- if (nbd_negotiate_write(ioc, name, name_len) < 0) { -+ if (write_sync(ioc, name, name_len) < 0) { - LOG("write failed (name buffer)"); - return -EINVAL; - } -- if (nbd_negotiate_write(ioc, desc, desc_len) < 0) { -+ if (write_sync(ioc, desc, desc_len) < 0) { - LOG("write failed (description buffer)"); - return -EINVAL; - } -@@ -308,7 +245,7 @@ static int nbd_negotiate_handle_list(NBDClient *client, uint32_t length) - NBDExport *exp; - - if (length) { -- if (nbd_negotiate_drop_sync(client->ioc, length) < 0) { -+ if (nbd_drop(client->ioc, length) < 0) { - return -EIO; - } - return nbd_negotiate_send_rep_err(client->ioc, -@@ -339,7 +276,7 @@ static int nbd_negotiate_handle_export_name(NBDClient *client, uint32_t length) - LOG("Bad length received"); - goto fail; - } -- if (nbd_negotiate_read(client->ioc, name, length) < 0) { -+ if (read_sync(client->ioc, name, length) < 0) { - LOG("read failed"); - goto fail; - } -@@ -372,7 +309,7 @@ static QIOChannel *nbd_negotiate_handle_starttls(NBDClient *client, - TRACE("Setting up TLS"); - ioc = client->ioc; - if (length) { -- if (nbd_negotiate_drop_sync(ioc, length) < 0) { -+ if (nbd_drop(ioc, length) < 0) { - return NULL; - } - nbd_negotiate_send_rep_err(ioc, NBD_REP_ERR_INVALID, NBD_OPT_STARTTLS, -@@ -436,7 +373,7 @@ static int nbd_negotiate_options(NBDClient *client) - ... Rest of request - */ - -- if (nbd_negotiate_read(client->ioc, &flags, sizeof(flags)) < 0) { -+ if (read_sync(client->ioc, &flags, sizeof(flags)) < 0) { - LOG("read failed"); - return -EIO; - } -@@ -462,7 +399,7 @@ static int nbd_negotiate_options(NBDClient *client) - uint32_t clientflags, length; - uint64_t magic; - -- if (nbd_negotiate_read(client->ioc, &magic, sizeof(magic)) < 0) { -+ if (read_sync(client->ioc, &magic, sizeof(magic)) < 0) { - LOG("read failed"); - return -EINVAL; - } -@@ -472,15 +409,14 @@ static int nbd_negotiate_options(NBDClient *client) - return -EINVAL; - } - -- if (nbd_negotiate_read(client->ioc, &clientflags, -- sizeof(clientflags)) < 0) -+ if (read_sync(client->ioc, &clientflags, sizeof(clientflags)) < 0) - { - LOG("read failed"); - return -EINVAL; - } - clientflags = be32_to_cpu(clientflags); - -- if (nbd_negotiate_read(client->ioc, &length, sizeof(length)) < 0) { -+ if (read_sync(client->ioc, &length, sizeof(length)) < 0) { - LOG("read failed"); - return -EINVAL; - } -@@ -510,7 +446,7 @@ static int nbd_negotiate_options(NBDClient *client) - return -EINVAL; - - default: -- if (nbd_negotiate_drop_sync(client->ioc, length) < 0) { -+ if (nbd_drop(client->ioc, length) < 0) { - return -EIO; - } - ret = nbd_negotiate_send_rep_err(client->ioc, -@@ -548,7 +484,7 @@ static int nbd_negotiate_options(NBDClient *client) - return nbd_negotiate_handle_export_name(client, length); - - case NBD_OPT_STARTTLS: -- if (nbd_negotiate_drop_sync(client->ioc, length) < 0) { -+ if (nbd_drop(client->ioc, length) < 0) { - return -EIO; - } - if (client->tlscreds) { -@@ -567,7 +503,7 @@ static int nbd_negotiate_options(NBDClient *client) - } - break; - default: -- if (nbd_negotiate_drop_sync(client->ioc, length) < 0) { -+ if (nbd_drop(client->ioc, length) < 0) { - return -EIO; - } - ret = nbd_negotiate_send_rep_err(client->ioc, -@@ -656,12 +592,12 @@ static coroutine_fn int nbd_negotiate(NBDClientNewData *data) - TRACE("TLS cannot be enabled with oldstyle protocol"); - goto fail; - } -- if (nbd_negotiate_write(client->ioc, buf, sizeof(buf)) < 0) { -+ if (write_sync(client->ioc, buf, sizeof(buf)) < 0) { - LOG("write failed"); - goto fail; - } - } else { -- if (nbd_negotiate_write(client->ioc, buf, 18) < 0) { -+ if (write_sync(client->ioc, buf, 18) < 0) { - LOG("write failed"); - goto fail; - } -@@ -676,7 +612,7 @@ static coroutine_fn int nbd_negotiate(NBDClientNewData *data) - stq_be_p(buf + 18, client->exp->size); - stw_be_p(buf + 26, client->exp->nbdflags | myflags); - len = client->no_zeroes ? 10 : sizeof(buf) - 18; -- if (nbd_negotiate_write(client->ioc, buf + 18, len) < 0) { -+ if (write_sync(client->ioc, buf + 18, len) < 0) { - LOG("write failed"); - goto fail; - } --- -1.8.3.1 - diff --git a/debian/patches/extra/0040-nbd-server-get-rid-of-nbd_negotiate_read-and-friends.patch b/debian/patches/extra/0040-nbd-server-get-rid-of-nbd_negotiate_read-and-friends.patch new file mode 100644 index 0000000..638e22f --- /dev/null +++ b/debian/patches/extra/0040-nbd-server-get-rid-of-nbd_negotiate_read-and-friends.patch @@ -0,0 +1,292 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Eric Blake +Date: Wed, 19 Jul 2017 18:02:02 +0200 +Subject: [PATCH] nbd/server: get rid of nbd_negotiate_read and friends + +RH-Author: Eric Blake +Message-id: <20170719180202.23329-5-eblake@redhat.com> +Patchwork-id: 75816 +O-Subject: [RHEV-7.4.z qemu-kvm-rhev PATCH 4/4] nbd/server: get rid of nbd_negotiate_read and friends +Bugzilla: 1467509 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Jeffrey Cody + +From: Vladimir Sementsov-Ogievskiy + +Functions nbd_negotiate_{read,write,drop_sync} were introduced in +1a6245a5b, when nbd_rwv (was nbd_wr_sync) was working through +qemu_co_sendv_recvv (the path is nbd_wr_sync -> qemu_co_{recv/send} -> +qemu_co_send_recv -> qemu_co_sendv_recvv), which just yields, without +setting any handlers. But starting from ff82911cd nbd_rwv (was +nbd_wr_syncv) works through qio_channel_yield() which sets handlers, so +watchers are redundant in nbd_negotiate_{read,write,drop_sync}, then, +let's just use nbd_{read,write,drop} functions. + +Functions nbd_{read,write,drop} has errp parameter, which is unused in +this patch. This will be fixed later. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Reviewed-by: Eric Blake +Message-Id: <20170602150150.258222-4-vsementsov@virtuozzo.com> +Signed-off-by: Paolo Bonzini +(cherry picked from commit 2b0bbc4f8809c972bad134bc1a2570dbb01dea0b) + +Signed-off-by: Miroslav Rezanina + +Conflicts: + nbd/server.c - missing errp addition (e44ed99) and bulk + rename (d1fdf25) +Fixes CVE-2017-7539 + +Signed-off-by: Eric Blake +--- + nbd/server.c | 106 ++++++++++++----------------------------------------------- + 1 file changed, 21 insertions(+), 85 deletions(-) + +diff --git a/nbd/server.c b/nbd/server.c +index c2a5909ad6..ddf93d4717 100644 +--- a/nbd/server.c ++++ b/nbd/server.c +@@ -104,69 +104,6 @@ struct NBDClient { + + static void nbd_client_receive_next_request(NBDClient *client); + +-static gboolean nbd_negotiate_continue(QIOChannel *ioc, +- GIOCondition condition, +- void *opaque) +-{ +- qemu_coroutine_enter(opaque); +- return TRUE; +-} +- +-static int nbd_negotiate_read(QIOChannel *ioc, void *buffer, size_t size) +-{ +- ssize_t ret; +- guint watch; +- +- assert(qemu_in_coroutine()); +- /* Negotiation are always in main loop. */ +- watch = qio_channel_add_watch(ioc, +- G_IO_IN, +- nbd_negotiate_continue, +- qemu_coroutine_self(), +- NULL); +- ret = read_sync(ioc, buffer, size); +- g_source_remove(watch); +- return ret; +- +-} +- +-static int nbd_negotiate_write(QIOChannel *ioc, const void *buffer, size_t size) +-{ +- ssize_t ret; +- guint watch; +- +- assert(qemu_in_coroutine()); +- /* Negotiation are always in main loop. */ +- watch = qio_channel_add_watch(ioc, +- G_IO_OUT, +- nbd_negotiate_continue, +- qemu_coroutine_self(), +- NULL); +- ret = write_sync(ioc, buffer, size); +- g_source_remove(watch); +- return ret; +-} +- +-static int nbd_negotiate_drop_sync(QIOChannel *ioc, size_t size) +-{ +- ssize_t ret; +- uint8_t *buffer = g_malloc(MIN(65536, size)); +- +- while (size > 0) { +- size_t count = MIN(65536, size); +- ret = nbd_negotiate_read(ioc, buffer, count); +- if (ret < 0) { +- g_free(buffer); +- return ret; +- } +- +- size -= count; +- } +- +- g_free(buffer); +- return 0; +-} +- + /* Basic flow for negotiation + + Server Client +@@ -205,22 +142,22 @@ static int nbd_negotiate_send_rep_len(QIOChannel *ioc, uint32_t type, + type, opt, len); + + magic = cpu_to_be64(NBD_REP_MAGIC); +- if (nbd_negotiate_write(ioc, &magic, sizeof(magic)) < 0) { ++ if (write_sync(ioc, &magic, sizeof(magic)) < 0) { + LOG("write failed (rep magic)"); + return -EINVAL; + } + opt = cpu_to_be32(opt); +- if (nbd_negotiate_write(ioc, &opt, sizeof(opt)) < 0) { ++ if (write_sync(ioc, &opt, sizeof(opt)) < 0) { + LOG("write failed (rep opt)"); + return -EINVAL; + } + type = cpu_to_be32(type); +- if (nbd_negotiate_write(ioc, &type, sizeof(type)) < 0) { ++ if (write_sync(ioc, &type, sizeof(type)) < 0) { + LOG("write failed (rep type)"); + return -EINVAL; + } + len = cpu_to_be32(len); +- if (nbd_negotiate_write(ioc, &len, sizeof(len)) < 0) { ++ if (write_sync(ioc, &len, sizeof(len)) < 0) { + LOG("write failed (rep data length)"); + return -EINVAL; + } +@@ -255,7 +192,7 @@ nbd_negotiate_send_rep_err(QIOChannel *ioc, uint32_t type, + if (ret < 0) { + goto out; + } +- if (nbd_negotiate_write(ioc, msg, len) < 0) { ++ if (write_sync(ioc, msg, len) < 0) { + LOG("write failed (error message)"); + ret = -EIO; + } else { +@@ -286,15 +223,15 @@ static int nbd_negotiate_send_rep_list(QIOChannel *ioc, NBDExport *exp) + } + + len = cpu_to_be32(name_len); +- if (nbd_negotiate_write(ioc, &len, sizeof(len)) < 0) { ++ if (write_sync(ioc, &len, sizeof(len)) < 0) { + LOG("write failed (name length)"); + return -EINVAL; + } +- if (nbd_negotiate_write(ioc, name, name_len) < 0) { ++ if (write_sync(ioc, name, name_len) < 0) { + LOG("write failed (name buffer)"); + return -EINVAL; + } +- if (nbd_negotiate_write(ioc, desc, desc_len) < 0) { ++ if (write_sync(ioc, desc, desc_len) < 0) { + LOG("write failed (description buffer)"); + return -EINVAL; + } +@@ -308,7 +245,7 @@ static int nbd_negotiate_handle_list(NBDClient *client, uint32_t length) + NBDExport *exp; + + if (length) { +- if (nbd_negotiate_drop_sync(client->ioc, length) < 0) { ++ if (nbd_drop(client->ioc, length) < 0) { + return -EIO; + } + return nbd_negotiate_send_rep_err(client->ioc, +@@ -339,7 +276,7 @@ static int nbd_negotiate_handle_export_name(NBDClient *client, uint32_t length) + LOG("Bad length received"); + goto fail; + } +- if (nbd_negotiate_read(client->ioc, name, length) < 0) { ++ if (read_sync(client->ioc, name, length) < 0) { + LOG("read failed"); + goto fail; + } +@@ -372,7 +309,7 @@ static QIOChannel *nbd_negotiate_handle_starttls(NBDClient *client, + TRACE("Setting up TLS"); + ioc = client->ioc; + if (length) { +- if (nbd_negotiate_drop_sync(ioc, length) < 0) { ++ if (nbd_drop(ioc, length) < 0) { + return NULL; + } + nbd_negotiate_send_rep_err(ioc, NBD_REP_ERR_INVALID, NBD_OPT_STARTTLS, +@@ -436,7 +373,7 @@ static int nbd_negotiate_options(NBDClient *client) + ... Rest of request + */ + +- if (nbd_negotiate_read(client->ioc, &flags, sizeof(flags)) < 0) { ++ if (read_sync(client->ioc, &flags, sizeof(flags)) < 0) { + LOG("read failed"); + return -EIO; + } +@@ -462,7 +399,7 @@ static int nbd_negotiate_options(NBDClient *client) + uint32_t clientflags, length; + uint64_t magic; + +- if (nbd_negotiate_read(client->ioc, &magic, sizeof(magic)) < 0) { ++ if (read_sync(client->ioc, &magic, sizeof(magic)) < 0) { + LOG("read failed"); + return -EINVAL; + } +@@ -472,15 +409,14 @@ static int nbd_negotiate_options(NBDClient *client) + return -EINVAL; + } + +- if (nbd_negotiate_read(client->ioc, &clientflags, +- sizeof(clientflags)) < 0) ++ if (read_sync(client->ioc, &clientflags, sizeof(clientflags)) < 0) + { + LOG("read failed"); + return -EINVAL; + } + clientflags = be32_to_cpu(clientflags); + +- if (nbd_negotiate_read(client->ioc, &length, sizeof(length)) < 0) { ++ if (read_sync(client->ioc, &length, sizeof(length)) < 0) { + LOG("read failed"); + return -EINVAL; + } +@@ -516,7 +452,7 @@ static int nbd_negotiate_options(NBDClient *client) + return -EINVAL; + + default: +- if (nbd_negotiate_drop_sync(client->ioc, length) < 0) { ++ if (nbd_drop(client->ioc, length) < 0) { + return -EIO; + } + ret = nbd_negotiate_send_rep_err(client->ioc, +@@ -554,7 +490,7 @@ static int nbd_negotiate_options(NBDClient *client) + return nbd_negotiate_handle_export_name(client, length); + + case NBD_OPT_STARTTLS: +- if (nbd_negotiate_drop_sync(client->ioc, length) < 0) { ++ if (nbd_drop(client->ioc, length) < 0) { + return -EIO; + } + if (client->tlscreds) { +@@ -573,7 +509,7 @@ static int nbd_negotiate_options(NBDClient *client) + } + break; + default: +- if (nbd_negotiate_drop_sync(client->ioc, length) < 0) { ++ if (nbd_drop(client->ioc, length) < 0) { + return -EIO; + } + ret = nbd_negotiate_send_rep_err(client->ioc, +@@ -662,12 +598,12 @@ static coroutine_fn int nbd_negotiate(NBDClientNewData *data) + TRACE("TLS cannot be enabled with oldstyle protocol"); + goto fail; + } +- if (nbd_negotiate_write(client->ioc, buf, sizeof(buf)) < 0) { ++ if (write_sync(client->ioc, buf, sizeof(buf)) < 0) { + LOG("write failed"); + goto fail; + } + } else { +- if (nbd_negotiate_write(client->ioc, buf, 18) < 0) { ++ if (write_sync(client->ioc, buf, 18) < 0) { + LOG("write failed"); + goto fail; + } +@@ -682,7 +618,7 @@ static coroutine_fn int nbd_negotiate(NBDClientNewData *data) + stq_be_p(buf + 18, client->exp->size); + stw_be_p(buf + 26, client->exp->nbdflags | myflags); + len = client->no_zeroes ? 10 : sizeof(buf) - 18; +- if (nbd_negotiate_write(client->ioc, buf + 18, len) < 0) { ++ if (write_sync(client->ioc, buf + 18, len) < 0) { + LOG("write failed"); + goto fail; + } +-- +2.11.0 + diff --git a/debian/patches/extra/0041-kvm-nbd-client-Fix-regression-when-server-sends-garbage.patch b/debian/patches/extra/0041-kvm-nbd-client-Fix-regression-when-server-sends-garbage.patch deleted file mode 100644 index 1d2c689..0000000 --- a/debian/patches/extra/0041-kvm-nbd-client-Fix-regression-when-server-sends-garbage.patch +++ /dev/null @@ -1,153 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Eric Blake -Date: Wed, 27 Sep 2017 17:57:19 +0200 -Subject: [PATCH] nbd-client: Fix regression when server sends garbage - -RH-Author: Eric Blake -Message-id: <20170927175725.20023-2-eblake@redhat.com> -Patchwork-id: 76672 -O-Subject: [RHEV-7.4.z qemu-kvm-rhev PATCH 1/7] nbd-client: Fix regression when server sends garbage -Bugzilla: 1495474 -RH-Acked-by: Max Reitz -RH-Acked-by: Jeffrey Cody -RH-Acked-by: Stefan Hajnoczi - -When we switched NBD to use coroutines for qemu 2.9 (in particular, -commit a12a712a), we introduced a regression: if a server sends us -garbage (such as a corrupted magic number), we quit the read loop -but do not stop sending further queued commands, resulting in the -client hanging when it never reads the response to those additional -commands. In qemu 2.8, we properly detected that the server is no -longer reliable, and cancelled all existing pending commands with -EIO, then tore down the socket so that all further command attempts -get EPIPE. - -Restore the proper behavior of quitting (almost) all communication -with a broken server: Once we know we are out of sync or otherwise -can't trust the server, we must assume that any further incoming -data is unreliable and therefore end all pending commands with EIO, -and quit trying to send any further commands. As an exception, we -still (try to) send NBD_CMD_DISC to let the server know we are going -away (in part, because it is easier to do that than to further -refactor nbd_teardown_connection, and in part because it is the -only command where we do not have to wait for a reply). - -Based on a patch by Vladimir Sementsov-Ogievskiy. - -A malicious server can be created with the following hack, -followed by setting NBD_SERVER_DEBUG to a non-zero value in the -environment when running qemu-nbd: - -| --- a/nbd/server.c -| +++ b/nbd/server.c -| @@ -919,6 +919,17 @@ static int nbd_send_reply(QIOChannel *ioc, NBDReply *reply, Error **errp) -| stl_be_p(buf + 4, reply->error); -| stq_be_p(buf + 8, reply->handle); -| -| + static int debug; -| + static int count; -| + if (!count++) { -| + const char *str = getenv("NBD_SERVER_DEBUG"); -| + if (str) { -| + debug = atoi(str); -| + } -| + } -| + if (debug && !(count % debug)) { -| + buf[0] = 0; -| + } -| return nbd_write(ioc, buf, sizeof(buf), errp); -| } - -Reported-by: Vladimir Sementsov-Ogievskiy -Signed-off-by: Eric Blake -Message-Id: <20170814213426.24681-1-eblake@redhat.com> -Reviewed-by: Stefan Hajnoczi -(cherry picked from commit 72b6ffc76653214b69a94a7b1643ff80df134486) -Signed-off-by: Eric Blake -Signed-off-by: Miroslav Rezanina - -Conflicts: - block/nbd-client.c ---- - block/nbd-client.c | 17 +++++++++++++---- - block/nbd-client.h | 1 + - 2 files changed, 14 insertions(+), 4 deletions(-) - -diff --git a/block/nbd-client.c b/block/nbd-client.c -index 282679b..701b4ce 100644 ---- a/block/nbd-client.c -+++ b/block/nbd-client.c -@@ -71,7 +71,7 @@ static coroutine_fn void nbd_read_reply_entry(void *opaque) - uint64_t i; - int ret; - -- for (;;) { -+ while (!s->quit) { - assert(s->reply.handle == 0); - ret = nbd_receive_reply(s->ioc, &s->reply); - if (ret <= 0) { -@@ -102,6 +102,9 @@ static coroutine_fn void nbd_read_reply_entry(void *opaque) - qemu_coroutine_yield(); - } - -+ if (ret < 0) { -+ s->quit = true; -+ } - nbd_recv_coroutines_enter_all(s); - s->read_reply_co = NULL; - } -@@ -130,6 +133,10 @@ static int nbd_co_send_request(BlockDriverState *bs, - assert(i < MAX_NBD_REQUESTS); - request->handle = INDEX_TO_HANDLE(s, i); - -+ if (s->quit) { -+ qemu_co_mutex_unlock(&s->send_mutex); -+ return -EIO; -+ } - if (!s->ioc) { - qemu_co_mutex_unlock(&s->send_mutex); - return -EPIPE; -@@ -138,7 +145,7 @@ static int nbd_co_send_request(BlockDriverState *bs, - if (qiov) { - qio_channel_set_cork(s->ioc, true); - rc = nbd_send_request(s->ioc, request); -- if (rc >= 0) { -+ if (rc >= 0 && !s->quit) { - ret = nbd_wr_syncv(s->ioc, qiov->iov, qiov->niov, request->len, - false); - if (ret != request->len) { -@@ -149,6 +156,9 @@ static int nbd_co_send_request(BlockDriverState *bs, - } else { - rc = nbd_send_request(s->ioc, request); - } -+ if (rc < 0) { -+ s->quit = true; -+ } - qemu_co_mutex_unlock(&s->send_mutex); - return rc; - } -@@ -163,8 +173,7 @@ static void nbd_co_receive_reply(NBDClientSession *s, - /* Wait until we're woken up by nbd_read_reply_entry. */ - qemu_coroutine_yield(); - *reply = s->reply; -- if (reply->handle != request->handle || -- !s->ioc) { -+ if (reply->handle != request->handle || !s->ioc || s->quit) { - reply->error = EIO; - } else { - if (qiov && reply->error == 0) { -diff --git a/block/nbd-client.h b/block/nbd-client.h -index 891ba44..9774a8e 100644 ---- a/block/nbd-client.h -+++ b/block/nbd-client.h -@@ -30,6 +30,7 @@ typedef struct NBDClientSession { - - Coroutine *recv_coroutine[MAX_NBD_REQUESTS]; - NBDReply reply; -+ bool quit; - } NBDClientSession; - - NBDClientSession *nbd_get_client_session(BlockDriverState *bs); --- -1.8.3.1 - diff --git a/debian/patches/extra/0041-nbd-client-Fix-regression-when-server-sends-garbage.patch b/debian/patches/extra/0041-nbd-client-Fix-regression-when-server-sends-garbage.patch new file mode 100644 index 0000000..2d7560d --- /dev/null +++ b/debian/patches/extra/0041-nbd-client-Fix-regression-when-server-sends-garbage.patch @@ -0,0 +1,153 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Eric Blake +Date: Wed, 27 Sep 2017 17:57:19 +0200 +Subject: [PATCH] nbd-client: Fix regression when server sends garbage + +RH-Author: Eric Blake +Message-id: <20170927175725.20023-2-eblake@redhat.com> +Patchwork-id: 76672 +O-Subject: [RHEV-7.4.z qemu-kvm-rhev PATCH 1/7] nbd-client: Fix regression when server sends garbage +Bugzilla: 1495474 +RH-Acked-by: Max Reitz +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Stefan Hajnoczi + +When we switched NBD to use coroutines for qemu 2.9 (in particular, +commit a12a712a), we introduced a regression: if a server sends us +garbage (such as a corrupted magic number), we quit the read loop +but do not stop sending further queued commands, resulting in the +client hanging when it never reads the response to those additional +commands. In qemu 2.8, we properly detected that the server is no +longer reliable, and cancelled all existing pending commands with +EIO, then tore down the socket so that all further command attempts +get EPIPE. + +Restore the proper behavior of quitting (almost) all communication +with a broken server: Once we know we are out of sync or otherwise +can't trust the server, we must assume that any further incoming +data is unreliable and therefore end all pending commands with EIO, +and quit trying to send any further commands. As an exception, we +still (try to) send NBD_CMD_DISC to let the server know we are going +away (in part, because it is easier to do that than to further +refactor nbd_teardown_connection, and in part because it is the +only command where we do not have to wait for a reply). + +Based on a patch by Vladimir Sementsov-Ogievskiy. + +A malicious server can be created with the following hack, +followed by setting NBD_SERVER_DEBUG to a non-zero value in the +environment when running qemu-nbd: + +| --- a/nbd/server.c +| +++ b/nbd/server.c +| @@ -919,6 +919,17 @@ static int nbd_send_reply(QIOChannel *ioc, NBDReply *reply, Error **errp) +| stl_be_p(buf + 4, reply->error); +| stq_be_p(buf + 8, reply->handle); +| +| + static int debug; +| + static int count; +| + if (!count++) { +| + const char *str = getenv("NBD_SERVER_DEBUG"); +| + if (str) { +| + debug = atoi(str); +| + } +| + } +| + if (debug && !(count % debug)) { +| + buf[0] = 0; +| + } +| return nbd_write(ioc, buf, sizeof(buf), errp); +| } + +Reported-by: Vladimir Sementsov-Ogievskiy +Signed-off-by: Eric Blake +Message-Id: <20170814213426.24681-1-eblake@redhat.com> +Reviewed-by: Stefan Hajnoczi +(cherry picked from commit 72b6ffc76653214b69a94a7b1643ff80df134486) +Signed-off-by: Eric Blake +Signed-off-by: Miroslav Rezanina + +Conflicts: + block/nbd-client.c +--- + block/nbd-client.c | 17 +++++++++++++---- + block/nbd-client.h | 1 + + 2 files changed, 14 insertions(+), 4 deletions(-) + +diff --git a/block/nbd-client.c b/block/nbd-client.c +index 282679b4f8..701b4ce2eb 100644 +--- a/block/nbd-client.c ++++ b/block/nbd-client.c +@@ -71,7 +71,7 @@ static coroutine_fn void nbd_read_reply_entry(void *opaque) + uint64_t i; + int ret; + +- for (;;) { ++ while (!s->quit) { + assert(s->reply.handle == 0); + ret = nbd_receive_reply(s->ioc, &s->reply); + if (ret <= 0) { +@@ -102,6 +102,9 @@ static coroutine_fn void nbd_read_reply_entry(void *opaque) + qemu_coroutine_yield(); + } + ++ if (ret < 0) { ++ s->quit = true; ++ } + nbd_recv_coroutines_enter_all(s); + s->read_reply_co = NULL; + } +@@ -130,6 +133,10 @@ static int nbd_co_send_request(BlockDriverState *bs, + assert(i < MAX_NBD_REQUESTS); + request->handle = INDEX_TO_HANDLE(s, i); + ++ if (s->quit) { ++ qemu_co_mutex_unlock(&s->send_mutex); ++ return -EIO; ++ } + if (!s->ioc) { + qemu_co_mutex_unlock(&s->send_mutex); + return -EPIPE; +@@ -138,7 +145,7 @@ static int nbd_co_send_request(BlockDriverState *bs, + if (qiov) { + qio_channel_set_cork(s->ioc, true); + rc = nbd_send_request(s->ioc, request); +- if (rc >= 0) { ++ if (rc >= 0 && !s->quit) { + ret = nbd_wr_syncv(s->ioc, qiov->iov, qiov->niov, request->len, + false); + if (ret != request->len) { +@@ -149,6 +156,9 @@ static int nbd_co_send_request(BlockDriverState *bs, + } else { + rc = nbd_send_request(s->ioc, request); + } ++ if (rc < 0) { ++ s->quit = true; ++ } + qemu_co_mutex_unlock(&s->send_mutex); + return rc; + } +@@ -163,8 +173,7 @@ static void nbd_co_receive_reply(NBDClientSession *s, + /* Wait until we're woken up by nbd_read_reply_entry. */ + qemu_coroutine_yield(); + *reply = s->reply; +- if (reply->handle != request->handle || +- !s->ioc) { ++ if (reply->handle != request->handle || !s->ioc || s->quit) { + reply->error = EIO; + } else { + if (qiov && reply->error == 0) { +diff --git a/block/nbd-client.h b/block/nbd-client.h +index 891ba44a20..9774a8ebbb 100644 +--- a/block/nbd-client.h ++++ b/block/nbd-client.h +@@ -30,6 +30,7 @@ typedef struct NBDClientSession { + + Coroutine *recv_coroutine[MAX_NBD_REQUESTS]; + NBDReply reply; ++ bool quit; + } NBDClientSession; + + NBDClientSession *nbd_get_client_session(BlockDriverState *bs); +-- +2.11.0 + diff --git a/debian/patches/extra/0042-fix-build-failure-in-nbd_read_reply_entry.patch b/debian/patches/extra/0042-fix-build-failure-in-nbd_read_reply_entry.patch new file mode 100644 index 0000000..27421cd --- /dev/null +++ b/debian/patches/extra/0042-fix-build-failure-in-nbd_read_reply_entry.patch @@ -0,0 +1,55 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Eric Blake +Date: Wed, 27 Sep 2017 17:57:20 +0200 +Subject: [PATCH] fix build failure in nbd_read_reply_entry() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Eric Blake +Message-id: <20170927175725.20023-3-eblake@redhat.com> +Patchwork-id: 76668 +O-Subject: [RHEV-7.4.z qemu-kvm-rhev PATCH 2/7] fix build failure in nbd_read_reply_entry() +Bugzilla: 1495474 +RH-Acked-by: Max Reitz +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Stefan Hajnoczi + +From: Igor Mammedov + +travis builds fail at HEAD at rc3 master with + + block/nbd-client.c: In function ‘nbd_read_reply_entry’: + block/nbd-client.c:110:8: error: ‘ret’ may be used uninitialized in this function [-Werror=uninitialized] + +fix it by initializing 'ret' to 0 + +Signed-off-by: Igor Mammedov +Reviewed-by: Eric Blake +Signed-off-by: Peter Maydell +(cherry picked from commit d0a180131c6655487b47ea72e7da0a909a479a3c) +Signed-off-by: Eric Blake +Signed-off-by: Miroslav Rezanina + +Conflicts: + block/nbd-client.c - context +--- + block/nbd-client.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/block/nbd-client.c b/block/nbd-client.c +index 701b4ce2eb..256dabeeef 100644 +--- a/block/nbd-client.c ++++ b/block/nbd-client.c +@@ -69,7 +69,7 @@ static coroutine_fn void nbd_read_reply_entry(void *opaque) + { + NBDClientSession *s = opaque; + uint64_t i; +- int ret; ++ int ret = 0; + + while (!s->quit) { + assert(s->reply.handle == 0); +-- +2.11.0 + diff --git a/debian/patches/extra/0042-kvm-fix-build-failure-in-nbd_read_reply_entry.patch b/debian/patches/extra/0042-kvm-fix-build-failure-in-nbd_read_reply_entry.patch deleted file mode 100644 index a64f863..0000000 --- a/debian/patches/extra/0042-kvm-fix-build-failure-in-nbd_read_reply_entry.patch +++ /dev/null @@ -1,55 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Eric Blake -Date: Wed, 27 Sep 2017 17:57:20 +0200 -Subject: [PATCH] fix build failure in nbd_read_reply_entry() -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -RH-Author: Eric Blake -Message-id: <20170927175725.20023-3-eblake@redhat.com> -Patchwork-id: 76668 -O-Subject: [RHEV-7.4.z qemu-kvm-rhev PATCH 2/7] fix build failure in nbd_read_reply_entry() -Bugzilla: 1495474 -RH-Acked-by: Max Reitz -RH-Acked-by: Jeffrey Cody -RH-Acked-by: Stefan Hajnoczi - -From: Igor Mammedov - -travis builds fail at HEAD at rc3 master with - - block/nbd-client.c: In function ‘nbd_read_reply_entry’: - block/nbd-client.c:110:8: error: ‘ret’ may be used uninitialized in this function [-Werror=uninitialized] - -fix it by initializing 'ret' to 0 - -Signed-off-by: Igor Mammedov -Reviewed-by: Eric Blake -Signed-off-by: Peter Maydell -(cherry picked from commit d0a180131c6655487b47ea72e7da0a909a479a3c) -Signed-off-by: Eric Blake -Signed-off-by: Miroslav Rezanina - -Conflicts: - block/nbd-client.c - context ---- - block/nbd-client.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/block/nbd-client.c b/block/nbd-client.c -index 701b4ce..256dabe 100644 ---- a/block/nbd-client.c -+++ b/block/nbd-client.c -@@ -69,7 +69,7 @@ static coroutine_fn void nbd_read_reply_entry(void *opaque) - { - NBDClientSession *s = opaque; - uint64_t i; -- int ret; -+ int ret = 0; - - while (!s->quit) { - assert(s->reply.handle == 0); --- -1.8.3.1 - diff --git a/debian/patches/extra/0043-kvm-nbd-client-avoid-spurious-qio_channel_yield-re-entry.patch b/debian/patches/extra/0043-kvm-nbd-client-avoid-spurious-qio_channel_yield-re-entry.patch deleted file mode 100644 index 86ac8ac..0000000 --- a/debian/patches/extra/0043-kvm-nbd-client-avoid-spurious-qio_channel_yield-re-entry.patch +++ /dev/null @@ -1,184 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Eric Blake -Date: Wed, 27 Sep 2017 17:57:21 +0200 -Subject: [PATCH] nbd-client: avoid spurious qio_channel_yield() re-entry - -RH-Author: Eric Blake -Message-id: <20170927175725.20023-4-eblake@redhat.com> -Patchwork-id: 76671 -O-Subject: [RHEV-7.4.z qemu-kvm-rhev PATCH 3/7] nbd-client: avoid spurious qio_channel_yield() re-entry -Bugzilla: 1495474 -RH-Acked-by: Max Reitz -RH-Acked-by: Jeffrey Cody -RH-Acked-by: Stefan Hajnoczi - -From: Stefan Hajnoczi - -The following scenario leads to an assertion failure in -qio_channel_yield(): - -1. Request coroutine calls qio_channel_yield() successfully when sending - would block on the socket. It is now yielded. -2. nbd_read_reply_entry() calls nbd_recv_coroutines_enter_all() because - nbd_receive_reply() failed. -3. Request coroutine is entered and returns from qio_channel_yield(). - Note that the socket fd handler has not fired yet so - ioc->write_coroutine is still set. -4. Request coroutine attempts to send the request body with nbd_rwv() - but the socket would still block. qio_channel_yield() is called - again and assert(!ioc->write_coroutine) is hit. - -The problem is that nbd_read_reply_entry() does not distinguish between -request coroutines that are waiting to receive a reply and those that -are not. - -This patch adds a per-request bool receiving flag so -nbd_read_reply_entry() can avoid spurious aio_wake() calls. - -Reported-by: Dr. David Alan Gilbert -Signed-off-by: Stefan Hajnoczi -Message-Id: <20170822125113.5025-1-stefanha@redhat.com> -Reviewed-by: Vladimir Sementsov-Ogievskiy -Tested-by: Eric Blake -Reviewed-by: Paolo Bonzini -Signed-off-by: Eric Blake -(cherry picked from commit 40f4a21895b5a7eae4011593837069f63460d983) -Signed-off-by: Miroslav Rezanina ---- - block/nbd-client.c | 35 ++++++++++++++++++++++------------- - block/nbd-client.h | 7 ++++++- - 2 files changed, 28 insertions(+), 14 deletions(-) - -diff --git a/block/nbd-client.c b/block/nbd-client.c -index 256dabe..f7bca3f 100644 ---- a/block/nbd-client.c -+++ b/block/nbd-client.c -@@ -38,8 +38,10 @@ static void nbd_recv_coroutines_enter_all(NBDClientSession *s) - int i; - - for (i = 0; i < MAX_NBD_REQUESTS; i++) { -- if (s->recv_coroutine[i]) { -- aio_co_wake(s->recv_coroutine[i]); -+ NBDClientRequest *req = &s->requests[i]; -+ -+ if (req->coroutine && req->receiving) { -+ aio_co_wake(req->coroutine); - } - } - } -@@ -83,28 +85,28 @@ static coroutine_fn void nbd_read_reply_entry(void *opaque) - * one coroutine is called until the reply finishes. - */ - i = HANDLE_TO_INDEX(s, s->reply.handle); -- if (i >= MAX_NBD_REQUESTS || !s->recv_coroutine[i]) { -+ if (i >= MAX_NBD_REQUESTS || -+ !s->requests[i].coroutine || -+ !s->requests[i].receiving) { - break; - } - -- /* We're woken up by the recv_coroutine itself. Note that there -+ /* We're woken up again by the request itself. Note that there - * is no race between yielding and reentering read_reply_co. This - * is because: - * -- * - if recv_coroutine[i] runs on the same AioContext, it is only -+ * - if the request runs on the same AioContext, it is only - * entered after we yield - * -- * - if recv_coroutine[i] runs on a different AioContext, reentering -+ * - if the request runs on a different AioContext, reentering - * read_reply_co happens through a bottom half, which can only - * run after we yield. - */ -- aio_co_wake(s->recv_coroutine[i]); -+ aio_co_wake(s->requests[i].coroutine); - qemu_coroutine_yield(); - } - -- if (ret < 0) { -- s->quit = true; -- } -+ s->quit = true; - nbd_recv_coroutines_enter_all(s); - s->read_reply_co = NULL; - } -@@ -123,14 +125,17 @@ static int nbd_co_send_request(BlockDriverState *bs, - s->in_flight++; - - for (i = 0; i < MAX_NBD_REQUESTS; i++) { -- if (s->recv_coroutine[i] == NULL) { -- s->recv_coroutine[i] = qemu_coroutine_self(); -+ if (s->requests[i].coroutine == NULL) { - break; - } - } - - g_assert(qemu_in_coroutine()); - assert(i < MAX_NBD_REQUESTS); -+ -+ s->requests[i].coroutine = qemu_coroutine_self(); -+ s->requests[i].receiving = false; -+ - request->handle = INDEX_TO_HANDLE(s, i); - - if (s->quit) { -@@ -168,10 +173,13 @@ static void nbd_co_receive_reply(NBDClientSession *s, - NBDReply *reply, - QEMUIOVector *qiov) - { -+ int i = HANDLE_TO_INDEX(s, request->handle); - int ret; - - /* Wait until we're woken up by nbd_read_reply_entry. */ -+ s->requests[i].receiving = true; - qemu_coroutine_yield(); -+ s->requests[i].receiving = false; - *reply = s->reply; - if (reply->handle != request->handle || !s->ioc || s->quit) { - reply->error = EIO; -@@ -181,6 +189,7 @@ static void nbd_co_receive_reply(NBDClientSession *s, - true); - if (ret != request->len) { - reply->error = EIO; -+ s->quit = true; - } - } - -@@ -195,7 +204,7 @@ static void nbd_coroutine_end(BlockDriverState *bs, - NBDClientSession *s = nbd_get_client_session(bs); - int i = HANDLE_TO_INDEX(s, request->handle); - -- s->recv_coroutine[i] = NULL; -+ s->requests[i].coroutine = NULL; - - /* Kick the read_reply_co to get the next reply. */ - if (s->read_reply_co) { -diff --git a/block/nbd-client.h b/block/nbd-client.h -index 9774a8e..f97792f 100644 ---- a/block/nbd-client.h -+++ b/block/nbd-client.h -@@ -17,6 +17,11 @@ - - #define MAX_NBD_REQUESTS 16 - -+typedef struct { -+ Coroutine *coroutine; -+ bool receiving; /* waiting for read_reply_co? */ -+} NBDClientRequest; -+ - typedef struct NBDClientSession { - QIOChannelSocket *sioc; /* The master data channel */ - QIOChannel *ioc; /* The current I/O channel which may differ (eg TLS) */ -@@ -28,7 +33,7 @@ typedef struct NBDClientSession { - Coroutine *read_reply_co; - int in_flight; - -- Coroutine *recv_coroutine[MAX_NBD_REQUESTS]; -+ NBDClientRequest requests[MAX_NBD_REQUESTS]; - NBDReply reply; - bool quit; - } NBDClientSession; --- -1.8.3.1 - diff --git a/debian/patches/extra/0043-nbd-client-avoid-spurious-qio_channel_yield-re-entry.patch b/debian/patches/extra/0043-nbd-client-avoid-spurious-qio_channel_yield-re-entry.patch new file mode 100644 index 0000000..ec3c61e --- /dev/null +++ b/debian/patches/extra/0043-nbd-client-avoid-spurious-qio_channel_yield-re-entry.patch @@ -0,0 +1,184 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Eric Blake +Date: Wed, 27 Sep 2017 17:57:21 +0200 +Subject: [PATCH] nbd-client: avoid spurious qio_channel_yield() re-entry + +RH-Author: Eric Blake +Message-id: <20170927175725.20023-4-eblake@redhat.com> +Patchwork-id: 76671 +O-Subject: [RHEV-7.4.z qemu-kvm-rhev PATCH 3/7] nbd-client: avoid spurious qio_channel_yield() re-entry +Bugzilla: 1495474 +RH-Acked-by: Max Reitz +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Stefan Hajnoczi + +From: Stefan Hajnoczi + +The following scenario leads to an assertion failure in +qio_channel_yield(): + +1. Request coroutine calls qio_channel_yield() successfully when sending + would block on the socket. It is now yielded. +2. nbd_read_reply_entry() calls nbd_recv_coroutines_enter_all() because + nbd_receive_reply() failed. +3. Request coroutine is entered and returns from qio_channel_yield(). + Note that the socket fd handler has not fired yet so + ioc->write_coroutine is still set. +4. Request coroutine attempts to send the request body with nbd_rwv() + but the socket would still block. qio_channel_yield() is called + again and assert(!ioc->write_coroutine) is hit. + +The problem is that nbd_read_reply_entry() does not distinguish between +request coroutines that are waiting to receive a reply and those that +are not. + +This patch adds a per-request bool receiving flag so +nbd_read_reply_entry() can avoid spurious aio_wake() calls. + +Reported-by: Dr. David Alan Gilbert +Signed-off-by: Stefan Hajnoczi +Message-Id: <20170822125113.5025-1-stefanha@redhat.com> +Reviewed-by: Vladimir Sementsov-Ogievskiy +Tested-by: Eric Blake +Reviewed-by: Paolo Bonzini +Signed-off-by: Eric Blake +(cherry picked from commit 40f4a21895b5a7eae4011593837069f63460d983) +Signed-off-by: Miroslav Rezanina +--- + block/nbd-client.c | 35 ++++++++++++++++++++++------------- + block/nbd-client.h | 7 ++++++- + 2 files changed, 28 insertions(+), 14 deletions(-) + +diff --git a/block/nbd-client.c b/block/nbd-client.c +index 256dabeeef..f7bca3f996 100644 +--- a/block/nbd-client.c ++++ b/block/nbd-client.c +@@ -38,8 +38,10 @@ static void nbd_recv_coroutines_enter_all(NBDClientSession *s) + int i; + + for (i = 0; i < MAX_NBD_REQUESTS; i++) { +- if (s->recv_coroutine[i]) { +- aio_co_wake(s->recv_coroutine[i]); ++ NBDClientRequest *req = &s->requests[i]; ++ ++ if (req->coroutine && req->receiving) { ++ aio_co_wake(req->coroutine); + } + } + } +@@ -83,28 +85,28 @@ static coroutine_fn void nbd_read_reply_entry(void *opaque) + * one coroutine is called until the reply finishes. + */ + i = HANDLE_TO_INDEX(s, s->reply.handle); +- if (i >= MAX_NBD_REQUESTS || !s->recv_coroutine[i]) { ++ if (i >= MAX_NBD_REQUESTS || ++ !s->requests[i].coroutine || ++ !s->requests[i].receiving) { + break; + } + +- /* We're woken up by the recv_coroutine itself. Note that there ++ /* We're woken up again by the request itself. Note that there + * is no race between yielding and reentering read_reply_co. This + * is because: + * +- * - if recv_coroutine[i] runs on the same AioContext, it is only ++ * - if the request runs on the same AioContext, it is only + * entered after we yield + * +- * - if recv_coroutine[i] runs on a different AioContext, reentering ++ * - if the request runs on a different AioContext, reentering + * read_reply_co happens through a bottom half, which can only + * run after we yield. + */ +- aio_co_wake(s->recv_coroutine[i]); ++ aio_co_wake(s->requests[i].coroutine); + qemu_coroutine_yield(); + } + +- if (ret < 0) { +- s->quit = true; +- } ++ s->quit = true; + nbd_recv_coroutines_enter_all(s); + s->read_reply_co = NULL; + } +@@ -123,14 +125,17 @@ static int nbd_co_send_request(BlockDriverState *bs, + s->in_flight++; + + for (i = 0; i < MAX_NBD_REQUESTS; i++) { +- if (s->recv_coroutine[i] == NULL) { +- s->recv_coroutine[i] = qemu_coroutine_self(); ++ if (s->requests[i].coroutine == NULL) { + break; + } + } + + g_assert(qemu_in_coroutine()); + assert(i < MAX_NBD_REQUESTS); ++ ++ s->requests[i].coroutine = qemu_coroutine_self(); ++ s->requests[i].receiving = false; ++ + request->handle = INDEX_TO_HANDLE(s, i); + + if (s->quit) { +@@ -168,10 +173,13 @@ static void nbd_co_receive_reply(NBDClientSession *s, + NBDReply *reply, + QEMUIOVector *qiov) + { ++ int i = HANDLE_TO_INDEX(s, request->handle); + int ret; + + /* Wait until we're woken up by nbd_read_reply_entry. */ ++ s->requests[i].receiving = true; + qemu_coroutine_yield(); ++ s->requests[i].receiving = false; + *reply = s->reply; + if (reply->handle != request->handle || !s->ioc || s->quit) { + reply->error = EIO; +@@ -181,6 +189,7 @@ static void nbd_co_receive_reply(NBDClientSession *s, + true); + if (ret != request->len) { + reply->error = EIO; ++ s->quit = true; + } + } + +@@ -195,7 +204,7 @@ static void nbd_coroutine_end(BlockDriverState *bs, + NBDClientSession *s = nbd_get_client_session(bs); + int i = HANDLE_TO_INDEX(s, request->handle); + +- s->recv_coroutine[i] = NULL; ++ s->requests[i].coroutine = NULL; + + /* Kick the read_reply_co to get the next reply. */ + if (s->read_reply_co) { +diff --git a/block/nbd-client.h b/block/nbd-client.h +index 9774a8ebbb..f97792ff49 100644 +--- a/block/nbd-client.h ++++ b/block/nbd-client.h +@@ -17,6 +17,11 @@ + + #define MAX_NBD_REQUESTS 16 + ++typedef struct { ++ Coroutine *coroutine; ++ bool receiving; /* waiting for read_reply_co? */ ++} NBDClientRequest; ++ + typedef struct NBDClientSession { + QIOChannelSocket *sioc; /* The master data channel */ + QIOChannel *ioc; /* The current I/O channel which may differ (eg TLS) */ +@@ -28,7 +33,7 @@ typedef struct NBDClientSession { + Coroutine *read_reply_co; + int in_flight; + +- Coroutine *recv_coroutine[MAX_NBD_REQUESTS]; ++ NBDClientRequest requests[MAX_NBD_REQUESTS]; + NBDReply reply; + bool quit; + } NBDClientSession; +-- +2.11.0 + diff --git a/debian/patches/extra/0044-kvm-nbd-client-avoid-read_reply_co-entry-if-send-failed.patch b/debian/patches/extra/0044-kvm-nbd-client-avoid-read_reply_co-entry-if-send-failed.patch deleted file mode 100644 index 30af881..0000000 --- a/debian/patches/extra/0044-kvm-nbd-client-avoid-read_reply_co-entry-if-send-failed.patch +++ /dev/null @@ -1,160 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Eric Blake -Date: Wed, 27 Sep 2017 17:57:22 +0200 -Subject: [PATCH] nbd-client: avoid read_reply_co entry if send failed - -RH-Author: Eric Blake -Message-id: <20170927175725.20023-5-eblake@redhat.com> -Patchwork-id: 76674 -O-Subject: [RHEV-7.4.z qemu-kvm-rhev PATCH 4/7] nbd-client: avoid read_reply_co entry if send failed -Bugzilla: 1495474 -RH-Acked-by: Max Reitz -RH-Acked-by: Jeffrey Cody -RH-Acked-by: Stefan Hajnoczi - -From: Stefan Hajnoczi - -The following segfault is encountered if the NBD server closes the UNIX -domain socket immediately after negotiation: - - Program terminated with signal SIGSEGV, Segmentation fault. - #0 aio_co_schedule (ctx=0x0, co=0xd3c0ff2ef0) at util/async.c:441 - 441 QSLIST_INSERT_HEAD_ATOMIC(&ctx->scheduled_coroutines, - (gdb) bt - #0 0x000000d3c01a50f8 in aio_co_schedule (ctx=0x0, co=0xd3c0ff2ef0) at util/async.c:441 - #1 0x000000d3c012fa90 in nbd_coroutine_end (bs=bs@entry=0xd3c0fec650, request=) at block/nbd-client.c:207 - #2 0x000000d3c012fb58 in nbd_client_co_preadv (bs=0xd3c0fec650, offset=0, bytes=, qiov=0x7ffc10a91b20, flags=0) at block/nbd-client.c:237 - #3 0x000000d3c0128e63 in bdrv_driver_preadv (bs=bs@entry=0xd3c0fec650, offset=offset@entry=0, bytes=bytes@entry=512, qiov=qiov@entry=0x7ffc10a91b20, flags=0) at block/io.c:836 - #4 0x000000d3c012c3e0 in bdrv_aligned_preadv (child=child@entry=0xd3c0ff51d0, req=req@entry=0x7f31885d6e90, offset=offset@entry=0, bytes=bytes@entry=512, align=align@entry=1, qiov=qiov@entry=0x7ffc10a91b20, f -+lags=0) at block/io.c:1086 - #5 0x000000d3c012c6b8 in bdrv_co_preadv (child=0xd3c0ff51d0, offset=offset@entry=0, bytes=bytes@entry=512, qiov=qiov@entry=0x7ffc10a91b20, flags=flags@entry=0) at block/io.c:1182 - #6 0x000000d3c011cc17 in blk_co_preadv (blk=0xd3c0ff4f80, offset=0, bytes=512, qiov=0x7ffc10a91b20, flags=0) at block/block-backend.c:1032 - #7 0x000000d3c011ccec in blk_read_entry (opaque=0x7ffc10a91b40) at block/block-backend.c:1079 - #8 0x000000d3c01bbb96 in coroutine_trampoline (i0=, i1=) at util/coroutine-ucontext.c:79 - #9 0x00007f3196cb8600 in __start_context () at /lib64/libc.so.6 - -The problem is that nbd_client_init() uses -nbd_client_attach_aio_context() -> aio_co_schedule(new_context, -client->read_reply_co). Execution of read_reply_co is deferred to a BH -which doesn't run until later. - -In the mean time blk_co_preadv() can be called and nbd_coroutine_end() -calls aio_wake() on read_reply_co. At this point in time -read_reply_co's ctx isn't set because it has never been entered yet. - -This patch simplifies the nbd_co_send_request() -> -nbd_co_receive_reply() -> nbd_coroutine_end() lifecycle to just -nbd_co_send_request() -> nbd_co_receive_reply(). The request is "ended" -if an error occurs at any point. Callers no longer have to invoke -nbd_coroutine_end(). - -This cleanup also eliminates the segfault because we don't call -aio_co_schedule() to wake up s->read_reply_co if sending the request -failed. It is only necessary to wake up s->read_reply_co if a reply was -received. - -Note this only happens with UNIX domain sockets on Linux. It doesn't -seem possible to reproduce this with TCP sockets. - -Suggested-by: Paolo Bonzini -Signed-off-by: Stefan Hajnoczi -Message-Id: <20170829122745.14309-2-stefanha@redhat.com> -Signed-off-by: Eric Blake -(cherry picked from commit 3c2d5183f9fa4eac3d17d841e26da65a0181ae7b) -Signed-off-by: Miroslav Rezanina ---- - block/nbd-client.c | 25 +++++++++---------------- - 1 file changed, 9 insertions(+), 16 deletions(-) - -diff --git a/block/nbd-client.c b/block/nbd-client.c -index f7bca3f..434acf6 100644 ---- a/block/nbd-client.c -+++ b/block/nbd-client.c -@@ -139,12 +139,12 @@ static int nbd_co_send_request(BlockDriverState *bs, - request->handle = INDEX_TO_HANDLE(s, i); - - if (s->quit) { -- qemu_co_mutex_unlock(&s->send_mutex); -- return -EIO; -+ rc = -EIO; -+ goto err; - } - if (!s->ioc) { -- qemu_co_mutex_unlock(&s->send_mutex); -- return -EPIPE; -+ rc = -EPIPE; -+ goto err; - } - - if (qiov) { -@@ -161,8 +161,13 @@ static int nbd_co_send_request(BlockDriverState *bs, - } else { - rc = nbd_send_request(s->ioc, request); - } -+ -+err: - if (rc < 0) { - s->quit = true; -+ s->requests[i].coroutine = NULL; -+ s->in_flight--; -+ qemu_co_queue_next(&s->free_sema); - } - qemu_co_mutex_unlock(&s->send_mutex); - return rc; -@@ -196,13 +201,6 @@ static void nbd_co_receive_reply(NBDClientSession *s, - /* Tell the read handler to read another header. */ - s->reply.handle = 0; - } --} -- --static void nbd_coroutine_end(BlockDriverState *bs, -- NBDRequest *request) --{ -- NBDClientSession *s = nbd_get_client_session(bs); -- int i = HANDLE_TO_INDEX(s, request->handle); - - s->requests[i].coroutine = NULL; - -@@ -238,7 +236,6 @@ int nbd_client_co_preadv(BlockDriverState *bs, uint64_t offset, - } else { - nbd_co_receive_reply(client, &request, &reply, qiov); - } -- nbd_coroutine_end(bs, &request); - return -reply.error; - } - -@@ -267,7 +264,6 @@ int nbd_client_co_pwritev(BlockDriverState *bs, uint64_t offset, - } else { - nbd_co_receive_reply(client, &request, &reply, NULL); - } -- nbd_coroutine_end(bs, &request); - return -reply.error; - } - -@@ -301,7 +297,6 @@ int nbd_client_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, - } else { - nbd_co_receive_reply(client, &request, &reply, NULL); - } -- nbd_coroutine_end(bs, &request); - return -reply.error; - } - -@@ -325,7 +320,6 @@ int nbd_client_co_flush(BlockDriverState *bs) - } else { - nbd_co_receive_reply(client, &request, &reply, NULL); - } -- nbd_coroutine_end(bs, &request); - return -reply.error; - } - -@@ -350,7 +344,6 @@ int nbd_client_co_pdiscard(BlockDriverState *bs, int64_t offset, int count) - } else { - nbd_co_receive_reply(client, &request, &reply, NULL); - } -- nbd_coroutine_end(bs, &request); - return -reply.error; - - } --- -1.8.3.1 - diff --git a/debian/patches/extra/0044-nbd-client-avoid-read_reply_co-entry-if-send-failed.patch b/debian/patches/extra/0044-nbd-client-avoid-read_reply_co-entry-if-send-failed.patch new file mode 100644 index 0000000..17baf21 --- /dev/null +++ b/debian/patches/extra/0044-nbd-client-avoid-read_reply_co-entry-if-send-failed.patch @@ -0,0 +1,160 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Eric Blake +Date: Wed, 27 Sep 2017 17:57:22 +0200 +Subject: [PATCH] nbd-client: avoid read_reply_co entry if send failed + +RH-Author: Eric Blake +Message-id: <20170927175725.20023-5-eblake@redhat.com> +Patchwork-id: 76674 +O-Subject: [RHEV-7.4.z qemu-kvm-rhev PATCH 4/7] nbd-client: avoid read_reply_co entry if send failed +Bugzilla: 1495474 +RH-Acked-by: Max Reitz +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Stefan Hajnoczi + +From: Stefan Hajnoczi + +The following segfault is encountered if the NBD server closes the UNIX +domain socket immediately after negotiation: + + Program terminated with signal SIGSEGV, Segmentation fault. + #0 aio_co_schedule (ctx=0x0, co=0xd3c0ff2ef0) at util/async.c:441 + 441 QSLIST_INSERT_HEAD_ATOMIC(&ctx->scheduled_coroutines, + (gdb) bt + #0 0x000000d3c01a50f8 in aio_co_schedule (ctx=0x0, co=0xd3c0ff2ef0) at util/async.c:441 + #1 0x000000d3c012fa90 in nbd_coroutine_end (bs=bs@entry=0xd3c0fec650, request=) at block/nbd-client.c:207 + #2 0x000000d3c012fb58 in nbd_client_co_preadv (bs=0xd3c0fec650, offset=0, bytes=, qiov=0x7ffc10a91b20, flags=0) at block/nbd-client.c:237 + #3 0x000000d3c0128e63 in bdrv_driver_preadv (bs=bs@entry=0xd3c0fec650, offset=offset@entry=0, bytes=bytes@entry=512, qiov=qiov@entry=0x7ffc10a91b20, flags=0) at block/io.c:836 + #4 0x000000d3c012c3e0 in bdrv_aligned_preadv (child=child@entry=0xd3c0ff51d0, req=req@entry=0x7f31885d6e90, offset=offset@entry=0, bytes=bytes@entry=512, align=align@entry=1, qiov=qiov@entry=0x7ffc10a91b20, f ++lags=0) at block/io.c:1086 + #5 0x000000d3c012c6b8 in bdrv_co_preadv (child=0xd3c0ff51d0, offset=offset@entry=0, bytes=bytes@entry=512, qiov=qiov@entry=0x7ffc10a91b20, flags=flags@entry=0) at block/io.c:1182 + #6 0x000000d3c011cc17 in blk_co_preadv (blk=0xd3c0ff4f80, offset=0, bytes=512, qiov=0x7ffc10a91b20, flags=0) at block/block-backend.c:1032 + #7 0x000000d3c011ccec in blk_read_entry (opaque=0x7ffc10a91b40) at block/block-backend.c:1079 + #8 0x000000d3c01bbb96 in coroutine_trampoline (i0=, i1=) at util/coroutine-ucontext.c:79 + #9 0x00007f3196cb8600 in __start_context () at /lib64/libc.so.6 + +The problem is that nbd_client_init() uses +nbd_client_attach_aio_context() -> aio_co_schedule(new_context, +client->read_reply_co). Execution of read_reply_co is deferred to a BH +which doesn't run until later. + +In the mean time blk_co_preadv() can be called and nbd_coroutine_end() +calls aio_wake() on read_reply_co. At this point in time +read_reply_co's ctx isn't set because it has never been entered yet. + +This patch simplifies the nbd_co_send_request() -> +nbd_co_receive_reply() -> nbd_coroutine_end() lifecycle to just +nbd_co_send_request() -> nbd_co_receive_reply(). The request is "ended" +if an error occurs at any point. Callers no longer have to invoke +nbd_coroutine_end(). + +This cleanup also eliminates the segfault because we don't call +aio_co_schedule() to wake up s->read_reply_co if sending the request +failed. It is only necessary to wake up s->read_reply_co if a reply was +received. + +Note this only happens with UNIX domain sockets on Linux. It doesn't +seem possible to reproduce this with TCP sockets. + +Suggested-by: Paolo Bonzini +Signed-off-by: Stefan Hajnoczi +Message-Id: <20170829122745.14309-2-stefanha@redhat.com> +Signed-off-by: Eric Blake +(cherry picked from commit 3c2d5183f9fa4eac3d17d841e26da65a0181ae7b) +Signed-off-by: Miroslav Rezanina +--- + block/nbd-client.c | 25 +++++++++---------------- + 1 file changed, 9 insertions(+), 16 deletions(-) + +diff --git a/block/nbd-client.c b/block/nbd-client.c +index f7bca3f996..434acf647f 100644 +--- a/block/nbd-client.c ++++ b/block/nbd-client.c +@@ -139,12 +139,12 @@ static int nbd_co_send_request(BlockDriverState *bs, + request->handle = INDEX_TO_HANDLE(s, i); + + if (s->quit) { +- qemu_co_mutex_unlock(&s->send_mutex); +- return -EIO; ++ rc = -EIO; ++ goto err; + } + if (!s->ioc) { +- qemu_co_mutex_unlock(&s->send_mutex); +- return -EPIPE; ++ rc = -EPIPE; ++ goto err; + } + + if (qiov) { +@@ -161,8 +161,13 @@ static int nbd_co_send_request(BlockDriverState *bs, + } else { + rc = nbd_send_request(s->ioc, request); + } ++ ++err: + if (rc < 0) { + s->quit = true; ++ s->requests[i].coroutine = NULL; ++ s->in_flight--; ++ qemu_co_queue_next(&s->free_sema); + } + qemu_co_mutex_unlock(&s->send_mutex); + return rc; +@@ -196,13 +201,6 @@ static void nbd_co_receive_reply(NBDClientSession *s, + /* Tell the read handler to read another header. */ + s->reply.handle = 0; + } +-} +- +-static void nbd_coroutine_end(BlockDriverState *bs, +- NBDRequest *request) +-{ +- NBDClientSession *s = nbd_get_client_session(bs); +- int i = HANDLE_TO_INDEX(s, request->handle); + + s->requests[i].coroutine = NULL; + +@@ -238,7 +236,6 @@ int nbd_client_co_preadv(BlockDriverState *bs, uint64_t offset, + } else { + nbd_co_receive_reply(client, &request, &reply, qiov); + } +- nbd_coroutine_end(bs, &request); + return -reply.error; + } + +@@ -267,7 +264,6 @@ int nbd_client_co_pwritev(BlockDriverState *bs, uint64_t offset, + } else { + nbd_co_receive_reply(client, &request, &reply, NULL); + } +- nbd_coroutine_end(bs, &request); + return -reply.error; + } + +@@ -301,7 +297,6 @@ int nbd_client_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, + } else { + nbd_co_receive_reply(client, &request, &reply, NULL); + } +- nbd_coroutine_end(bs, &request); + return -reply.error; + } + +@@ -325,7 +320,6 @@ int nbd_client_co_flush(BlockDriverState *bs) + } else { + nbd_co_receive_reply(client, &request, &reply, NULL); + } +- nbd_coroutine_end(bs, &request); + return -reply.error; + } + +@@ -350,7 +344,6 @@ int nbd_client_co_pdiscard(BlockDriverState *bs, int64_t offset, int count) + } else { + nbd_co_receive_reply(client, &request, &reply, NULL); + } +- nbd_coroutine_end(bs, &request); + return -reply.error; + + } +-- +2.11.0 + diff --git a/debian/patches/extra/0045-kvm-qemu-iotests-improve-nbd-fault-injector.py-startup-p.patch b/debian/patches/extra/0045-kvm-qemu-iotests-improve-nbd-fault-injector.py-startup-p.patch deleted file mode 100644 index d91cd7e..0000000 --- a/debian/patches/extra/0045-kvm-qemu-iotests-improve-nbd-fault-injector.py-startup-p.patch +++ /dev/null @@ -1,61 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Eric Blake -Date: Wed, 27 Sep 2017 17:57:23 +0200 -Subject: [PATCH] qemu-iotests: improve nbd-fault-injector.py startup - protocol - -RH-Author: Eric Blake -Message-id: <20170927175725.20023-6-eblake@redhat.com> -Patchwork-id: 76675 -O-Subject: [RHEV-7.4.z qemu-kvm-rhev PATCH 5/7] qemu-iotests: improve nbd-fault-injector.py startup protocol -Bugzilla: 1495474 -RH-Acked-by: Max Reitz -RH-Acked-by: Jeffrey Cody -RH-Acked-by: Stefan Hajnoczi - -From: Stefan Hajnoczi - -Currently 083 waits for the nbd-fault-injector.py server to start up by -looping until netstat shows the TCP listen socket. - -The startup protocol can be simplified by passing a 0 port number to -nbd-fault-injector.py. The kernel will allocate a port in bind(2) and -the final port number can be printed by nbd-fault-injector.py. - -This should make it slightly nicer and less TCP-specific to wait for -server startup. This patch changes nbd-fault-injector.py, the next one -will rewrite server startup in 083. - -Reviewed-by: Eric Blake -Signed-off-by: Stefan Hajnoczi -Message-Id: <20170829122745.14309-3-stefanha@redhat.com> -Signed-off-by: Eric Blake -(cherry picked from commit 6e592fc92234a58c7156c385840633c17dedd24f) -Signed-off-by: Miroslav Rezanina ---- - tests/qemu-iotests/nbd-fault-injector.py | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/tests/qemu-iotests/nbd-fault-injector.py b/tests/qemu-iotests/nbd-fault-injector.py -index 6c07191..1c10dcb 100755 ---- a/tests/qemu-iotests/nbd-fault-injector.py -+++ b/tests/qemu-iotests/nbd-fault-injector.py -@@ -235,11 +235,15 @@ def open_socket(path): - sock = socket.socket() - sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - sock.bind((host, int(port))) -+ -+ # If given port was 0 the final port number is now available -+ path = '%s:%d' % sock.getsockname() - else: - sock = socket.socket(socket.AF_UNIX) - sock.bind(path) - sock.listen(0) - print 'Listening on %s' % path -+ sys.stdout.flush() # another process may be waiting, show message now - return sock - - def usage(args): --- -1.8.3.1 - diff --git a/debian/patches/extra/0045-qemu-iotests-improve-nbd-fault-injector.py-startup-p.patch b/debian/patches/extra/0045-qemu-iotests-improve-nbd-fault-injector.py-startup-p.patch new file mode 100644 index 0000000..1053a7f --- /dev/null +++ b/debian/patches/extra/0045-qemu-iotests-improve-nbd-fault-injector.py-startup-p.patch @@ -0,0 +1,60 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Eric Blake +Date: Wed, 27 Sep 2017 17:57:23 +0200 +Subject: [PATCH] qemu-iotests: improve nbd-fault-injector.py startup protocol + +RH-Author: Eric Blake +Message-id: <20170927175725.20023-6-eblake@redhat.com> +Patchwork-id: 76675 +O-Subject: [RHEV-7.4.z qemu-kvm-rhev PATCH 5/7] qemu-iotests: improve nbd-fault-injector.py startup protocol +Bugzilla: 1495474 +RH-Acked-by: Max Reitz +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Stefan Hajnoczi + +From: Stefan Hajnoczi + +Currently 083 waits for the nbd-fault-injector.py server to start up by +looping until netstat shows the TCP listen socket. + +The startup protocol can be simplified by passing a 0 port number to +nbd-fault-injector.py. The kernel will allocate a port in bind(2) and +the final port number can be printed by nbd-fault-injector.py. + +This should make it slightly nicer and less TCP-specific to wait for +server startup. This patch changes nbd-fault-injector.py, the next one +will rewrite server startup in 083. + +Reviewed-by: Eric Blake +Signed-off-by: Stefan Hajnoczi +Message-Id: <20170829122745.14309-3-stefanha@redhat.com> +Signed-off-by: Eric Blake +(cherry picked from commit 6e592fc92234a58c7156c385840633c17dedd24f) +Signed-off-by: Miroslav Rezanina +--- + tests/qemu-iotests/nbd-fault-injector.py | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/tests/qemu-iotests/nbd-fault-injector.py b/tests/qemu-iotests/nbd-fault-injector.py +index 6c07191a5a..1c10dcb51c 100755 +--- a/tests/qemu-iotests/nbd-fault-injector.py ++++ b/tests/qemu-iotests/nbd-fault-injector.py +@@ -235,11 +235,15 @@ def open_socket(path): + sock = socket.socket() + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + sock.bind((host, int(port))) ++ ++ # If given port was 0 the final port number is now available ++ path = '%s:%d' % sock.getsockname() + else: + sock = socket.socket(socket.AF_UNIX) + sock.bind(path) + sock.listen(0) + print 'Listening on %s' % path ++ sys.stdout.flush() # another process may be waiting, show message now + return sock + + def usage(args): +-- +2.11.0 + diff --git a/debian/patches/extra/0046-kvm-qemu-iotests-test-NBD-over-UNIX-domain-sockets-in-08.patch b/debian/patches/extra/0046-kvm-qemu-iotests-test-NBD-over-UNIX-domain-sockets-in-08.patch deleted file mode 100644 index 995f238..0000000 --- a/debian/patches/extra/0046-kvm-qemu-iotests-test-NBD-over-UNIX-domain-sockets-in-08.patch +++ /dev/null @@ -1,454 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Eric Blake -Date: Wed, 27 Sep 2017 17:57:24 +0200 -Subject: [PATCH] qemu-iotests: test NBD over UNIX domain sockets in 083 - -RH-Author: Eric Blake -Message-id: <20170927175725.20023-7-eblake@redhat.com> -Patchwork-id: 76670 -O-Subject: [RHEV-7.4.z qemu-kvm-rhev PATCH 6/7] qemu-iotests: test NBD over UNIX domain sockets in 083 -Bugzilla: 1495474 -RH-Acked-by: Max Reitz -RH-Acked-by: Jeffrey Cody -RH-Acked-by: Stefan Hajnoczi - -From: Stefan Hajnoczi - -083 only tests TCP. Some failures might be specific to UNIX domain -sockets. - -A few adjustments are necessary: - -1. Generating a port number and waiting for server startup is - TCP-specific. Use the new nbd-fault-injector.py startup protocol to - fetch the address. This is a little more elegant because we don't - need netstat anymore. - -2. The NBD filter does not work for the UNIX domain sockets URIs we - generate and must be extended. - -3. Run all tests twice: once for TCP and once for UNIX domain sockets. - -Reviewed-by: Eric Blake -Signed-off-by: Stefan Hajnoczi -Message-Id: <20170829122745.14309-4-stefanha@redhat.com> -Signed-off-by: Eric Blake -(cherry picked from commit 02d2d860d25e439f0e88658c701668ab684568fb) -Signed-off-by: Miroslav Rezanina - -Conflicts: - tests/qemu-iotests/083.out - error message improvements not backported - -Signed-off-by: Eric Blake ---- - tests/qemu-iotests/083 | 136 +++++++++++++++++++++++-------------- - tests/qemu-iotests/083.out | 143 ++++++++++++++++++++++++++++++++++----- - tests/qemu-iotests/common.filter | 4 +- - 3 files changed, 212 insertions(+), 71 deletions(-) - -diff --git a/tests/qemu-iotests/083 b/tests/qemu-iotests/083 -index bff9360..0306f11 100755 ---- a/tests/qemu-iotests/083 -+++ b/tests/qemu-iotests/083 -@@ -27,6 +27,14 @@ echo "QA output created by $seq" - here=`pwd` - status=1 # failure is the default! - -+_cleanup() -+{ -+ rm -f nbd.sock -+ rm -f nbd-fault-injector.out -+ rm -f nbd-fault-injector.conf -+} -+trap "_cleanup; exit \$status" 0 1 2 3 15 -+ - # get standard environment, filters and checks - . ./common.rc - . ./common.filter -@@ -35,81 +43,105 @@ _supported_fmt generic - _supported_proto nbd - _supported_os Linux - --# Pick a TCP port based on our pid. This way multiple instances of this test --# can run in parallel without conflicting. --choose_tcp_port() { -- echo $((($$ % 31744) + 1024)) # 1024 <= port < 32768 --} -- --wait_for_tcp_port() { -- while ! (netstat --tcp --listening --numeric | \ -- grep "$1.*0\\.0\\.0\\.0:\\*.*LISTEN") >/dev/null 2>&1; do -- sleep 0.1 -+check_disconnect() { -+ local event export_name=foo extra_args nbd_addr nbd_url proto when -+ -+ while true; do -+ case $1 in -+ --classic-negotiation) -+ shift -+ extra_args=--classic-negotiation -+ export_name= -+ ;; -+ --tcp) -+ shift -+ proto=tcp -+ ;; -+ --unix) -+ shift -+ proto=unix -+ ;; -+ *) -+ break -+ ;; -+ esac - done --} - --check_disconnect() { - event=$1 - when=$2 -- negotiation=$3 - echo "=== Check disconnect $when $event ===" - echo - -- port=$(choose_tcp_port) -- - cat > "$TEST_DIR/nbd-fault-injector.conf" <"$TEST_DIR/nbd-fault-injector.out" 2>&1 & -+ -+ # Wait for server to be ready -+ while ! grep -q 'Listening on ' "$TEST_DIR/nbd-fault-injector.out"; do -+ sleep 0.1 -+ done -+ -+ # Extract the final address (port number has now been assigned in tcp case) -+ nbd_addr=$(sed 's/Listening on \(.*\)$/\1/' "$TEST_DIR/nbd-fault-injector.out") -+ -+ if [ "$proto" = "tcp" ]; then -+ nbd_url="nbd+tcp://$nbd_addr/$export_name" -+ else -+ nbd_url="nbd+unix:///$export_name?socket=$nbd_addr" - fi - -- $PYTHON nbd-fault-injector.py $extra_args "127.0.0.1:$port" "$TEST_DIR/nbd-fault-injector.conf" >/dev/null 2>&1 & -- wait_for_tcp_port "127\\.0\\.0\\.1:$port" - $QEMU_IO -c "read 0 512" "$nbd_url" 2>&1 | _filter_qemu_io | _filter_nbd - - echo - } - --for event in neg1 "export" neg2 request reply data; do -- for when in before after; do -- check_disconnect "$event" "$when" -- done -- -- # Also inject short replies from the NBD server -- case "$event" in -- neg1) -- for when in 8 16; do -- check_disconnect "$event" "$when" -- done -- ;; -- "export") -- for when in 4 12 16; do -- check_disconnect "$event" "$when" -+for proto in tcp unix; do -+ for event in neg1 "export" neg2 request reply data; do -+ for when in before after; do -+ check_disconnect "--$proto" "$event" "$when" - done -- ;; -- neg2) -- for when in 8 10; do -- check_disconnect "$event" "$when" -- done -- ;; -- reply) -- for when in 4 8; do -- check_disconnect "$event" "$when" -- done -- ;; -- esac --done - --# Also check classic negotiation without export information --for when in before 8 16 24 28 after; do -- check_disconnect "neg-classic" "$when" --classic-negotiation -+ # Also inject short replies from the NBD server -+ case "$event" in -+ neg1) -+ for when in 8 16; do -+ check_disconnect "--$proto" "$event" "$when" -+ done -+ ;; -+ "export") -+ for when in 4 12 16; do -+ check_disconnect "--$proto" "$event" "$when" -+ done -+ ;; -+ neg2) -+ for when in 8 10; do -+ check_disconnect "--$proto" "$event" "$when" -+ done -+ ;; -+ reply) -+ for when in 4 8; do -+ check_disconnect "--$proto" "$event" "$when" -+ done -+ ;; -+ esac -+ done -+ -+ # Also check classic negotiation without export information -+ for when in before 8 16 24 28 after; do -+ check_disconnect "--$proto" --classic-negotiation "neg-classic" "$when" -+ done - done - - # success, all done -diff --git a/tests/qemu-iotests/083.out b/tests/qemu-iotests/083.out -index 0c13888..7419722 100644 ---- a/tests/qemu-iotests/083.out -+++ b/tests/qemu-iotests/083.out -@@ -1,43 +1,43 @@ - QA output created by 083 - === Check disconnect before neg1 === - --can't open device nbd:127.0.0.1:PORT:exportname=foo -+can't open device nbd+tcp://127.0.0.1:PORT/foo - - === Check disconnect after neg1 === - --can't open device nbd:127.0.0.1:PORT:exportname=foo -+can't open device nbd+tcp://127.0.0.1:PORT/foo - - === Check disconnect 8 neg1 === - --can't open device nbd:127.0.0.1:PORT:exportname=foo -+can't open device nbd+tcp://127.0.0.1:PORT/foo - - === Check disconnect 16 neg1 === - --can't open device nbd:127.0.0.1:PORT:exportname=foo -+can't open device nbd+tcp://127.0.0.1:PORT/foo - - === Check disconnect before export === - --can't open device nbd:127.0.0.1:PORT:exportname=foo -+can't open device nbd+tcp://127.0.0.1:PORT/foo - - === Check disconnect after export === - --can't open device nbd:127.0.0.1:PORT:exportname=foo -+can't open device nbd+tcp://127.0.0.1:PORT/foo - - === Check disconnect 4 export === - --can't open device nbd:127.0.0.1:PORT:exportname=foo -+can't open device nbd+tcp://127.0.0.1:PORT/foo - - === Check disconnect 12 export === - --can't open device nbd:127.0.0.1:PORT:exportname=foo -+can't open device nbd+tcp://127.0.0.1:PORT/foo - - === Check disconnect 16 export === - --can't open device nbd:127.0.0.1:PORT:exportname=foo -+can't open device nbd+tcp://127.0.0.1:PORT/foo - - === Check disconnect before neg2 === - --can't open device nbd:127.0.0.1:PORT:exportname=foo -+can't open device nbd+tcp://127.0.0.1:PORT/foo - - === Check disconnect after neg2 === - -@@ -45,11 +45,11 @@ read failed: Input/output error - - === Check disconnect 8 neg2 === - --can't open device nbd:127.0.0.1:PORT:exportname=foo -+can't open device nbd+tcp://127.0.0.1:PORT/foo - - === Check disconnect 10 neg2 === - --can't open device nbd:127.0.0.1:PORT:exportname=foo -+can't open device nbd+tcp://127.0.0.1:PORT/foo - - === Check disconnect before request === - -@@ -86,23 +86,132 @@ read 512/512 bytes at offset 0 - - === Check disconnect before neg-classic === - --can't open device nbd:127.0.0.1:PORT -+can't open device nbd+tcp://127.0.0.1:PORT/ - - === Check disconnect 8 neg-classic === - --can't open device nbd:127.0.0.1:PORT -+can't open device nbd+tcp://127.0.0.1:PORT/ - - === Check disconnect 16 neg-classic === - --can't open device nbd:127.0.0.1:PORT -+can't open device nbd+tcp://127.0.0.1:PORT/ - - === Check disconnect 24 neg-classic === - --can't open device nbd:127.0.0.1:PORT -+can't open device nbd+tcp://127.0.0.1:PORT/ - - === Check disconnect 28 neg-classic === - --can't open device nbd:127.0.0.1:PORT -+can't open device nbd+tcp://127.0.0.1:PORT/ -+ -+=== Check disconnect after neg-classic === -+ -+read failed: Input/output error -+ -+=== Check disconnect before neg1 === -+ -+can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock -+ -+=== Check disconnect after neg1 === -+ -+can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock -+ -+=== Check disconnect 8 neg1 === -+ -+can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock -+ -+=== Check disconnect 16 neg1 === -+ -+can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock -+ -+=== Check disconnect before export === -+ -+can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock -+ -+=== Check disconnect after export === -+ -+can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock -+ -+=== Check disconnect 4 export === -+ -+can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock -+ -+=== Check disconnect 12 export === -+ -+can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock -+ -+=== Check disconnect 16 export === -+ -+can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock -+ -+=== Check disconnect before neg2 === -+ -+can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock -+ -+=== Check disconnect after neg2 === -+ -+read failed: Input/output error -+ -+=== Check disconnect 8 neg2 === -+ -+can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock -+ -+=== Check disconnect 10 neg2 === -+ -+can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock -+ -+=== Check disconnect before request === -+ -+read failed: Input/output error -+ -+=== Check disconnect after request === -+ -+read failed: Input/output error -+ -+=== Check disconnect before reply === -+ -+read failed: Input/output error -+ -+=== Check disconnect after reply === -+ -+read failed: Input/output error -+ -+=== Check disconnect 4 reply === -+ -+read failed: Input/output error -+ -+=== Check disconnect 8 reply === -+ -+read failed: Input/output error -+ -+=== Check disconnect before data === -+ -+read failed: Input/output error -+ -+=== Check disconnect after data === -+ -+read 512/512 bytes at offset 0 -+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -+ -+=== Check disconnect before neg-classic === -+ -+can't open device nbd+unix:///?socket=TEST_DIR/nbd.sock -+ -+=== Check disconnect 8 neg-classic === -+ -+can't open device nbd+unix:///?socket=TEST_DIR/nbd.sock -+ -+=== Check disconnect 16 neg-classic === -+ -+can't open device nbd+unix:///?socket=TEST_DIR/nbd.sock -+ -+=== Check disconnect 24 neg-classic === -+ -+can't open device nbd+unix:///?socket=TEST_DIR/nbd.sock -+ -+=== Check disconnect 28 neg-classic === -+ -+can't open device nbd+unix:///?socket=TEST_DIR/nbd.sock - - === Check disconnect after neg-classic === - -diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter -index c9a2d5c..f06d4dc 100644 ---- a/tests/qemu-iotests/common.filter -+++ b/tests/qemu-iotests/common.filter -@@ -154,9 +154,9 @@ _filter_nbd() - # - # Filter out the TCP port number since this changes between runs. - sed -e '/nbd\/.*\.c:/d' \ -- -e 's#nbd:\(//\)\?127\.0\.0\.1:[0-9]*#nbd:\1127.0.0.1:PORT#g' \ -+ -e 's#127\.0\.0\.1:[0-9]*#127.0.0.1:PORT#g' \ - -e "s#?socket=$TEST_DIR#?socket=TEST_DIR#g" \ -- -e 's#\(exportname=foo\|PORT\): Failed to .*$#\1#' -+ -e 's#\(foo\|PORT/\?\|.sock\): Failed to .*$#\1#' - } - - # make sure this script returns success --- -1.8.3.1 - diff --git a/debian/patches/extra/0046-qemu-iotests-test-NBD-over-UNIX-domain-sockets-in-08.patch b/debian/patches/extra/0046-qemu-iotests-test-NBD-over-UNIX-domain-sockets-in-08.patch new file mode 100644 index 0000000..4c4d618 --- /dev/null +++ b/debian/patches/extra/0046-qemu-iotests-test-NBD-over-UNIX-domain-sockets-in-08.patch @@ -0,0 +1,454 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Eric Blake +Date: Wed, 27 Sep 2017 17:57:24 +0200 +Subject: [PATCH] qemu-iotests: test NBD over UNIX domain sockets in 083 + +RH-Author: Eric Blake +Message-id: <20170927175725.20023-7-eblake@redhat.com> +Patchwork-id: 76670 +O-Subject: [RHEV-7.4.z qemu-kvm-rhev PATCH 6/7] qemu-iotests: test NBD over UNIX domain sockets in 083 +Bugzilla: 1495474 +RH-Acked-by: Max Reitz +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Stefan Hajnoczi + +From: Stefan Hajnoczi + +083 only tests TCP. Some failures might be specific to UNIX domain +sockets. + +A few adjustments are necessary: + +1. Generating a port number and waiting for server startup is + TCP-specific. Use the new nbd-fault-injector.py startup protocol to + fetch the address. This is a little more elegant because we don't + need netstat anymore. + +2. The NBD filter does not work for the UNIX domain sockets URIs we + generate and must be extended. + +3. Run all tests twice: once for TCP and once for UNIX domain sockets. + +Reviewed-by: Eric Blake +Signed-off-by: Stefan Hajnoczi +Message-Id: <20170829122745.14309-4-stefanha@redhat.com> +Signed-off-by: Eric Blake +(cherry picked from commit 02d2d860d25e439f0e88658c701668ab684568fb) +Signed-off-by: Miroslav Rezanina + +Conflicts: + tests/qemu-iotests/083.out - error message improvements not backported + +Signed-off-by: Eric Blake +--- + tests/qemu-iotests/083 | 136 +++++++++++++++++++++++-------------- + tests/qemu-iotests/083.out | 143 ++++++++++++++++++++++++++++++++++----- + tests/qemu-iotests/common.filter | 4 +- + 3 files changed, 212 insertions(+), 71 deletions(-) + +diff --git a/tests/qemu-iotests/083 b/tests/qemu-iotests/083 +index bff9360048..0306f112da 100755 +--- a/tests/qemu-iotests/083 ++++ b/tests/qemu-iotests/083 +@@ -27,6 +27,14 @@ echo "QA output created by $seq" + here=`pwd` + status=1 # failure is the default! + ++_cleanup() ++{ ++ rm -f nbd.sock ++ rm -f nbd-fault-injector.out ++ rm -f nbd-fault-injector.conf ++} ++trap "_cleanup; exit \$status" 0 1 2 3 15 ++ + # get standard environment, filters and checks + . ./common.rc + . ./common.filter +@@ -35,81 +43,105 @@ _supported_fmt generic + _supported_proto nbd + _supported_os Linux + +-# Pick a TCP port based on our pid. This way multiple instances of this test +-# can run in parallel without conflicting. +-choose_tcp_port() { +- echo $((($$ % 31744) + 1024)) # 1024 <= port < 32768 +-} +- +-wait_for_tcp_port() { +- while ! (netstat --tcp --listening --numeric | \ +- grep "$1.*0\\.0\\.0\\.0:\\*.*LISTEN") >/dev/null 2>&1; do +- sleep 0.1 ++check_disconnect() { ++ local event export_name=foo extra_args nbd_addr nbd_url proto when ++ ++ while true; do ++ case $1 in ++ --classic-negotiation) ++ shift ++ extra_args=--classic-negotiation ++ export_name= ++ ;; ++ --tcp) ++ shift ++ proto=tcp ++ ;; ++ --unix) ++ shift ++ proto=unix ++ ;; ++ *) ++ break ++ ;; ++ esac + done +-} + +-check_disconnect() { + event=$1 + when=$2 +- negotiation=$3 + echo "=== Check disconnect $when $event ===" + echo + +- port=$(choose_tcp_port) +- + cat > "$TEST_DIR/nbd-fault-injector.conf" <"$TEST_DIR/nbd-fault-injector.out" 2>&1 & ++ ++ # Wait for server to be ready ++ while ! grep -q 'Listening on ' "$TEST_DIR/nbd-fault-injector.out"; do ++ sleep 0.1 ++ done ++ ++ # Extract the final address (port number has now been assigned in tcp case) ++ nbd_addr=$(sed 's/Listening on \(.*\)$/\1/' "$TEST_DIR/nbd-fault-injector.out") ++ ++ if [ "$proto" = "tcp" ]; then ++ nbd_url="nbd+tcp://$nbd_addr/$export_name" ++ else ++ nbd_url="nbd+unix:///$export_name?socket=$nbd_addr" + fi + +- $PYTHON nbd-fault-injector.py $extra_args "127.0.0.1:$port" "$TEST_DIR/nbd-fault-injector.conf" >/dev/null 2>&1 & +- wait_for_tcp_port "127\\.0\\.0\\.1:$port" + $QEMU_IO -c "read 0 512" "$nbd_url" 2>&1 | _filter_qemu_io | _filter_nbd + + echo + } + +-for event in neg1 "export" neg2 request reply data; do +- for when in before after; do +- check_disconnect "$event" "$when" +- done +- +- # Also inject short replies from the NBD server +- case "$event" in +- neg1) +- for when in 8 16; do +- check_disconnect "$event" "$when" +- done +- ;; +- "export") +- for when in 4 12 16; do +- check_disconnect "$event" "$when" ++for proto in tcp unix; do ++ for event in neg1 "export" neg2 request reply data; do ++ for when in before after; do ++ check_disconnect "--$proto" "$event" "$when" + done +- ;; +- neg2) +- for when in 8 10; do +- check_disconnect "$event" "$when" +- done +- ;; +- reply) +- for when in 4 8; do +- check_disconnect "$event" "$when" +- done +- ;; +- esac +-done + +-# Also check classic negotiation without export information +-for when in before 8 16 24 28 after; do +- check_disconnect "neg-classic" "$when" --classic-negotiation ++ # Also inject short replies from the NBD server ++ case "$event" in ++ neg1) ++ for when in 8 16; do ++ check_disconnect "--$proto" "$event" "$when" ++ done ++ ;; ++ "export") ++ for when in 4 12 16; do ++ check_disconnect "--$proto" "$event" "$when" ++ done ++ ;; ++ neg2) ++ for when in 8 10; do ++ check_disconnect "--$proto" "$event" "$when" ++ done ++ ;; ++ reply) ++ for when in 4 8; do ++ check_disconnect "--$proto" "$event" "$when" ++ done ++ ;; ++ esac ++ done ++ ++ # Also check classic negotiation without export information ++ for when in before 8 16 24 28 after; do ++ check_disconnect "--$proto" --classic-negotiation "neg-classic" "$when" ++ done + done + + # success, all done +diff --git a/tests/qemu-iotests/083.out b/tests/qemu-iotests/083.out +index 0c13888ba1..7419722cd7 100644 +--- a/tests/qemu-iotests/083.out ++++ b/tests/qemu-iotests/083.out +@@ -1,43 +1,43 @@ + QA output created by 083 + === Check disconnect before neg1 === + +-can't open device nbd:127.0.0.1:PORT:exportname=foo ++can't open device nbd+tcp://127.0.0.1:PORT/foo + + === Check disconnect after neg1 === + +-can't open device nbd:127.0.0.1:PORT:exportname=foo ++can't open device nbd+tcp://127.0.0.1:PORT/foo + + === Check disconnect 8 neg1 === + +-can't open device nbd:127.0.0.1:PORT:exportname=foo ++can't open device nbd+tcp://127.0.0.1:PORT/foo + + === Check disconnect 16 neg1 === + +-can't open device nbd:127.0.0.1:PORT:exportname=foo ++can't open device nbd+tcp://127.0.0.1:PORT/foo + + === Check disconnect before export === + +-can't open device nbd:127.0.0.1:PORT:exportname=foo ++can't open device nbd+tcp://127.0.0.1:PORT/foo + + === Check disconnect after export === + +-can't open device nbd:127.0.0.1:PORT:exportname=foo ++can't open device nbd+tcp://127.0.0.1:PORT/foo + + === Check disconnect 4 export === + +-can't open device nbd:127.0.0.1:PORT:exportname=foo ++can't open device nbd+tcp://127.0.0.1:PORT/foo + + === Check disconnect 12 export === + +-can't open device nbd:127.0.0.1:PORT:exportname=foo ++can't open device nbd+tcp://127.0.0.1:PORT/foo + + === Check disconnect 16 export === + +-can't open device nbd:127.0.0.1:PORT:exportname=foo ++can't open device nbd+tcp://127.0.0.1:PORT/foo + + === Check disconnect before neg2 === + +-can't open device nbd:127.0.0.1:PORT:exportname=foo ++can't open device nbd+tcp://127.0.0.1:PORT/foo + + === Check disconnect after neg2 === + +@@ -45,11 +45,11 @@ read failed: Input/output error + + === Check disconnect 8 neg2 === + +-can't open device nbd:127.0.0.1:PORT:exportname=foo ++can't open device nbd+tcp://127.0.0.1:PORT/foo + + === Check disconnect 10 neg2 === + +-can't open device nbd:127.0.0.1:PORT:exportname=foo ++can't open device nbd+tcp://127.0.0.1:PORT/foo + + === Check disconnect before request === + +@@ -86,23 +86,132 @@ read 512/512 bytes at offset 0 + + === Check disconnect before neg-classic === + +-can't open device nbd:127.0.0.1:PORT ++can't open device nbd+tcp://127.0.0.1:PORT/ + + === Check disconnect 8 neg-classic === + +-can't open device nbd:127.0.0.1:PORT ++can't open device nbd+tcp://127.0.0.1:PORT/ + + === Check disconnect 16 neg-classic === + +-can't open device nbd:127.0.0.1:PORT ++can't open device nbd+tcp://127.0.0.1:PORT/ + + === Check disconnect 24 neg-classic === + +-can't open device nbd:127.0.0.1:PORT ++can't open device nbd+tcp://127.0.0.1:PORT/ + + === Check disconnect 28 neg-classic === + +-can't open device nbd:127.0.0.1:PORT ++can't open device nbd+tcp://127.0.0.1:PORT/ ++ ++=== Check disconnect after neg-classic === ++ ++read failed: Input/output error ++ ++=== Check disconnect before neg1 === ++ ++can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock ++ ++=== Check disconnect after neg1 === ++ ++can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock ++ ++=== Check disconnect 8 neg1 === ++ ++can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock ++ ++=== Check disconnect 16 neg1 === ++ ++can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock ++ ++=== Check disconnect before export === ++ ++can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock ++ ++=== Check disconnect after export === ++ ++can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock ++ ++=== Check disconnect 4 export === ++ ++can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock ++ ++=== Check disconnect 12 export === ++ ++can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock ++ ++=== Check disconnect 16 export === ++ ++can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock ++ ++=== Check disconnect before neg2 === ++ ++can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock ++ ++=== Check disconnect after neg2 === ++ ++read failed: Input/output error ++ ++=== Check disconnect 8 neg2 === ++ ++can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock ++ ++=== Check disconnect 10 neg2 === ++ ++can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock ++ ++=== Check disconnect before request === ++ ++read failed: Input/output error ++ ++=== Check disconnect after request === ++ ++read failed: Input/output error ++ ++=== Check disconnect before reply === ++ ++read failed: Input/output error ++ ++=== Check disconnect after reply === ++ ++read failed: Input/output error ++ ++=== Check disconnect 4 reply === ++ ++read failed: Input/output error ++ ++=== Check disconnect 8 reply === ++ ++read failed: Input/output error ++ ++=== Check disconnect before data === ++ ++read failed: Input/output error ++ ++=== Check disconnect after data === ++ ++read 512/512 bytes at offset 0 ++512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++ ++=== Check disconnect before neg-classic === ++ ++can't open device nbd+unix:///?socket=TEST_DIR/nbd.sock ++ ++=== Check disconnect 8 neg-classic === ++ ++can't open device nbd+unix:///?socket=TEST_DIR/nbd.sock ++ ++=== Check disconnect 16 neg-classic === ++ ++can't open device nbd+unix:///?socket=TEST_DIR/nbd.sock ++ ++=== Check disconnect 24 neg-classic === ++ ++can't open device nbd+unix:///?socket=TEST_DIR/nbd.sock ++ ++=== Check disconnect 28 neg-classic === ++ ++can't open device nbd+unix:///?socket=TEST_DIR/nbd.sock + + === Check disconnect after neg-classic === + +diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter +index 104001358b..65ec315f25 100644 +--- a/tests/qemu-iotests/common.filter ++++ b/tests/qemu-iotests/common.filter +@@ -153,9 +153,9 @@ _filter_nbd() + # + # Filter out the TCP port number since this changes between runs. + sed -e '/nbd\/.*\.c:/d' \ +- -e 's#nbd:\(//\)\?127\.0\.0\.1:[0-9]*#nbd:\1127.0.0.1:PORT#g' \ ++ -e 's#127\.0\.0\.1:[0-9]*#127.0.0.1:PORT#g' \ + -e "s#?socket=$TEST_DIR#?socket=TEST_DIR#g" \ +- -e 's#\(exportname=foo\|PORT\): Failed to .*$#\1#' ++ -e 's#\(foo\|PORT/\?\|.sock\): Failed to .*$#\1#' + } + + # make sure this script returns success +-- +2.11.0 + diff --git a/debian/patches/extra/0047-block-nbd-client-nbd_co_send_request-fix-return-code.patch b/debian/patches/extra/0047-block-nbd-client-nbd_co_send_request-fix-return-code.patch new file mode 100644 index 0000000..84b7815 --- /dev/null +++ b/debian/patches/extra/0047-block-nbd-client-nbd_co_send_request-fix-return-code.patch @@ -0,0 +1,45 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Eric Blake +Date: Wed, 27 Sep 2017 17:57:25 +0200 +Subject: [PATCH] block/nbd-client: nbd_co_send_request: fix return code + +RH-Author: Eric Blake +Message-id: <20170927175725.20023-8-eblake@redhat.com> +Patchwork-id: 76673 +O-Subject: [RHEV-7.4.z qemu-kvm-rhev PATCH 7/7] block/nbd-client: nbd_co_send_request: fix return code +Bugzilla: 1495474 +RH-Acked-by: Max Reitz +RH-Acked-by: Jeffrey Cody +RH-Acked-by: Stefan Hajnoczi + +From: Vladimir Sementsov-Ogievskiy + +It's incorrect to return success rc >= 0 if we skip qio_channel_writev_all() +call due to s->quit. + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Reviewed-by: Eric Blake +Message-Id: <20170920124507.18841-4-vsementsov@virtuozzo.com> +Signed-off-by: Eric Blake +(cherry picked from commit a693437037328a95d815ad5aec37ac2f8e130e58) +Signed-off-by: Miroslav Rezanina +--- + block/nbd-client.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/block/nbd-client.c b/block/nbd-client.c +index 434acf647f..76789c1829 100644 +--- a/block/nbd-client.c ++++ b/block/nbd-client.c +@@ -156,6 +156,8 @@ static int nbd_co_send_request(BlockDriverState *bs, + if (ret != request->len) { + rc = -EIO; + } ++ } else if (rc >= 0) { ++ rc = -EIO; + } + qio_channel_set_cork(s->ioc, false); + } else { +-- +2.11.0 + diff --git a/debian/patches/extra/0047-kvm-block-nbd-client-nbd_co_send_request-fix-return-code.patch b/debian/patches/extra/0047-kvm-block-nbd-client-nbd_co_send_request-fix-return-code.patch deleted file mode 100644 index 952cd07..0000000 --- a/debian/patches/extra/0047-kvm-block-nbd-client-nbd_co_send_request-fix-return-code.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Eric Blake -Date: Wed, 27 Sep 2017 17:57:25 +0200 -Subject: [PATCH] block/nbd-client: nbd_co_send_request: fix return code - -RH-Author: Eric Blake -Message-id: <20170927175725.20023-8-eblake@redhat.com> -Patchwork-id: 76673 -O-Subject: [RHEV-7.4.z qemu-kvm-rhev PATCH 7/7] block/nbd-client: nbd_co_send_request: fix return code -Bugzilla: 1495474 -RH-Acked-by: Max Reitz -RH-Acked-by: Jeffrey Cody -RH-Acked-by: Stefan Hajnoczi - -From: Vladimir Sementsov-Ogievskiy - -It's incorrect to return success rc >= 0 if we skip qio_channel_writev_all() -call due to s->quit. - -Signed-off-by: Vladimir Sementsov-Ogievskiy -Reviewed-by: Eric Blake -Message-Id: <20170920124507.18841-4-vsementsov@virtuozzo.com> -Signed-off-by: Eric Blake -(cherry picked from commit a693437037328a95d815ad5aec37ac2f8e130e58) -Signed-off-by: Miroslav Rezanina ---- - block/nbd-client.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/block/nbd-client.c b/block/nbd-client.c -index 434acf6..76789c1 100644 ---- a/block/nbd-client.c -+++ b/block/nbd-client.c -@@ -156,6 +156,8 @@ static int nbd_co_send_request(BlockDriverState *bs, - if (ret != request->len) { - rc = -EIO; - } -+ } else if (rc >= 0) { -+ rc = -EIO; - } - qio_channel_set_cork(s->ioc, false); - } else { --- -1.8.3.1 - diff --git a/debian/patches/extra/0048-target-i386-cpu-Add-new-EPYC-CPU-model.patch b/debian/patches/extra/0048-target-i386-cpu-Add-new-EPYC-CPU-model.patch new file mode 100644 index 0000000..8a20217 --- /dev/null +++ b/debian/patches/extra/0048-target-i386-cpu-Add-new-EPYC-CPU-model.patch @@ -0,0 +1,86 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Brijesh Singh +Date: Tue, 15 Aug 2017 12:00:51 -0500 +Subject: [PATCH] target-i386/cpu: Add new EPYC CPU model + +Add a new base CPU model called 'EPYC' to model processors from AMD EPYC +family (which includes EPYC 76xx,75xx,74xx, 73xx and 72xx). + +The following features bits have been added/removed compare to Opteron_G5 + +Added: monitor, movbe, rdrand, mmxext, ffxsr, rdtscp, cr8legacy, osvw, + fsgsbase, bmi1, avx2, smep, bmi2, rdseed, adx, smap, clfshopt, sha + xsaveopt, xsavec, xgetbv1, arat + +Removed: xop, fma4, tbm + +Cc: Paolo Bonzini +Cc: Richard Henderson +Cc: Eduardo Habkost +Cc: Tom Lendacky +Signed-off-by: Brijesh Singh +Message-Id: <20170815170051.127257-1-brijesh.singh@amd.com> +Reviewed-by: Eduardo Habkost +Signed-off-by: Eduardo Habkost +--- + target/i386/cpu.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 44 insertions(+) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index e4a2d5a012..e977c6c616 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -1923,6 +1923,50 @@ static X86CPUDefinition builtin_x86_defs[] = { + .xlevel = 0x8000001A, + .model_id = "AMD Opteron 63xx class CPU", + }, ++ { ++ .name = "EPYC", ++ .level = 0xd, ++ .vendor = CPUID_VENDOR_AMD, ++ .family = 23, ++ .model = 1, ++ .stepping = 2, ++ .features[FEAT_1_EDX] = ++ CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX | CPUID_CLFLUSH | ++ CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA | CPUID_PGE | ++ CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 | CPUID_MCE | ++ CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE | CPUID_DE | ++ CPUID_VME | CPUID_FP87, ++ .features[FEAT_1_ECX] = ++ CPUID_EXT_RDRAND | CPUID_EXT_F16C | CPUID_EXT_AVX | ++ CPUID_EXT_XSAVE | CPUID_EXT_AES | CPUID_EXT_POPCNT | ++ CPUID_EXT_MOVBE | CPUID_EXT_SSE42 | CPUID_EXT_SSE41 | ++ CPUID_EXT_CX16 | CPUID_EXT_FMA | CPUID_EXT_SSSE3 | ++ CPUID_EXT_MONITOR | CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3, ++ .features[FEAT_8000_0001_EDX] = ++ CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_PDPE1GB | ++ CPUID_EXT2_FFXSR | CPUID_EXT2_MMXEXT | CPUID_EXT2_NX | ++ CPUID_EXT2_SYSCALL, ++ .features[FEAT_8000_0001_ECX] = ++ CPUID_EXT3_OSVW | CPUID_EXT3_3DNOWPREFETCH | ++ CPUID_EXT3_MISALIGNSSE | CPUID_EXT3_SSE4A | CPUID_EXT3_ABM | ++ CPUID_EXT3_CR8LEG | CPUID_EXT3_SVM | CPUID_EXT3_LAHF_LM, ++ .features[FEAT_7_0_EBX] = ++ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_AVX2 | ++ CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_RDSEED | ++ CPUID_7_0_EBX_ADX | CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_CLFLUSHOPT | ++ CPUID_7_0_EBX_SHA_NI, ++ /* Missing: XSAVES (not supported by some Linux versions, ++ * including v4.1 to v4.12). ++ * KVM doesn't yet expose any XSAVES state save component. ++ */ ++ .features[FEAT_XSAVE] = ++ CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC | ++ CPUID_XSAVE_XGETBV1, ++ .features[FEAT_6_EAX] = ++ CPUID_6_EAX_ARAT, ++ .xlevel = 0x8000000A, ++ .model_id = "AMD EPYC Processor", ++ }, + }; + + typedef struct PropValue { +-- +2.11.0 + diff --git a/debian/patches/extra/0049-i386-Add-EPYC-IBPB-CPU-model.patch b/debian/patches/extra/0049-i386-Add-EPYC-IBPB-CPU-model.patch new file mode 100644 index 0000000..665aefe --- /dev/null +++ b/debian/patches/extra/0049-i386-Add-EPYC-IBPB-CPU-model.patch @@ -0,0 +1,78 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Eduardo Habkost +Date: Tue, 9 Jan 2018 13:45:18 -0200 +Subject: [PATCH] i386: Add EPYC-IBPB CPU model + +EPYC-IBPB is a copy of the EPYC CPU model with +just CPUID_8000_0008_EBX_IBPB added. + +Cc: Jiri Denemark +Cc: Tom Lendacky +Cc: Brijesh Singh +Signed-off-by: Eduardo Habkost +Message-Id: <20180109154519.25634-7-ehabkost@redhat.com> +Signed-off-by: Eduardo Habkost +--- + target/i386/cpu.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 46 insertions(+) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index e977c6c616..95e6a1f122 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -1967,6 +1967,52 @@ static X86CPUDefinition builtin_x86_defs[] = { + .xlevel = 0x8000000A, + .model_id = "AMD EPYC Processor", + }, ++ { ++ .name = "EPYC-IBPB", ++ .level = 0xd, ++ .vendor = CPUID_VENDOR_AMD, ++ .family = 23, ++ .model = 1, ++ .stepping = 2, ++ .features[FEAT_1_EDX] = ++ CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX | CPUID_CLFLUSH | ++ CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA | CPUID_PGE | ++ CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 | CPUID_MCE | ++ CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE | CPUID_DE | ++ CPUID_VME | CPUID_FP87, ++ .features[FEAT_1_ECX] = ++ CPUID_EXT_RDRAND | CPUID_EXT_F16C | CPUID_EXT_AVX | ++ CPUID_EXT_XSAVE | CPUID_EXT_AES | CPUID_EXT_POPCNT | ++ CPUID_EXT_MOVBE | CPUID_EXT_SSE42 | CPUID_EXT_SSE41 | ++ CPUID_EXT_CX16 | CPUID_EXT_FMA | CPUID_EXT_SSSE3 | ++ CPUID_EXT_MONITOR | CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3, ++ .features[FEAT_8000_0001_EDX] = ++ CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_PDPE1GB | ++ CPUID_EXT2_FFXSR | CPUID_EXT2_MMXEXT | CPUID_EXT2_NX | ++ CPUID_EXT2_SYSCALL, ++ .features[FEAT_8000_0001_ECX] = ++ CPUID_EXT3_OSVW | CPUID_EXT3_3DNOWPREFETCH | ++ CPUID_EXT3_MISALIGNSSE | CPUID_EXT3_SSE4A | CPUID_EXT3_ABM | ++ CPUID_EXT3_CR8LEG | CPUID_EXT3_SVM | CPUID_EXT3_LAHF_LM, ++ .features[FEAT_8000_0008_EBX] = ++ CPUID_8000_0008_EBX_IBPB, ++ .features[FEAT_7_0_EBX] = ++ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_AVX2 | ++ CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_RDSEED | ++ CPUID_7_0_EBX_ADX | CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_CLFLUSHOPT | ++ CPUID_7_0_EBX_SHA_NI, ++ /* Missing: XSAVES (not supported by some Linux versions, ++ * including v4.1 to v4.12). ++ * KVM doesn't yet expose any XSAVES state save component. ++ */ ++ .features[FEAT_XSAVE] = ++ CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC | ++ CPUID_XSAVE_XGETBV1, ++ .features[FEAT_6_EAX] = ++ CPUID_6_EAX_ARAT, ++ .xlevel = 0x8000000A, ++ .model_id = "AMD EPYC Processor (with IBPB)", ++ }, + }; + + typedef struct PropValue { +-- +2.11.0 + diff --git a/debian/patches/series b/debian/patches/series index eb0e7d5..c49ca96 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -63,15 +63,17 @@ extra/0032-i386-Add-spec-ctrl-CPUID-bit.patch extra/0033-i386-Add-FEAT_8000_0008_EBX-CPUID-feature-word.patch extra/0034-i386-Add-new-IBRS-versions-of-Intel-CPU-models.patch extra/0035-ratelimit-don-t-align-wait-time-with-slices.patch -extra/0036-kvm-nbd-make-it-thread-safe-fix-qcow2-over-nbd.patch -extra/0037-kvm-nbd-strict-nbd_wr_syncv.patch -extra/0038-kvm-nbd-read_sync-and-friends-return-0-on-success.patch -extra/0039-kvm-nbd-make-nbd_drop-public.patch -extra/0040-kvm-nbd-server-get-rid-of-nbd_negotiate_read-and-friends.patch -extra/0041-kvm-nbd-client-Fix-regression-when-server-sends-garbage.patch -extra/0042-kvm-fix-build-failure-in-nbd_read_reply_entry.patch -extra/0043-kvm-nbd-client-avoid-spurious-qio_channel_yield-re-entry.patch -extra/0044-kvm-nbd-client-avoid-read_reply_co-entry-if-send-failed.patch -extra/0045-kvm-qemu-iotests-improve-nbd-fault-injector.py-startup-p.patch -extra/0046-kvm-qemu-iotests-test-NBD-over-UNIX-domain-sockets-in-08.patch -extra/0047-kvm-block-nbd-client-nbd_co_send_request-fix-return-code.patch +extra/0036-nbd-make-it-thread-safe-fix-qcow2-over-nbd.patch +extra/0037-nbd-strict-nbd_wr_syncv.patch +extra/0038-nbd-read_sync-and-friends-return-0-on-success.patch +extra/0039-nbd-make-nbd_drop-public.patch +extra/0040-nbd-server-get-rid-of-nbd_negotiate_read-and-friends.patch +extra/0041-nbd-client-Fix-regression-when-server-sends-garbage.patch +extra/0042-fix-build-failure-in-nbd_read_reply_entry.patch +extra/0043-nbd-client-avoid-spurious-qio_channel_yield-re-entry.patch +extra/0044-nbd-client-avoid-read_reply_co-entry-if-send-failed.patch +extra/0045-qemu-iotests-improve-nbd-fault-injector.py-startup-p.patch +extra/0046-qemu-iotests-test-NBD-over-UNIX-domain-sockets-in-08.patch +extra/0047-block-nbd-client-nbd_co_send_request-fix-return-code.patch +extra/0048-target-i386-cpu-Add-new-EPYC-CPU-model.patch +extra/0049-i386-Add-EPYC-IBPB-CPU-model.patch