1 | The following changes since commit 22dbfdecc3c52228d3489da3fe81da92b21197bf: | 1 | The following changes since commit e3acc2c1961cbe22ca474cd5da4163b7bbf7cea3: |
---|---|---|---|
2 | 2 | ||
3 | Merge remote-tracking branch 'remotes/awilliam/tags/vfio-update-20191010.0' into staging (2019-10-14 15:09:08 +0100) | 3 | tests/docker/dockerfiles: Bump fedora-i386-cross to fedora 34 (2021-10-05 16:40:39 -0700) |
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 | git://repo.or.cz/qemu/kevin.git tags/for-upstream |
8 | 8 | ||
9 | for you to fetch changes up to a1406a9262a087d9ec9627b88da13c4590b61dae: | 9 | for you to fetch changes up to 3765315d4c84f9c0799744f43a314169baaccc05: |
10 | 10 | ||
11 | iotests: Test large write request to qcow2 file (2019-10-14 17:12:48 +0200) | 11 | iotests: Update for pylint 2.11.1 (2021-10-06 10:25:55 +0200) |
12 | 12 | ||
13 | ---------------------------------------------------------------- | 13 | ---------------------------------------------------------------- |
14 | Block layer patches: | 14 | Block layer patches |
15 | 15 | ||
16 | - block: Fix crash with qcow2 partial cluster COW with small cluster | 16 | - Fix I/O errors because of incorrectly detected max_iov |
17 | sizes (misaligned write requests with BDRV_REQ_NO_FALLBACK) | 17 | - Fix not white-listed copy-before-write |
18 | - qcow2: Fix integer overflow potentially causing corruption with huge | 18 | - qemu-storage-daemon: Only display FUSE help when FUSE is built-in |
19 | requests | 19 | - iotests: update environment and linting configuration |
20 | - vhdx: Detect truncated image files | ||
21 | - tools: Support help options for --object | ||
22 | - Various block-related replay improvements | ||
23 | - iotests/028: Fix for long $TEST_DIRs | ||
24 | 20 | ||
25 | ---------------------------------------------------------------- | 21 | ---------------------------------------------------------------- |
26 | Alberto Garcia (1): | 22 | Emanuele Giuseppe Esposito (1): |
27 | block: Reject misaligned write requests with BDRV_REQ_NO_FALLBACK | 23 | include/block.h: remove outdated comment |
28 | 24 | ||
29 | Kevin Wolf (4): | 25 | John Snow (5): |
30 | vl: Split off user_creatable_print_help() | 26 | iotests: add 'qemu' package location to PYTHONPATH in testenv |
31 | qemu-io: Support help options for --object | 27 | iotests/linters: check mypy files all at once |
32 | qemu-img: Support help options for --object | 28 | iotests/mirror-top-perms: Adjust imports |
33 | qemu-nbd: Support help options for --object | 29 | iotests/migrate-bitmaps-test: delint |
30 | iotests: Update for pylint 2.11.1 | ||
34 | 31 | ||
35 | Max Reitz (3): | 32 | Paolo Bonzini (1): |
36 | iotests/028: Fix for long $TEST_DIRs | 33 | block: introduce max_hw_iov for use in scsi-generic |
37 | qcow2: Limit total allocation range to INT_MAX | ||
38 | iotests: Test large write request to qcow2 file | ||
39 | 34 | ||
40 | Pavel Dovgaluk (6): | 35 | Philippe Mathieu-Daudé (1): |
41 | block: implement bdrv_snapshot_goto for blkreplay | 36 | qemu-storage-daemon: Only display FUSE help when FUSE is built-in |
42 | replay: disable default snapshot for record/replay | ||
43 | replay: update docs for record/replay with block devices | ||
44 | replay: don't drain/flush bdrv queue while RR is working | ||
45 | replay: finish record/replay before closing the disks | ||
46 | replay: add BH oneshot event for block layer | ||
47 | 37 | ||
48 | Peter Lieven (1): | 38 | Vladimir Sementsov-Ogievskiy (5): |
49 | block/vhdx: add check for truncated image files | 39 | block: implement bdrv_new_open_driver_opts() |
40 | block: bdrv_insert_node(): fix and improve error handling | ||
41 | block: bdrv_insert_node(): doc and style | ||
42 | block: bdrv_insert_node(): don't use bdrv_open() | ||
43 | iotests/image-fleecing: declare requirement of copy-before-write | ||
50 | 44 | ||
51 | docs/replay.txt | 12 +++- | 45 | include/block/block.h | 8 ++- |
52 | include/qom/object_interfaces.h | 12 ++++ | 46 | include/block/block_int.h | 7 +++ |
53 | include/sysemu/replay.h | 4 ++ | 47 | include/sysemu/block-backend.h | 1 + |
54 | replay/replay-internal.h | 1 + | 48 | block.c | 79 ++++++++++++++++++++++----- |
55 | block/blkreplay.c | 8 +++ | 49 | block/block-backend.c | 6 ++ |
56 | block/block-backend.c | 9 ++- | 50 | block/file-posix.c | 2 +- |
57 | block/io.c | 39 ++++++++++++- | 51 | block/io.c | 1 + |
58 | block/iscsi.c | 5 +- | 52 | hw/scsi/scsi-generic.c | 2 +- |
59 | block/nfs.c | 6 +- | 53 | storage-daemon/qemu-storage-daemon.c | 2 + |
60 | block/null.c | 4 +- | 54 | tests/qemu-iotests/iotests.py | 2 - |
61 | block/nvme.c | 6 +- | 55 | tests/qemu-iotests/testenv.py | 15 +++-- |
62 | block/qcow2-cluster.c | 5 +- | 56 | tests/qemu-iotests/testrunner.py | 7 ++- |
63 | block/rbd.c | 5 +- | 57 | tests/qemu-iotests/235 | 2 - |
64 | block/vhdx.c | 120 ++++++++++++++++++++++++++++++++++------ | 58 | tests/qemu-iotests/297 | 52 +++++++----------- |
65 | block/vxhs.c | 5 +- | 59 | tests/qemu-iotests/300 | 5 +- |
66 | cpus.c | 2 - | 60 | tests/qemu-iotests/pylintrc | 6 +- |
67 | qemu-img.c | 34 +++++++----- | 61 | tests/qemu-iotests/tests/image-fleecing | 1 + |
68 | qemu-io.c | 9 ++- | 62 | tests/qemu-iotests/tests/migrate-bitmaps-test | 50 +++++++++-------- |
69 | qemu-nbd.c | 9 ++- | 63 | tests/qemu-iotests/tests/mirror-top-perms | 12 ++-- |
70 | qom/object_interfaces.c | 61 ++++++++++++++++++++ | 64 | 19 files changed, 164 insertions(+), 96 deletions(-) |
71 | replay/replay-events.c | 16 ++++++ | ||
72 | replay/replay.c | 2 + | ||
73 | stubs/replay-user.c | 9 +++ | ||
74 | vl.c | 63 ++++----------------- | ||
75 | stubs/Makefile.objs | 1 + | ||
76 | tests/qemu-iotests/028 | 11 +++- | ||
77 | tests/qemu-iotests/028.out | 1 - | ||
78 | tests/qemu-iotests/268 | 55 ++++++++++++++++++ | ||
79 | tests/qemu-iotests/268.out | 7 +++ | ||
80 | tests/qemu-iotests/270 | 83 +++++++++++++++++++++++++++ | ||
81 | tests/qemu-iotests/270.out | 9 +++ | ||
82 | tests/qemu-iotests/group | 2 + | ||
83 | 32 files changed, 504 insertions(+), 111 deletions(-) | ||
84 | create mode 100644 stubs/replay-user.c | ||
85 | create mode 100755 tests/qemu-iotests/268 | ||
86 | create mode 100644 tests/qemu-iotests/268.out | ||
87 | create mode 100755 tests/qemu-iotests/270 | ||
88 | create mode 100644 tests/qemu-iotests/270.out | ||
89 | 65 | ||
66 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
1 | 2 | ||
3 | There are a couple of errors in bdrv_drained_begin header comment: | ||
4 | - block_job_pause does not exist anymore, it has been replaced | ||
5 | with job_pause in b15de82867 | ||
6 | - job_pause is automatically invoked as a .drained_begin callback | ||
7 | (child_job_drained_begin) by the child_job BdrvChildClass struct | ||
8 | in blockjob.c. So no additional pause should be required. | ||
9 | |||
10 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
11 | Message-Id: <20210903113800.59970-1-eesposit@redhat.com> | ||
12 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
13 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
14 | --- | ||
15 | include/block/block.h | 4 +--- | ||
16 | 1 file changed, 1 insertion(+), 3 deletions(-) | ||
17 | |||
18 | diff --git a/include/block/block.h b/include/block/block.h | ||
19 | index XXXXXXX..XXXXXXX 100644 | ||
20 | --- a/include/block/block.h | ||
21 | +++ b/include/block/block.h | ||
22 | @@ -XXX,XX +XXX,XX @@ bool bdrv_drain_poll(BlockDriverState *bs, bool recursive, | ||
23 | * bdrv_drained_begin: | ||
24 | * | ||
25 | * Begin a quiesced section for exclusive access to the BDS, by disabling | ||
26 | - * external request sources including NBD server and device model. Note that | ||
27 | - * this doesn't block timers or coroutines from submitting more requests, which | ||
28 | - * means block_job_pause is still necessary. | ||
29 | + * external request sources including NBD server, block jobs, and device model. | ||
30 | * | ||
31 | * This function can be recursive. | ||
32 | */ | ||
33 | -- | ||
34 | 2.31.1 | ||
35 | |||
36 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Philippe Mathieu-Daudé <philmd@redhat.com> | ||
1 | 2 | ||
3 | When configuring QEMU with --disable-fuse, the qemu-storage-daemon | ||
4 | still reports FUSE command line options in its help: | ||
5 | |||
6 | $ qemu-storage-daemon -h | ||
7 | Usage: qemu-storage-daemon [options] | ||
8 | QEMU storage daemon | ||
9 | |||
10 | --export [type=]fuse,id=<id>,node-name=<node-name>,mountpoint=<file> | ||
11 | [,growable=on|off][,writable=on|off] | ||
12 | export the specified block node over FUSE | ||
13 | |||
14 | Remove this help message when FUSE is disabled, to avoid: | ||
15 | |||
16 | $ qemu-storage-daemon --export fuse | ||
17 | qemu-storage-daemon: --export fuse: Invalid parameter 'fuse' | ||
18 | |||
19 | Reported-by: Qing Wang <qinwang@redhat.com> | ||
20 | Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com> | ||
21 | Message-Id: <20210816180442.2000642-1-philmd@redhat.com> | ||
22 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
23 | Reviewed-by: Hanna Reitz <hreitz@redhat.com> | ||
24 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
25 | --- | ||
26 | storage-daemon/qemu-storage-daemon.c | 2 ++ | ||
27 | 1 file changed, 2 insertions(+) | ||
28 | |||
29 | diff --git a/storage-daemon/qemu-storage-daemon.c b/storage-daemon/qemu-storage-daemon.c | ||
30 | index XXXXXXX..XXXXXXX 100644 | ||
31 | --- a/storage-daemon/qemu-storage-daemon.c | ||
32 | +++ b/storage-daemon/qemu-storage-daemon.c | ||
33 | @@ -XXX,XX +XXX,XX @@ static void help(void) | ||
34 | " export the specified block node over NBD\n" | ||
35 | " (requires --nbd-server)\n" | ||
36 | "\n" | ||
37 | +#ifdef CONFIG_FUSE | ||
38 | " --export [type=]fuse,id=<id>,node-name=<node-name>,mountpoint=<file>\n" | ||
39 | " [,growable=on|off][,writable=on|off]\n" | ||
40 | " export the specified block node over FUSE\n" | ||
41 | "\n" | ||
42 | +#endif /* CONFIG_FUSE */ | ||
43 | " --monitor [chardev=]name[,mode=control][,pretty[=on|off]]\n" | ||
44 | " configure a QMP monitor\n" | ||
45 | "\n" | ||
46 | -- | ||
47 | 2.31.1 | ||
48 | |||
49 | diff view generated by jsdifflib |
1 | From: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru> | 1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> |
---|---|---|---|
2 | 2 | ||
3 | This patch enables making snapshots with blkreplay used in | 3 | Add version of bdrv_new_open_driver() that supports QDict options. |
4 | block devices. | 4 | We'll use it in further commit. |
5 | This function is required to make bdrv_snapshot_goto without | ||
6 | calling .bdrv_open which is not implemented. | ||
7 | 5 | ||
8 | Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru> | 6 | Simply add one more argument to bdrv_new_open_driver() is worse, as |
9 | Acked-by: Kevin Wolf <kwolf@redhat.com> | 7 | there are too many invocations of bdrv_new_open_driver() to update |
8 | then. | ||
9 | |||
10 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
11 | Suggested-by: Kevin Wolf <kwolf@redhat.com> | ||
12 | Message-Id: <20210920115538.264372-2-vsementsov@virtuozzo.com> | ||
10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 13 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
11 | --- | 14 | --- |
12 | block/blkreplay.c | 8 ++++++++ | 15 | include/block/block.h | 4 ++++ |
13 | 1 file changed, 8 insertions(+) | 16 | block.c | 25 +++++++++++++++++++++---- |
17 | 2 files changed, 25 insertions(+), 4 deletions(-) | ||
14 | 18 | ||
15 | diff --git a/block/blkreplay.c b/block/blkreplay.c | 19 | diff --git a/include/block/block.h b/include/block/block.h |
16 | index XXXXXXX..XXXXXXX 100644 | 20 | index XXXXXXX..XXXXXXX 100644 |
17 | --- a/block/blkreplay.c | 21 | --- a/include/block/block.h |
18 | +++ b/block/blkreplay.c | 22 | +++ b/include/block/block.h |
19 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn blkreplay_co_flush(BlockDriverState *bs) | 23 | @@ -XXX,XX +XXX,XX @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options, |
24 | const char *bdref_key, Error **errp); | ||
25 | BlockDriverState *bdrv_open(const char *filename, const char *reference, | ||
26 | QDict *options, int flags, Error **errp); | ||
27 | +BlockDriverState *bdrv_new_open_driver_opts(BlockDriver *drv, | ||
28 | + const char *node_name, | ||
29 | + QDict *options, int flags, | ||
30 | + Error **errp); | ||
31 | BlockDriverState *bdrv_new_open_driver(BlockDriver *drv, const char *node_name, | ||
32 | int flags, Error **errp); | ||
33 | BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue, | ||
34 | diff --git a/block.c b/block.c | ||
35 | index XXXXXXX..XXXXXXX 100644 | ||
36 | --- a/block.c | ||
37 | +++ b/block.c | ||
38 | @@ -XXX,XX +XXX,XX @@ open_failed: | ||
20 | return ret; | 39 | return ret; |
21 | } | 40 | } |
22 | 41 | ||
23 | +static int blkreplay_snapshot_goto(BlockDriverState *bs, | 42 | -BlockDriverState *bdrv_new_open_driver(BlockDriver *drv, const char *node_name, |
24 | + const char *snapshot_id) | 43 | - int flags, Error **errp) |
44 | +/* | ||
45 | + * Create and open a block node. | ||
46 | + * | ||
47 | + * @options is a QDict of options to pass to the block drivers, or NULL for an | ||
48 | + * empty set of options. The reference to the QDict belongs to the block layer | ||
49 | + * after the call (even on failure), so if the caller intends to reuse the | ||
50 | + * dictionary, it needs to use qobject_ref() before calling bdrv_open. | ||
51 | + */ | ||
52 | +BlockDriverState *bdrv_new_open_driver_opts(BlockDriver *drv, | ||
53 | + const char *node_name, | ||
54 | + QDict *options, int flags, | ||
55 | + Error **errp) | ||
56 | { | ||
57 | BlockDriverState *bs; | ||
58 | int ret; | ||
59 | |||
60 | bs = bdrv_new(); | ||
61 | bs->open_flags = flags; | ||
62 | - bs->explicit_options = qdict_new(); | ||
63 | - bs->options = qdict_new(); | ||
64 | + bs->options = options ?: qdict_new(); | ||
65 | + bs->explicit_options = qdict_clone_shallow(bs->options); | ||
66 | bs->opaque = NULL; | ||
67 | |||
68 | update_options_from_flags(bs->options, flags); | ||
69 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_new_open_driver(BlockDriver *drv, const char *node_name, | ||
70 | return bs; | ||
71 | } | ||
72 | |||
73 | +/* Create and open a block node. */ | ||
74 | +BlockDriverState *bdrv_new_open_driver(BlockDriver *drv, const char *node_name, | ||
75 | + int flags, Error **errp) | ||
25 | +{ | 76 | +{ |
26 | + return bdrv_snapshot_goto(bs->file->bs, snapshot_id, NULL); | 77 | + return bdrv_new_open_driver_opts(drv, node_name, NULL, flags, errp); |
27 | +} | 78 | +} |
28 | + | 79 | + |
29 | static BlockDriver bdrv_blkreplay = { | 80 | QemuOptsList bdrv_runtime_opts = { |
30 | .format_name = "blkreplay", | 81 | .name = "bdrv_common", |
31 | .instance_size = 0, | 82 | .head = QTAILQ_HEAD_INITIALIZER(bdrv_runtime_opts.head), |
32 | @@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_blkreplay = { | ||
33 | .bdrv_co_pwrite_zeroes = blkreplay_co_pwrite_zeroes, | ||
34 | .bdrv_co_pdiscard = blkreplay_co_pdiscard, | ||
35 | .bdrv_co_flush = blkreplay_co_flush, | ||
36 | + | ||
37 | + .bdrv_snapshot_goto = blkreplay_snapshot_goto, | ||
38 | }; | ||
39 | |||
40 | static void bdrv_blkreplay_init(void) | ||
41 | -- | 83 | -- |
42 | 2.20.1 | 84 | 2.31.1 |
43 | 85 | ||
44 | 86 | diff view generated by jsdifflib |
1 | From: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru> | 1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> |
---|---|---|---|
2 | 2 | ||
3 | In record/replay mode bdrv queue is controlled by replay mechanism. | 3 | - use ERRP_GUARD(): function calls error_prepend(), so it must use |
4 | It does not allow saving or loading the snapshots | 4 | ERRP_GUARD(), otherwise error_prepend() would not be called when |
5 | when bdrv queue is not empty. Stopping the VM is not blocked by nonempty | 5 | passed errp is error_fatal |
6 | queue, but flushing the queue is still impossible there, | ||
7 | because it may cause deadlocks in replay mode. | ||
8 | This patch disables bdrv_drain_all and bdrv_flush_all in | ||
9 | record/replay mode. | ||
10 | 6 | ||
11 | Stopping the machine when the IO requests are not finished is needed | 7 | - drop error propagation, handle return code instead |
12 | for the debugging. E.g., breakpoint may be set at the specified step, | ||
13 | and forcing the IO requests to finish may break the determinism | ||
14 | of the execution. | ||
15 | 8 | ||
16 | Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru> | 9 | - for symmetry, do error_prepend() for the second failure |
17 | Acked-by: Kevin Wolf <kwolf@redhat.com> | 10 | |
11 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
12 | Message-Id: <20210920115538.264372-3-vsementsov@virtuozzo.com> | ||
18 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 13 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
19 | --- | 14 | --- |
20 | block/io.c | 28 ++++++++++++++++++++++++++++ | 15 | block.c | 9 +++++---- |
21 | cpus.c | 2 -- | 16 | 1 file changed, 5 insertions(+), 4 deletions(-) |
22 | 2 files changed, 28 insertions(+), 2 deletions(-) | ||
23 | 17 | ||
24 | diff --git a/block/io.c b/block/io.c | 18 | diff --git a/block.c b/block.c |
25 | index XXXXXXX..XXXXXXX 100644 | 19 | index XXXXXXX..XXXXXXX 100644 |
26 | --- a/block/io.c | 20 | --- a/block.c |
27 | +++ b/block/io.c | 21 | +++ b/block.c |
28 | @@ -XXX,XX +XXX,XX @@ | 22 | @@ -XXX,XX +XXX,XX @@ static void bdrv_delete(BlockDriverState *bs) |
29 | #include "qapi/error.h" | 23 | BlockDriverState *bdrv_insert_node(BlockDriverState *bs, QDict *node_options, |
30 | #include "qemu/error-report.h" | 24 | int flags, Error **errp) |
31 | #include "qemu/main-loop.h" | 25 | { |
32 | +#include "sysemu/replay.h" | 26 | + ERRP_GUARD(); |
33 | 27 | + int ret; | |
34 | #define NOT_DONE 0x7fffffff /* used while emulated sync operation in progress */ | 28 | BlockDriverState *new_node_bs; |
35 | 29 | - Error *local_err = NULL; | |
36 | @@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void) | 30 | |
37 | return; | 31 | new_node_bs = bdrv_open(NULL, NULL, node_options, flags, errp); |
32 | if (new_node_bs == NULL) { | ||
33 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_insert_node(BlockDriverState *bs, QDict *node_options, | ||
38 | } | 34 | } |
39 | 35 | ||
40 | + /* | 36 | bdrv_drained_begin(bs); |
41 | + * bdrv queue is managed by record/replay, | 37 | - bdrv_replace_node(bs, new_node_bs, &local_err); |
42 | + * waiting for finishing the I/O requests may | 38 | + ret = bdrv_replace_node(bs, new_node_bs, errp); |
43 | + * be infinite | 39 | bdrv_drained_end(bs); |
44 | + */ | 40 | |
45 | + if (replay_events_enabled()) { | 41 | - if (local_err) { |
46 | + return; | 42 | + if (ret < 0) { |
47 | + } | 43 | + error_prepend(errp, "Could not replace node: "); |
48 | + | 44 | bdrv_unref(new_node_bs); |
49 | /* AIO_WAIT_WHILE() with a NULL context can only be called from the main | 45 | - error_propagate(errp, local_err); |
50 | * loop AioContext, so make sure we're in the main context. */ | 46 | return NULL; |
51 | assert(qemu_get_current_aio_context() == qemu_get_aio_context()); | ||
52 | @@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_end(void) | ||
53 | BlockDriverState *bs = NULL; | ||
54 | int drained_end_counter = 0; | ||
55 | |||
56 | + /* | ||
57 | + * bdrv queue is managed by record/replay, | ||
58 | + * waiting for finishing the I/O requests may | ||
59 | + * be endless | ||
60 | + */ | ||
61 | + if (replay_events_enabled()) { | ||
62 | + return; | ||
63 | + } | ||
64 | + | ||
65 | while ((bs = bdrv_next_all_states(bs))) { | ||
66 | AioContext *aio_context = bdrv_get_aio_context(bs); | ||
67 | |||
68 | @@ -XXX,XX +XXX,XX @@ int bdrv_flush_all(void) | ||
69 | BlockDriverState *bs = NULL; | ||
70 | int result = 0; | ||
71 | |||
72 | + /* | ||
73 | + * bdrv queue is managed by record/replay, | ||
74 | + * creating new flush request for stopping | ||
75 | + * the VM may break the determinism | ||
76 | + */ | ||
77 | + if (replay_events_enabled()) { | ||
78 | + return result; | ||
79 | + } | ||
80 | + | ||
81 | for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { | ||
82 | AioContext *aio_context = bdrv_get_aio_context(bs); | ||
83 | int ret; | ||
84 | diff --git a/cpus.c b/cpus.c | ||
85 | index XXXXXXX..XXXXXXX 100644 | ||
86 | --- a/cpus.c | ||
87 | +++ b/cpus.c | ||
88 | @@ -XXX,XX +XXX,XX @@ static int do_vm_stop(RunState state, bool send_stop) | ||
89 | } | 47 | } |
90 | 48 | ||
91 | bdrv_drain_all(); | ||
92 | - replay_disable_events(); | ||
93 | ret = bdrv_flush_all(); | ||
94 | |||
95 | return ret; | ||
96 | @@ -XXX,XX +XXX,XX @@ int vm_prepare_start(void) | ||
97 | /* We are sending this now, but the CPUs will be resumed shortly later */ | ||
98 | qapi_event_send_resume(); | ||
99 | |||
100 | - replay_enable_events(); | ||
101 | cpu_enable_ticks(); | ||
102 | runstate_set(RUN_STATE_RUNNING); | ||
103 | vm_state_notify(1, RUN_STATE_RUNNING); | ||
104 | -- | 49 | -- |
105 | 2.20.1 | 50 | 2.31.1 |
106 | 51 | ||
107 | 52 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
1 | 2 | ||
3 | - options & flags is common pair for open-like functions, let's use it | ||
4 | - add a comment that specifies use of @options | ||
5 | |||
6 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
7 | Message-Id: <20210920115538.264372-4-vsementsov@virtuozzo.com> | ||
8 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
9 | --- | ||
10 | block.c | 13 +++++++++++-- | ||
11 | 1 file changed, 11 insertions(+), 2 deletions(-) | ||
12 | |||
13 | diff --git a/block.c b/block.c | ||
14 | index XXXXXXX..XXXXXXX 100644 | ||
15 | --- a/block.c | ||
16 | +++ b/block.c | ||
17 | @@ -XXX,XX +XXX,XX @@ static void bdrv_delete(BlockDriverState *bs) | ||
18 | g_free(bs); | ||
19 | } | ||
20 | |||
21 | -BlockDriverState *bdrv_insert_node(BlockDriverState *bs, QDict *node_options, | ||
22 | + | ||
23 | +/* | ||
24 | + * Replace @bs by newly created block node. | ||
25 | + * | ||
26 | + * @options is a QDict of options to pass to the block drivers, or NULL for an | ||
27 | + * empty set of options. The reference to the QDict belongs to the block layer | ||
28 | + * after the call (even on failure), so if the caller intends to reuse the | ||
29 | + * dictionary, it needs to use qobject_ref() before calling bdrv_open. | ||
30 | + */ | ||
31 | +BlockDriverState *bdrv_insert_node(BlockDriverState *bs, QDict *options, | ||
32 | int flags, Error **errp) | ||
33 | { | ||
34 | ERRP_GUARD(); | ||
35 | int ret; | ||
36 | BlockDriverState *new_node_bs; | ||
37 | |||
38 | - new_node_bs = bdrv_open(NULL, NULL, node_options, flags, errp); | ||
39 | + new_node_bs = bdrv_open(NULL, NULL, options, flags, errp); | ||
40 | if (new_node_bs == NULL) { | ||
41 | error_prepend(errp, "Could not create node: "); | ||
42 | return NULL; | ||
43 | -- | ||
44 | 2.31.1 | ||
45 | |||
46 | diff view generated by jsdifflib |
1 | From: Alberto Garcia <berto@igalia.com> | 1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> |
---|---|---|---|
2 | 2 | ||
3 | The BDRV_REQ_NO_FALLBACK flag means that an operation should only be | 3 | Use bdrv_new_open_driver_opts() instead of complicated bdrv_open(). |
4 | performed if it can be offloaded or otherwise performed efficiently. | ||
5 | 4 | ||
6 | However a misaligned write request requires a RMW so we should return | 5 | Among other extra things bdrv_open() also check for white-listed |
7 | an error and let the caller decide how to proceed. | 6 | formats, which we don't want for internal node creation: currently |
7 | backup doesn't work when copy-before-write filter is not white-listed. | ||
8 | As well block-stream doesn't work when copy-on-read is not | ||
9 | white-listed. | ||
8 | 10 | ||
9 | This hits an assertion since commit c8bb23cbdb if the required | 11 | Fixes: 751cec7a261adaf1145dc7adf6de7c9c084e5a0b |
10 | alignment is larger than the cluster size: | 12 | Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=2004812 |
11 | 13 | Reported-by: Yanan Fu | |
12 | qemu-img create -f qcow2 -o cluster_size=2k img.qcow2 4G | 14 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> |
13 | qemu-io -c "open -o driver=qcow2,file.align=4k blkdebug::img.qcow2" \ | 15 | Message-Id: <20210920115538.264372-5-vsementsov@virtuozzo.com> |
14 | -c 'write 0 512' | ||
15 | qemu-io: block/io.c:1127: bdrv_driver_pwritev: Assertion `!(flags & BDRV_REQ_NO_FALLBACK)' failed. | ||
16 | Aborted | ||
17 | |||
18 | The reason is that when writing to an unallocated cluster we try to | ||
19 | skip the copy-on-write part and zeroize it using BDRV_REQ_NO_FALLBACK | ||
20 | instead, resulting in a write request that is too small (2KB cluster | ||
21 | size vs 4KB required alignment). | ||
22 | |||
23 | Signed-off-by: Alberto Garcia <berto@igalia.com> | ||
24 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 16 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
25 | --- | 17 | --- |
26 | block/io.c | 7 +++++ | 18 | block.c | 34 ++++++++++++++++++++++++++++------ |
27 | tests/qemu-iotests/268 | 55 ++++++++++++++++++++++++++++++++++++++ | 19 | 1 file changed, 28 insertions(+), 6 deletions(-) |
28 | tests/qemu-iotests/268.out | 7 +++++ | ||
29 | tests/qemu-iotests/group | 1 + | ||
30 | 4 files changed, 70 insertions(+) | ||
31 | create mode 100755 tests/qemu-iotests/268 | ||
32 | create mode 100644 tests/qemu-iotests/268.out | ||
33 | 20 | ||
34 | diff --git a/block/io.c b/block/io.c | 21 | diff --git a/block.c b/block.c |
35 | index XXXXXXX..XXXXXXX 100644 | 22 | index XXXXXXX..XXXXXXX 100644 |
36 | --- a/block/io.c | 23 | --- a/block.c |
37 | +++ b/block/io.c | 24 | +++ b/block.c |
38 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_pwritev_part(BdrvChild *child, | 25 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_insert_node(BlockDriverState *bs, QDict *options, |
39 | return ret; | 26 | { |
40 | } | 27 | ERRP_GUARD(); |
41 | 28 | int ret; | |
42 | + /* If the request is misaligned then we can't make it efficient */ | 29 | - BlockDriverState *new_node_bs; |
43 | + if ((flags & BDRV_REQ_NO_FALLBACK) && | 30 | + BlockDriverState *new_node_bs = NULL; |
44 | + !QEMU_IS_ALIGNED(offset | bytes, align)) | 31 | + const char *drvname, *node_name; |
45 | + { | 32 | + BlockDriver *drv; |
46 | + return -ENOTSUP; | 33 | + |
34 | + drvname = qdict_get_try_str(options, "driver"); | ||
35 | + if (!drvname) { | ||
36 | + error_setg(errp, "driver is not specified"); | ||
37 | + goto fail; | ||
47 | + } | 38 | + } |
48 | + | 39 | + |
49 | bdrv_inc_in_flight(bs); | 40 | + drv = bdrv_find_format(drvname); |
50 | /* | 41 | + if (!drv) { |
51 | * Align write if necessary by performing a read-modify-write cycle. | 42 | + error_setg(errp, "Unknown driver: '%s'", drvname); |
52 | diff --git a/tests/qemu-iotests/268 b/tests/qemu-iotests/268 | 43 | + goto fail; |
53 | new file mode 100755 | 44 | + } |
54 | index XXXXXXX..XXXXXXX | 45 | |
55 | --- /dev/null | 46 | - new_node_bs = bdrv_open(NULL, NULL, options, flags, errp); |
56 | +++ b/tests/qemu-iotests/268 | 47 | - if (new_node_bs == NULL) { |
57 | @@ -XXX,XX +XXX,XX @@ | 48 | + node_name = qdict_get_try_str(options, "node-name"); |
58 | +#!/usr/bin/env bash | ||
59 | +# | ||
60 | +# Test write request with required alignment larger than the cluster size | ||
61 | +# | ||
62 | +# Copyright (C) 2019 Igalia, S.L. | ||
63 | +# Author: Alberto Garcia <berto@igalia.com> | ||
64 | +# | ||
65 | +# This program is free software; you can redistribute it and/or modify | ||
66 | +# it under the terms of the GNU General Public License as published by | ||
67 | +# the Free Software Foundation; either version 2 of the License, or | ||
68 | +# (at your option) any later version. | ||
69 | +# | ||
70 | +# This program is distributed in the hope that it will be useful, | ||
71 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
72 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
73 | +# GNU General Public License for more details. | ||
74 | +# | ||
75 | +# You should have received a copy of the GNU General Public License | ||
76 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
77 | +# | ||
78 | + | 49 | + |
79 | +# creator | 50 | + new_node_bs = bdrv_new_open_driver_opts(drv, node_name, options, flags, |
80 | +owner=berto@igalia.com | 51 | + errp); |
52 | + options = NULL; /* bdrv_new_open_driver() eats options */ | ||
53 | + if (!new_node_bs) { | ||
54 | error_prepend(errp, "Could not create node: "); | ||
55 | - return NULL; | ||
56 | + goto fail; | ||
57 | } | ||
58 | |||
59 | bdrv_drained_begin(bs); | ||
60 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_insert_node(BlockDriverState *bs, QDict *options, | ||
61 | |||
62 | if (ret < 0) { | ||
63 | error_prepend(errp, "Could not replace node: "); | ||
64 | - bdrv_unref(new_node_bs); | ||
65 | - return NULL; | ||
66 | + goto fail; | ||
67 | } | ||
68 | |||
69 | return new_node_bs; | ||
81 | + | 70 | + |
82 | +seq=`basename $0` | 71 | +fail: |
83 | +echo "QA output created by $seq" | 72 | + qobject_unref(options); |
84 | + | 73 | + bdrv_unref(new_node_bs); |
85 | +status=1 # failure is the default! | 74 | + return NULL; |
86 | + | 75 | } |
87 | +_cleanup() | 76 | |
88 | +{ | 77 | /* |
89 | + _cleanup_test_img | ||
90 | +} | ||
91 | +trap "_cleanup; exit \$status" 0 1 2 3 15 | ||
92 | + | ||
93 | +# get standard environment, filters and checks | ||
94 | +. ./common.rc | ||
95 | +. ./common.filter | ||
96 | + | ||
97 | +_supported_fmt qcow2 | ||
98 | +_supported_proto file | ||
99 | + | ||
100 | +echo | ||
101 | +echo "== Required alignment larger than cluster size ==" | ||
102 | + | ||
103 | +CLUSTER_SIZE=2k _make_test_img 1M | ||
104 | +# Since commit c8bb23cbdb writing to an unallocated cluster fills the | ||
105 | +# empty COW areas with bdrv_write_zeroes(flags=BDRV_REQ_NO_FALLBACK) | ||
106 | +$QEMU_IO -c "open -o driver=$IMGFMT,file.align=4k blkdebug::$TEST_IMG" \ | ||
107 | + -c "write 0 512" | _filter_qemu_io | ||
108 | + | ||
109 | +# success, all done | ||
110 | +echo "*** done" | ||
111 | +rm -f $seq.full | ||
112 | +status=0 | ||
113 | diff --git a/tests/qemu-iotests/268.out b/tests/qemu-iotests/268.out | ||
114 | new file mode 100644 | ||
115 | index XXXXXXX..XXXXXXX | ||
116 | --- /dev/null | ||
117 | +++ b/tests/qemu-iotests/268.out | ||
118 | @@ -XXX,XX +XXX,XX @@ | ||
119 | +QA output created by 268 | ||
120 | + | ||
121 | +== Required alignment larger than cluster size == | ||
122 | +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 | ||
123 | +wrote 512/512 bytes at offset 0 | ||
124 | +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
125 | +*** done | ||
126 | diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group | ||
127 | index XXXXXXX..XXXXXXX 100644 | ||
128 | --- a/tests/qemu-iotests/group | ||
129 | +++ b/tests/qemu-iotests/group | ||
130 | @@ -XXX,XX +XXX,XX @@ | ||
131 | 265 rw auto quick | ||
132 | 266 rw quick | ||
133 | 267 rw auto quick snapshot | ||
134 | +268 rw auto quick | ||
135 | -- | 78 | -- |
136 | 2.20.1 | 79 | 2.31.1 |
137 | 80 | ||
138 | 81 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
1 | 2 | ||
3 | Now test fails if copy-before-write is not white-listed. | ||
4 | Let's skip test instead. | ||
5 | |||
6 | Fixes: c0605985696a19ef034fa25d04f53f3b3b383896 | ||
7 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
8 | Message-Id: <20210920115538.264372-6-vsementsov@virtuozzo.com> | ||
9 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
10 | --- | ||
11 | tests/qemu-iotests/tests/image-fleecing | 1 + | ||
12 | 1 file changed, 1 insertion(+) | ||
13 | |||
14 | diff --git a/tests/qemu-iotests/tests/image-fleecing b/tests/qemu-iotests/tests/image-fleecing | ||
15 | index XXXXXXX..XXXXXXX 100755 | ||
16 | --- a/tests/qemu-iotests/tests/image-fleecing | ||
17 | +++ b/tests/qemu-iotests/tests/image-fleecing | ||
18 | @@ -XXX,XX +XXX,XX @@ from iotests import log, qemu_img, qemu_io, qemu_io_silent | ||
19 | iotests.script_initialize( | ||
20 | supported_fmts=['qcow2', 'qcow', 'qed', 'vmdk', 'vhdx', 'raw'], | ||
21 | supported_platforms=['linux'], | ||
22 | + required_fmts=['copy-before-write'], | ||
23 | ) | ||
24 | |||
25 | patterns = [('0x5d', '0', '64k'), | ||
26 | -- | ||
27 | 2.31.1 | ||
28 | |||
29 | diff view generated by jsdifflib |
1 | From: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru> | 1 | From: Paolo Bonzini <pbonzini@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Replay is capable of recording normal BH events, but sometimes | 3 | Linux limits the size of iovecs to 1024 (UIO_MAXIOV in the kernel |
4 | there are single use callbacks scheduled with aio_bh_schedule_oneshot | 4 | sources, IOV_MAX in POSIX). Because of this, on some host adapters |
5 | function. This patch enables recording and replaying such callbacks. | 5 | requests with many iovecs are rejected with -EINVAL by the |
6 | Block layer uses these events for calling the completion function. | 6 | io_submit() or readv()/writev() system calls. |
7 | Replaying these calls makes the execution deterministic. | ||
8 | 7 | ||
9 | Signed-off-by: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru> | 8 | In fact, the same limit applies to SG_IO as well. To fix both the |
10 | Acked-by: Kevin Wolf <kwolf@redhat.com> | 9 | EINVAL and the possible performance issues from using fewer iovecs |
10 | than allowed by Linux (some HBAs have max_segments as low as 128), | ||
11 | introduce a separate entry in BlockLimits to hold the max_segments | ||
12 | value from sysfs. This new limit is used only for SG_IO and clamped | ||
13 | to bs->bl.max_iov anyway, just like max_hw_transfer is clamped to | ||
14 | bs->bl.max_transfer. | ||
15 | |||
16 | Reported-by: Halil Pasic <pasic@linux.ibm.com> | ||
17 | Cc: Hanna Reitz <hreitz@redhat.com> | ||
18 | Cc: Kevin Wolf <kwolf@redhat.com> | ||
19 | Cc: qemu-block@nongnu.org | ||
20 | Cc: qemu-stable@nongnu.org | ||
21 | Fixes: 18473467d5 ("file-posix: try BLKSECTGET on block devices too, do not round to power of 2", 2021-06-25) | ||
22 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> | ||
23 | Message-Id: <20210923130436.1187591-1-pbonzini@redhat.com> | ||
11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 24 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
12 | --- | 25 | --- |
13 | include/sysemu/replay.h | 4 ++++ | 26 | include/block/block_int.h | 7 +++++++ |
14 | replay/replay-internal.h | 1 + | 27 | include/sysemu/block-backend.h | 1 + |
15 | block/block-backend.c | 9 ++++++--- | 28 | block/block-backend.c | 6 ++++++ |
16 | block/io.c | 4 ++-- | 29 | block/file-posix.c | 2 +- |
17 | block/iscsi.c | 5 +++-- | 30 | block/io.c | 1 + |
18 | block/nfs.c | 6 ++++-- | 31 | hw/scsi/scsi-generic.c | 2 +- |
19 | block/null.c | 4 +++- | 32 | 6 files changed, 17 insertions(+), 2 deletions(-) |
20 | block/nvme.c | 6 ++++-- | ||
21 | block/rbd.c | 5 +++-- | ||
22 | block/vxhs.c | 5 +++-- | ||
23 | replay/replay-events.c | 16 ++++++++++++++++ | ||
24 | stubs/replay-user.c | 9 +++++++++ | ||
25 | stubs/Makefile.objs | 1 + | ||
26 | 13 files changed, 59 insertions(+), 16 deletions(-) | ||
27 | create mode 100644 stubs/replay-user.c | ||
28 | 33 | ||
29 | diff --git a/include/sysemu/replay.h b/include/sysemu/replay.h | 34 | diff --git a/include/block/block_int.h b/include/block/block_int.h |
30 | index XXXXXXX..XXXXXXX 100644 | 35 | index XXXXXXX..XXXXXXX 100644 |
31 | --- a/include/sysemu/replay.h | 36 | --- a/include/block/block_int.h |
32 | +++ b/include/sysemu/replay.h | 37 | +++ b/include/block/block_int.h |
33 | @@ -XXX,XX +XXX,XX @@ | 38 | @@ -XXX,XX +XXX,XX @@ typedef struct BlockLimits { |
34 | #include "qapi/qapi-types-misc.h" | 39 | */ |
35 | #include "qapi/qapi-types-run-state.h" | 40 | uint64_t max_hw_transfer; |
36 | #include "qapi/qapi-types-ui.h" | 41 | |
37 | +#include "block/aio.h" | 42 | + /* Maximal number of scatter/gather elements allowed by the hardware. |
38 | 43 | + * Applies whenever transfers to the device bypass the kernel I/O | |
39 | /* replay clock kinds */ | 44 | + * scheduler, for example with SG_IO. If larger than max_iov |
40 | enum ReplayClockKind { | 45 | + * or if zero, blk_get_max_hw_iov will fall back to max_iov. |
41 | @@ -XXX,XX +XXX,XX @@ void replay_enable_events(void); | 46 | + */ |
42 | bool replay_events_enabled(void); | 47 | + int max_hw_iov; |
43 | /*! Adds bottom half event to the queue */ | 48 | + |
44 | void replay_bh_schedule_event(QEMUBH *bh); | 49 | /* memory alignment, in bytes so that no bounce buffer is needed */ |
45 | +/* Adds oneshot bottom half event to the queue */ | 50 | size_t min_mem_alignment; |
46 | +void replay_bh_schedule_oneshot_event(AioContext *ctx, | 51 | |
47 | + QEMUBHFunc *cb, void *opaque); | 52 | diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h |
48 | /*! Adds input event to the queue */ | ||
49 | void replay_input_event(QemuConsole *src, InputEvent *evt); | ||
50 | /*! Adds input sync event to the queue */ | ||
51 | diff --git a/replay/replay-internal.h b/replay/replay-internal.h | ||
52 | index XXXXXXX..XXXXXXX 100644 | 53 | index XXXXXXX..XXXXXXX 100644 |
53 | --- a/replay/replay-internal.h | 54 | --- a/include/sysemu/block-backend.h |
54 | +++ b/replay/replay-internal.h | 55 | +++ b/include/sysemu/block-backend.h |
55 | @@ -XXX,XX +XXX,XX @@ enum ReplayEvents { | 56 | @@ -XXX,XX +XXX,XX @@ uint32_t blk_get_request_alignment(BlockBackend *blk); |
56 | 57 | uint32_t blk_get_max_transfer(BlockBackend *blk); | |
57 | enum ReplayAsyncEventKind { | 58 | uint64_t blk_get_max_hw_transfer(BlockBackend *blk); |
58 | REPLAY_ASYNC_EVENT_BH, | 59 | int blk_get_max_iov(BlockBackend *blk); |
59 | + REPLAY_ASYNC_EVENT_BH_ONESHOT, | 60 | +int blk_get_max_hw_iov(BlockBackend *blk); |
60 | REPLAY_ASYNC_EVENT_INPUT, | 61 | void blk_set_guest_block_size(BlockBackend *blk, int align); |
61 | REPLAY_ASYNC_EVENT_INPUT_SYNC, | 62 | void *blk_try_blockalign(BlockBackend *blk, size_t size); |
62 | REPLAY_ASYNC_EVENT_CHAR_READ, | 63 | void *blk_blockalign(BlockBackend *blk, size_t size); |
63 | diff --git a/block/block-backend.c b/block/block-backend.c | 64 | diff --git a/block/block-backend.c b/block/block-backend.c |
64 | index XXXXXXX..XXXXXXX 100644 | 65 | index XXXXXXX..XXXXXXX 100644 |
65 | --- a/block/block-backend.c | 66 | --- a/block/block-backend.c |
66 | +++ b/block/block-backend.c | 67 | +++ b/block/block-backend.c |
67 | @@ -XXX,XX +XXX,XX @@ | 68 | @@ -XXX,XX +XXX,XX @@ uint32_t blk_get_max_transfer(BlockBackend *blk) |
68 | #include "hw/qdev-core.h" | 69 | return ROUND_DOWN(max, blk_get_request_alignment(blk)); |
69 | #include "sysemu/blockdev.h" | ||
70 | #include "sysemu/runstate.h" | ||
71 | +#include "sysemu/sysemu.h" | ||
72 | +#include "sysemu/replay.h" | ||
73 | #include "qapi/error.h" | ||
74 | #include "qapi/qapi-events-block.h" | ||
75 | #include "qemu/id.h" | ||
76 | @@ -XXX,XX +XXX,XX @@ BlockAIOCB *blk_abort_aio_request(BlockBackend *blk, | ||
77 | acb->blk = blk; | ||
78 | acb->ret = ret; | ||
79 | |||
80 | - aio_bh_schedule_oneshot(blk_get_aio_context(blk), error_callback_bh, acb); | ||
81 | + replay_bh_schedule_oneshot_event(blk_get_aio_context(blk), | ||
82 | + error_callback_bh, acb); | ||
83 | return &acb->common; | ||
84 | } | 70 | } |
85 | 71 | ||
86 | @@ -XXX,XX +XXX,XX @@ static BlockAIOCB *blk_aio_prwv(BlockBackend *blk, int64_t offset, int bytes, | 72 | +int blk_get_max_hw_iov(BlockBackend *blk) |
87 | 73 | +{ | |
88 | acb->has_returned = true; | 74 | + return MIN_NON_ZERO(blk->root->bs->bl.max_hw_iov, |
89 | if (acb->rwco.ret != NOT_DONE) { | 75 | + blk->root->bs->bl.max_iov); |
90 | - aio_bh_schedule_oneshot(blk_get_aio_context(blk), | 76 | +} |
91 | - blk_aio_complete_bh, acb); | 77 | + |
92 | + replay_bh_schedule_oneshot_event(blk_get_aio_context(blk), | 78 | int blk_get_max_iov(BlockBackend *blk) |
93 | + blk_aio_complete_bh, acb); | 79 | { |
80 | return blk->root->bs->bl.max_iov; | ||
81 | diff --git a/block/file-posix.c b/block/file-posix.c | ||
82 | index XXXXXXX..XXXXXXX 100644 | ||
83 | --- a/block/file-posix.c | ||
84 | +++ b/block/file-posix.c | ||
85 | @@ -XXX,XX +XXX,XX @@ static void raw_refresh_limits(BlockDriverState *bs, Error **errp) | ||
86 | |||
87 | ret = hdev_get_max_segments(s->fd, &st); | ||
88 | if (ret > 0) { | ||
89 | - bs->bl.max_iov = ret; | ||
90 | + bs->bl.max_hw_iov = ret; | ||
91 | } | ||
94 | } | 92 | } |
95 | 93 | } | |
96 | return &acb->common; | ||
97 | diff --git a/block/io.c b/block/io.c | 94 | diff --git a/block/io.c b/block/io.c |
98 | index XXXXXXX..XXXXXXX 100644 | 95 | index XXXXXXX..XXXXXXX 100644 |
99 | --- a/block/io.c | 96 | --- a/block/io.c |
100 | +++ b/block/io.c | 97 | +++ b/block/io.c |
101 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs, | 98 | @@ -XXX,XX +XXX,XX @@ static void bdrv_merge_limits(BlockLimits *dst, const BlockLimits *src) |
102 | if (bs) { | 99 | dst->min_mem_alignment = MAX(dst->min_mem_alignment, |
103 | bdrv_inc_in_flight(bs); | 100 | src->min_mem_alignment); |
104 | } | 101 | dst->max_iov = MIN_NON_ZERO(dst->max_iov, src->max_iov); |
105 | - aio_bh_schedule_oneshot(bdrv_get_aio_context(bs), | 102 | + dst->max_hw_iov = MIN_NON_ZERO(dst->max_hw_iov, src->max_hw_iov); |
106 | - bdrv_co_drain_bh_cb, &data); | 103 | } |
107 | + replay_bh_schedule_oneshot_event(bdrv_get_aio_context(bs), | 104 | |
108 | + bdrv_co_drain_bh_cb, &data); | 105 | typedef struct BdrvRefreshLimitsState { |
109 | 106 | diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c | |
110 | qemu_coroutine_yield(); | ||
111 | /* If we are resumed from some other event (such as an aio completion or a | ||
112 | diff --git a/block/iscsi.c b/block/iscsi.c | ||
113 | index XXXXXXX..XXXXXXX 100644 | 107 | index XXXXXXX..XXXXXXX 100644 |
114 | --- a/block/iscsi.c | 108 | --- a/hw/scsi/scsi-generic.c |
115 | +++ b/block/iscsi.c | 109 | +++ b/hw/scsi/scsi-generic.c |
116 | @@ -XXX,XX +XXX,XX @@ | 110 | @@ -XXX,XX +XXX,XX @@ static int scsi_handle_inquiry_reply(SCSIGenericReq *r, SCSIDevice *s, int len) |
117 | #include "qemu/module.h" | 111 | page = r->req.cmd.buf[2]; |
118 | #include "qemu/option.h" | 112 | if (page == 0xb0) { |
119 | #include "qemu/uuid.h" | 113 | uint64_t max_transfer = blk_get_max_hw_transfer(s->conf.blk); |
120 | +#include "sysemu/replay.h" | 114 | - uint32_t max_iov = blk_get_max_iov(s->conf.blk); |
121 | #include "qapi/error.h" | 115 | + uint32_t max_iov = blk_get_max_hw_iov(s->conf.blk); |
122 | #include "qapi/qapi-commands-misc.h" | 116 | |
123 | #include "qapi/qmp/qdict.h" | 117 | assert(max_transfer); |
124 | @@ -XXX,XX +XXX,XX @@ iscsi_co_generic_cb(struct iscsi_context *iscsi, int status, | 118 | max_transfer = MIN_NON_ZERO(max_transfer, max_iov * qemu_real_host_page_size) |
125 | } | ||
126 | |||
127 | if (iTask->co) { | ||
128 | - aio_bh_schedule_oneshot(iTask->iscsilun->aio_context, | ||
129 | - iscsi_co_generic_bh_cb, iTask); | ||
130 | + replay_bh_schedule_oneshot_event(iTask->iscsilun->aio_context, | ||
131 | + iscsi_co_generic_bh_cb, iTask); | ||
132 | } else { | ||
133 | iTask->complete = 1; | ||
134 | } | ||
135 | diff --git a/block/nfs.c b/block/nfs.c | ||
136 | index XXXXXXX..XXXXXXX 100644 | ||
137 | --- a/block/nfs.c | ||
138 | +++ b/block/nfs.c | ||
139 | @@ -XXX,XX +XXX,XX @@ | ||
140 | #include "qemu/option.h" | ||
141 | #include "qemu/uri.h" | ||
142 | #include "qemu/cutils.h" | ||
143 | +#include "sysemu/sysemu.h" | ||
144 | +#include "sysemu/replay.h" | ||
145 | #include "qapi/qapi-visit-block-core.h" | ||
146 | #include "qapi/qmp/qdict.h" | ||
147 | #include "qapi/qmp/qstring.h" | ||
148 | @@ -XXX,XX +XXX,XX @@ nfs_co_generic_cb(int ret, struct nfs_context *nfs, void *data, | ||
149 | if (task->ret < 0) { | ||
150 | error_report("NFS Error: %s", nfs_get_error(nfs)); | ||
151 | } | ||
152 | - aio_bh_schedule_oneshot(task->client->aio_context, | ||
153 | - nfs_co_generic_bh_cb, task); | ||
154 | + replay_bh_schedule_oneshot_event(task->client->aio_context, | ||
155 | + nfs_co_generic_bh_cb, task); | ||
156 | } | ||
157 | |||
158 | static int coroutine_fn nfs_co_preadv(BlockDriverState *bs, uint64_t offset, | ||
159 | diff --git a/block/null.c b/block/null.c | ||
160 | index XXXXXXX..XXXXXXX 100644 | ||
161 | --- a/block/null.c | ||
162 | +++ b/block/null.c | ||
163 | @@ -XXX,XX +XXX,XX @@ | ||
164 | #include "qemu/module.h" | ||
165 | #include "qemu/option.h" | ||
166 | #include "block/block_int.h" | ||
167 | +#include "sysemu/replay.h" | ||
168 | |||
169 | #define NULL_OPT_LATENCY "latency-ns" | ||
170 | #define NULL_OPT_ZEROES "read-zeroes" | ||
171 | @@ -XXX,XX +XXX,XX @@ static inline BlockAIOCB *null_aio_common(BlockDriverState *bs, | ||
172 | timer_mod_ns(&acb->timer, | ||
173 | qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + s->latency_ns); | ||
174 | } else { | ||
175 | - aio_bh_schedule_oneshot(bdrv_get_aio_context(bs), null_bh_cb, acb); | ||
176 | + replay_bh_schedule_oneshot_event(bdrv_get_aio_context(bs), | ||
177 | + null_bh_cb, acb); | ||
178 | } | ||
179 | return &acb->common; | ||
180 | } | ||
181 | diff --git a/block/nvme.c b/block/nvme.c | ||
182 | index XXXXXXX..XXXXXXX 100644 | ||
183 | --- a/block/nvme.c | ||
184 | +++ b/block/nvme.c | ||
185 | @@ -XXX,XX +XXX,XX @@ | ||
186 | #include "qemu/option.h" | ||
187 | #include "qemu/vfio-helpers.h" | ||
188 | #include "block/block_int.h" | ||
189 | +#include "sysemu/replay.h" | ||
190 | #include "trace.h" | ||
191 | |||
192 | #include "block/nvme.h" | ||
193 | @@ -XXX,XX +XXX,XX @@ static bool nvme_process_completion(BDRVNVMeState *s, NVMeQueuePair *q) | ||
194 | smp_mb_release(); | ||
195 | *q->cq.doorbell = cpu_to_le32(q->cq.head); | ||
196 | if (!qemu_co_queue_empty(&q->free_req_queue)) { | ||
197 | - aio_bh_schedule_oneshot(s->aio_context, nvme_free_req_queue_cb, q); | ||
198 | + replay_bh_schedule_oneshot_event(s->aio_context, | ||
199 | + nvme_free_req_queue_cb, q); | ||
200 | } | ||
201 | } | ||
202 | q->busy = false; | ||
203 | @@ -XXX,XX +XXX,XX @@ static void nvme_rw_cb(void *opaque, int ret) | ||
204 | /* The rw coroutine hasn't yielded, don't try to enter. */ | ||
205 | return; | ||
206 | } | ||
207 | - aio_bh_schedule_oneshot(data->ctx, nvme_rw_cb_bh, data); | ||
208 | + replay_bh_schedule_oneshot_event(data->ctx, nvme_rw_cb_bh, data); | ||
209 | } | ||
210 | |||
211 | static coroutine_fn int nvme_co_prw_aligned(BlockDriverState *bs, | ||
212 | diff --git a/block/rbd.c b/block/rbd.c | ||
213 | index XXXXXXX..XXXXXXX 100644 | ||
214 | --- a/block/rbd.c | ||
215 | +++ b/block/rbd.c | ||
216 | @@ -XXX,XX +XXX,XX @@ | ||
217 | #include "block/qdict.h" | ||
218 | #include "crypto/secret.h" | ||
219 | #include "qemu/cutils.h" | ||
220 | +#include "sysemu/replay.h" | ||
221 | #include "qapi/qmp/qstring.h" | ||
222 | #include "qapi/qmp/qdict.h" | ||
223 | #include "qapi/qmp/qjson.h" | ||
224 | @@ -XXX,XX +XXX,XX @@ static void rbd_finish_aiocb(rbd_completion_t c, RADOSCB *rcb) | ||
225 | rcb->ret = rbd_aio_get_return_value(c); | ||
226 | rbd_aio_release(c); | ||
227 | |||
228 | - aio_bh_schedule_oneshot(bdrv_get_aio_context(acb->common.bs), | ||
229 | - rbd_finish_bh, rcb); | ||
230 | + replay_bh_schedule_oneshot_event(bdrv_get_aio_context(acb->common.bs), | ||
231 | + rbd_finish_bh, rcb); | ||
232 | } | ||
233 | |||
234 | static int rbd_aio_discard_wrapper(rbd_image_t image, | ||
235 | diff --git a/block/vxhs.c b/block/vxhs.c | ||
236 | index XXXXXXX..XXXXXXX 100644 | ||
237 | --- a/block/vxhs.c | ||
238 | +++ b/block/vxhs.c | ||
239 | @@ -XXX,XX +XXX,XX @@ | ||
240 | #include "qapi/error.h" | ||
241 | #include "qemu/uuid.h" | ||
242 | #include "crypto/tlscredsx509.h" | ||
243 | +#include "sysemu/replay.h" | ||
244 | |||
245 | #define VXHS_OPT_FILENAME "filename" | ||
246 | #define VXHS_OPT_VDISK_ID "vdisk-id" | ||
247 | @@ -XXX,XX +XXX,XX @@ static void vxhs_iio_callback(void *ctx, uint32_t opcode, uint32_t error) | ||
248 | trace_vxhs_iio_callback(error); | ||
249 | } | ||
250 | |||
251 | - aio_bh_schedule_oneshot(bdrv_get_aio_context(acb->common.bs), | ||
252 | - vxhs_complete_aio_bh, acb); | ||
253 | + replay_bh_schedule_oneshot_event(bdrv_get_aio_context(acb->common.bs), | ||
254 | + vxhs_complete_aio_bh, acb); | ||
255 | break; | ||
256 | |||
257 | default: | ||
258 | diff --git a/replay/replay-events.c b/replay/replay-events.c | ||
259 | index XXXXXXX..XXXXXXX 100644 | ||
260 | --- a/replay/replay-events.c | ||
261 | +++ b/replay/replay-events.c | ||
262 | @@ -XXX,XX +XXX,XX @@ static void replay_run_event(Event *event) | ||
263 | case REPLAY_ASYNC_EVENT_BH: | ||
264 | aio_bh_call(event->opaque); | ||
265 | break; | ||
266 | + case REPLAY_ASYNC_EVENT_BH_ONESHOT: | ||
267 | + ((QEMUBHFunc *)event->opaque)(event->opaque2); | ||
268 | + break; | ||
269 | case REPLAY_ASYNC_EVENT_INPUT: | ||
270 | qemu_input_event_send_impl(NULL, (InputEvent *)event->opaque); | ||
271 | qapi_free_InputEvent((InputEvent *)event->opaque); | ||
272 | @@ -XXX,XX +XXX,XX @@ void replay_bh_schedule_event(QEMUBH *bh) | ||
273 | } | ||
274 | } | ||
275 | |||
276 | +void replay_bh_schedule_oneshot_event(AioContext *ctx, | ||
277 | + QEMUBHFunc *cb, void *opaque) | ||
278 | +{ | ||
279 | + if (events_enabled) { | ||
280 | + uint64_t id = replay_get_current_icount(); | ||
281 | + replay_add_event(REPLAY_ASYNC_EVENT_BH_ONESHOT, cb, opaque, id); | ||
282 | + } else { | ||
283 | + aio_bh_schedule_oneshot(ctx, cb, opaque); | ||
284 | + } | ||
285 | +} | ||
286 | + | ||
287 | void replay_add_input_event(struct InputEvent *event) | ||
288 | { | ||
289 | replay_add_event(REPLAY_ASYNC_EVENT_INPUT, event, NULL, 0); | ||
290 | @@ -XXX,XX +XXX,XX @@ static void replay_save_event(Event *event, int checkpoint) | ||
291 | /* save event-specific data */ | ||
292 | switch (event->event_kind) { | ||
293 | case REPLAY_ASYNC_EVENT_BH: | ||
294 | + case REPLAY_ASYNC_EVENT_BH_ONESHOT: | ||
295 | replay_put_qword(event->id); | ||
296 | break; | ||
297 | case REPLAY_ASYNC_EVENT_INPUT: | ||
298 | @@ -XXX,XX +XXX,XX @@ static Event *replay_read_event(int checkpoint) | ||
299 | /* Events that has not to be in the queue */ | ||
300 | switch (replay_state.read_event_kind) { | ||
301 | case REPLAY_ASYNC_EVENT_BH: | ||
302 | + case REPLAY_ASYNC_EVENT_BH_ONESHOT: | ||
303 | if (replay_state.read_event_id == -1) { | ||
304 | replay_state.read_event_id = replay_get_qword(); | ||
305 | } | ||
306 | diff --git a/stubs/replay-user.c b/stubs/replay-user.c | ||
307 | new file mode 100644 | ||
308 | index XXXXXXX..XXXXXXX | ||
309 | --- /dev/null | ||
310 | +++ b/stubs/replay-user.c | ||
311 | @@ -XXX,XX +XXX,XX @@ | ||
312 | +#include "qemu/osdep.h" | ||
313 | +#include "sysemu/replay.h" | ||
314 | +#include "sysemu/sysemu.h" | ||
315 | + | ||
316 | +void replay_bh_schedule_oneshot_event(AioContext *ctx, | ||
317 | + QEMUBHFunc *cb, void *opaque) | ||
318 | +{ | ||
319 | + aio_bh_schedule_oneshot(ctx, cb, opaque); | ||
320 | +} | ||
321 | diff --git a/stubs/Makefile.objs b/stubs/Makefile.objs | ||
322 | index XXXXXXX..XXXXXXX 100644 | ||
323 | --- a/stubs/Makefile.objs | ||
324 | +++ b/stubs/Makefile.objs | ||
325 | @@ -XXX,XX +XXX,XX @@ stub-obj-y += monitor.o | ||
326 | stub-obj-y += notify-event.o | ||
327 | stub-obj-y += qtest.o | ||
328 | stub-obj-y += replay.o | ||
329 | +stub-obj-y += replay-user.o | ||
330 | stub-obj-y += runstate-check.o | ||
331 | stub-obj-y += set-fd-handler.o | ||
332 | stub-obj-y += sysbus.o | ||
333 | -- | 119 | -- |
334 | 2.20.1 | 120 | 2.31.1 |
335 | 121 | ||
336 | 122 | diff view generated by jsdifflib |
1 | From: Max Reitz <mreitz@redhat.com> | 1 | From: John Snow <jsnow@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | For long test image paths, the order of the "Formatting" line and the | 3 | We can drop the sys.path hacking in various places by doing |
4 | "(qemu)" prompt after a drive_backup HMP command may be reversed. In | 4 | this. Additionally, by doing it in one place right up top, we can print |
5 | fact, the interaction between the prompt and the line may lead to the | 5 | interesting warnings in case the environment does not look correct. (See |
6 | "Formatting" to being greppable at all after "read"-ing it (if the | 6 | next commit.) |
7 | prompt injects an IFS character into the "Formatting" string). | ||
8 | 7 | ||
9 | So just wait until we get a prompt. At that point, the block job must | 8 | If we ever decide to change how the environment is crafted, all of the |
10 | have been started, so "info block-jobs" will only return "No active | 9 | "help me find my python packages" goop is all in one place, right in one |
11 | jobs" once it is done. | 10 | function. |
12 | 11 | ||
13 | Reported-by: Thomas Huth <thuth@redhat.com> | 12 | Signed-off-by: John Snow <jsnow@redhat.com> |
14 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 13 | Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> |
15 | Reviewed-by: John Snow <jsnow@redhat.com> | 14 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> |
15 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
16 | Message-Id: <20210923180715.4168522-2-jsnow@redhat.com> | ||
16 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 17 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
17 | --- | 18 | --- |
18 | tests/qemu-iotests/028 | 11 ++++++++--- | 19 | tests/qemu-iotests/iotests.py | 2 -- |
19 | tests/qemu-iotests/028.out | 1 - | 20 | tests/qemu-iotests/testenv.py | 15 +++++++++------ |
20 | 2 files changed, 8 insertions(+), 4 deletions(-) | 21 | tests/qemu-iotests/235 | 2 -- |
22 | tests/qemu-iotests/297 | 6 ------ | ||
23 | tests/qemu-iotests/300 | 5 ++--- | ||
24 | tests/qemu-iotests/tests/mirror-top-perms | 7 +++---- | ||
25 | 6 files changed, 14 insertions(+), 23 deletions(-) | ||
21 | 26 | ||
22 | diff --git a/tests/qemu-iotests/028 b/tests/qemu-iotests/028 | 27 | diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py |
28 | index XXXXXXX..XXXXXXX 100644 | ||
29 | --- a/tests/qemu-iotests/iotests.py | ||
30 | +++ b/tests/qemu-iotests/iotests.py | ||
31 | @@ -XXX,XX +XXX,XX @@ | ||
32 | |||
33 | from contextlib import contextmanager | ||
34 | |||
35 | -# pylint: disable=import-error, wrong-import-position | ||
36 | -sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python')) | ||
37 | from qemu.machine import qtest | ||
38 | from qemu.qmp import QMPMessage | ||
39 | |||
40 | diff --git a/tests/qemu-iotests/testenv.py b/tests/qemu-iotests/testenv.py | ||
41 | index XXXXXXX..XXXXXXX 100644 | ||
42 | --- a/tests/qemu-iotests/testenv.py | ||
43 | +++ b/tests/qemu-iotests/testenv.py | ||
44 | @@ -XXX,XX +XXX,XX @@ def init_directories(self) -> None: | ||
45 | SAMPLE_IMG_DIR | ||
46 | OUTPUT_DIR | ||
47 | """ | ||
48 | - self.pythonpath = os.getenv('PYTHONPATH') | ||
49 | - if self.pythonpath: | ||
50 | - self.pythonpath = self.source_iotests + os.pathsep + \ | ||
51 | - self.pythonpath | ||
52 | - else: | ||
53 | - self.pythonpath = self.source_iotests | ||
54 | + | ||
55 | + # Path where qemu goodies live in this source tree. | ||
56 | + qemu_srctree_path = Path(__file__, '../../../python').resolve() | ||
57 | + | ||
58 | + self.pythonpath = os.pathsep.join(filter(None, ( | ||
59 | + self.source_iotests, | ||
60 | + str(qemu_srctree_path), | ||
61 | + os.getenv('PYTHONPATH'), | ||
62 | + ))) | ||
63 | |||
64 | self.test_dir = os.getenv('TEST_DIR', | ||
65 | os.path.join(os.getcwd(), 'scratch')) | ||
66 | diff --git a/tests/qemu-iotests/235 b/tests/qemu-iotests/235 | ||
23 | index XXXXXXX..XXXXXXX 100755 | 67 | index XXXXXXX..XXXXXXX 100755 |
24 | --- a/tests/qemu-iotests/028 | 68 | --- a/tests/qemu-iotests/235 |
25 | +++ b/tests/qemu-iotests/028 | 69 | +++ b/tests/qemu-iotests/235 |
26 | @@ -XXX,XX +XXX,XX @@ fi | 70 | @@ -XXX,XX +XXX,XX @@ import os |
27 | # Silence output since it contains the disk image path and QEMU's readline | 71 | import iotests |
28 | # character echoing makes it very hard to filter the output. Plus, there | 72 | from iotests import qemu_img_create, qemu_io, file_path, log |
29 | # is no telling how many times the command will repeat before succeeding. | 73 | |
30 | -_send_qemu_cmd $h "drive_backup disk ${TEST_IMG}.copy" "(qemu)" >/dev/null | 74 | -sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python')) |
31 | -_send_qemu_cmd $h "" "Formatting" | _filter_img_create | 75 | - |
32 | -qemu_cmd_repeat=20 _send_qemu_cmd $h "info block-jobs" "No active jobs" >/dev/null | 76 | from qemu.machine import QEMUMachine |
33 | +# (Note that creating the image results in a "Formatting..." message over | 77 | |
34 | +# stdout, which is the same channel the monitor uses. We cannot reliably | 78 | iotests.script_initialize(supported_fmts=['qcow2']) |
35 | +# wait for it because the monitor output may interact with it in such a | 79 | diff --git a/tests/qemu-iotests/297 b/tests/qemu-iotests/297 |
36 | +# way that _timed_wait_for cannot read it. However, once the block job is | 80 | index XXXXXXX..XXXXXXX 100755 |
37 | +# done, we know that the "Formatting..." message must have appeared | 81 | --- a/tests/qemu-iotests/297 |
38 | +# already, so the output is still deterministic.) | 82 | +++ b/tests/qemu-iotests/297 |
39 | +silent=y _send_qemu_cmd $h "drive_backup disk ${TEST_IMG}.copy" "(qemu)" | 83 | @@ -XXX,XX +XXX,XX @@ def run_linters(): |
40 | +silent=y qemu_cmd_repeat=20 _send_qemu_cmd $h "info block-jobs" "No active jobs" | 84 | # Todo notes are fine, but fixme's or xxx's should probably just be |
41 | _send_qemu_cmd $h "info block-jobs" "No active jobs" | 85 | # fixed (in tests, at least) |
42 | _send_qemu_cmd $h 'quit' "" | 86 | env = os.environ.copy() |
43 | 87 | - qemu_module_path = os.path.join(os.path.dirname(__file__), | |
44 | diff --git a/tests/qemu-iotests/028.out b/tests/qemu-iotests/028.out | 88 | - '..', '..', 'python') |
45 | index XXXXXXX..XXXXXXX 100644 | 89 | - try: |
46 | --- a/tests/qemu-iotests/028.out | 90 | - env['PYTHONPATH'] += os.pathsep + qemu_module_path |
47 | +++ b/tests/qemu-iotests/028.out | 91 | - except KeyError: |
48 | @@ -XXX,XX +XXX,XX @@ No errors were found on the image. | 92 | - env['PYTHONPATH'] = qemu_module_path |
49 | 93 | subprocess.run(('pylint-3', '--score=n', '--notes=FIXME,XXX', *files), | |
50 | block-backup | 94 | env=env, check=False) |
51 | 95 | ||
52 | -Formatting 'TEST_DIR/t.IMGFMT.copy', fmt=IMGFMT size=4294968832 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT | 96 | diff --git a/tests/qemu-iotests/300 b/tests/qemu-iotests/300 |
53 | (qemu) info block-jobs | 97 | index XXXXXXX..XXXXXXX 100755 |
54 | No active jobs | 98 | --- a/tests/qemu-iotests/300 |
55 | === IO: pattern 195 | 99 | +++ b/tests/qemu-iotests/300 |
100 | @@ -XXX,XX +XXX,XX @@ import random | ||
101 | import re | ||
102 | from typing import Dict, List, Optional | ||
103 | |||
104 | +from qemu.machine import machine | ||
105 | + | ||
106 | import iotests | ||
107 | |||
108 | -# Import qemu after iotests.py has amended sys.path | ||
109 | -# pylint: disable=wrong-import-order | ||
110 | -from qemu.machine import machine | ||
111 | |||
112 | BlockBitmapMapping = List[Dict[str, object]] | ||
113 | |||
114 | diff --git a/tests/qemu-iotests/tests/mirror-top-perms b/tests/qemu-iotests/tests/mirror-top-perms | ||
115 | index XXXXXXX..XXXXXXX 100755 | ||
116 | --- a/tests/qemu-iotests/tests/mirror-top-perms | ||
117 | +++ b/tests/qemu-iotests/tests/mirror-top-perms | ||
118 | @@ -XXX,XX +XXX,XX @@ | ||
119 | # | ||
120 | |||
121 | import os | ||
122 | -import iotests | ||
123 | -from iotests import qemu_img | ||
124 | |||
125 | -# Import qemu after iotests.py has amended sys.path | ||
126 | -# pylint: disable=wrong-import-order | ||
127 | import qemu | ||
128 | |||
129 | +import iotests | ||
130 | +from iotests import qemu_img | ||
131 | + | ||
132 | |||
133 | image_size = 1 * 1024 * 1024 | ||
134 | source = os.path.join(iotests.test_dir, 'source.img') | ||
56 | -- | 135 | -- |
57 | 2.20.1 | 136 | 2.31.1 |
58 | 137 | ||
59 | 138 | diff view generated by jsdifflib |
1 | From: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru> | 1 | From: John Snow <jsnow@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | After recent updates block devices cannot be closed on qemu exit. | 3 | We can circumvent the '__main__' redefinition problem by passing |
4 | This happens due to the block request polling when replay is not finished. | 4 | --scripts-are-modules. Take mypy out of the loop per-filename and check |
5 | Therefore now we stop execution recording before closing the block devices. | 5 | everything in one go: it's quite a bit faster. |
6 | 6 | ||
7 | Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru> | 7 | Signed-off-by: John Snow <jsnow@redhat.com> |
8 | Reviewed-by: Hanna Reitz <hreitz@redhat.com> | ||
9 | Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> | ||
10 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
11 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
12 | Message-Id: <20210923180715.4168522-4-jsnow@redhat.com> | ||
8 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 13 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
9 | --- | 14 | --- |
10 | replay/replay.c | 2 ++ | 15 | tests/qemu-iotests/297 | 46 +++++++++++++++++++----------------------- |
11 | vl.c | 1 + | 16 | 1 file changed, 21 insertions(+), 25 deletions(-) |
12 | 2 files changed, 3 insertions(+) | ||
13 | 17 | ||
14 | diff --git a/replay/replay.c b/replay/replay.c | 18 | diff --git a/tests/qemu-iotests/297 b/tests/qemu-iotests/297 |
15 | index XXXXXXX..XXXXXXX 100644 | 19 | index XXXXXXX..XXXXXXX 100755 |
16 | --- a/replay/replay.c | 20 | --- a/tests/qemu-iotests/297 |
17 | +++ b/replay/replay.c | 21 | +++ b/tests/qemu-iotests/297 |
18 | @@ -XXX,XX +XXX,XX @@ void replay_finish(void) | 22 | @@ -XXX,XX +XXX,XX @@ def run_linters(): |
19 | g_free(replay_snapshot); | 23 | print('=== mypy ===') |
20 | replay_snapshot = NULL; | 24 | sys.stdout.flush() |
21 | 25 | ||
22 | + replay_mode = REPLAY_MODE_NONE; | 26 | - # We have to call mypy separately for each file. Otherwise, it |
27 | - # will interpret all given files as belonging together (i.e., they | ||
28 | - # may not both define the same classes, etc.; most notably, they | ||
29 | - # must not both define the __main__ module). | ||
30 | env['MYPYPATH'] = env['PYTHONPATH'] | ||
31 | - for filename in files: | ||
32 | - p = subprocess.run(('mypy', | ||
33 | - '--warn-unused-configs', | ||
34 | - '--disallow-subclassing-any', | ||
35 | - '--disallow-any-generics', | ||
36 | - '--disallow-incomplete-defs', | ||
37 | - '--disallow-untyped-decorators', | ||
38 | - '--no-implicit-optional', | ||
39 | - '--warn-redundant-casts', | ||
40 | - '--warn-unused-ignores', | ||
41 | - '--no-implicit-reexport', | ||
42 | - '--namespace-packages', | ||
43 | - filename), | ||
44 | - env=env, | ||
45 | - check=False, | ||
46 | - stdout=subprocess.PIPE, | ||
47 | - stderr=subprocess.STDOUT, | ||
48 | - universal_newlines=True) | ||
49 | - | ||
50 | - if p.returncode != 0: | ||
51 | - print(p.stdout) | ||
52 | + p = subprocess.run(('mypy', | ||
53 | + '--warn-unused-configs', | ||
54 | + '--disallow-subclassing-any', | ||
55 | + '--disallow-any-generics', | ||
56 | + '--disallow-incomplete-defs', | ||
57 | + '--disallow-untyped-decorators', | ||
58 | + '--no-implicit-optional', | ||
59 | + '--warn-redundant-casts', | ||
60 | + '--warn-unused-ignores', | ||
61 | + '--no-implicit-reexport', | ||
62 | + '--namespace-packages', | ||
63 | + '--scripts-are-modules', | ||
64 | + *files), | ||
65 | + env=env, | ||
66 | + check=False, | ||
67 | + stdout=subprocess.PIPE, | ||
68 | + stderr=subprocess.STDOUT, | ||
69 | + universal_newlines=True) | ||
23 | + | 70 | + |
24 | replay_finish_events(); | 71 | + if p.returncode != 0: |
25 | } | 72 | + print(p.stdout) |
26 | 73 | ||
27 | diff --git a/vl.c b/vl.c | 74 | |
28 | index XXXXXXX..XXXXXXX 100644 | 75 | for linter in ('pylint-3', 'mypy'): |
29 | --- a/vl.c | ||
30 | +++ b/vl.c | ||
31 | @@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv, char **envp) | ||
32 | |||
33 | /* No more vcpu or device emulation activity beyond this point */ | ||
34 | vm_shutdown(); | ||
35 | + replay_finish(); | ||
36 | |||
37 | job_cancel_sync_all(); | ||
38 | bdrv_close_all(); | ||
39 | -- | 76 | -- |
40 | 2.20.1 | 77 | 2.31.1 |
41 | 78 | ||
42 | 79 | diff view generated by jsdifflib |
1 | From: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru> | 1 | From: John Snow <jsnow@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | This patch updates the description of the command lines for using | 3 | We need to import subpackages from the qemu namespace package; importing |
4 | record/replay with attached block devices. | 4 | the namespace package alone doesn't bring the subpackages with it -- |
5 | unless someone else (like iotests.py) imports them too. | ||
5 | 6 | ||
6 | Signed-off-by: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru> | 7 | Adjust the imports. |
8 | |||
9 | Signed-off-by: John Snow <jsnow@redhat.com> | ||
10 | Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> | ||
11 | Reviewed-by: Hanna Reitz <hreitz@redhat.com> | ||
12 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
13 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
14 | Message-Id: <20210923180715.4168522-5-jsnow@redhat.com> | ||
7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 15 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
8 | --- | 16 | --- |
9 | docs/replay.txt | 12 +++++++++--- | 17 | tests/qemu-iotests/tests/mirror-top-perms | 7 ++++--- |
10 | 1 file changed, 9 insertions(+), 3 deletions(-) | 18 | 1 file changed, 4 insertions(+), 3 deletions(-) |
11 | 19 | ||
12 | diff --git a/docs/replay.txt b/docs/replay.txt | 20 | diff --git a/tests/qemu-iotests/tests/mirror-top-perms b/tests/qemu-iotests/tests/mirror-top-perms |
13 | index XXXXXXX..XXXXXXX 100644 | 21 | index XXXXXXX..XXXXXXX 100755 |
14 | --- a/docs/replay.txt | 22 | --- a/tests/qemu-iotests/tests/mirror-top-perms |
15 | +++ b/docs/replay.txt | 23 | +++ b/tests/qemu-iotests/tests/mirror-top-perms |
16 | @@ -XXX,XX +XXX,XX @@ Usage of the record/replay: | 24 | @@ -XXX,XX +XXX,XX @@ |
17 | * First, record the execution with the following command line: | 25 | |
18 | qemu-system-i386 \ | 26 | import os |
19 | -icount shift=7,rr=record,rrfile=replay.bin \ | 27 | |
20 | - -drive file=disk.qcow2,if=none,id=img-direct \ | 28 | -import qemu |
21 | + -drive file=disk.qcow2,if=none,snapshot,id=img-direct \ | 29 | +from qemu import qmp |
22 | -drive driver=blkreplay,if=none,image=img-direct,id=img-blkreplay \ | 30 | +from qemu.machine import machine |
23 | -device ide-hd,drive=img-blkreplay \ | 31 | |
24 | -netdev user,id=net1 -device rtl8139,netdev=net1 \ | 32 | import iotests |
25 | @@ -XXX,XX +XXX,XX @@ Usage of the record/replay: | 33 | from iotests import qemu_img |
26 | * After recording, you can replay it by using another command line: | 34 | @@ -XXX,XX +XXX,XX @@ class TestMirrorTopPerms(iotests.QMPTestCase): |
27 | qemu-system-i386 \ | 35 | def tearDown(self): |
28 | -icount shift=7,rr=replay,rrfile=replay.bin \ | 36 | try: |
29 | - -drive file=disk.qcow2,if=none,id=img-direct \ | 37 | self.vm.shutdown() |
30 | + -drive file=disk.qcow2,if=none,snapshot,id=img-direct \ | 38 | - except qemu.machine.machine.AbnormalShutdown: |
31 | -drive driver=blkreplay,if=none,image=img-direct,id=img-blkreplay \ | 39 | + except machine.AbnormalShutdown: |
32 | -device ide-hd,drive=img-blkreplay \ | 40 | pass |
33 | -netdev user,id=net1 -device rtl8139,netdev=net1 \ | 41 | |
34 | @@ -XXX,XX +XXX,XX @@ Block devices record/replay module intercepts calls of | 42 | if self.vm_b is not None: |
35 | bdrv coroutine functions at the top of block drivers stack. | 43 | @@ -XXX,XX +XXX,XX @@ class TestMirrorTopPerms(iotests.QMPTestCase): |
36 | To record and replay block operations the drive must be configured | 44 | self.vm_b.launch() |
37 | as following: | 45 | print('ERROR: VM B launched successfully, this should not have ' |
38 | - -drive file=disk.qcow2,if=none,id=img-direct | 46 | 'happened') |
39 | + -drive file=disk.qcow2,if=none,snapshot,id=img-direct | 47 | - except qemu.qmp.QMPConnectError: |
40 | -drive driver=blkreplay,if=none,image=img-direct,id=img-blkreplay | 48 | + except qmp.QMPConnectError: |
41 | -device ide-hd,drive=img-blkreplay | 49 | assert 'Is another process using the image' in self.vm_b.get_log() |
42 | 50 | ||
43 | @@ -XXX,XX +XXX,XX @@ This snapshot is created at start of recording and restored at start | 51 | result = self.vm.qmp('block-job-cancel', |
44 | of replaying. It also can be loaded while replaying to roll back | ||
45 | the execution. | ||
46 | |||
47 | +'snapshot' flag of the disk image must be removed to save the snapshots | ||
48 | +in the overlay (or original image) instead of using the temporary overlay. | ||
49 | + -drive file=disk.ovl,if=none,id=img-direct | ||
50 | + -drive driver=blkreplay,if=none,image=img-direct,id=img-blkreplay | ||
51 | + -device ide-hd,drive=img-blkreplay | ||
52 | + | ||
53 | Use QEMU monitor to create additional snapshots. 'savevm <name>' command | ||
54 | created the snapshot and 'loadvm <name>' restores it. To prevent corruption | ||
55 | of the original disk image, use overlay files linked to the original images. | ||
56 | -- | 52 | -- |
57 | 2.20.1 | 53 | 2.31.1 |
58 | 54 | ||
59 | 55 | diff view generated by jsdifflib |
1 | From: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru> | 1 | From: John Snow <jsnow@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | This patch disables setting '-snapshot' option on by default | 3 | Mostly uninteresting stuff. Move the test injections under a function |
4 | in record/replay mode. This is needed for creating vmstates in record | 4 | named main() so that the variables used during that process aren't in |
5 | and replay modes. | 5 | the global scope. |
6 | 6 | ||
7 | Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru> | 7 | Signed-off-by: John Snow <jsnow@redhat.com> |
8 | Acked-by: Kevin Wolf <kwolf@redhat.com> | 8 | Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> |
9 | Reviewed-by: Hanna Reitz <hreitz@redhat.com> | ||
10 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
11 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
12 | Message-Id: <20210923180715.4168522-6-jsnow@redhat.com> | ||
9 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 13 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
10 | --- | 14 | --- |
11 | vl.c | 10 ++++++++-- | 15 | tests/qemu-iotests/tests/migrate-bitmaps-test | 50 +++++++++++-------- |
12 | 1 file changed, 8 insertions(+), 2 deletions(-) | 16 | 1 file changed, 28 insertions(+), 22 deletions(-) |
13 | 17 | ||
14 | diff --git a/vl.c b/vl.c | 18 | diff --git a/tests/qemu-iotests/tests/migrate-bitmaps-test b/tests/qemu-iotests/tests/migrate-bitmaps-test |
15 | index XXXXXXX..XXXXXXX 100644 | 19 | index XXXXXXX..XXXXXXX 100755 |
16 | --- a/vl.c | 20 | --- a/tests/qemu-iotests/tests/migrate-bitmaps-test |
17 | +++ b/vl.c | 21 | +++ b/tests/qemu-iotests/tests/migrate-bitmaps-test |
18 | @@ -XXX,XX +XXX,XX @@ static void configure_blockdev(BlockdevOptionsQueue *bdo_queue, | 22 | @@ -XXX,XX +XXX,XX @@ |
19 | qapi_free_BlockdevOptions(bdo->bdo); | 23 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
20 | g_free(bdo); | 24 | # |
21 | } | 25 | |
22 | - if (snapshot || replay_mode != REPLAY_MODE_NONE) { | 26 | -import os |
23 | + if (snapshot) { | 27 | import itertools |
24 | qemu_opts_foreach(qemu_find_opts("drive"), drive_enable_snapshot, | 28 | import operator |
25 | NULL, NULL); | 29 | +import os |
26 | } | 30 | import re |
27 | @@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv, char **envp) | 31 | + |
28 | drive_add(IF_PFLASH, -1, optarg, PFLASH_OPTS); | 32 | import iotests |
29 | break; | 33 | from iotests import qemu_img, qemu_img_create, Timeout |
30 | case QEMU_OPTION_snapshot: | 34 | |
31 | - snapshot = 1; | 35 | @@ -XXX,XX +XXX,XX @@ def inject_test_case(klass, suffix, method, *args, **kwargs): |
32 | + { | 36 | setattr(klass, 'test_' + method + suffix, lambda self: mc(self)) |
33 | + Error *blocker = NULL; | 37 | |
34 | + snapshot = 1; | 38 | |
35 | + error_setg(&blocker, QERR_REPLAY_NOT_SUPPORTED, | 39 | -for cmb in list(itertools.product((True, False), repeat=5)): |
36 | + "-snapshot"); | 40 | - name = ('_' if cmb[0] else '_not_') + 'persistent_' |
37 | + replay_add_blocker(blocker); | 41 | - name += ('_' if cmb[1] else '_not_') + 'migbitmap_' |
38 | + } | 42 | - name += '_online' if cmb[2] else '_offline' |
39 | break; | 43 | - name += '_shared' if cmb[3] else '_nonshared' |
40 | case QEMU_OPTION_numa: | 44 | - if cmb[4]: |
41 | opts = qemu_opts_parse_noisily(qemu_find_opts("numa"), | 45 | - name += '__pre_shutdown' |
46 | - | ||
47 | - inject_test_case(TestDirtyBitmapMigration, name, 'do_test_migration', | ||
48 | - *list(cmb)) | ||
49 | - | ||
50 | -for cmb in list(itertools.product((True, False), repeat=2)): | ||
51 | - name = ('_' if cmb[0] else '_not_') + 'persistent_' | ||
52 | - name += ('_' if cmb[1] else '_not_') + 'migbitmap' | ||
53 | - | ||
54 | - inject_test_case(TestDirtyBitmapMigration, name, | ||
55 | - 'do_test_migration_resume_source', *list(cmb)) | ||
56 | - | ||
57 | - | ||
58 | class TestDirtyBitmapBackingMigration(iotests.QMPTestCase): | ||
59 | def setUp(self): | ||
60 | qemu_img_create('-f', iotests.imgfmt, base_a, size) | ||
61 | @@ -XXX,XX +XXX,XX @@ class TestDirtyBitmapBackingMigration(iotests.QMPTestCase): | ||
62 | self.assert_qmp(result, 'return', {}) | ||
63 | |||
64 | |||
65 | +def main() -> None: | ||
66 | + for cmb in list(itertools.product((True, False), repeat=5)): | ||
67 | + name = ('_' if cmb[0] else '_not_') + 'persistent_' | ||
68 | + name += ('_' if cmb[1] else '_not_') + 'migbitmap_' | ||
69 | + name += '_online' if cmb[2] else '_offline' | ||
70 | + name += '_shared' if cmb[3] else '_nonshared' | ||
71 | + if cmb[4]: | ||
72 | + name += '__pre_shutdown' | ||
73 | + | ||
74 | + inject_test_case(TestDirtyBitmapMigration, name, 'do_test_migration', | ||
75 | + *list(cmb)) | ||
76 | + | ||
77 | + for cmb in list(itertools.product((True, False), repeat=2)): | ||
78 | + name = ('_' if cmb[0] else '_not_') + 'persistent_' | ||
79 | + name += ('_' if cmb[1] else '_not_') + 'migbitmap' | ||
80 | + | ||
81 | + inject_test_case(TestDirtyBitmapMigration, name, | ||
82 | + 'do_test_migration_resume_source', *list(cmb)) | ||
83 | + | ||
84 | + iotests.main( | ||
85 | + supported_fmts=['qcow2'], | ||
86 | + supported_protocols=['file'] | ||
87 | + ) | ||
88 | + | ||
89 | + | ||
90 | if __name__ == '__main__': | ||
91 | - iotests.main(supported_fmts=['qcow2'], | ||
92 | - supported_protocols=['file']) | ||
93 | + main() | ||
42 | -- | 94 | -- |
43 | 2.20.1 | 95 | 2.31.1 |
44 | 96 | ||
45 | 97 | diff view generated by jsdifflib |
1 | From: Peter Lieven <pl@kamp.de> | 1 | From: John Snow <jsnow@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | qemu is currently not able to detect truncated vhdx image files. | 3 | 1. Ignore the new f-strings warning, we're not interested in doing a |
4 | Add a basic check if all allocated blocks are reachable at open and | 4 | full conversion at this time. |
5 | report all errors during bdrv_co_check. | ||
6 | 5 | ||
7 | Signed-off-by: Peter Lieven <pl@kamp.de> | 6 | 2. Just mute the unbalanced-tuple-unpacking warning, it's not a real |
7 | error in this case and muting the dozens of callsites is just not | ||
8 | worth it. | ||
9 | |||
10 | 3. Add encodings to read_text(). | ||
11 | |||
12 | Signed-off-by: John Snow <jsnow@redhat.com> | ||
13 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
14 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
15 | Message-Id: <20210923180715.4168522-7-jsnow@redhat.com> | ||
8 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 16 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
9 | --- | 17 | --- |
10 | block/vhdx.c | 120 +++++++++++++++++++++++++++++++++++++++++++-------- | 18 | tests/qemu-iotests/testrunner.py | 7 ++++--- |
11 | 1 file changed, 103 insertions(+), 17 deletions(-) | 19 | tests/qemu-iotests/pylintrc | 6 +++++- |
20 | 2 files changed, 9 insertions(+), 4 deletions(-) | ||
12 | 21 | ||
13 | diff --git a/block/vhdx.c b/block/vhdx.c | 22 | diff --git a/tests/qemu-iotests/testrunner.py b/tests/qemu-iotests/testrunner.py |
14 | index XXXXXXX..XXXXXXX 100644 | 23 | index XXXXXXX..XXXXXXX 100644 |
15 | --- a/block/vhdx.c | 24 | --- a/tests/qemu-iotests/testrunner.py |
16 | +++ b/block/vhdx.c | 25 | +++ b/tests/qemu-iotests/testrunner.py |
17 | @@ -XXX,XX +XXX,XX @@ | 26 | @@ -XXX,XX +XXX,XX @@ def do_run_test(self, test: str) -> TestResult: |
18 | #include "qemu/option.h" | 27 | diff=file_diff(str(f_reference), str(f_bad))) |
19 | #include "qemu/crc32c.h" | 28 | |
20 | #include "qemu/bswap.h" | 29 | if f_notrun.exists(): |
21 | +#include "qemu/error-report.h" | 30 | - return TestResult(status='not run', |
22 | #include "vhdx.h" | 31 | - description=f_notrun.read_text().strip()) |
23 | #include "migration/blocker.h" | 32 | + return TestResult( |
24 | #include "qemu/uuid.h" | 33 | + status='not run', |
25 | @@ -XXX,XX +XXX,XX @@ static int vhdx_region_check(BDRVVHDXState *s, uint64_t start, uint64_t length) | 34 | + description=f_notrun.read_text(encoding='utf-8').strip()) |
26 | end = start + length; | 35 | |
27 | QLIST_FOREACH(r, &s->regions, entries) { | 36 | casenotrun = '' |
28 | if (!((start >= r->end) || (end <= r->start))) { | 37 | if f_casenotrun.exists(): |
29 | + error_report("VHDX region %" PRIu64 "-%" PRIu64 " overlaps with " | 38 | - casenotrun = f_casenotrun.read_text() |
30 | + "region %" PRIu64 "-%." PRIu64, start, end, r->start, | 39 | + casenotrun = f_casenotrun.read_text(encoding='utf-8') |
31 | + r->end); | 40 | |
32 | ret = -EINVAL; | 41 | diff = file_diff(str(f_reference), str(f_bad)) |
33 | goto exit; | 42 | if diff: |
34 | } | 43 | diff --git a/tests/qemu-iotests/pylintrc b/tests/qemu-iotests/pylintrc |
35 | @@ -XXX,XX +XXX,XX @@ static void vhdx_calc_bat_entries(BDRVVHDXState *s) | 44 | index XXXXXXX..XXXXXXX 100644 |
36 | 45 | --- a/tests/qemu-iotests/pylintrc | |
37 | } | 46 | +++ b/tests/qemu-iotests/pylintrc |
38 | 47 | @@ -XXX,XX +XXX,XX @@ disable=invalid-name, | |
39 | +static int vhdx_check_bat_entries(BlockDriverState *bs, int *errcnt) | 48 | too-many-public-methods, |
40 | +{ | 49 | # pylint warns about Optional[] etc. as unsubscriptable in 3.9 |
41 | + BDRVVHDXState *s = bs->opaque; | 50 | unsubscriptable-object, |
42 | + int64_t image_file_size = bdrv_getlength(bs->file->bs); | 51 | + # pylint's static analysis causes false positivies for file_path(); |
43 | + uint64_t payblocks = s->chunk_ratio; | 52 | + # If we really care to make it statically knowable, we'll use mypy. |
44 | + uint64_t i; | 53 | + unbalanced-tuple-unpacking, |
45 | + int ret = 0; | 54 | # Sometimes we need to disable a newly introduced pylint warning. |
46 | + | 55 | # Doing so should not produce a warning in older versions of pylint. |
47 | + if (image_file_size < 0) { | 56 | bad-option-value, |
48 | + error_report("Could not determinate VHDX image file size."); | 57 | # These are temporary, and should be removed: |
49 | + return image_file_size; | 58 | missing-docstring, |
50 | + } | 59 | too-many-return-statements, |
51 | + | 60 | - too-many-statements |
52 | + for (i = 0; i < s->bat_entries; i++) { | 61 | + too-many-statements, |
53 | + if ((s->bat[i] & VHDX_BAT_STATE_BIT_MASK) == | 62 | + consider-using-f-string, |
54 | + PAYLOAD_BLOCK_FULLY_PRESENT) { | 63 | |
55 | + uint64_t offset = s->bat[i] & VHDX_BAT_FILE_OFF_MASK; | 64 | [FORMAT] |
56 | + /* | ||
57 | + * Allow that the last block exists only partially. The VHDX spec | ||
58 | + * states that the image file can only grow in blocksize increments, | ||
59 | + * but QEMU created images with partial last blocks in the past. | ||
60 | + */ | ||
61 | + uint32_t block_length = MIN(s->block_size, | ||
62 | + bs->total_sectors * BDRV_SECTOR_SIZE - i * s->block_size); | ||
63 | + /* | ||
64 | + * Check for BAT entry overflow. | ||
65 | + */ | ||
66 | + if (offset > INT64_MAX - s->block_size) { | ||
67 | + error_report("VHDX BAT entry %" PRIu64 " offset overflow.", i); | ||
68 | + ret = -EINVAL; | ||
69 | + if (!errcnt) { | ||
70 | + break; | ||
71 | + } | ||
72 | + (*errcnt)++; | ||
73 | + } | ||
74 | + /* | ||
75 | + * Check if fully allocated BAT entries do not reside after | ||
76 | + * end of the image file. | ||
77 | + */ | ||
78 | + if (offset >= image_file_size) { | ||
79 | + error_report("VHDX BAT entry %" PRIu64 " start offset %" PRIu64 | ||
80 | + " points after end of file (%" PRIi64 "). Image" | ||
81 | + " has probably been truncated.", | ||
82 | + i, offset, image_file_size); | ||
83 | + ret = -EINVAL; | ||
84 | + if (!errcnt) { | ||
85 | + break; | ||
86 | + } | ||
87 | + (*errcnt)++; | ||
88 | + } else if (offset + block_length > image_file_size) { | ||
89 | + error_report("VHDX BAT entry %" PRIu64 " end offset %" PRIu64 | ||
90 | + " points after end of file (%" PRIi64 "). Image" | ||
91 | + " has probably been truncated.", | ||
92 | + i, offset + block_length - 1, image_file_size); | ||
93 | + ret = -EINVAL; | ||
94 | + if (!errcnt) { | ||
95 | + break; | ||
96 | + } | ||
97 | + (*errcnt)++; | ||
98 | + } | ||
99 | + | ||
100 | + /* | ||
101 | + * verify populated BAT field file offsets against | ||
102 | + * region table and log entries | ||
103 | + */ | ||
104 | + if (payblocks--) { | ||
105 | + /* payload bat entries */ | ||
106 | + int ret2; | ||
107 | + ret2 = vhdx_region_check(s, offset, s->block_size); | ||
108 | + if (ret2 < 0) { | ||
109 | + ret = -EINVAL; | ||
110 | + if (!errcnt) { | ||
111 | + break; | ||
112 | + } | ||
113 | + (*errcnt)++; | ||
114 | + } | ||
115 | + } else { | ||
116 | + payblocks = s->chunk_ratio; | ||
117 | + /* | ||
118 | + * Once differencing files are supported, verify sector bitmap | ||
119 | + * blocks here | ||
120 | + */ | ||
121 | + } | ||
122 | + } | ||
123 | + } | ||
124 | + | ||
125 | + return ret; | ||
126 | +} | ||
127 | + | ||
128 | static void vhdx_close(BlockDriverState *bs) | ||
129 | { | ||
130 | BDRVVHDXState *s = bs->opaque; | ||
131 | @@ -XXX,XX +XXX,XX @@ static int vhdx_open(BlockDriverState *bs, QDict *options, int flags, | ||
132 | goto fail; | ||
133 | } | ||
134 | |||
135 | - uint64_t payblocks = s->chunk_ratio; | ||
136 | - /* endian convert, and verify populated BAT field file offsets against | ||
137 | - * region table and log entries */ | ||
138 | + /* endian convert populated BAT field entires */ | ||
139 | for (i = 0; i < s->bat_entries; i++) { | ||
140 | s->bat[i] = le64_to_cpu(s->bat[i]); | ||
141 | - if (payblocks--) { | ||
142 | - /* payload bat entries */ | ||
143 | - if ((s->bat[i] & VHDX_BAT_STATE_BIT_MASK) == | ||
144 | - PAYLOAD_BLOCK_FULLY_PRESENT) { | ||
145 | - ret = vhdx_region_check(s, s->bat[i] & VHDX_BAT_FILE_OFF_MASK, | ||
146 | - s->block_size); | ||
147 | - if (ret < 0) { | ||
148 | - goto fail; | ||
149 | - } | ||
150 | - } | ||
151 | - } else { | ||
152 | - payblocks = s->chunk_ratio; | ||
153 | - /* Once differencing files are supported, verify sector bitmap | ||
154 | - * blocks here */ | ||
155 | + } | ||
156 | + | ||
157 | + if (!(flags & BDRV_O_CHECK)) { | ||
158 | + ret = vhdx_check_bat_entries(bs, NULL); | ||
159 | + if (ret < 0) { | ||
160 | + goto fail; | ||
161 | } | ||
162 | } | ||
163 | |||
164 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn vhdx_co_check(BlockDriverState *bs, | ||
165 | if (s->log_replayed_on_open) { | ||
166 | result->corruptions_fixed++; | ||
167 | } | ||
168 | + | ||
169 | + vhdx_check_bat_entries(bs, &result->corruptions); | ||
170 | + | ||
171 | return 0; | ||
172 | } | ||
173 | 65 | ||
174 | -- | 66 | -- |
175 | 2.20.1 | 67 | 2.31.1 |
176 | 68 | ||
177 | 69 | diff view generated by jsdifflib |