1 | The following changes since commit ec11dc41eec5142b4776db1296972c6323ba5847: | 1 | The following changes since commit 48804eebd4a327e4b11f902ba80a00876ee53a43: |
---|---|---|---|
2 | 2 | ||
3 | Merge tag 'pull-misc-2022-05-11' of git://repo.or.cz/qemu/armbru into staging (2022-05-11 09:00:26 -0700) | 3 | Merge tag 'pull-misc-2022-12-14' of https://repo.or.cz/qemu/armbru into staging (2022-12-15 10:13:46 +0000) |
4 | 4 | ||
5 | are available in the Git repository at: | 5 | are available in the Git repository at: |
6 | 6 | ||
7 | git://repo.or.cz/qemu/kevin.git tags/for-upstream | 7 | https://repo.or.cz/qemu/kevin.git tags/for-upstream |
8 | 8 | ||
9 | for you to fetch changes up to f70625299ecc9ba577c87f3d1d75012c747c7d88: | 9 | for you to fetch changes up to 1b3ff9feb942c2ad0b01ac931e99ad451ab0ef39: |
10 | 10 | ||
11 | qemu-iotests: inline common.config into common.rc (2022-05-12 15:42:49 +0200) | 11 | block: GRAPH_RDLOCK for functions only called by co_wrappers (2022-12-15 16:08:23 +0100) |
12 | |||
13 | v3: | ||
14 | - Dropped "configure: Enable -Wthread-safety if present" because FreeBSD | ||
15 | has TSA annotations in its pthread locking functions, so we would have | ||
16 | to annotate the use of every lock in QEMU first before we can enable | ||
17 | it. | ||
18 | |||
19 | v2: | ||
20 | - Changed TSA capability name to "mutex" to work with older clang | ||
21 | versions. The tsan-build CI job succeeds now. | ||
12 | 22 | ||
13 | ---------------------------------------------------------------- | 23 | ---------------------------------------------------------------- |
14 | Block layer patches | 24 | Block layer patches |
15 | 25 | ||
16 | - coroutine: Fix crashes due to too large pool batch size | 26 | - Code cleanups around block graph modification |
17 | - fdc: Prevent end-of-track overrun | 27 | - Simplify drain |
18 | - nbd: MULTI_CONN for shared writable exports | 28 | - coroutine_fn correctness fixes, including splitting generated |
19 | - iotests test runner improvements | 29 | coroutine wrappers into co_wrapper (to be called only from |
30 | non-coroutine context) and co_wrapper_mixed (both coroutine and | ||
31 | non-coroutine context) | ||
32 | - Introduce a block graph rwlock | ||
20 | 33 | ||
21 | ---------------------------------------------------------------- | 34 | ---------------------------------------------------------------- |
22 | Daniel P. Berrangé (2): | 35 | Emanuele Giuseppe Esposito (21): |
23 | tests/qemu-iotests: print intent to run a test in TAP mode | 36 | block-io: introduce coroutine_fn duplicates for bdrv_common_block_status_above callers |
24 | .gitlab-ci.d: export meson testlog.txt as an artifact | 37 | block-copy: add coroutine_fn annotations |
38 | nbd/server.c: add coroutine_fn annotations | ||
39 | block-backend: replace bdrv_*_above with blk_*_above | ||
40 | block/vmdk: add coroutine_fn annotations | ||
41 | block: avoid duplicating filename string in bdrv_create | ||
42 | block: distinguish between bdrv_create running in coroutine and not | ||
43 | block: bdrv_create_file is a coroutine_fn | ||
44 | block: rename generated_co_wrapper in co_wrapper_mixed | ||
45 | block-coroutine-wrapper.py: introduce co_wrapper | ||
46 | block-coroutine-wrapper.py: support functions without bs arg | ||
47 | block-coroutine-wrapper.py: support also basic return types | ||
48 | block: convert bdrv_create to co_wrapper | ||
49 | block/dirty-bitmap: convert coroutine-only functions to co_wrapper | ||
50 | graph-lock: Implement guard macros | ||
51 | async: Register/unregister aiocontext in graph lock list | ||
52 | block: wrlock in bdrv_replace_child_noperm | ||
53 | block: remove unnecessary assert_bdrv_graph_writable() | ||
54 | block: assert that graph read and writes are performed correctly | ||
55 | block-coroutine-wrapper.py: introduce annotations that take the graph rdlock | ||
56 | block: use co_wrapper_mixed_bdrv_rdlock in functions taking the rdlock | ||
25 | 57 | ||
26 | Eric Blake (2): | 58 | Kevin Wolf (24): |
27 | qemu-nbd: Pass max connections to blockdev layer | 59 | qed: Don't yield in bdrv_qed_co_drain_begin() |
28 | nbd/server: Allow MULTI_CONN for shared writable exports | 60 | test-bdrv-drain: Don't yield in .bdrv_co_drained_begin/end() |
29 | 61 | block: Revert .bdrv_drained_begin/end to non-coroutine_fn | |
30 | Hanna Reitz (1): | 62 | block: Remove drained_end_counter |
31 | iotests/testrunner: Flush after run_test() | 63 | block: Inline bdrv_drain_invoke() |
32 | 64 | block: Fix locking for bdrv_reopen_queue_child() | |
33 | Kevin Wolf (2): | 65 | block: Drain individual nodes during reopen |
34 | coroutine: Rename qemu_coroutine_inc/dec_pool_size() | 66 | block: Don't use subtree drains in bdrv_drop_intermediate() |
35 | coroutine: Revert to constant batch size | 67 | stream: Replace subtree drain with a single node drain |
68 | block: Remove subtree drains | ||
69 | block: Call drain callbacks only once | ||
70 | block: Remove ignore_bds_parents parameter from drain_begin/end. | ||
71 | block: Drop out of coroutine in bdrv_do_drained_begin_quiesce() | ||
72 | block: Don't poll in bdrv_replace_child_noperm() | ||
73 | block: Remove poll parameter from bdrv_parent_drained_begin_single() | ||
74 | block: Factor out bdrv_drain_all_begin_nopoll() | ||
75 | Import clang-tsa.h | ||
76 | clang-tsa: Add TSA_ASSERT() macro | ||
77 | clang-tsa: Add macros for shared locks | ||
78 | test-bdrv-drain: Fix incorrrect drain assumptions | ||
79 | block: Fix locking in external_snapshot_prepare() | ||
80 | graph-lock: TSA annotations for lock/unlock functions | ||
81 | Mark assert_bdrv_graph_readable/writable() GRAPH_RD/WRLOCK | ||
82 | block: GRAPH_RDLOCK for functions only called by co_wrappers | ||
36 | 83 | ||
37 | Paolo Bonzini (1): | 84 | Paolo Bonzini (1): |
38 | qemu-iotests: inline common.config into common.rc | 85 | graph-lock: Introduce a lock to protect block graph operations |
39 | 86 | ||
40 | Philippe Mathieu-Daudé (2): | 87 | Vladimir Sementsov-Ogievskiy (4): |
41 | hw/block/fdc: Prevent end-of-track overrun (CVE-2021-3507) | 88 | block: Inline bdrv_detach_child() |
42 | tests/qtest/fdc-test: Add a regression test for CVE-2021-3507 | 89 | block: drop bdrv_remove_filter_or_cow_child |
90 | block: bdrv_refresh_perms(): allow external tran | ||
91 | block: refactor bdrv_list_refresh_perms to allow any list of nodes | ||
43 | 92 | ||
44 | qapi/block-export.json | 8 +- | 93 | docs/devel/block-coroutine-wrapper.rst | 6 +- |
45 | docs/interop/nbd.txt | 1 + | 94 | block/block-gen.h | 11 +- |
46 | docs/tools/qemu-nbd.rst | 3 +- | 95 | block/coroutines.h | 21 +- |
47 | include/block/nbd.h | 5 +- | 96 | include/block/aio.h | 9 + |
48 | include/qemu/coroutine.h | 6 +- | 97 | include/block/block-common.h | 27 ++- |
49 | blockdev-nbd.c | 13 +- | 98 | include/block/block-copy.h | 5 +- |
50 | hw/block/fdc.c | 8 ++ | 99 | include/block/block-global-state.h | 15 +- |
51 | hw/block/virtio-blk.c | 6 +- | 100 | include/block/block-io.h | 136 +++++------ |
52 | nbd/server.c | 10 +- | 101 | include/block/block_int-common.h | 49 ++-- |
53 | qemu-nbd.c | 2 +- | 102 | include/block/block_int-global-state.h | 17 -- |
54 | tests/qtest/fdc-test.c | 21 ++++ | 103 | include/block/block_int-io.h | 12 - |
55 | util/qemu-coroutine.c | 26 ++-- | 104 | include/block/block_int.h | 1 + |
56 | tests/qemu-iotests/testrunner.py | 4 + | 105 | include/block/dirty-bitmap.h | 10 +- |
57 | .gitlab-ci.d/buildtest-template.yml | 12 +- | 106 | include/block/graph-lock.h | 280 +++++++++++++++++++++++ |
58 | MAINTAINERS | 1 + | 107 | include/qemu/clang-tsa.h | 114 ++++++++++ |
59 | tests/qemu-iotests/common.config | 41 ------- | 108 | include/sysemu/block-backend-io.h | 77 ++++--- |
60 | tests/qemu-iotests/common.rc | 31 +++-- | 109 | block.c | 404 ++++++++++++++++++--------------- |
61 | tests/qemu-iotests/tests/nbd-multiconn | 145 +++++++++++++++++++++++ | 110 | block/block-backend.c | 25 +- |
62 | tests/qemu-iotests/tests/nbd-multiconn.out | 5 + | 111 | block/block-copy.c | 21 +- |
63 | tests/qemu-iotests/tests/nbd-qemu-allocation.out | 2 +- | 112 | block/commit.c | 4 +- |
64 | 20 files changed, 261 insertions(+), 89 deletions(-) | 113 | block/crypto.c | 2 +- |
65 | delete mode 100644 tests/qemu-iotests/common.config | 114 | block/dirty-bitmap.c | 88 +------ |
66 | create mode 100755 tests/qemu-iotests/tests/nbd-multiconn | 115 | block/graph-lock.c | 275 ++++++++++++++++++++++ |
67 | create mode 100644 tests/qemu-iotests/tests/nbd-multiconn.out | 116 | block/io.c | 367 ++++++++++-------------------- |
68 | 117 | block/parallels.c | 2 +- | |
69 | 118 | block/qcow.c | 2 +- | |
119 | block/qcow2.c | 4 +- | ||
120 | block/qed.c | 28 ++- | ||
121 | block/raw-format.c | 2 +- | ||
122 | block/replication.c | 6 - | ||
123 | block/stream.c | 26 ++- | ||
124 | block/throttle.c | 8 +- | ||
125 | block/vdi.c | 2 +- | ||
126 | block/vhdx.c | 2 +- | ||
127 | block/vmdk.c | 38 ++-- | ||
128 | block/vpc.c | 2 +- | ||
129 | blockdev.c | 17 +- | ||
130 | blockjob.c | 2 +- | ||
131 | nbd/server.c | 47 ++-- | ||
132 | stubs/graph-lock.c | 10 + | ||
133 | tests/unit/test-bdrv-drain.c | 387 +++++++++---------------------- | ||
134 | util/async.c | 4 + | ||
135 | scripts/block-coroutine-wrapper.py | 133 ++++++++--- | ||
136 | block/meson.build | 2 + | ||
137 | stubs/meson.build | 1 + | ||
138 | 45 files changed, 1574 insertions(+), 1127 deletions(-) | ||
139 | create mode 100644 include/block/graph-lock.h | ||
140 | create mode 100644 include/qemu/clang-tsa.h | ||
141 | create mode 100644 block/graph-lock.c | ||
142 | create mode 100644 stubs/graph-lock.c | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | It's true that these functions currently affect the batch size in which | ||
2 | coroutines are reused (i.e. moved from the global release pool to the | ||
3 | allocation pool of a specific thread), but this is a bug and will be | ||
4 | fixed in a separate patch. | ||
5 | 1 | ||
6 | In fact, the comment in the header file already just promises that it | ||
7 | influences the pool size, so reflect this in the name of the functions. | ||
8 | As a nice side effect, the shorter function name makes some line | ||
9 | wrapping unnecessary. | ||
10 | |||
11 | Cc: qemu-stable@nongnu.org | ||
12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
13 | Message-Id: <20220510151020.105528-2-kwolf@redhat.com> | ||
14 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
15 | --- | ||
16 | include/qemu/coroutine.h | 6 +++--- | ||
17 | hw/block/virtio-blk.c | 6 ++---- | ||
18 | util/qemu-coroutine.c | 4 ++-- | ||
19 | 3 files changed, 7 insertions(+), 9 deletions(-) | ||
20 | |||
21 | diff --git a/include/qemu/coroutine.h b/include/qemu/coroutine.h | ||
22 | index XXXXXXX..XXXXXXX 100644 | ||
23 | --- a/include/qemu/coroutine.h | ||
24 | +++ b/include/qemu/coroutine.h | ||
25 | @@ -XXX,XX +XXX,XX @@ void coroutine_fn yield_until_fd_readable(int fd); | ||
26 | /** | ||
27 | * Increase coroutine pool size | ||
28 | */ | ||
29 | -void qemu_coroutine_increase_pool_batch_size(unsigned int additional_pool_size); | ||
30 | +void qemu_coroutine_inc_pool_size(unsigned int additional_pool_size); | ||
31 | |||
32 | /** | ||
33 | - * Devcrease coroutine pool size | ||
34 | + * Decrease coroutine pool size | ||
35 | */ | ||
36 | -void qemu_coroutine_decrease_pool_batch_size(unsigned int additional_pool_size); | ||
37 | +void qemu_coroutine_dec_pool_size(unsigned int additional_pool_size); | ||
38 | |||
39 | #include "qemu/lockable.h" | ||
40 | |||
41 | diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c | ||
42 | index XXXXXXX..XXXXXXX 100644 | ||
43 | --- a/hw/block/virtio-blk.c | ||
44 | +++ b/hw/block/virtio-blk.c | ||
45 | @@ -XXX,XX +XXX,XX @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp) | ||
46 | for (i = 0; i < conf->num_queues; i++) { | ||
47 | virtio_add_queue(vdev, conf->queue_size, virtio_blk_handle_output); | ||
48 | } | ||
49 | - qemu_coroutine_increase_pool_batch_size(conf->num_queues * conf->queue_size | ||
50 | - / 2); | ||
51 | + qemu_coroutine_inc_pool_size(conf->num_queues * conf->queue_size / 2); | ||
52 | virtio_blk_data_plane_create(vdev, conf, &s->dataplane, &err); | ||
53 | if (err != NULL) { | ||
54 | error_propagate(errp, err); | ||
55 | @@ -XXX,XX +XXX,XX @@ static void virtio_blk_device_unrealize(DeviceState *dev) | ||
56 | for (i = 0; i < conf->num_queues; i++) { | ||
57 | virtio_del_queue(vdev, i); | ||
58 | } | ||
59 | - qemu_coroutine_decrease_pool_batch_size(conf->num_queues * conf->queue_size | ||
60 | - / 2); | ||
61 | + qemu_coroutine_dec_pool_size(conf->num_queues * conf->queue_size / 2); | ||
62 | qemu_del_vm_change_state_handler(s->change); | ||
63 | blockdev_mark_auto_del(s->blk); | ||
64 | virtio_cleanup(vdev); | ||
65 | diff --git a/util/qemu-coroutine.c b/util/qemu-coroutine.c | ||
66 | index XXXXXXX..XXXXXXX 100644 | ||
67 | --- a/util/qemu-coroutine.c | ||
68 | +++ b/util/qemu-coroutine.c | ||
69 | @@ -XXX,XX +XXX,XX @@ AioContext *coroutine_fn qemu_coroutine_get_aio_context(Coroutine *co) | ||
70 | return co->ctx; | ||
71 | } | ||
72 | |||
73 | -void qemu_coroutine_increase_pool_batch_size(unsigned int additional_pool_size) | ||
74 | +void qemu_coroutine_inc_pool_size(unsigned int additional_pool_size) | ||
75 | { | ||
76 | qatomic_add(&pool_batch_size, additional_pool_size); | ||
77 | } | ||
78 | |||
79 | -void qemu_coroutine_decrease_pool_batch_size(unsigned int removing_pool_size) | ||
80 | +void qemu_coroutine_dec_pool_size(unsigned int removing_pool_size) | ||
81 | { | ||
82 | qatomic_sub(&pool_batch_size, removing_pool_size); | ||
83 | } | ||
84 | -- | ||
85 | 2.35.3 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | Commit 4c41c69e changed the way the coroutine pool is sized because for | ||
2 | virtio-blk devices with a large queue size and heavy I/O, it was just | ||
3 | too small and caused coroutines to be deleted and reallocated soon | ||
4 | afterwards. The change made the size dynamic based on the number of | ||
5 | queues and the queue size of virtio-blk devices. | ||
6 | 1 | ||
7 | There are two important numbers here: Slightly simplified, when a | ||
8 | coroutine terminates, it is generally stored in the global release pool | ||
9 | up to a certain pool size, and if the pool is full, it is freed. | ||
10 | Conversely, when allocating a new coroutine, the coroutines in the | ||
11 | release pool are reused if the pool already has reached a certain | ||
12 | minimum size (the batch size), otherwise we allocate new coroutines. | ||
13 | |||
14 | The problem after commit 4c41c69e is that it not only increases the | ||
15 | maximum pool size (which is the intended effect), but also the batch | ||
16 | size for reusing coroutines (which is a bug). It means that in cases | ||
17 | with many devices and/or a large queue size (which defaults to the | ||
18 | number of vcpus for virtio-blk-pci), many thousand coroutines could be | ||
19 | sitting in the release pool without being reused. | ||
20 | |||
21 | This is not only a waste of memory and allocations, but it actually | ||
22 | makes the QEMU process likely to hit the vm.max_map_count limit on Linux | ||
23 | because each coroutine requires two mappings (its stack and the guard | ||
24 | page for the stack), causing it to abort() in qemu_alloc_stack() because | ||
25 | when the limit is hit, mprotect() starts to fail with ENOMEM. | ||
26 | |||
27 | In order to fix the problem, change the batch size back to 64 to avoid | ||
28 | uselessly accumulating coroutines in the release pool, but keep the | ||
29 | dynamic maximum pool size so that coroutines aren't freed too early | ||
30 | in heavy I/O scenarios. | ||
31 | |||
32 | Note that this fix doesn't strictly make it impossible to hit the limit, | ||
33 | but this would only happen if most of the coroutines are actually in use | ||
34 | at the same time, not just sitting in a pool. This is the same behaviour | ||
35 | as we already had before commit 4c41c69e. Fully preventing this would | ||
36 | require allowing qemu_coroutine_create() to return an error, but it | ||
37 | doesn't seem to be a scenario that people hit in practice. | ||
38 | |||
39 | Cc: qemu-stable@nongnu.org | ||
40 | Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2079938 | ||
41 | Fixes: 4c41c69e05fe28c0f95f8abd2ebf407e95a4f04b | ||
42 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
43 | Message-Id: <20220510151020.105528-3-kwolf@redhat.com> | ||
44 | Tested-by: Hiroki Narukawa <hnarukaw@yahoo-corp.jp> | ||
45 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
46 | --- | ||
47 | util/qemu-coroutine.c | 22 ++++++++++++++-------- | ||
48 | 1 file changed, 14 insertions(+), 8 deletions(-) | ||
49 | |||
50 | diff --git a/util/qemu-coroutine.c b/util/qemu-coroutine.c | ||
51 | index XXXXXXX..XXXXXXX 100644 | ||
52 | --- a/util/qemu-coroutine.c | ||
53 | +++ b/util/qemu-coroutine.c | ||
54 | @@ -XXX,XX +XXX,XX @@ | ||
55 | #include "qemu/coroutine-tls.h" | ||
56 | #include "block/aio.h" | ||
57 | |||
58 | -/** Initial batch size is 64, and is increased on demand */ | ||
59 | +/** | ||
60 | + * The minimal batch size is always 64, coroutines from the release_pool are | ||
61 | + * reused as soon as there are 64 coroutines in it. The maximum pool size starts | ||
62 | + * with 64 and is increased on demand so that coroutines are not deleted even if | ||
63 | + * they are not immediately reused. | ||
64 | + */ | ||
65 | enum { | ||
66 | - POOL_INITIAL_BATCH_SIZE = 64, | ||
67 | + POOL_MIN_BATCH_SIZE = 64, | ||
68 | + POOL_INITIAL_MAX_SIZE = 64, | ||
69 | }; | ||
70 | |||
71 | /** Free list to speed up creation */ | ||
72 | static QSLIST_HEAD(, Coroutine) release_pool = QSLIST_HEAD_INITIALIZER(pool); | ||
73 | -static unsigned int pool_batch_size = POOL_INITIAL_BATCH_SIZE; | ||
74 | +static unsigned int pool_max_size = POOL_INITIAL_MAX_SIZE; | ||
75 | static unsigned int release_pool_size; | ||
76 | |||
77 | typedef QSLIST_HEAD(, Coroutine) CoroutineQSList; | ||
78 | @@ -XXX,XX +XXX,XX @@ Coroutine *qemu_coroutine_create(CoroutineEntry *entry, void *opaque) | ||
79 | |||
80 | co = QSLIST_FIRST(alloc_pool); | ||
81 | if (!co) { | ||
82 | - if (release_pool_size > qatomic_read(&pool_batch_size)) { | ||
83 | + if (release_pool_size > POOL_MIN_BATCH_SIZE) { | ||
84 | /* Slow path; a good place to register the destructor, too. */ | ||
85 | Notifier *notifier = get_ptr_coroutine_pool_cleanup_notifier(); | ||
86 | if (!notifier->notify) { | ||
87 | @@ -XXX,XX +XXX,XX @@ static void coroutine_delete(Coroutine *co) | ||
88 | co->caller = NULL; | ||
89 | |||
90 | if (CONFIG_COROUTINE_POOL) { | ||
91 | - if (release_pool_size < qatomic_read(&pool_batch_size) * 2) { | ||
92 | + if (release_pool_size < qatomic_read(&pool_max_size) * 2) { | ||
93 | QSLIST_INSERT_HEAD_ATOMIC(&release_pool, co, pool_next); | ||
94 | qatomic_inc(&release_pool_size); | ||
95 | return; | ||
96 | } | ||
97 | - if (get_alloc_pool_size() < qatomic_read(&pool_batch_size)) { | ||
98 | + if (get_alloc_pool_size() < qatomic_read(&pool_max_size)) { | ||
99 | QSLIST_INSERT_HEAD(get_ptr_alloc_pool(), co, pool_next); | ||
100 | set_alloc_pool_size(get_alloc_pool_size() + 1); | ||
101 | return; | ||
102 | @@ -XXX,XX +XXX,XX @@ AioContext *coroutine_fn qemu_coroutine_get_aio_context(Coroutine *co) | ||
103 | |||
104 | void qemu_coroutine_inc_pool_size(unsigned int additional_pool_size) | ||
105 | { | ||
106 | - qatomic_add(&pool_batch_size, additional_pool_size); | ||
107 | + qatomic_add(&pool_max_size, additional_pool_size); | ||
108 | } | ||
109 | |||
110 | void qemu_coroutine_dec_pool_size(unsigned int removing_pool_size) | ||
111 | { | ||
112 | - qatomic_sub(&pool_batch_size, removing_pool_size); | ||
113 | + qatomic_sub(&pool_max_size, removing_pool_size); | ||
114 | } | ||
115 | -- | ||
116 | 2.35.3 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Hanna Reitz <hreitz@redhat.com> | ||
2 | 1 | ||
3 | When stdout is not a terminal, the buffer may not be flushed at each end | ||
4 | of line, so we should flush after each test is done. This is especially | ||
5 | apparent when run by check-block, in two ways: | ||
6 | |||
7 | First, when running make check-block -jX with X > 1, progress indication | ||
8 | was missing, even though testrunner.py does theoretically print each | ||
9 | test's status once it has been run, even in multi-processing mode. | ||
10 | Flushing after each test restores this progress indication. | ||
11 | |||
12 | Second, sometimes make check-block failed altogether, with an error | ||
13 | message that "too few tests [were] run". I presume that's because one | ||
14 | worker process in the job pool did not get to flush its stdout before | ||
15 | the main process exited, and so meson did not get to see that worker's | ||
16 | test results. In any case, by flushing at the end of run_test(), the | ||
17 | problem has disappeared for me. | ||
18 | |||
19 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
20 | Message-Id: <20220506134215.10086-1-hreitz@redhat.com> | ||
21 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
22 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
23 | --- | ||
24 | tests/qemu-iotests/testrunner.py | 1 + | ||
25 | 1 file changed, 1 insertion(+) | ||
26 | |||
27 | diff --git a/tests/qemu-iotests/testrunner.py b/tests/qemu-iotests/testrunner.py | ||
28 | index XXXXXXX..XXXXXXX 100644 | ||
29 | --- a/tests/qemu-iotests/testrunner.py | ||
30 | +++ b/tests/qemu-iotests/testrunner.py | ||
31 | @@ -XXX,XX +XXX,XX @@ def run_test(self, test: str, | ||
32 | else: | ||
33 | print(res.casenotrun) | ||
34 | |||
35 | + sys.stdout.flush() | ||
36 | return res | ||
37 | |||
38 | def run_tests(self, tests: List[str], jobs: int = 1) -> bool: | ||
39 | -- | ||
40 | 2.35.3 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Daniel P. Berrangé <berrange@redhat.com> | ||
2 | 1 | ||
3 | When running I/O tests using TAP output mode, we get a single TAP test | ||
4 | with a sub-test reported for each I/O test that is run. The output looks | ||
5 | something like this: | ||
6 | |||
7 | 1..123 | ||
8 | ok qcow2 011 | ||
9 | ok qcow2 012 | ||
10 | ok qcow2 013 | ||
11 | ok qcow2 217 | ||
12 | ... | ||
13 | |||
14 | If everything runs or fails normally this is fine, but periodically we | ||
15 | have been seeing the test harness abort early before all 123 tests have | ||
16 | been run, just leaving a fairly useless message like | ||
17 | |||
18 | TAP parsing error: Too few tests run (expected 123, got 107) | ||
19 | |||
20 | we have no idea which tests were running at the time the test harness | ||
21 | abruptly exited. This change causes us to print a message about our | ||
22 | intent to run each test, so we have a record of what is active at the | ||
23 | time the harness exits abnormally. | ||
24 | |||
25 | 1..123 | ||
26 | # running qcow2 011 | ||
27 | ok qcow2 011 | ||
28 | # running qcow2 012 | ||
29 | ok qcow2 012 | ||
30 | # running qcow2 013 | ||
31 | ok qcow2 013 | ||
32 | # running qcow2 217 | ||
33 | ok qcow2 217 | ||
34 | ... | ||
35 | |||
36 | Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> | ||
37 | Message-Id: <20220509124134.867431-2-berrange@redhat.com> | ||
38 | Reviewed-by: Thomas Huth <thuth@redhat.com> | ||
39 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
40 | --- | ||
41 | tests/qemu-iotests/testrunner.py | 3 +++ | ||
42 | 1 file changed, 3 insertions(+) | ||
43 | |||
44 | diff --git a/tests/qemu-iotests/testrunner.py b/tests/qemu-iotests/testrunner.py | ||
45 | index XXXXXXX..XXXXXXX 100644 | ||
46 | --- a/tests/qemu-iotests/testrunner.py | ||
47 | +++ b/tests/qemu-iotests/testrunner.py | ||
48 | @@ -XXX,XX +XXX,XX @@ def run_test(self, test: str, | ||
49 | starttime=start, | ||
50 | lasttime=last_el, | ||
51 | end = '\n' if mp else '\r') | ||
52 | + else: | ||
53 | + testname = os.path.basename(test) | ||
54 | + print(f'# running {self.env.imgfmt} {testname}') | ||
55 | |||
56 | res = self.do_run_test(test, mp) | ||
57 | |||
58 | -- | ||
59 | 2.35.3 | ||
60 | |||
61 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Daniel P. Berrangé <berrange@redhat.com> | ||
2 | 1 | ||
3 | When running 'make check' we only get a summary of progress on the | ||
4 | console. Fortunately meson/ninja have saved the raw test output to a | ||
5 | logfile. Exposing this log will make it easier to debug failures that | ||
6 | happen in CI. | ||
7 | |||
8 | Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> | ||
9 | Message-Id: <20220509124134.867431-3-berrange@redhat.com> | ||
10 | Reviewed-by: Thomas Huth <thuth@redhat.com> | ||
11 | Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org> | ||
12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
13 | --- | ||
14 | .gitlab-ci.d/buildtest-template.yml | 12 ++++++++++-- | ||
15 | 1 file changed, 10 insertions(+), 2 deletions(-) | ||
16 | |||
17 | diff --git a/.gitlab-ci.d/buildtest-template.yml b/.gitlab-ci.d/buildtest-template.yml | ||
18 | index XXXXXXX..XXXXXXX 100644 | ||
19 | --- a/.gitlab-ci.d/buildtest-template.yml | ||
20 | +++ b/.gitlab-ci.d/buildtest-template.yml | ||
21 | @@ -XXX,XX +XXX,XX @@ | ||
22 | make -j"$JOBS" $MAKE_CHECK_ARGS ; | ||
23 | fi | ||
24 | |||
25 | -.native_test_job_template: | ||
26 | +.common_test_job_template: | ||
27 | stage: test | ||
28 | image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:latest | ||
29 | script: | ||
30 | @@ -XXX,XX +XXX,XX @@ | ||
31 | # Avoid recompiling by hiding ninja with NINJA=":" | ||
32 | - make NINJA=":" $MAKE_CHECK_ARGS | ||
33 | |||
34 | +.native_test_job_template: | ||
35 | + extends: .common_test_job_template | ||
36 | + artifacts: | ||
37 | + name: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG" | ||
38 | + expire_in: 7 days | ||
39 | + paths: | ||
40 | + - build/meson-logs/testlog.txt | ||
41 | + | ||
42 | .avocado_test_job_template: | ||
43 | - extends: .native_test_job_template | ||
44 | + extends: .common_test_job_template | ||
45 | cache: | ||
46 | key: "${CI_JOB_NAME}-cache" | ||
47 | paths: | ||
48 | -- | ||
49 | 2.35.3 | ||
50 | |||
51 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Philippe Mathieu-Daudé <philmd@redhat.com> | ||
2 | 1 | ||
3 | Per the 82078 datasheet, if the end-of-track (EOT byte in | ||
4 | the FIFO) is more than the number of sectors per side, the | ||
5 | command is terminated unsuccessfully: | ||
6 | |||
7 | * 5.2.5 DATA TRANSFER TERMINATION | ||
8 | |||
9 | The 82078 supports terminal count explicitly through | ||
10 | the TC pin and implicitly through the underrun/over- | ||
11 | run and end-of-track (EOT) functions. For full sector | ||
12 | transfers, the EOT parameter can define the last | ||
13 | sector to be transferred in a single or multisector | ||
14 | transfer. If the last sector to be transferred is a par- | ||
15 | tial sector, the host can stop transferring the data in | ||
16 | mid-sector, and the 82078 will continue to complete | ||
17 | the sector as if a hardware TC was received. The | ||
18 | only difference between these implicit functions and | ||
19 | TC is that they return "abnormal termination" result | ||
20 | status. Such status indications can be ignored if they | ||
21 | were expected. | ||
22 | |||
23 | * 6.1.3 READ TRACK | ||
24 | |||
25 | This command terminates when the EOT specified | ||
26 | number of sectors have been read. If the 82078 | ||
27 | does not find an I D Address Mark on the diskette | ||
28 | after the second· occurrence of a pulse on the | ||
29 | INDX# pin, then it sets the IC code in Status Regis- | ||
30 | ter 0 to "01" (Abnormal termination), sets the MA bit | ||
31 | in Status Register 1 to "1", and terminates the com- | ||
32 | mand. | ||
33 | |||
34 | * 6.1.6 VERIFY | ||
35 | |||
36 | Refer to Table 6-6 and Table 6-7 for information | ||
37 | concerning the values of MT and EC versus SC and | ||
38 | EOT value. | ||
39 | |||
40 | * Table 6·6. Result Phase Table | ||
41 | |||
42 | * Table 6-7. Verify Command Result Phase Table | ||
43 | |||
44 | Fix by aborting the transfer when EOT > # Sectors Per Side. | ||
45 | |||
46 | Cc: qemu-stable@nongnu.org | ||
47 | Cc: Hervé Poussineau <hpoussin@reactos.org> | ||
48 | Fixes: baca51faff0 ("floppy driver: disk geometry auto detect") | ||
49 | Reported-by: Alexander Bulekov <alxndr@bu.edu> | ||
50 | Resolves: https://gitlab.com/qemu-project/qemu/-/issues/339 | ||
51 | Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com> | ||
52 | Message-Id: <20211118115733.4038610-2-philmd@redhat.com> | ||
53 | Reviewed-by: Hanna Reitz <hreitz@redhat.com> | ||
54 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
55 | --- | ||
56 | hw/block/fdc.c | 8 ++++++++ | ||
57 | 1 file changed, 8 insertions(+) | ||
58 | |||
59 | diff --git a/hw/block/fdc.c b/hw/block/fdc.c | ||
60 | index XXXXXXX..XXXXXXX 100644 | ||
61 | --- a/hw/block/fdc.c | ||
62 | +++ b/hw/block/fdc.c | ||
63 | @@ -XXX,XX +XXX,XX @@ static void fdctrl_start_transfer(FDCtrl *fdctrl, int direction) | ||
64 | int tmp; | ||
65 | fdctrl->data_len = 128 << (fdctrl->fifo[5] > 7 ? 7 : fdctrl->fifo[5]); | ||
66 | tmp = (fdctrl->fifo[6] - ks + 1); | ||
67 | + if (tmp < 0) { | ||
68 | + FLOPPY_DPRINTF("invalid EOT: %d\n", tmp); | ||
69 | + fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, FD_SR1_MA, 0x00); | ||
70 | + fdctrl->fifo[3] = kt; | ||
71 | + fdctrl->fifo[4] = kh; | ||
72 | + fdctrl->fifo[5] = ks; | ||
73 | + return; | ||
74 | + } | ||
75 | if (fdctrl->fifo[0] & 0x80) | ||
76 | tmp += fdctrl->fifo[6]; | ||
77 | fdctrl->data_len *= tmp; | ||
78 | -- | ||
79 | 2.35.3 | ||
80 | |||
81 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Philippe Mathieu-Daudé <philmd@redhat.com> | ||
2 | 1 | ||
3 | Add the reproducer from https://gitlab.com/qemu-project/qemu/-/issues/339 | ||
4 | |||
5 | Without the previous commit, when running 'make check-qtest-i386' | ||
6 | with QEMU configured with '--enable-sanitizers' we get: | ||
7 | |||
8 | ==4028352==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x619000062a00 at pc 0x5626d03c491a bp 0x7ffdb4199410 sp 0x7ffdb4198bc0 | ||
9 | READ of size 786432 at 0x619000062a00 thread T0 | ||
10 | #0 0x5626d03c4919 in __asan_memcpy (qemu-system-i386+0x1e65919) | ||
11 | #1 0x5626d1c023cc in flatview_write_continue softmmu/physmem.c:2787:13 | ||
12 | #2 0x5626d1bf0c0f in flatview_write softmmu/physmem.c:2822:14 | ||
13 | #3 0x5626d1bf0798 in address_space_write softmmu/physmem.c:2914:18 | ||
14 | #4 0x5626d1bf0f37 in address_space_rw softmmu/physmem.c:2924:16 | ||
15 | #5 0x5626d1bf14c8 in cpu_physical_memory_rw softmmu/physmem.c:2933:5 | ||
16 | #6 0x5626d0bd5649 in cpu_physical_memory_write include/exec/cpu-common.h:82:5 | ||
17 | #7 0x5626d0bd0a07 in i8257_dma_write_memory hw/dma/i8257.c:452:9 | ||
18 | #8 0x5626d09f825d in fdctrl_transfer_handler hw/block/fdc.c:1616:13 | ||
19 | #9 0x5626d0a048b4 in fdctrl_start_transfer hw/block/fdc.c:1539:13 | ||
20 | #10 0x5626d09f4c3e in fdctrl_write_data hw/block/fdc.c:2266:13 | ||
21 | #11 0x5626d09f22f7 in fdctrl_write hw/block/fdc.c:829:9 | ||
22 | #12 0x5626d1c20bc5 in portio_write softmmu/ioport.c:207:17 | ||
23 | |||
24 | 0x619000062a00 is located 0 bytes to the right of 512-byte region [0x619000062800,0x619000062a00) | ||
25 | allocated by thread T0 here: | ||
26 | #0 0x5626d03c66ec in posix_memalign (qemu-system-i386+0x1e676ec) | ||
27 | #1 0x5626d2b988d4 in qemu_try_memalign util/oslib-posix.c:210:11 | ||
28 | #2 0x5626d2b98b0c in qemu_memalign util/oslib-posix.c:226:27 | ||
29 | #3 0x5626d09fbaf0 in fdctrl_realize_common hw/block/fdc.c:2341:20 | ||
30 | #4 0x5626d0a150ed in isabus_fdc_realize hw/block/fdc-isa.c:113:5 | ||
31 | #5 0x5626d2367935 in device_set_realized hw/core/qdev.c:531:13 | ||
32 | |||
33 | SUMMARY: AddressSanitizer: heap-buffer-overflow (qemu-system-i386+0x1e65919) in __asan_memcpy | ||
34 | Shadow bytes around the buggy address: | ||
35 | 0x0c32800044f0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa | ||
36 | 0x0c3280004500: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ||
37 | 0x0c3280004510: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ||
38 | 0x0c3280004520: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ||
39 | 0x0c3280004530: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ||
40 | =>0x0c3280004540:[fa]fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa | ||
41 | 0x0c3280004550: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa | ||
42 | 0x0c3280004560: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa | ||
43 | 0x0c3280004570: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa | ||
44 | 0x0c3280004580: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa | ||
45 | 0x0c3280004590: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd | ||
46 | Shadow byte legend (one shadow byte represents 8 application bytes): | ||
47 | Addressable: 00 | ||
48 | Heap left redzone: fa | ||
49 | Freed heap region: fd | ||
50 | ==4028352==ABORTING | ||
51 | |||
52 | [ kwolf: Added snapshot=on to prevent write file lock failure ] | ||
53 | |||
54 | Reported-by: Alexander Bulekov <alxndr@bu.edu> | ||
55 | Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com> | ||
56 | Reviewed-by: Alexander Bulekov <alxndr@bu.edu> | ||
57 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
58 | --- | ||
59 | tests/qtest/fdc-test.c | 21 +++++++++++++++++++++ | ||
60 | 1 file changed, 21 insertions(+) | ||
61 | |||
62 | diff --git a/tests/qtest/fdc-test.c b/tests/qtest/fdc-test.c | ||
63 | index XXXXXXX..XXXXXXX 100644 | ||
64 | --- a/tests/qtest/fdc-test.c | ||
65 | +++ b/tests/qtest/fdc-test.c | ||
66 | @@ -XXX,XX +XXX,XX @@ static void test_cve_2021_20196(void) | ||
67 | qtest_quit(s); | ||
68 | } | ||
69 | |||
70 | +static void test_cve_2021_3507(void) | ||
71 | +{ | ||
72 | + QTestState *s; | ||
73 | + | ||
74 | + s = qtest_initf("-nographic -m 32M -nodefaults " | ||
75 | + "-drive file=%s,format=raw,if=floppy,snapshot=on", | ||
76 | + test_image); | ||
77 | + qtest_outl(s, 0x9, 0x0a0206); | ||
78 | + qtest_outw(s, 0x3f4, 0x1600); | ||
79 | + qtest_outw(s, 0x3f4, 0x0000); | ||
80 | + qtest_outw(s, 0x3f4, 0x0000); | ||
81 | + qtest_outw(s, 0x3f4, 0x0000); | ||
82 | + qtest_outw(s, 0x3f4, 0x0200); | ||
83 | + qtest_outw(s, 0x3f4, 0x0200); | ||
84 | + qtest_outw(s, 0x3f4, 0x0000); | ||
85 | + qtest_outw(s, 0x3f4, 0x0000); | ||
86 | + qtest_outw(s, 0x3f4, 0x0000); | ||
87 | + qtest_quit(s); | ||
88 | +} | ||
89 | + | ||
90 | int main(int argc, char **argv) | ||
91 | { | ||
92 | int fd; | ||
93 | @@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv) | ||
94 | qtest_add_func("/fdc/read_no_dma_19", test_read_no_dma_19); | ||
95 | qtest_add_func("/fdc/fuzz-registers", fuzz_registers); | ||
96 | qtest_add_func("/fdc/fuzz/cve_2021_20196", test_cve_2021_20196); | ||
97 | + qtest_add_func("/fdc/fuzz/cve_2021_3507", test_cve_2021_3507); | ||
98 | |||
99 | ret = g_test_run(); | ||
100 | |||
101 | -- | ||
102 | 2.35.3 | ||
103 | |||
104 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Eric Blake <eblake@redhat.com> | ||
2 | 1 | ||
3 | The next patch wants to adjust whether the NBD server code advertises | ||
4 | MULTI_CONN based on whether it is known if the server limits to | ||
5 | exactly one client. For a server started by QMP, this information is | ||
6 | obtained through nbd_server_start (which can support more than one | ||
7 | export); but for qemu-nbd (which supports exactly one export), it is | ||
8 | controlled only by the command-line option -e/--shared. Since we | ||
9 | already have a hook function used by qemu-nbd, it's easiest to just | ||
10 | alter its signature to fit our needs. | ||
11 | |||
12 | Signed-off-by: Eric Blake <eblake@redhat.com> | ||
13 | Message-Id: <20220512004924.417153-2-eblake@redhat.com> | ||
14 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
15 | --- | ||
16 | include/block/nbd.h | 2 +- | ||
17 | blockdev-nbd.c | 8 ++++---- | ||
18 | qemu-nbd.c | 2 +- | ||
19 | 3 files changed, 6 insertions(+), 6 deletions(-) | ||
20 | |||
21 | diff --git a/include/block/nbd.h b/include/block/nbd.h | ||
22 | index XXXXXXX..XXXXXXX 100644 | ||
23 | --- a/include/block/nbd.h | ||
24 | +++ b/include/block/nbd.h | ||
25 | @@ -XXX,XX +XXX,XX @@ void nbd_client_new(QIOChannelSocket *sioc, | ||
26 | void nbd_client_get(NBDClient *client); | ||
27 | void nbd_client_put(NBDClient *client); | ||
28 | |||
29 | -void nbd_server_is_qemu_nbd(bool value); | ||
30 | +void nbd_server_is_qemu_nbd(int max_connections); | ||
31 | bool nbd_server_is_running(void); | ||
32 | void nbd_server_start(SocketAddress *addr, const char *tls_creds, | ||
33 | const char *tls_authz, uint32_t max_connections, | ||
34 | diff --git a/blockdev-nbd.c b/blockdev-nbd.c | ||
35 | index XXXXXXX..XXXXXXX 100644 | ||
36 | --- a/blockdev-nbd.c | ||
37 | +++ b/blockdev-nbd.c | ||
38 | @@ -XXX,XX +XXX,XX @@ typedef struct NBDServerData { | ||
39 | } NBDServerData; | ||
40 | |||
41 | static NBDServerData *nbd_server; | ||
42 | -static bool is_qemu_nbd; | ||
43 | +static int qemu_nbd_connections = -1; /* Non-negative if this is qemu-nbd */ | ||
44 | |||
45 | static void nbd_update_server_watch(NBDServerData *s); | ||
46 | |||
47 | -void nbd_server_is_qemu_nbd(bool value) | ||
48 | +void nbd_server_is_qemu_nbd(int max_connections) | ||
49 | { | ||
50 | - is_qemu_nbd = value; | ||
51 | + qemu_nbd_connections = max_connections; | ||
52 | } | ||
53 | |||
54 | bool nbd_server_is_running(void) | ||
55 | { | ||
56 | - return nbd_server || is_qemu_nbd; | ||
57 | + return nbd_server || qemu_nbd_connections >= 0; | ||
58 | } | ||
59 | |||
60 | static void nbd_blockdev_client_closed(NBDClient *client, bool ignored) | ||
61 | diff --git a/qemu-nbd.c b/qemu-nbd.c | ||
62 | index XXXXXXX..XXXXXXX 100644 | ||
63 | --- a/qemu-nbd.c | ||
64 | +++ b/qemu-nbd.c | ||
65 | @@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv) | ||
66 | |||
67 | bs->detect_zeroes = detect_zeroes; | ||
68 | |||
69 | - nbd_server_is_qemu_nbd(true); | ||
70 | + nbd_server_is_qemu_nbd(shared); | ||
71 | |||
72 | export_opts = g_new(BlockExportOptions, 1); | ||
73 | *export_opts = (BlockExportOptions) { | ||
74 | -- | ||
75 | 2.35.3 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Eric Blake <eblake@redhat.com> | ||
2 | 1 | ||
3 | According to the NBD spec, a server that advertises | ||
4 | NBD_FLAG_CAN_MULTI_CONN promises that multiple client connections will | ||
5 | not see any cache inconsistencies: when properly separated by a single | ||
6 | flush, actions performed by one client will be visible to another | ||
7 | client, regardless of which client did the flush. | ||
8 | |||
9 | We always satisfy these conditions in qemu - even when we support | ||
10 | multiple clients, ALL clients go through a single point of reference | ||
11 | into the block layer, with no local caching. The effect of one client | ||
12 | is instantly visible to the next client. Even if our backend were a | ||
13 | network device, we argue that any multi-path caching effects that | ||
14 | would cause inconsistencies in back-to-back actions not seeing the | ||
15 | effect of previous actions would be a bug in that backend, and not the | ||
16 | fault of caching in qemu. As such, it is safe to unconditionally | ||
17 | advertise CAN_MULTI_CONN for any qemu NBD server situation that | ||
18 | supports parallel clients. | ||
19 | |||
20 | Note, however, that we don't want to advertise CAN_MULTI_CONN when we | ||
21 | know that a second client cannot connect (for historical reasons, | ||
22 | qemu-nbd defaults to a single connection while nbd-server-add and QMP | ||
23 | commands default to unlimited connections; but we already have | ||
24 | existing means to let either style of NBD server creation alter those | ||
25 | defaults). This is visible by no longer advertising MULTI_CONN for | ||
26 | 'qemu-nbd -r' without -e, as in the iotest nbd-qemu-allocation. | ||
27 | |||
28 | The harder part of this patch is setting up an iotest to demonstrate | ||
29 | behavior of multiple NBD clients to a single server. It might be | ||
30 | possible with parallel qemu-io processes, but I found it easier to do | ||
31 | in python with the help of libnbd, and help from Nir and Vladimir in | ||
32 | writing the test. | ||
33 | |||
34 | Signed-off-by: Eric Blake <eblake@redhat.com> | ||
35 | Suggested-by: Nir Soffer <nsoffer@redhat.com> | ||
36 | Suggested-by: Vladimir Sementsov-Ogievskiy <v.sementsov-og@mail.ru> | ||
37 | Message-Id: <20220512004924.417153-3-eblake@redhat.com> | ||
38 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
39 | --- | ||
40 | qapi/block-export.json | 8 +- | ||
41 | docs/interop/nbd.txt | 1 + | ||
42 | docs/tools/qemu-nbd.rst | 3 +- | ||
43 | include/block/nbd.h | 3 +- | ||
44 | blockdev-nbd.c | 5 + | ||
45 | nbd/server.c | 10 +- | ||
46 | MAINTAINERS | 1 + | ||
47 | tests/qemu-iotests/tests/nbd-multiconn | 145 ++++++++++++++++++ | ||
48 | tests/qemu-iotests/tests/nbd-multiconn.out | 5 + | ||
49 | .../tests/nbd-qemu-allocation.out | 2 +- | ||
50 | 10 files changed, 172 insertions(+), 11 deletions(-) | ||
51 | create mode 100755 tests/qemu-iotests/tests/nbd-multiconn | ||
52 | create mode 100644 tests/qemu-iotests/tests/nbd-multiconn.out | ||
53 | |||
54 | diff --git a/qapi/block-export.json b/qapi/block-export.json | ||
55 | index XXXXXXX..XXXXXXX 100644 | ||
56 | --- a/qapi/block-export.json | ||
57 | +++ b/qapi/block-export.json | ||
58 | @@ -XXX,XX +XXX,XX @@ | ||
59 | # recreated on the fly while the NBD server is active. | ||
60 | # If missing, it will default to denying access (since 4.0). | ||
61 | # @max-connections: The maximum number of connections to allow at the same | ||
62 | -# time, 0 for unlimited. (since 5.2; default: 0) | ||
63 | +# time, 0 for unlimited. Setting this to 1 also stops | ||
64 | +# the server from advertising multiple client support | ||
65 | +# (since 5.2; default: 0) | ||
66 | # | ||
67 | # Since: 4.2 | ||
68 | ## | ||
69 | @@ -XXX,XX +XXX,XX @@ | ||
70 | # recreated on the fly while the NBD server is active. | ||
71 | # If missing, it will default to denying access (since 4.0). | ||
72 | # @max-connections: The maximum number of connections to allow at the same | ||
73 | -# time, 0 for unlimited. (since 5.2; default: 0) | ||
74 | +# time, 0 for unlimited. Setting this to 1 also stops | ||
75 | +# the server from advertising multiple client support | ||
76 | +# (since 5.2; default: 0). | ||
77 | # | ||
78 | # Returns: error if the server is already running. | ||
79 | # | ||
80 | diff --git a/docs/interop/nbd.txt b/docs/interop/nbd.txt | ||
81 | index XXXXXXX..XXXXXXX 100644 | ||
82 | --- a/docs/interop/nbd.txt | ||
83 | +++ b/docs/interop/nbd.txt | ||
84 | @@ -XXX,XX +XXX,XX @@ NBD_CMD_BLOCK_STATUS for "qemu:dirty-bitmap:", NBD_CMD_CACHE | ||
85 | * 4.2: NBD_FLAG_CAN_MULTI_CONN for shareable read-only exports, | ||
86 | NBD_CMD_FLAG_FAST_ZERO | ||
87 | * 5.2: NBD_CMD_BLOCK_STATUS for "qemu:allocation-depth" | ||
88 | +* 7.1: NBD_FLAG_CAN_MULTI_CONN for shareable writable exports | ||
89 | diff --git a/docs/tools/qemu-nbd.rst b/docs/tools/qemu-nbd.rst | ||
90 | index XXXXXXX..XXXXXXX 100644 | ||
91 | --- a/docs/tools/qemu-nbd.rst | ||
92 | +++ b/docs/tools/qemu-nbd.rst | ||
93 | @@ -XXX,XX +XXX,XX @@ driver options if :option:`--image-opts` is specified. | ||
94 | .. option:: -e, --shared=NUM | ||
95 | |||
96 | Allow up to *NUM* clients to share the device (default | ||
97 | - ``1``), 0 for unlimited. Safe for readers, but for now, | ||
98 | - consistency is not guaranteed between multiple writers. | ||
99 | + ``1``), 0 for unlimited. | ||
100 | |||
101 | .. option:: -t, --persistent | ||
102 | |||
103 | diff --git a/include/block/nbd.h b/include/block/nbd.h | ||
104 | index XXXXXXX..XXXXXXX 100644 | ||
105 | --- a/include/block/nbd.h | ||
106 | +++ b/include/block/nbd.h | ||
107 | @@ -XXX,XX +XXX,XX @@ | ||
108 | /* | ||
109 | - * Copyright (C) 2016-2020 Red Hat, Inc. | ||
110 | + * Copyright (C) 2016-2022 Red Hat, Inc. | ||
111 | * Copyright (C) 2005 Anthony Liguori <anthony@codemonkey.ws> | ||
112 | * | ||
113 | * Network Block Device | ||
114 | @@ -XXX,XX +XXX,XX @@ void nbd_client_put(NBDClient *client); | ||
115 | |||
116 | void nbd_server_is_qemu_nbd(int max_connections); | ||
117 | bool nbd_server_is_running(void); | ||
118 | +int nbd_server_max_connections(void); | ||
119 | void nbd_server_start(SocketAddress *addr, const char *tls_creds, | ||
120 | const char *tls_authz, uint32_t max_connections, | ||
121 | Error **errp); | ||
122 | diff --git a/blockdev-nbd.c b/blockdev-nbd.c | ||
123 | index XXXXXXX..XXXXXXX 100644 | ||
124 | --- a/blockdev-nbd.c | ||
125 | +++ b/blockdev-nbd.c | ||
126 | @@ -XXX,XX +XXX,XX @@ bool nbd_server_is_running(void) | ||
127 | return nbd_server || qemu_nbd_connections >= 0; | ||
128 | } | ||
129 | |||
130 | +int nbd_server_max_connections(void) | ||
131 | +{ | ||
132 | + return nbd_server ? nbd_server->max_connections : qemu_nbd_connections; | ||
133 | +} | ||
134 | + | ||
135 | static void nbd_blockdev_client_closed(NBDClient *client, bool ignored) | ||
136 | { | ||
137 | nbd_client_put(client); | ||
138 | diff --git a/nbd/server.c b/nbd/server.c | ||
139 | index XXXXXXX..XXXXXXX 100644 | ||
140 | --- a/nbd/server.c | ||
141 | +++ b/nbd/server.c | ||
142 | @@ -XXX,XX +XXX,XX @@ | ||
143 | /* | ||
144 | - * Copyright (C) 2016-2021 Red Hat, Inc. | ||
145 | + * Copyright (C) 2016-2022 Red Hat, Inc. | ||
146 | * Copyright (C) 2005 Anthony Liguori <anthony@codemonkey.ws> | ||
147 | * | ||
148 | * Network Block Device Server Side | ||
149 | @@ -XXX,XX +XXX,XX @@ static int nbd_export_create(BlockExport *blk_exp, BlockExportOptions *exp_args, | ||
150 | int64_t size; | ||
151 | uint64_t perm, shared_perm; | ||
152 | bool readonly = !exp_args->writable; | ||
153 | - bool shared = !exp_args->writable; | ||
154 | BlockDirtyBitmapOrStrList *bitmaps; | ||
155 | size_t i; | ||
156 | int ret; | ||
157 | @@ -XXX,XX +XXX,XX @@ static int nbd_export_create(BlockExport *blk_exp, BlockExportOptions *exp_args, | ||
158 | exp->description = g_strdup(arg->description); | ||
159 | exp->nbdflags = (NBD_FLAG_HAS_FLAGS | NBD_FLAG_SEND_FLUSH | | ||
160 | NBD_FLAG_SEND_FUA | NBD_FLAG_SEND_CACHE); | ||
161 | + | ||
162 | + if (nbd_server_max_connections() != 1) { | ||
163 | + exp->nbdflags |= NBD_FLAG_CAN_MULTI_CONN; | ||
164 | + } | ||
165 | if (readonly) { | ||
166 | exp->nbdflags |= NBD_FLAG_READ_ONLY; | ||
167 | - if (shared) { | ||
168 | - exp->nbdflags |= NBD_FLAG_CAN_MULTI_CONN; | ||
169 | - } | ||
170 | } else { | ||
171 | exp->nbdflags |= (NBD_FLAG_SEND_TRIM | NBD_FLAG_SEND_WRITE_ZEROES | | ||
172 | NBD_FLAG_SEND_FAST_ZERO); | ||
173 | diff --git a/MAINTAINERS b/MAINTAINERS | ||
174 | index XXXXXXX..XXXXXXX 100644 | ||
175 | --- a/MAINTAINERS | ||
176 | +++ b/MAINTAINERS | ||
177 | @@ -XXX,XX +XXX,XX @@ F: qemu-nbd.* | ||
178 | F: blockdev-nbd.c | ||
179 | F: docs/interop/nbd.txt | ||
180 | F: docs/tools/qemu-nbd.rst | ||
181 | +F: tests/qemu-iotests/tests/*nbd* | ||
182 | T: git https://repo.or.cz/qemu/ericb.git nbd | ||
183 | T: git https://src.openvz.org/scm/~vsementsov/qemu.git nbd | ||
184 | |||
185 | diff --git a/tests/qemu-iotests/tests/nbd-multiconn b/tests/qemu-iotests/tests/nbd-multiconn | ||
186 | new file mode 100755 | ||
187 | index XXXXXXX..XXXXXXX | ||
188 | --- /dev/null | ||
189 | +++ b/tests/qemu-iotests/tests/nbd-multiconn | ||
190 | @@ -XXX,XX +XXX,XX @@ | ||
191 | +#!/usr/bin/env python3 | ||
192 | +# group: rw auto quick | ||
193 | +# | ||
194 | +# Test cases for NBD multi-conn advertisement | ||
195 | +# | ||
196 | +# Copyright (C) 2022 Red Hat, Inc. | ||
197 | +# | ||
198 | +# This program is free software; you can redistribute it and/or modify | ||
199 | +# it under the terms of the GNU General Public License as published by | ||
200 | +# the Free Software Foundation; either version 2 of the License, or | ||
201 | +# (at your option) any later version. | ||
202 | +# | ||
203 | +# This program is distributed in the hope that it will be useful, | ||
204 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
205 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
206 | +# GNU General Public License for more details. | ||
207 | +# | ||
208 | +# You should have received a copy of the GNU General Public License | ||
209 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
210 | + | ||
211 | +import os | ||
212 | +from contextlib import contextmanager | ||
213 | +import iotests | ||
214 | +from iotests import qemu_img_create, qemu_io | ||
215 | + | ||
216 | + | ||
217 | +disk = os.path.join(iotests.test_dir, 'disk') | ||
218 | +size = '4M' | ||
219 | +nbd_sock = os.path.join(iotests.sock_dir, 'nbd_sock') | ||
220 | +nbd_uri = 'nbd+unix:///{}?socket=' + nbd_sock | ||
221 | + | ||
222 | + | ||
223 | +@contextmanager | ||
224 | +def open_nbd(export_name): | ||
225 | + h = nbd.NBD() | ||
226 | + try: | ||
227 | + h.connect_uri(nbd_uri.format(export_name)) | ||
228 | + yield h | ||
229 | + finally: | ||
230 | + h.shutdown() | ||
231 | + | ||
232 | +class TestNbdMulticonn(iotests.QMPTestCase): | ||
233 | + def setUp(self): | ||
234 | + qemu_img_create('-f', iotests.imgfmt, disk, size) | ||
235 | + qemu_io('-c', 'w -P 1 0 2M', '-c', 'w -P 2 2M 2M', disk) | ||
236 | + | ||
237 | + self.vm = iotests.VM() | ||
238 | + self.vm.launch() | ||
239 | + result = self.vm.qmp('blockdev-add', { | ||
240 | + 'driver': 'qcow2', | ||
241 | + 'node-name': 'n', | ||
242 | + 'file': {'driver': 'file', 'filename': disk} | ||
243 | + }) | ||
244 | + self.assert_qmp(result, 'return', {}) | ||
245 | + | ||
246 | + def tearDown(self): | ||
247 | + self.vm.shutdown() | ||
248 | + os.remove(disk) | ||
249 | + try: | ||
250 | + os.remove(nbd_sock) | ||
251 | + except OSError: | ||
252 | + pass | ||
253 | + | ||
254 | + @contextmanager | ||
255 | + def run_server(self, max_connections=None): | ||
256 | + args = { | ||
257 | + 'addr': { | ||
258 | + 'type': 'unix', | ||
259 | + 'data': {'path': nbd_sock} | ||
260 | + } | ||
261 | + } | ||
262 | + if max_connections is not None: | ||
263 | + args['max-connections'] = max_connections | ||
264 | + | ||
265 | + result = self.vm.qmp('nbd-server-start', args) | ||
266 | + self.assert_qmp(result, 'return', {}) | ||
267 | + yield | ||
268 | + | ||
269 | + result = self.vm.qmp('nbd-server-stop') | ||
270 | + self.assert_qmp(result, 'return', {}) | ||
271 | + | ||
272 | + def add_export(self, name, writable=None): | ||
273 | + args = { | ||
274 | + 'type': 'nbd', | ||
275 | + 'id': name, | ||
276 | + 'node-name': 'n', | ||
277 | + 'name': name, | ||
278 | + } | ||
279 | + if writable is not None: | ||
280 | + args['writable'] = writable | ||
281 | + | ||
282 | + result = self.vm.qmp('block-export-add', args) | ||
283 | + self.assert_qmp(result, 'return', {}) | ||
284 | + | ||
285 | + def test_default_settings(self): | ||
286 | + with self.run_server(): | ||
287 | + self.add_export('r') | ||
288 | + self.add_export('w', writable=True) | ||
289 | + with open_nbd('r') as h: | ||
290 | + self.assertTrue(h.can_multi_conn()) | ||
291 | + with open_nbd('w') as h: | ||
292 | + self.assertTrue(h.can_multi_conn()) | ||
293 | + | ||
294 | + def test_limited_connections(self): | ||
295 | + with self.run_server(max_connections=1): | ||
296 | + self.add_export('r') | ||
297 | + self.add_export('w', writable=True) | ||
298 | + with open_nbd('r') as h: | ||
299 | + self.assertFalse(h.can_multi_conn()) | ||
300 | + with open_nbd('w') as h: | ||
301 | + self.assertFalse(h.can_multi_conn()) | ||
302 | + | ||
303 | + def test_parallel_writes(self): | ||
304 | + with self.run_server(): | ||
305 | + self.add_export('w', writable=True) | ||
306 | + | ||
307 | + clients = [nbd.NBD() for _ in range(3)] | ||
308 | + for c in clients: | ||
309 | + c.connect_uri(nbd_uri.format('w')) | ||
310 | + self.assertTrue(c.can_multi_conn()) | ||
311 | + | ||
312 | + initial_data = clients[0].pread(1024 * 1024, 0) | ||
313 | + self.assertEqual(initial_data, b'\x01' * 1024 * 1024) | ||
314 | + | ||
315 | + updated_data = b'\x03' * 1024 * 1024 | ||
316 | + clients[1].pwrite(updated_data, 0) | ||
317 | + clients[2].flush() | ||
318 | + current_data = clients[0].pread(1024 * 1024, 0) | ||
319 | + | ||
320 | + self.assertEqual(updated_data, current_data) | ||
321 | + | ||
322 | + for i in range(3): | ||
323 | + clients[i].shutdown() | ||
324 | + | ||
325 | + | ||
326 | +if __name__ == '__main__': | ||
327 | + try: | ||
328 | + # Easier to use libnbd than to try and set up parallel | ||
329 | + # 'qemu-nbd --list' or 'qemu-io' processes, but not all systems | ||
330 | + # have libnbd installed. | ||
331 | + import nbd # type: ignore | ||
332 | + | ||
333 | + iotests.main(supported_fmts=['qcow2']) | ||
334 | + except ImportError: | ||
335 | + iotests.notrun('libnbd not installed') | ||
336 | diff --git a/tests/qemu-iotests/tests/nbd-multiconn.out b/tests/qemu-iotests/tests/nbd-multiconn.out | ||
337 | new file mode 100644 | ||
338 | index XXXXXXX..XXXXXXX | ||
339 | --- /dev/null | ||
340 | +++ b/tests/qemu-iotests/tests/nbd-multiconn.out | ||
341 | @@ -XXX,XX +XXX,XX @@ | ||
342 | +... | ||
343 | +---------------------------------------------------------------------- | ||
344 | +Ran 3 tests | ||
345 | + | ||
346 | +OK | ||
347 | diff --git a/tests/qemu-iotests/tests/nbd-qemu-allocation.out b/tests/qemu-iotests/tests/nbd-qemu-allocation.out | ||
348 | index XXXXXXX..XXXXXXX 100644 | ||
349 | --- a/tests/qemu-iotests/tests/nbd-qemu-allocation.out | ||
350 | +++ b/tests/qemu-iotests/tests/nbd-qemu-allocation.out | ||
351 | @@ -XXX,XX +XXX,XX @@ wrote 2097152/2097152 bytes at offset 1048576 | ||
352 | exports available: 1 | ||
353 | export: '' | ||
354 | size: 4194304 | ||
355 | - flags: 0x58f ( readonly flush fua df multi cache ) | ||
356 | + flags: 0x48f ( readonly flush fua df cache ) | ||
357 | min block: 1 | ||
358 | opt block: 4096 | ||
359 | max block: 33554432 | ||
360 | -- | ||
361 | 2.35.3 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Paolo Bonzini <pbonzini@redhat.com> | ||
2 | 1 | ||
3 | common.rc has some complicated logic to find the common.config that | ||
4 | dates back to xfstests and is completely unnecessary now. Just include | ||
5 | the contents of the file. | ||
6 | |||
7 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> | ||
8 | Message-Id: <20220505094723.732116-1-pbonzini@redhat.com> | ||
9 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
10 | --- | ||
11 | tests/qemu-iotests/common.config | 41 -------------------------------- | ||
12 | tests/qemu-iotests/common.rc | 31 ++++++++++++++---------- | ||
13 | 2 files changed, 19 insertions(+), 53 deletions(-) | ||
14 | delete mode 100644 tests/qemu-iotests/common.config | ||
15 | |||
16 | diff --git a/tests/qemu-iotests/common.config b/tests/qemu-iotests/common.config | ||
17 | deleted file mode 100644 | ||
18 | index XXXXXXX..XXXXXXX | ||
19 | --- a/tests/qemu-iotests/common.config | ||
20 | +++ /dev/null | ||
21 | @@ -XXX,XX +XXX,XX @@ | ||
22 | -#!/usr/bin/env bash | ||
23 | -# | ||
24 | -# Copyright (C) 2009 Red Hat, Inc. | ||
25 | -# Copyright (c) 2000-2003,2006 Silicon Graphics, Inc. All Rights Reserved. | ||
26 | -# | ||
27 | -# This program is free software; you can redistribute it and/or | ||
28 | -# modify it under the terms of the GNU General Public License as | ||
29 | -# published by the Free Software Foundation. | ||
30 | -# | ||
31 | -# This program is distributed in the hope that it would be useful, | ||
32 | -# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
33 | -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
34 | -# GNU General Public License for more details. | ||
35 | -# | ||
36 | -# You should have received a copy of the GNU General Public License | ||
37 | -# along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
38 | -# | ||
39 | -# all tests should use a common language setting to prevent golden | ||
40 | -# output mismatches. | ||
41 | -export LANG=C | ||
42 | - | ||
43 | -PATH=".:$PATH" | ||
44 | - | ||
45 | -HOSTOS=$(uname -s) | ||
46 | -arch=$(uname -m) | ||
47 | -[[ "$arch" =~ "ppc64" ]] && qemu_arch=ppc64 || qemu_arch="$arch" | ||
48 | - | ||
49 | -# make sure we have a standard umask | ||
50 | -umask 022 | ||
51 | - | ||
52 | -_optstr_add() | ||
53 | -{ | ||
54 | - if [ -n "$1" ]; then | ||
55 | - echo "$1,$2" | ||
56 | - else | ||
57 | - echo "$2" | ||
58 | - fi | ||
59 | -} | ||
60 | - | ||
61 | -# make sure this script returns success | ||
62 | -true | ||
63 | diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc | ||
64 | index XXXXXXX..XXXXXXX 100644 | ||
65 | --- a/tests/qemu-iotests/common.rc | ||
66 | +++ b/tests/qemu-iotests/common.rc | ||
67 | @@ -XXX,XX +XXX,XX @@ | ||
68 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
69 | # | ||
70 | |||
71 | +export LANG=C | ||
72 | + | ||
73 | +PATH=".:$PATH" | ||
74 | + | ||
75 | +HOSTOS=$(uname -s) | ||
76 | +arch=$(uname -m) | ||
77 | +[[ "$arch" =~ "ppc64" ]] && qemu_arch=ppc64 || qemu_arch="$arch" | ||
78 | + | ||
79 | +# make sure we have a standard umask | ||
80 | +umask 022 | ||
81 | + | ||
82 | # bail out, setting up .notrun file | ||
83 | _notrun() | ||
84 | { | ||
85 | @@ -XXX,XX +XXX,XX @@ peek_file_raw() | ||
86 | dd if="$1" bs=1 skip="$2" count="$3" status=none | ||
87 | } | ||
88 | |||
89 | -config=common.config | ||
90 | -test -f $config || config=../common.config | ||
91 | -if ! test -f $config | ||
92 | -then | ||
93 | - echo "$0: failed to find common.config" | ||
94 | - exit 1 | ||
95 | -fi | ||
96 | -if ! . $config | ||
97 | - then | ||
98 | - echo "$0: failed to source common.config" | ||
99 | - exit 1 | ||
100 | -fi | ||
101 | +_optstr_add() | ||
102 | +{ | ||
103 | + if [ -n "$1" ]; then | ||
104 | + echo "$1,$2" | ||
105 | + else | ||
106 | + echo "$2" | ||
107 | + fi | ||
108 | +} | ||
109 | |||
110 | # Set the variables to the empty string to turn Valgrind off | ||
111 | # for specific processes, e.g. | ||
112 | -- | ||
113 | 2.35.3 | diff view generated by jsdifflib |