1 | The following changes since commit 81b2d5ceb0cfb4cdc2163492e3169ed714b0cda9: | 1 | The following changes since commit 825b96dbcee23d134b691fc75618b59c5f53da32: |
---|---|---|---|
2 | 2 | ||
3 | Merge remote-tracking branch 'remotes/rth/tags/pull-tcg-20170426' into staging (2017-04-26 20:50:49 +0100) | 3 | Merge tag 'migration-20250310-pull-request' of https://gitlab.com/farosas/qemu into staging (2025-03-11 09:32:07 +0800) |
4 | 4 | ||
5 | are available in the git repository at: | 5 | are available in the Git repository at: |
6 | 6 | ||
7 | https://repo.or.cz/qemu/kevin.git tags/for-upstream | ||
7 | 8 | ||
8 | git://repo.or.cz/qemu/kevin.git tags/for-upstream | 9 | for you to fetch changes up to a93c04f3cbe690877b3297a9df4767aa811fcd97: |
9 | 10 | ||
10 | for you to fetch changes up to 5fc0fe383fff318b38291dcdf2cf38e329ec232a: | 11 | virtio-scsi: only expose cmd vqs via iothread-vq-mapping (2025-03-11 15:49:22 +0100) |
11 | |||
12 | Merge remote-tracking branch 'mreitz/tags/pull-block-2017-04-28' into queue-block (2017-04-28 20:52:17 +0200) | ||
13 | 12 | ||
14 | ---------------------------------------------------------------- | 13 | ---------------------------------------------------------------- |
15 | |||
16 | Block layer patches | 14 | Block layer patches |
17 | 15 | ||
16 | - virtio-scsi: add iothread-vq-mapping parameter | ||
17 | - Improve writethrough performance | ||
18 | - Fix missing zero init in bdrv_snapshot_goto() | ||
19 | - Code cleanup and iotests fixes | ||
20 | |||
18 | ---------------------------------------------------------------- | 21 | ---------------------------------------------------------------- |
19 | Denis V. Lunev (2): | 22 | Kevin Wolf (8): |
20 | block: fix alignment calculations in bdrv_co_do_zero_pwritev | 23 | block: Remove unused blk_op_is_blocked() |
21 | block: assert no image modification under BDRV_O_INACTIVE | 24 | block: Zero block driver state before reopening |
25 | file-posix: Support FUA writes | ||
26 | block/io: Ignore FUA with cache.no-flush=on | ||
27 | aio: Create AioPolledEvent | ||
28 | aio-posix: Factor out adjust_polling_time() | ||
29 | aio-posix: Separate AioPolledEvent per AioHandler | ||
30 | aio-posix: Adjust polling time also for new handlers | ||
22 | 31 | ||
23 | Eric Blake (2): | 32 | Stefan Hajnoczi (13): |
24 | iotests: Fix typo in 026 | 33 | scsi-disk: drop unused SCSIDiskState->bh field |
25 | qcow2: Allow discard of final unaligned cluster | 34 | dma: use current AioContext for dma_blk_io() |
26 | 35 | scsi: track per-SCSIRequest AioContext | |
27 | Fam Zheng (2): | 36 | scsi: introduce requests_lock |
28 | block: Remove NULL check in bdrv_co_flush | 37 | virtio-scsi: introduce event and ctrl virtqueue locks |
29 | iotests: 109: Filter out "len" of failed jobs | 38 | virtio-scsi: protect events_dropped field |
30 | 39 | virtio-scsi: perform TMFs in appropriate AioContexts | |
31 | John Snow (2): | 40 | virtio-blk: extract cleanup_iothread_vq_mapping() function |
32 | iotests: clarify help text | 41 | virtio-blk: tidy up iothread_vq_mapping functions |
33 | iotests: fix exclusion option | 42 | virtio: extract iothread-vq-mapping.h API |
34 | 43 | virtio-scsi: add iothread-vq-mapping parameter | |
35 | Kevin Wolf (8): | 44 | virtio-scsi: handle ctrl virtqueue in main loop |
36 | file-posix: Remove unnecessary includes | 45 | virtio-scsi: only expose cmd vqs via iothread-vq-mapping |
37 | file-win32: Remove unnecessary include | ||
38 | migration: Call blk_resume_after_migration() for postcopy | ||
39 | qemu-iotests: Filter HMP readline escape characters | ||
40 | qemu-iotests: Test postcopy migration | ||
41 | qemu-iotests: Remove PERL_PROG and BC_PROG | ||
42 | qemu_iotests: Remove _readlink() | ||
43 | Merge remote-tracking branch 'mreitz/tags/pull-block-2017-04-28' into queue-block | ||
44 | |||
45 | Klim Kireev (1): | ||
46 | block: fix obvious coding style mistakes in block_int.h | ||
47 | |||
48 | Krzysztof Kozlowski (1): | ||
49 | block: Constify data passed by pointer to blk_name | ||
50 | |||
51 | Lidong Chen (1): | ||
52 | qemu-img: use blk_co_pwrite_zeroes for zero sectors when compressed | ||
53 | |||
54 | Max Reitz (13): | ||
55 | Revert "block/io: Comment out permission assertions" | ||
56 | block: An empty filename counts as no filename | ||
57 | iotests/051: Add test for empty filename | ||
58 | iotests: Launch qemu-nbd with -e 42 | ||
59 | block: Do not unref bs->file on error in BD's open | ||
60 | qemu-img/convert: Use @opts for one thing only | ||
61 | qemu-img/convert: Move bs_n > 1 && -B check down | ||
62 | qemu-img: Document backing options | ||
63 | block/vhdx: Make vhdx_create() always set errp | ||
64 | block: Add errp to b{lk,drv}_truncate() | ||
65 | block: Add errp to BD.bdrv_truncate() | ||
66 | block: Add .bdrv_truncate() error messages | ||
67 | progress: Show current progress on SIGINFO | ||
68 | |||
69 | Peter Lieven (1): | ||
70 | qemu-img: simplify img_convert | ||
71 | 46 | ||
72 | Thomas Huth (1): | 47 | Thomas Huth (1): |
73 | Issue a deprecation warning if the user specifies the "-hdachs" option. | 48 | iotests: Limit qsd-migrate to working formats |
74 | 49 | ||
75 | Vladimir Sementsov-Ogievskiy (1): | 50 | include/block/aio.h | 5 +- |
76 | qemu-img: improve convert_iteration_sectors() | 51 | include/block/raw-aio.h | 8 +- |
77 | 52 | include/hw/scsi/scsi.h | 8 +- | |
78 | block.c | 26 +-- | 53 | include/hw/virtio/iothread-vq-mapping.h | 45 +++ |
79 | block/blkdebug.c | 8 +- | 54 | include/hw/virtio/virtio-scsi.h | 15 +- |
80 | block/blkreplay.c | 3 - | 55 | include/system/block-backend-global-state.h | 1 - |
81 | block/blkverify.c | 3 - | 56 | include/system/dma.h | 3 +- |
82 | block/block-backend.c | 7 +- | 57 | util/aio-posix.h | 1 + |
83 | block/commit.c | 5 +- | 58 | block/block-backend.c | 12 - |
84 | block/crypto.c | 5 +- | 59 | block/file-posix.c | 26 +- |
85 | block/file-posix.c | 21 ++- | 60 | block/io.c | 4 + |
86 | block/file-win32.c | 7 +- | 61 | block/io_uring.c | 13 +- |
87 | block/gluster.c | 7 +- | 62 | block/linux-aio.c | 24 +- |
88 | block/io.c | 16 +- | 63 | block/snapshot.c | 1 + |
89 | block/iscsi.c | 6 +- | 64 | hw/block/virtio-blk.c | 132 +------- |
90 | block/mirror.c | 2 +- | 65 | hw/ide/core.c | 3 +- |
91 | block/nfs.c | 12 +- | 66 | hw/ide/macio.c | 3 +- |
92 | block/parallels.c | 13 +- | 67 | hw/scsi/scsi-bus.c | 121 +++++-- |
93 | block/qcow.c | 6 +- | 68 | hw/scsi/scsi-disk.c | 24 +- |
94 | block/qcow2-refcount.c | 5 +- | 69 | hw/scsi/virtio-scsi-dataplane.c | 103 ++++-- |
95 | block/qcow2.c | 31 ++-- | 70 | hw/scsi/virtio-scsi.c | 502 ++++++++++++++++------------ |
96 | block/qed.c | 8 +- | 71 | hw/virtio/iothread-vq-mapping.c | 131 ++++++++ |
97 | block/raw-format.c | 6 +- | 72 | system/dma-helpers.c | 8 +- |
98 | block/rbd.c | 3 +- | 73 | util/aio-posix.c | 114 ++++--- |
99 | block/sheepdog.c | 14 +- | 74 | util/async.c | 1 - |
100 | block/vdi.c | 4 +- | 75 | hw/virtio/meson.build | 1 + |
101 | block/vhdx-log.c | 2 +- | 76 | meson.build | 4 + |
102 | block/vhdx.c | 25 ++- | 77 | tests/qemu-iotests/tests/qsd-migrate | 2 +- |
103 | block/vmdk.c | 13 +- | 78 | 28 files changed, 803 insertions(+), 512 deletions(-) |
104 | block/vpc.c | 13 +- | 79 | create mode 100644 include/hw/virtio/iothread-vq-mapping.h |
105 | blockdev.c | 21 +-- | 80 | create mode 100644 hw/virtio/iothread-vq-mapping.c |
106 | include/block/block.h | 2 +- | ||
107 | include/block/block_int.h | 8 +- | ||
108 | include/sysemu/block-backend.h | 4 +- | ||
109 | migration/savevm.c | 8 + | ||
110 | qemu-img-cmds.hx | 8 +- | ||
111 | qemu-img.c | 313 ++++++++++++++----------------------- | ||
112 | qemu-img.texi | 7 +- | ||
113 | qemu-io-cmds.c | 5 +- | ||
114 | qemu-options.hx | 4 +- | ||
115 | tests/qemu-iotests/026 | 2 +- | ||
116 | tests/qemu-iotests/026.out | 2 +- | ||
117 | tests/qemu-iotests/026.out.nocache | 2 +- | ||
118 | tests/qemu-iotests/028.out | 2 +- | ||
119 | tests/qemu-iotests/051 | 4 +- | ||
120 | tests/qemu-iotests/051.out | 109 ++++++------- | ||
121 | tests/qemu-iotests/051.pc.out | 135 ++++++++-------- | ||
122 | tests/qemu-iotests/066 | 12 +- | ||
123 | tests/qemu-iotests/066.out | 12 +- | ||
124 | tests/qemu-iotests/068 | 4 +- | ||
125 | tests/qemu-iotests/068.out | 6 +- | ||
126 | tests/qemu-iotests/109 | 6 +- | ||
127 | tests/qemu-iotests/109.out | 20 +-- | ||
128 | tests/qemu-iotests/122.out | 4 +- | ||
129 | tests/qemu-iotests/130.out | 4 +- | ||
130 | tests/qemu-iotests/142 | 2 +- | ||
131 | tests/qemu-iotests/142.out | 10 +- | ||
132 | tests/qemu-iotests/145 | 3 +- | ||
133 | tests/qemu-iotests/145.out | 2 +- | ||
134 | tests/qemu-iotests/181 | 119 ++++++++++++++ | ||
135 | tests/qemu-iotests/181.out | 38 +++++ | ||
136 | tests/qemu-iotests/common | 11 +- | ||
137 | tests/qemu-iotests/common.config | 24 --- | ||
138 | tests/qemu-iotests/common.filter | 13 ++ | ||
139 | tests/qemu-iotests/common.qemu | 4 +- | ||
140 | tests/qemu-iotests/common.rc | 4 +- | ||
141 | tests/qemu-iotests/group | 1 + | ||
142 | util/qemu-progress.c | 3 + | ||
143 | vl.c | 2 + | ||
144 | 66 files changed, 669 insertions(+), 542 deletions(-) | ||
145 | create mode 100755 tests/qemu-iotests/181 | ||
146 | create mode 100644 tests/qemu-iotests/181.out | ||
147 | diff view generated by jsdifflib |
1 | From: Krzysztof Kozlowski <krzk@kernel.org> | 1 | Commit fc4e394b28 removed the last caller of blk_op_is_blocked(). Remove |
---|---|---|---|
2 | the now unused function. | ||
2 | 3 | ||
3 | blk_name() is not modifying data passed to it through pointer and it | 4 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
4 | returns also a pointer to const so the argument can be made const for | 5 | Message-ID: <20250206165331.379033-1-kwolf@redhat.com> |
5 | code safeness. | 6 | Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> |
6 | 7 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | |
7 | Signed-off-by: Krzysztof Kozlowski <krzk@kernel.org> | ||
8 | Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org> | ||
9 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 8 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
10 | --- | 9 | --- |
11 | block/block-backend.c | 2 +- | 10 | include/system/block-backend-global-state.h | 1 - |
12 | include/sysemu/block-backend.h | 2 +- | 11 | block/block-backend.c | 12 ------------ |
13 | 2 files changed, 2 insertions(+), 2 deletions(-) | 12 | 2 files changed, 13 deletions(-) |
14 | 13 | ||
14 | diff --git a/include/system/block-backend-global-state.h b/include/system/block-backend-global-state.h | ||
15 | index XXXXXXX..XXXXXXX 100644 | ||
16 | --- a/include/system/block-backend-global-state.h | ||
17 | +++ b/include/system/block-backend-global-state.h | ||
18 | @@ -XXX,XX +XXX,XX @@ bool blk_supports_write_perm(BlockBackend *blk); | ||
19 | bool blk_is_sg(BlockBackend *blk); | ||
20 | void blk_set_enable_write_cache(BlockBackend *blk, bool wce); | ||
21 | int blk_get_flags(BlockBackend *blk); | ||
22 | -bool blk_op_is_blocked(BlockBackend *blk, BlockOpType op, Error **errp); | ||
23 | int blk_set_aio_context(BlockBackend *blk, AioContext *new_context, | ||
24 | Error **errp); | ||
25 | void blk_add_aio_context_notifier(BlockBackend *blk, | ||
15 | diff --git a/block/block-backend.c b/block/block-backend.c | 26 | diff --git a/block/block-backend.c b/block/block-backend.c |
16 | index XXXXXXX..XXXXXXX 100644 | 27 | index XXXXXXX..XXXXXXX 100644 |
17 | --- a/block/block-backend.c | 28 | --- a/block/block-backend.c |
18 | +++ b/block/block-backend.c | 29 | +++ b/block/block-backend.c |
19 | @@ -XXX,XX +XXX,XX @@ void monitor_remove_blk(BlockBackend *blk) | 30 | @@ -XXX,XX +XXX,XX @@ void *blk_blockalign(BlockBackend *blk, size_t size) |
20 | * Return @blk's name, a non-null string. | 31 | return qemu_blockalign(blk ? blk_bs(blk) : NULL, size); |
21 | * Returns an empty string iff @blk is not referenced by the monitor. | ||
22 | */ | ||
23 | -const char *blk_name(BlockBackend *blk) | ||
24 | +const char *blk_name(const BlockBackend *blk) | ||
25 | { | ||
26 | return blk->name ?: ""; | ||
27 | } | 32 | } |
28 | diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h | 33 | |
29 | index XXXXXXX..XXXXXXX 100644 | 34 | -bool blk_op_is_blocked(BlockBackend *blk, BlockOpType op, Error **errp) |
30 | --- a/include/sysemu/block-backend.h | 35 | -{ |
31 | +++ b/include/sysemu/block-backend.h | 36 | - BlockDriverState *bs = blk_bs(blk); |
32 | @@ -XXX,XX +XXX,XX @@ int blk_get_refcnt(BlockBackend *blk); | 37 | - GLOBAL_STATE_CODE(); |
33 | void blk_ref(BlockBackend *blk); | 38 | - GRAPH_RDLOCK_GUARD_MAINLOOP(); |
34 | void blk_unref(BlockBackend *blk); | 39 | - |
35 | void blk_remove_all_bs(void); | 40 | - if (!bs) { |
36 | -const char *blk_name(BlockBackend *blk); | 41 | - return false; |
37 | +const char *blk_name(const BlockBackend *blk); | 42 | - } |
38 | BlockBackend *blk_by_name(const char *name); | 43 | - |
39 | BlockBackend *blk_next(BlockBackend *blk); | 44 | - return bdrv_op_is_blocked(bs, op, errp); |
40 | bool monitor_add_blk(BlockBackend *blk, const char *name, Error **errp); | 45 | -} |
46 | |||
47 | /** | ||
48 | * Return BB's current AioContext. Note that this context may change | ||
41 | -- | 49 | -- |
42 | 1.8.3.1 | 50 | 2.48.1 |
43 | 51 | ||
44 | 52 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
2 | --- | ||
3 | block/file-posix.c | 2 -- | ||
4 | 1 file changed, 2 deletions(-) | ||
5 | 1 | ||
6 | diff --git a/block/file-posix.c b/block/file-posix.c | ||
7 | index XXXXXXX..XXXXXXX 100644 | ||
8 | --- a/block/file-posix.c | ||
9 | +++ b/block/file-posix.c | ||
10 | @@ -XXX,XX +XXX,XX @@ | ||
11 | #include "qapi/error.h" | ||
12 | #include "qemu/cutils.h" | ||
13 | #include "qemu/error-report.h" | ||
14 | -#include "qemu/timer.h" | ||
15 | -#include "qemu/log.h" | ||
16 | #include "block/block_int.h" | ||
17 | #include "qemu/module.h" | ||
18 | #include "trace.h" | ||
19 | -- | ||
20 | 1.8.3.1 | ||
21 | |||
22 | diff view generated by jsdifflib |
1 | From: Max Reitz <mreitz@redhat.com> | 1 | Block drivers assume in their .bdrv_open() implementation that their |
---|---|---|---|
2 | state in bs->opaque has been zeroed; it is initially allocated with | ||
3 | g_malloc0() in bdrv_open_driver(). | ||
2 | 4 | ||
3 | The create and convert subcommands have shorthands to set the | 5 | bdrv_snapshot_goto() needs to make sure that it is zeroed again before |
4 | backing_file and, in the case of create, the backing_fmt options for the | 6 | calling drv->bdrv_open() to avoid that block drivers use stale values. |
5 | new image. However, they have not been documented so far, which is | ||
6 | remedied by this patch. | ||
7 | 7 | ||
8 | Reported-by: Eric Blake <eblake@redhat.com> | 8 | One symptom of this bug is VMDK running into a double free when the user |
9 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 9 | tries to apply an internal snapshot like 'qemu-img snapshot -a test |
10 | Reviewed-by: Eric Blake <eblake@redhat.com> | 10 | test.vmdk'. This should be a graceful error because VMDK doesn't support |
11 | internal snapshots. | ||
12 | |||
13 | ==25507== Invalid free() / delete / delete[] / realloc() | ||
14 | ==25507== at 0x484B347: realloc (vg_replace_malloc.c:1801) | ||
15 | ==25507== by 0x54B592A: g_realloc (gmem.c:171) | ||
16 | ==25507== by 0x1B221D: vmdk_add_extent (../block/vmdk.c:570) | ||
17 | ==25507== by 0x1B1084: vmdk_open_sparse (../block/vmdk.c:1059) | ||
18 | ==25507== by 0x1AF3D8: vmdk_open (../block/vmdk.c:1371) | ||
19 | ==25507== by 0x1A2AE0: bdrv_snapshot_goto (../block/snapshot.c:299) | ||
20 | ==25507== by 0x205C77: img_snapshot (../qemu-img.c:3500) | ||
21 | ==25507== by 0x58FA087: (below main) (libc_start_call_main.h:58) | ||
22 | ==25507== Address 0x832f3e0 is 0 bytes inside a block of size 272 free'd | ||
23 | ==25507== at 0x4846B83: free (vg_replace_malloc.c:989) | ||
24 | ==25507== by 0x54AEAC4: g_free (gmem.c:208) | ||
25 | ==25507== by 0x1AF629: vmdk_close (../block/vmdk.c:2889) | ||
26 | ==25507== by 0x1A2A9C: bdrv_snapshot_goto (../block/snapshot.c:290) | ||
27 | ==25507== by 0x205C77: img_snapshot (../qemu-img.c:3500) | ||
28 | ==25507== by 0x58FA087: (below main) (libc_start_call_main.h:58) | ||
29 | |||
30 | This error was discovered by fuzzing qemu-img. | ||
31 | |||
32 | Cc: qemu-stable@nongnu.org | ||
33 | Closes: https://gitlab.com/qemu-project/qemu/-/issues/2853 | ||
34 | Closes: https://gitlab.com/qemu-project/qemu/-/issues/2851 | ||
35 | Reported-by: Denis Rastyogin <gerben@altlinux.org> | ||
36 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
37 | Message-ID: <20250310104858.28221-1-kwolf@redhat.com> | ||
11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 38 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
12 | --- | 39 | --- |
13 | qemu-img-cmds.hx | 8 ++++---- | 40 | block/snapshot.c | 1 + |
14 | qemu-img.texi | 4 ++-- | 41 | 1 file changed, 1 insertion(+) |
15 | 2 files changed, 6 insertions(+), 6 deletions(-) | ||
16 | 42 | ||
17 | diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx | 43 | diff --git a/block/snapshot.c b/block/snapshot.c |
18 | index XXXXXXX..XXXXXXX 100644 | 44 | index XXXXXXX..XXXXXXX 100644 |
19 | --- a/qemu-img-cmds.hx | 45 | --- a/block/snapshot.c |
20 | +++ b/qemu-img-cmds.hx | 46 | +++ b/block/snapshot.c |
21 | @@ -XXX,XX +XXX,XX @@ STEXI | 47 | @@ -XXX,XX +XXX,XX @@ int bdrv_snapshot_goto(BlockDriverState *bs, |
22 | ETEXI | 48 | bdrv_graph_wrunlock(); |
23 | 49 | ||
24 | DEF("create", img_create, | 50 | ret = bdrv_snapshot_goto(fallback_bs, snapshot_id, errp); |
25 | - "create [-q] [--object objectdef] [-f fmt] [-o options] filename [size]") | 51 | + memset(bs->opaque, 0, drv->instance_size); |
26 | + "create [-q] [--object objectdef] [-f fmt] [-b backing_file] [-F backing_fmt] [-o options] filename [size]") | 52 | open_ret = drv->bdrv_open(bs, options, bs->open_flags, &local_err); |
27 | STEXI | 53 | qobject_unref(options); |
28 | -@item create [--object @var{objectdef}] [-q] [-f @var{fmt}] [-o @var{options}] @var{filename} [@var{size}] | 54 | if (open_ret < 0) { |
29 | +@item create [--object @var{objectdef}] [-q] [-f @var{fmt}] [-b @var{backing_file}] [-F @var{backing_fmt}] [-o @var{options}] @var{filename} [@var{size}] | ||
30 | ETEXI | ||
31 | |||
32 | DEF("commit", img_commit, | ||
33 | @@ -XXX,XX +XXX,XX @@ STEXI | ||
34 | ETEXI | ||
35 | |||
36 | DEF("convert", img_convert, | ||
37 | - "convert [--object objectdef] [--image-opts] [-c] [-p] [-q] [-n] [-f fmt] [-t cache] [-T src_cache] [-O output_fmt] [-o options] [-s snapshot_id_or_name] [-l snapshot_param] [-S sparse_size] [-m num_coroutines] [-W] filename [filename2 [...]] output_filename") | ||
38 | + "convert [--object objectdef] [--image-opts] [-c] [-p] [-q] [-n] [-f fmt] [-t cache] [-T src_cache] [-O output_fmt] [-B backing_file] [-o options] [-s snapshot_id_or_name] [-l snapshot_param] [-S sparse_size] [-m num_coroutines] [-W] filename [filename2 [...]] output_filename") | ||
39 | STEXI | ||
40 | -@item convert [--object @var{objectdef}] [--image-opts] [-c] [-p] [-q] [-n] [-f @var{fmt}] [-t @var{cache}] [-T @var{src_cache}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_id_or_name}] [-l @var{snapshot_param}] [-S @var{sparse_size}] [-m @var{num_coroutines}] [-W] @var{filename} [@var{filename2} [...]] @var{output_filename} | ||
41 | +@item convert [--object @var{objectdef}] [--image-opts] [-c] [-p] [-q] [-n] [-f @var{fmt}] [-t @var{cache}] [-T @var{src_cache}] [-O @var{output_fmt}] [-B @var{backing_file}] [-o @var{options}] [-s @var{snapshot_id_or_name}] [-l @var{snapshot_param}] [-S @var{sparse_size}] [-m @var{num_coroutines}] [-W] @var{filename} [@var{filename2} [...]] @var{output_filename} | ||
42 | ETEXI | ||
43 | |||
44 | DEF("dd", img_dd, | ||
45 | diff --git a/qemu-img.texi b/qemu-img.texi | ||
46 | index XXXXXXX..XXXXXXX 100644 | ||
47 | --- a/qemu-img.texi | ||
48 | +++ b/qemu-img.texi | ||
49 | @@ -XXX,XX +XXX,XX @@ If @code{-r} is specified, exit codes representing the image state refer to the | ||
50 | state after (the attempt at) repairing it. That is, a successful @code{-r all} | ||
51 | will yield the exit code 0, independently of the image state before. | ||
52 | |||
53 | -@item create [-f @var{fmt}] [-o @var{options}] @var{filename} [@var{size}] | ||
54 | +@item create [-f @var{fmt}] [-b @var{backing_file}] [-F @var{backing_fmt}] [-o @var{options}] @var{filename} [@var{size}] | ||
55 | |||
56 | Create the new disk image @var{filename} of size @var{size} and format | ||
57 | @var{fmt}. Depending on the file format, you can add one or more @var{options} | ||
58 | @@ -XXX,XX +XXX,XX @@ Error on reading data | ||
59 | |||
60 | @end table | ||
61 | |||
62 | -@item convert [-c] [-p] [-n] [-f @var{fmt}] [-t @var{cache}] [-T @var{src_cache}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_id_or_name}] [-l @var{snapshot_param}] [-m @var{num_coroutines}] [-W] [-S @var{sparse_size}] @var{filename} [@var{filename2} [...]] @var{output_filename} | ||
63 | +@item convert [-c] [-p] [-n] [-f @var{fmt}] [-t @var{cache}] [-T @var{src_cache}] [-O @var{output_fmt}] [-B @var{backing_file}] [-o @var{options}] [-s @var{snapshot_id_or_name}] [-l @var{snapshot_param}] [-m @var{num_coroutines}] [-W] [-S @var{sparse_size}] @var{filename} [@var{filename2} [...]] @var{output_filename} | ||
64 | |||
65 | Convert the disk image @var{filename} or a snapshot @var{snapshot_param}(@var{snapshot_id_or_name} is deprecated) | ||
66 | to disk image @var{output_filename} using format @var{output_fmt}. It can be optionally compressed (@code{-c} | ||
67 | -- | 55 | -- |
68 | 1.8.3.1 | 56 | 2.48.1 |
69 | |||
70 | diff view generated by jsdifflib |
1 | From: Max Reitz <mreitz@redhat.com> | 1 | Until now, FUA was always emulated with a separate flush after the write |
---|---|---|---|
2 | 2 | for file-posix. The overhead of processing a second request can reduce | |
3 | Add missing error messages for the block driver implementations of | 3 | performance significantly for a guest disk that has disabled the write |
4 | .bdrv_truncate(); drop the generic one from block.c's bdrv_truncate(). | 4 | cache, especially if the host disk is already write through, too, and |
5 | 5 | the flush isn't actually doing anything. | |
6 | Since one of these changes touches a mis-indented block in | 6 | |
7 | block/file-posix.c, this patch fixes that coding style issue along the | 7 | Advertise support for REQ_FUA in write requests and implement it for |
8 | way. | 8 | Linux AIO and io_uring using the RWF_DSYNC flag for write requests. The |
9 | 9 | thread pool still performs a separate fdatasync() call. This can be | |
10 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 10 | improved later by using the pwritev2() syscall if available. |
11 | Message-id: 20170328205129.15138-5-mreitz@redhat.com | 11 | |
12 | As an example, this is how fio numbers can be improved in some scenarios | ||
13 | with this patch (all using virtio-blk with cache=directsync on an nvme | ||
14 | block device for the VM, fio with ioengine=libaio,direct=1,sync=1): | ||
15 | |||
16 | | old | with FUA support | ||
17 | ------------------------------+---------------+------------------- | ||
18 | bs=4k, iodepth=1, numjobs=1 | 45.6k iops | 56.1k iops | ||
19 | bs=4k, iodepth=1, numjobs=16 | 183.3k iops | 236.0k iops | ||
20 | bs=4k, iodepth=16, numjobs=1 | 258.4k iops | 311.1k iops | ||
21 | |||
22 | However, not all scenarios are clear wins. On another slower disk I saw | ||
23 | little to no improvment. In fact, in two corner case scenarios, I even | ||
24 | observed a regression, which I however consider acceptable: | ||
25 | |||
26 | 1. On slow host disks in a write through cache mode, when the guest is | ||
27 | using virtio-blk in a separate iothread so that polling can be | ||
28 | enabled, and each completion is quickly followed up with a new | ||
29 | request (so that polling gets it), it can happen that enabling FUA | ||
30 | makes things slower - the additional very fast no-op flush we used to | ||
31 | have gave the adaptive polling algorithm a success so that it kept | ||
32 | polling. Without it, we only have the slow write request, which | ||
33 | disables polling. This is a problem in the polling algorithm that | ||
34 | will be fixed later in this series. | ||
35 | |||
36 | 2. With a high queue depth, it can be beneficial to have flush requests | ||
37 | for another reason: The optimisation in bdrv_co_flush() that flushes | ||
38 | only once per write generation acts as a synchronisation mechanism | ||
39 | that lets all requests complete at the same time. This can result in | ||
40 | better batching and if the disk is very fast (I only saw this with a | ||
41 | null_blk backend), this can make up for the overhead of the flush and | ||
42 | improve throughput. In theory, we could optionally introduce a | ||
43 | similar artificial latency in the normal completion path to achieve | ||
44 | the same kind of completion batching. This is not implemented in this | ||
45 | series. | ||
46 | |||
47 | Compatibility is not a concern for io_uring, it has supported RWF_DSYNC | ||
48 | from the start. Linux AIO started supporting it in Linux 4.13 and libaio | ||
49 | 0.3.111. The kernel is not a problem for any supported build platform, | ||
50 | so it's not necessary to add runtime checks. However, openSUSE is still | ||
51 | stuck with an older libaio version that would break the build. We must | ||
52 | detect this at build time to avoid build failures. | ||
53 | |||
54 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
55 | Message-ID: <20250307221634.71951-2-kwolf@redhat.com> | ||
12 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | 56 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> |
13 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 57 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
14 | --- | 58 | --- |
15 | block.c | 2 -- | 59 | include/block/raw-aio.h | 8 ++++++-- |
16 | block/file-posix.c | 17 ++++++++++++----- | 60 | block/file-posix.c | 26 ++++++++++++++++++-------- |
17 | block/gluster.c | 4 +++- | 61 | block/io_uring.c | 13 ++++++++----- |
18 | block/iscsi.c | 2 ++ | 62 | block/linux-aio.c | 24 +++++++++++++++++++++--- |
19 | block/nfs.c | 10 +++++++++- | 63 | meson.build | 4 ++++ |
20 | block/qcow2.c | 2 ++ | 64 | 5 files changed, 57 insertions(+), 18 deletions(-) |
21 | block/qed.c | 4 +++- | 65 | |
22 | block/raw-format.c | 2 ++ | 66 | diff --git a/include/block/raw-aio.h b/include/block/raw-aio.h |
23 | block/rbd.c | 1 + | 67 | index XXXXXXX..XXXXXXX 100644 |
24 | 9 files changed, 34 insertions(+), 10 deletions(-) | 68 | --- a/include/block/raw-aio.h |
25 | 69 | +++ b/include/block/raw-aio.h | |
26 | diff --git a/block.c b/block.c | 70 | @@ -XXX,XX +XXX,XX @@ |
27 | index XXXXXXX..XXXXXXX 100644 | 71 | #define QEMU_RAW_AIO_H |
28 | --- a/block.c | 72 | |
29 | +++ b/block.c | 73 | #include "block/aio.h" |
30 | @@ -XXX,XX +XXX,XX @@ int bdrv_truncate(BdrvChild *child, int64_t offset, Error **errp) | 74 | +#include "block/block-common.h" |
31 | bdrv_dirty_bitmap_truncate(bs); | 75 | #include "qemu/iov.h" |
32 | bdrv_parent_cb_resize(bs); | 76 | |
33 | ++bs->write_gen; | 77 | /* AIO request types */ |
34 | - } else if (errp && !*errp) { | 78 | @@ -XXX,XX +XXX,XX @@ void laio_cleanup(LinuxAioState *s); |
35 | - error_setg_errno(errp, -ret, "Failed to resize image"); | 79 | |
36 | } | 80 | /* laio_co_submit: submit I/O requests in the thread's current AioContext. */ |
37 | return ret; | 81 | int coroutine_fn laio_co_submit(int fd, uint64_t offset, QEMUIOVector *qiov, |
38 | } | 82 | - int type, uint64_t dev_max_batch); |
83 | + int type, BdrvRequestFlags flags, | ||
84 | + uint64_t dev_max_batch); | ||
85 | |||
86 | bool laio_has_fdsync(int); | ||
87 | +bool laio_has_fua(void); | ||
88 | void laio_detach_aio_context(LinuxAioState *s, AioContext *old_context); | ||
89 | void laio_attach_aio_context(LinuxAioState *s, AioContext *new_context); | ||
90 | #endif | ||
91 | @@ -XXX,XX +XXX,XX @@ void luring_cleanup(LuringState *s); | ||
92 | |||
93 | /* luring_co_submit: submit I/O requests in the thread's current AioContext. */ | ||
94 | int coroutine_fn luring_co_submit(BlockDriverState *bs, int fd, uint64_t offset, | ||
95 | - QEMUIOVector *qiov, int type); | ||
96 | + QEMUIOVector *qiov, int type, | ||
97 | + BdrvRequestFlags flags); | ||
98 | void luring_detach_aio_context(LuringState *s, AioContext *old_context); | ||
99 | void luring_attach_aio_context(LuringState *s, AioContext *new_context); | ||
100 | #endif | ||
39 | diff --git a/block/file-posix.c b/block/file-posix.c | 101 | diff --git a/block/file-posix.c b/block/file-posix.c |
40 | index XXXXXXX..XXXXXXX 100644 | 102 | index XXXXXXX..XXXXXXX 100644 |
41 | --- a/block/file-posix.c | 103 | --- a/block/file-posix.c |
42 | +++ b/block/file-posix.c | 104 | +++ b/block/file-posix.c |
43 | @@ -XXX,XX +XXX,XX @@ static int raw_truncate(BlockDriverState *bs, int64_t offset, Error **errp) | 105 | @@ -XXX,XX +XXX,XX @@ static int fd_open(BlockDriverState *bs) |
44 | { | 106 | } |
45 | BDRVRawState *s = bs->opaque; | 107 | |
46 | struct stat st; | 108 | static int64_t raw_getlength(BlockDriverState *bs); |
47 | + int ret; | 109 | +static int coroutine_fn raw_co_flush_to_disk(BlockDriverState *bs); |
48 | 110 | ||
49 | if (fstat(s->fd, &st)) { | 111 | typedef struct RawPosixAIOData { |
50 | - return -errno; | 112 | BlockDriverState *bs; |
51 | + ret = -errno; | 113 | @@ -XXX,XX +XXX,XX @@ static int raw_open_common(BlockDriverState *bs, QDict *options, |
52 | + error_setg_errno(errp, -ret, "Failed to fstat() the file"); | 114 | #endif |
53 | + return ret; | 115 | s->needs_alignment = raw_needs_alignment(bs); |
54 | } | 116 | |
55 | 117 | + if (!s->use_linux_aio || laio_has_fua()) { | |
56 | if (S_ISREG(st.st_mode)) { | 118 | + bs->supported_write_flags = BDRV_REQ_FUA; |
57 | if (ftruncate(s->fd, offset) < 0) { | ||
58 | - return -errno; | ||
59 | + ret = -errno; | ||
60 | + error_setg_errno(errp, -ret, "Failed to resize the file"); | ||
61 | + return ret; | ||
62 | } | ||
63 | } else if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) { | ||
64 | - if (offset > raw_getlength(bs)) { | ||
65 | - return -EINVAL; | ||
66 | - } | ||
67 | + if (offset > raw_getlength(bs)) { | ||
68 | + error_setg(errp, "Cannot grow device files"); | ||
69 | + return -EINVAL; | ||
70 | + } | ||
71 | } else { | ||
72 | + error_setg(errp, "Resizing this file is not supported"); | ||
73 | return -ENOTSUP; | ||
74 | } | ||
75 | |||
76 | diff --git a/block/gluster.c b/block/gluster.c | ||
77 | index XXXXXXX..XXXXXXX 100644 | ||
78 | --- a/block/gluster.c | ||
79 | +++ b/block/gluster.c | ||
80 | @@ -XXX,XX +XXX,XX @@ static int qemu_gluster_truncate(BlockDriverState *bs, int64_t offset, | ||
81 | |||
82 | ret = glfs_ftruncate(s->fd, offset); | ||
83 | if (ret < 0) { | ||
84 | - return -errno; | ||
85 | + ret = -errno; | ||
86 | + error_setg_errno(errp, -ret, "Failed to truncate file"); | ||
87 | + return ret; | ||
88 | } | ||
89 | |||
90 | return 0; | ||
91 | diff --git a/block/iscsi.c b/block/iscsi.c | ||
92 | index XXXXXXX..XXXXXXX 100644 | ||
93 | --- a/block/iscsi.c | ||
94 | +++ b/block/iscsi.c | ||
95 | @@ -XXX,XX +XXX,XX @@ static int iscsi_truncate(BlockDriverState *bs, int64_t offset, Error **errp) | ||
96 | Error *local_err = NULL; | ||
97 | |||
98 | if (iscsilun->type != TYPE_DISK) { | ||
99 | + error_setg(errp, "Cannot resize non-disk iSCSI devices"); | ||
100 | return -ENOTSUP; | ||
101 | } | ||
102 | |||
103 | @@ -XXX,XX +XXX,XX @@ static int iscsi_truncate(BlockDriverState *bs, int64_t offset, Error **errp) | ||
104 | } | ||
105 | |||
106 | if (offset > iscsi_getlength(bs)) { | ||
107 | + error_setg(errp, "Cannot grow iSCSI devices"); | ||
108 | return -EINVAL; | ||
109 | } | ||
110 | |||
111 | diff --git a/block/nfs.c b/block/nfs.c | ||
112 | index XXXXXXX..XXXXXXX 100644 | ||
113 | --- a/block/nfs.c | ||
114 | +++ b/block/nfs.c | ||
115 | @@ -XXX,XX +XXX,XX @@ static int64_t nfs_get_allocated_file_size(BlockDriverState *bs) | ||
116 | static int nfs_file_truncate(BlockDriverState *bs, int64_t offset, Error **errp) | ||
117 | { | ||
118 | NFSClient *client = bs->opaque; | ||
119 | - return nfs_ftruncate(client->context, client->fh, offset); | ||
120 | + int ret; | ||
121 | + | ||
122 | + ret = nfs_ftruncate(client->context, client->fh, offset); | ||
123 | + if (ret < 0) { | ||
124 | + error_setg_errno(errp, -ret, "Failed to truncate file"); | ||
125 | + return ret; | ||
126 | + } | 119 | + } |
127 | + | 120 | + |
128 | + return 0; | 121 | bs->supported_zero_flags = BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK; |
129 | } | 122 | if (S_ISREG(st.st_mode)) { |
130 | 123 | /* When extending regular files, we get zeros from the OS */ | |
131 | /* Note that this will not re-establish a connection with the NFS server | 124 | @@ -XXX,XX +XXX,XX @@ static inline bool raw_check_linux_aio(BDRVRawState *s) |
132 | diff --git a/block/qcow2.c b/block/qcow2.c | 125 | #endif |
133 | index XXXXXXX..XXXXXXX 100644 | 126 | |
134 | --- a/block/qcow2.c | 127 | static int coroutine_fn raw_co_prw(BlockDriverState *bs, int64_t *offset_ptr, |
135 | +++ b/block/qcow2.c | 128 | - uint64_t bytes, QEMUIOVector *qiov, int type) |
136 | @@ -XXX,XX +XXX,XX @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset, Error **errp) | 129 | + uint64_t bytes, QEMUIOVector *qiov, int type, |
137 | new_l1_size = size_to_l1(s, offset); | 130 | + int flags) |
138 | ret = qcow2_grow_l1_table(bs, new_l1_size, true); | 131 | { |
132 | BDRVRawState *s = bs->opaque; | ||
133 | RawPosixAIOData acb; | ||
134 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_prw(BlockDriverState *bs, int64_t *offset_ptr, | ||
135 | #ifdef CONFIG_LINUX_IO_URING | ||
136 | } else if (raw_check_linux_io_uring(s)) { | ||
137 | assert(qiov->size == bytes); | ||
138 | - ret = luring_co_submit(bs, s->fd, offset, qiov, type); | ||
139 | + ret = luring_co_submit(bs, s->fd, offset, qiov, type, flags); | ||
140 | goto out; | ||
141 | #endif | ||
142 | #ifdef CONFIG_LINUX_AIO | ||
143 | } else if (raw_check_linux_aio(s)) { | ||
144 | assert(qiov->size == bytes); | ||
145 | - ret = laio_co_submit(s->fd, offset, qiov, type, | ||
146 | + ret = laio_co_submit(s->fd, offset, qiov, type, flags, | ||
147 | s->aio_max_batch); | ||
148 | goto out; | ||
149 | #endif | ||
150 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_prw(BlockDriverState *bs, int64_t *offset_ptr, | ||
151 | |||
152 | assert(qiov->size == bytes); | ||
153 | ret = raw_thread_pool_submit(handle_aiocb_rw, &acb); | ||
154 | + if (ret == 0 && (flags & BDRV_REQ_FUA)) { | ||
155 | + /* TODO Use pwritev2() instead if it's available */ | ||
156 | + ret = raw_co_flush_to_disk(bs); | ||
157 | + } | ||
158 | goto out; /* Avoid the compiler err of unused label */ | ||
159 | |||
160 | out: | ||
161 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_preadv(BlockDriverState *bs, int64_t offset, | ||
162 | int64_t bytes, QEMUIOVector *qiov, | ||
163 | BdrvRequestFlags flags) | ||
164 | { | ||
165 | - return raw_co_prw(bs, &offset, bytes, qiov, QEMU_AIO_READ); | ||
166 | + return raw_co_prw(bs, &offset, bytes, qiov, QEMU_AIO_READ, flags); | ||
167 | } | ||
168 | |||
169 | static int coroutine_fn raw_co_pwritev(BlockDriverState *bs, int64_t offset, | ||
170 | int64_t bytes, QEMUIOVector *qiov, | ||
171 | BdrvRequestFlags flags) | ||
172 | { | ||
173 | - return raw_co_prw(bs, &offset, bytes, qiov, QEMU_AIO_WRITE); | ||
174 | + return raw_co_prw(bs, &offset, bytes, qiov, QEMU_AIO_WRITE, flags); | ||
175 | } | ||
176 | |||
177 | static int coroutine_fn raw_co_flush_to_disk(BlockDriverState *bs) | ||
178 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_flush_to_disk(BlockDriverState *bs) | ||
179 | |||
180 | #ifdef CONFIG_LINUX_IO_URING | ||
181 | if (raw_check_linux_io_uring(s)) { | ||
182 | - return luring_co_submit(bs, s->fd, 0, NULL, QEMU_AIO_FLUSH); | ||
183 | + return luring_co_submit(bs, s->fd, 0, NULL, QEMU_AIO_FLUSH, 0); | ||
184 | } | ||
185 | #endif | ||
186 | #ifdef CONFIG_LINUX_AIO | ||
187 | if (s->has_laio_fdsync && raw_check_linux_aio(s)) { | ||
188 | - return laio_co_submit(s->fd, 0, NULL, QEMU_AIO_FLUSH, 0); | ||
189 | + return laio_co_submit(s->fd, 0, NULL, QEMU_AIO_FLUSH, 0, 0); | ||
190 | } | ||
191 | #endif | ||
192 | return raw_thread_pool_submit(handle_aiocb_flush, &acb); | ||
193 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_zone_append(BlockDriverState *bs, | ||
194 | } | ||
195 | |||
196 | trace_zbd_zone_append(bs, *offset >> BDRV_SECTOR_BITS); | ||
197 | - return raw_co_prw(bs, offset, len, qiov, QEMU_AIO_ZONE_APPEND); | ||
198 | + return raw_co_prw(bs, offset, len, qiov, QEMU_AIO_ZONE_APPEND, 0); | ||
199 | } | ||
200 | #endif | ||
201 | |||
202 | diff --git a/block/io_uring.c b/block/io_uring.c | ||
203 | index XXXXXXX..XXXXXXX 100644 | ||
204 | --- a/block/io_uring.c | ||
205 | +++ b/block/io_uring.c | ||
206 | @@ -XXX,XX +XXX,XX @@ static void luring_deferred_fn(void *opaque) | ||
207 | * | ||
208 | */ | ||
209 | static int luring_do_submit(int fd, LuringAIOCB *luringcb, LuringState *s, | ||
210 | - uint64_t offset, int type) | ||
211 | + uint64_t offset, int type, BdrvRequestFlags flags) | ||
212 | { | ||
213 | int ret; | ||
214 | struct io_uring_sqe *sqes = &luringcb->sqeq; | ||
215 | + int luring_flags; | ||
216 | |||
217 | switch (type) { | ||
218 | case QEMU_AIO_WRITE: | ||
219 | - io_uring_prep_writev(sqes, fd, luringcb->qiov->iov, | ||
220 | - luringcb->qiov->niov, offset); | ||
221 | + luring_flags = (flags & BDRV_REQ_FUA) ? RWF_DSYNC : 0; | ||
222 | + io_uring_prep_writev2(sqes, fd, luringcb->qiov->iov, | ||
223 | + luringcb->qiov->niov, offset, luring_flags); | ||
224 | break; | ||
225 | case QEMU_AIO_ZONE_APPEND: | ||
226 | io_uring_prep_writev(sqes, fd, luringcb->qiov->iov, | ||
227 | @@ -XXX,XX +XXX,XX @@ static int luring_do_submit(int fd, LuringAIOCB *luringcb, LuringState *s, | ||
228 | } | ||
229 | |||
230 | int coroutine_fn luring_co_submit(BlockDriverState *bs, int fd, uint64_t offset, | ||
231 | - QEMUIOVector *qiov, int type) | ||
232 | + QEMUIOVector *qiov, int type, | ||
233 | + BdrvRequestFlags flags) | ||
234 | { | ||
235 | int ret; | ||
236 | AioContext *ctx = qemu_get_current_aio_context(); | ||
237 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn luring_co_submit(BlockDriverState *bs, int fd, uint64_t offset, | ||
238 | }; | ||
239 | trace_luring_co_submit(bs, s, &luringcb, fd, offset, qiov ? qiov->size : 0, | ||
240 | type); | ||
241 | - ret = luring_do_submit(fd, &luringcb, s, offset, type); | ||
242 | + ret = luring_do_submit(fd, &luringcb, s, offset, type, flags); | ||
243 | |||
139 | if (ret < 0) { | 244 | if (ret < 0) { |
140 | + error_setg_errno(errp, -ret, "Failed to grow the L1 table"); | 245 | return ret; |
246 | diff --git a/block/linux-aio.c b/block/linux-aio.c | ||
247 | index XXXXXXX..XXXXXXX 100644 | ||
248 | --- a/block/linux-aio.c | ||
249 | +++ b/block/linux-aio.c | ||
250 | @@ -XXX,XX +XXX,XX @@ static void laio_deferred_fn(void *opaque) | ||
251 | } | ||
252 | |||
253 | static int laio_do_submit(int fd, struct qemu_laiocb *laiocb, off_t offset, | ||
254 | - int type, uint64_t dev_max_batch) | ||
255 | + int type, BdrvRequestFlags flags, | ||
256 | + uint64_t dev_max_batch) | ||
257 | { | ||
258 | LinuxAioState *s = laiocb->ctx; | ||
259 | struct iocb *iocbs = &laiocb->iocb; | ||
260 | QEMUIOVector *qiov = laiocb->qiov; | ||
261 | + int laio_flags; | ||
262 | |||
263 | switch (type) { | ||
264 | case QEMU_AIO_WRITE: | ||
265 | +#ifdef HAVE_IO_PREP_PWRITEV2 | ||
266 | + laio_flags = (flags & BDRV_REQ_FUA) ? RWF_DSYNC : 0; | ||
267 | + io_prep_pwritev2(iocbs, fd, qiov->iov, qiov->niov, offset, laio_flags); | ||
268 | +#else | ||
269 | + assert(flags == 0); | ||
270 | io_prep_pwritev(iocbs, fd, qiov->iov, qiov->niov, offset); | ||
271 | +#endif | ||
272 | break; | ||
273 | case QEMU_AIO_ZONE_APPEND: | ||
274 | io_prep_pwritev(iocbs, fd, qiov->iov, qiov->niov, offset); | ||
275 | @@ -XXX,XX +XXX,XX @@ static int laio_do_submit(int fd, struct qemu_laiocb *laiocb, off_t offset, | ||
276 | } | ||
277 | |||
278 | int coroutine_fn laio_co_submit(int fd, uint64_t offset, QEMUIOVector *qiov, | ||
279 | - int type, uint64_t dev_max_batch) | ||
280 | + int type, BdrvRequestFlags flags, | ||
281 | + uint64_t dev_max_batch) | ||
282 | { | ||
283 | int ret; | ||
284 | AioContext *ctx = qemu_get_current_aio_context(); | ||
285 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn laio_co_submit(int fd, uint64_t offset, QEMUIOVector *qiov, | ||
286 | .qiov = qiov, | ||
287 | }; | ||
288 | |||
289 | - ret = laio_do_submit(fd, &laiocb, offset, type, dev_max_batch); | ||
290 | + ret = laio_do_submit(fd, &laiocb, offset, type, flags, dev_max_batch); | ||
291 | if (ret < 0) { | ||
141 | return ret; | 292 | return ret; |
142 | } | 293 | } |
143 | 294 | @@ -XXX,XX +XXX,XX @@ bool laio_has_fdsync(int fd) | |
144 | @@ -XXX,XX +XXX,XX @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset, Error **errp) | 295 | io_destroy(ctx); |
145 | ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, size), | 296 | return (ret == -EINVAL) ? false : true; |
146 | &offset, sizeof(uint64_t)); | 297 | } |
147 | if (ret < 0) { | 298 | + |
148 | + error_setg_errno(errp, -ret, "Failed to update the image size"); | 299 | +bool laio_has_fua(void) |
149 | return ret; | 300 | +{ |
150 | } | 301 | +#ifdef HAVE_IO_PREP_PWRITEV2 |
151 | 302 | + return true; | |
152 | diff --git a/block/qed.c b/block/qed.c | 303 | +#else |
153 | index XXXXXXX..XXXXXXX 100644 | 304 | + return false; |
154 | --- a/block/qed.c | 305 | +#endif |
155 | +++ b/block/qed.c | 306 | +} |
156 | @@ -XXX,XX +XXX,XX @@ static int bdrv_qed_truncate(BlockDriverState *bs, int64_t offset, Error **errp) | 307 | diff --git a/meson.build b/meson.build |
157 | 308 | index XXXXXXX..XXXXXXX 100644 | |
158 | if (!qed_is_image_size_valid(offset, s->header.cluster_size, | 309 | --- a/meson.build |
159 | s->header.table_size)) { | 310 | +++ b/meson.build |
160 | + error_setg(errp, "Invalid image size specified"); | 311 | @@ -XXX,XX +XXX,XX @@ config_host_data.set('HAVE_OPTRESET', |
161 | return -EINVAL; | 312 | cc.has_header_symbol('getopt.h', 'optreset')) |
162 | } | 313 | config_host_data.set('HAVE_IPPROTO_MPTCP', |
163 | 314 | cc.has_header_symbol('netinet/in.h', 'IPPROTO_MPTCP')) | |
164 | - /* Shrinking is currently not supported */ | 315 | +if libaio.found() |
165 | if ((uint64_t)offset < s->header.image_size) { | 316 | + config_host_data.set('HAVE_IO_PREP_PWRITEV2', |
166 | + error_setg(errp, "Shrinking images is currently not supported"); | 317 | + cc.has_header_symbol('libaio.h', 'io_prep_pwritev2')) |
167 | return -ENOTSUP; | 318 | +endif |
168 | } | 319 | |
169 | 320 | # has_member | |
170 | @@ -XXX,XX +XXX,XX @@ static int bdrv_qed_truncate(BlockDriverState *bs, int64_t offset, Error **errp) | 321 | config_host_data.set('HAVE_SIGEV_NOTIFY_THREAD_ID', |
171 | ret = qed_write_header_sync(s); | ||
172 | if (ret < 0) { | ||
173 | s->header.image_size = old_image_size; | ||
174 | + error_setg_errno(errp, -ret, "Failed to update the image size"); | ||
175 | } | ||
176 | return ret; | ||
177 | } | ||
178 | diff --git a/block/raw-format.c b/block/raw-format.c | ||
179 | index XXXXXXX..XXXXXXX 100644 | ||
180 | --- a/block/raw-format.c | ||
181 | +++ b/block/raw-format.c | ||
182 | @@ -XXX,XX +XXX,XX @@ static int raw_truncate(BlockDriverState *bs, int64_t offset, Error **errp) | ||
183 | BDRVRawState *s = bs->opaque; | ||
184 | |||
185 | if (s->has_size) { | ||
186 | + error_setg(errp, "Cannot resize fixed-size raw disks"); | ||
187 | return -ENOTSUP; | ||
188 | } | ||
189 | |||
190 | if (INT64_MAX - offset < s->offset) { | ||
191 | + error_setg(errp, "Disk size too large for the chosen offset"); | ||
192 | return -EINVAL; | ||
193 | } | ||
194 | |||
195 | diff --git a/block/rbd.c b/block/rbd.c | ||
196 | index XXXXXXX..XXXXXXX 100644 | ||
197 | --- a/block/rbd.c | ||
198 | +++ b/block/rbd.c | ||
199 | @@ -XXX,XX +XXX,XX @@ static int qemu_rbd_truncate(BlockDriverState *bs, int64_t offset, Error **errp) | ||
200 | |||
201 | r = rbd_resize(s->image, offset); | ||
202 | if (r < 0) { | ||
203 | + error_setg_errno(errp, -r, "Failed to resize file"); | ||
204 | return r; | ||
205 | } | ||
206 | |||
207 | -- | 322 | -- |
208 | 1.8.3.1 | 323 | 2.48.1 |
209 | |||
210 | diff view generated by jsdifflib |
1 | From: Fam Zheng <famz@redhat.com> | 1 | For block drivers that don't advertise FUA support, we already call |
---|---|---|---|
2 | bdrv_co_flush(), which considers BDRV_O_NO_FLUSH. However, drivers that | ||
3 | do support FUA still see the FUA flag with BDRV_O_NO_FLUSH and get the | ||
4 | associated performance penalty that cache.no-flush=on was supposed to | ||
5 | avoid. | ||
2 | 6 | ||
3 | Reported by Coverity. We already use bs in bdrv_inc_in_flight before | 7 | Clear FUA for write requests if BDRV_O_NO_FLUSH is set. |
4 | checking for NULL. It is unnecessary as all callers pass non-NULL bs, so | ||
5 | drop it. | ||
6 | 8 | ||
7 | Signed-off-by: Fam Zheng <famz@redhat.com> | 9 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
8 | Reviewed-by: Max Reitz <mreitz@redhat.com> | 10 | Message-ID: <20250307221634.71951-3-kwolf@redhat.com> |
11 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
9 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
10 | --- | 13 | --- |
11 | block/io.c | 2 +- | 14 | block/io.c | 4 ++++ |
12 | 1 file changed, 1 insertion(+), 1 deletion(-) | 15 | 1 file changed, 4 insertions(+) |
13 | 16 | ||
14 | diff --git a/block/io.c b/block/io.c | 17 | diff --git a/block/io.c b/block/io.c |
15 | index XXXXXXX..XXXXXXX 100644 | 18 | index XXXXXXX..XXXXXXX 100644 |
16 | --- a/block/io.c | 19 | --- a/block/io.c |
17 | +++ b/block/io.c | 20 | +++ b/block/io.c |
18 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_flush(BlockDriverState *bs) | 21 | @@ -XXX,XX +XXX,XX @@ bdrv_driver_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes, |
19 | 22 | return -ENOMEDIUM; | |
20 | bdrv_inc_in_flight(bs); | ||
21 | |||
22 | - if (!bs || !bdrv_is_inserted(bs) || bdrv_is_read_only(bs) || | ||
23 | + if (!bdrv_is_inserted(bs) || bdrv_is_read_only(bs) || | ||
24 | bdrv_is_sg(bs)) { | ||
25 | goto early_exit; | ||
26 | } | 23 | } |
24 | |||
25 | + if (bs->open_flags & BDRV_O_NO_FLUSH) { | ||
26 | + flags &= ~BDRV_REQ_FUA; | ||
27 | + } | ||
28 | + | ||
29 | if ((flags & BDRV_REQ_FUA) && | ||
30 | (~bs->supported_write_flags & BDRV_REQ_FUA)) { | ||
31 | flags &= ~BDRV_REQ_FUA; | ||
27 | -- | 32 | -- |
28 | 1.8.3.1 | 33 | 2.48.1 |
29 | |||
30 | diff view generated by jsdifflib |
1 | From: "Denis V. Lunev" <den@openvz.org> | 1 | As a preparation for having multiple adaptive polling states per |
---|---|---|---|
2 | AioContext, move the 'ns' field into a separate struct. | ||
2 | 3 | ||
3 | As long as BDRV_O_INACTIVE is set, the image file is only opened so we | 4 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
4 | have a file descriptor for it. We're definitely not supposed to modify | 5 | Message-ID: <20250307221634.71951-4-kwolf@redhat.com> |
5 | the image, it's still owned by the migration source. | 6 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> |
7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
8 | --- | ||
9 | include/block/aio.h | 6 +++++- | ||
10 | util/aio-posix.c | 31 ++++++++++++++++--------------- | ||
11 | util/async.c | 3 ++- | ||
12 | 3 files changed, 23 insertions(+), 17 deletions(-) | ||
6 | 13 | ||
7 | This commit is an addition to 09e0c771 but the assert() is added to | 14 | diff --git a/include/block/aio.h b/include/block/aio.h |
8 | bdrv_truncate(). | ||
9 | |||
10 | Signed-off-by: Denis V. Lunev <den@openvz.org> | ||
11 | CC: Kevin Wolf <kwolf@redhat.com> | ||
12 | CC: Max Reitz <mreitz@redhat.com> | ||
13 | Message-id: 1491405505-31620-3-git-send-email-den@openvz.org | ||
14 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
15 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
16 | --- | ||
17 | block.c | 2 ++ | ||
18 | 1 file changed, 2 insertions(+) | ||
19 | |||
20 | diff --git a/block.c b/block.c | ||
21 | index XXXXXXX..XXXXXXX 100644 | 15 | index XXXXXXX..XXXXXXX 100644 |
22 | --- a/block.c | 16 | --- a/include/block/aio.h |
23 | +++ b/block.c | 17 | +++ b/include/block/aio.h |
24 | @@ -XXX,XX +XXX,XX @@ int bdrv_truncate(BdrvChild *child, int64_t offset, Error **errp) | 18 | @@ -XXX,XX +XXX,XX @@ struct BHListSlice { |
25 | return -EACCES; | 19 | |
20 | typedef QSLIST_HEAD(, AioHandler) AioHandlerSList; | ||
21 | |||
22 | +typedef struct AioPolledEvent { | ||
23 | + int64_t ns; /* current polling time in nanoseconds */ | ||
24 | +} AioPolledEvent; | ||
25 | + | ||
26 | struct AioContext { | ||
27 | GSource source; | ||
28 | |||
29 | @@ -XXX,XX +XXX,XX @@ struct AioContext { | ||
30 | int poll_disable_cnt; | ||
31 | |||
32 | /* Polling mode parameters */ | ||
33 | - int64_t poll_ns; /* current polling time in nanoseconds */ | ||
34 | + AioPolledEvent poll; | ||
35 | int64_t poll_max_ns; /* maximum polling time in nanoseconds */ | ||
36 | int64_t poll_grow; /* polling time growth factor */ | ||
37 | int64_t poll_shrink; /* polling time shrink factor */ | ||
38 | diff --git a/util/aio-posix.c b/util/aio-posix.c | ||
39 | index XXXXXXX..XXXXXXX 100644 | ||
40 | --- a/util/aio-posix.c | ||
41 | +++ b/util/aio-posix.c | ||
42 | @@ -XXX,XX +XXX,XX @@ static bool try_poll_mode(AioContext *ctx, AioHandlerList *ready_list, | ||
43 | return false; | ||
26 | } | 44 | } |
27 | 45 | ||
28 | + assert(!(bs->open_flags & BDRV_O_INACTIVE)); | 46 | - max_ns = qemu_soonest_timeout(*timeout, ctx->poll_ns); |
47 | + max_ns = qemu_soonest_timeout(*timeout, ctx->poll.ns); | ||
48 | if (max_ns && !ctx->fdmon_ops->need_wait(ctx)) { | ||
49 | /* | ||
50 | * Enable poll mode. It pairs with the poll_set_started() in | ||
51 | @@ -XXX,XX +XXX,XX @@ bool aio_poll(AioContext *ctx, bool blocking) | ||
52 | if (ctx->poll_max_ns) { | ||
53 | int64_t block_ns = qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - start; | ||
54 | |||
55 | - if (block_ns <= ctx->poll_ns) { | ||
56 | + if (block_ns <= ctx->poll.ns) { | ||
57 | /* This is the sweet spot, no adjustment needed */ | ||
58 | } else if (block_ns > ctx->poll_max_ns) { | ||
59 | /* We'd have to poll for too long, poll less */ | ||
60 | - int64_t old = ctx->poll_ns; | ||
61 | + int64_t old = ctx->poll.ns; | ||
62 | |||
63 | if (ctx->poll_shrink) { | ||
64 | - ctx->poll_ns /= ctx->poll_shrink; | ||
65 | + ctx->poll.ns /= ctx->poll_shrink; | ||
66 | } else { | ||
67 | - ctx->poll_ns = 0; | ||
68 | + ctx->poll.ns = 0; | ||
69 | } | ||
70 | |||
71 | - trace_poll_shrink(ctx, old, ctx->poll_ns); | ||
72 | - } else if (ctx->poll_ns < ctx->poll_max_ns && | ||
73 | + trace_poll_shrink(ctx, old, ctx->poll.ns); | ||
74 | + } else if (ctx->poll.ns < ctx->poll_max_ns && | ||
75 | block_ns < ctx->poll_max_ns) { | ||
76 | /* There is room to grow, poll longer */ | ||
77 | - int64_t old = ctx->poll_ns; | ||
78 | + int64_t old = ctx->poll.ns; | ||
79 | int64_t grow = ctx->poll_grow; | ||
80 | |||
81 | if (grow == 0) { | ||
82 | grow = 2; | ||
83 | } | ||
84 | |||
85 | - if (ctx->poll_ns) { | ||
86 | - ctx->poll_ns *= grow; | ||
87 | + if (ctx->poll.ns) { | ||
88 | + ctx->poll.ns *= grow; | ||
89 | } else { | ||
90 | - ctx->poll_ns = 4000; /* start polling at 4 microseconds */ | ||
91 | + ctx->poll.ns = 4000; /* start polling at 4 microseconds */ | ||
92 | } | ||
93 | |||
94 | - if (ctx->poll_ns > ctx->poll_max_ns) { | ||
95 | - ctx->poll_ns = ctx->poll_max_ns; | ||
96 | + if (ctx->poll.ns > ctx->poll_max_ns) { | ||
97 | + ctx->poll.ns = ctx->poll_max_ns; | ||
98 | } | ||
99 | |||
100 | - trace_poll_grow(ctx, old, ctx->poll_ns); | ||
101 | + trace_poll_grow(ctx, old, ctx->poll.ns); | ||
102 | } | ||
103 | } | ||
104 | |||
105 | @@ -XXX,XX +XXX,XX @@ void aio_context_set_poll_params(AioContext *ctx, int64_t max_ns, | ||
106 | /* No thread synchronization here, it doesn't matter if an incorrect value | ||
107 | * is used once. | ||
108 | */ | ||
109 | + ctx->poll.ns = 0; | ||
29 | + | 110 | + |
30 | ret = drv->bdrv_truncate(bs, offset, errp); | 111 | ctx->poll_max_ns = max_ns; |
31 | if (ret == 0) { | 112 | - ctx->poll_ns = 0; |
32 | ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS); | 113 | ctx->poll_grow = grow; |
114 | ctx->poll_shrink = shrink; | ||
115 | |||
116 | diff --git a/util/async.c b/util/async.c | ||
117 | index XXXXXXX..XXXXXXX 100644 | ||
118 | --- a/util/async.c | ||
119 | +++ b/util/async.c | ||
120 | @@ -XXX,XX +XXX,XX @@ AioContext *aio_context_new(Error **errp) | ||
121 | qemu_rec_mutex_init(&ctx->lock); | ||
122 | timerlistgroup_init(&ctx->tlg, aio_timerlist_notify, ctx); | ||
123 | |||
124 | - ctx->poll_ns = 0; | ||
125 | + ctx->poll.ns = 0; | ||
126 | + | ||
127 | ctx->poll_max_ns = 0; | ||
128 | ctx->poll_grow = 0; | ||
129 | ctx->poll_shrink = 0; | ||
33 | -- | 130 | -- |
34 | 1.8.3.1 | 131 | 2.48.1 |
35 | |||
36 | diff view generated by jsdifflib |
1 | The only thing the escape characters achieve is making the reference | 1 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
---|---|---|---|
2 | output unreadable and lines that are potentially so long that git | 2 | Message-ID: <20250307221634.71951-5-kwolf@redhat.com> |
3 | doesn't want to put them into an email any more. Let's filter them out. | 3 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> |
4 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
5 | --- | ||
6 | util/aio-posix.c | 77 ++++++++++++++++++++++++++---------------------- | ||
7 | 1 file changed, 41 insertions(+), 36 deletions(-) | ||
4 | 8 | ||
5 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 9 | diff --git a/util/aio-posix.c b/util/aio-posix.c |
6 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
7 | --- | ||
8 | tests/qemu-iotests/028.out | 2 +- | ||
9 | tests/qemu-iotests/051 | 3 +- | ||
10 | tests/qemu-iotests/051.out | 106 +++++++++++++++---------------- | ||
11 | tests/qemu-iotests/051.pc.out | 132 +++++++++++++++++++-------------------- | ||
12 | tests/qemu-iotests/068 | 4 +- | ||
13 | tests/qemu-iotests/068.out | 6 +- | ||
14 | tests/qemu-iotests/130.out | 4 +- | ||
15 | tests/qemu-iotests/142 | 2 +- | ||
16 | tests/qemu-iotests/142.out | 10 +-- | ||
17 | tests/qemu-iotests/145 | 3 +- | ||
18 | tests/qemu-iotests/145.out | 2 +- | ||
19 | tests/qemu-iotests/common.filter | 7 +++ | ||
20 | tests/qemu-iotests/common.qemu | 4 +- | ||
21 | 13 files changed, 147 insertions(+), 138 deletions(-) | ||
22 | |||
23 | diff --git a/tests/qemu-iotests/028.out b/tests/qemu-iotests/028.out | ||
24 | index XXXXXXX..XXXXXXX 100644 | 10 | index XXXXXXX..XXXXXXX 100644 |
25 | --- a/tests/qemu-iotests/028.out | 11 | --- a/util/aio-posix.c |
26 | +++ b/tests/qemu-iotests/028.out | 12 | +++ b/util/aio-posix.c |
27 | @@ -XXX,XX +XXX,XX @@ No errors were found on the image. | 13 | @@ -XXX,XX +XXX,XX @@ static bool try_poll_mode(AioContext *ctx, AioHandlerList *ready_list, |
28 | block-backup | 14 | return false; |
29 | |||
30 | Formatting 'TEST_DIR/t.IMGFMT.copy', fmt=IMGFMT size=4294968832 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT | ||
31 | -(qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K[D[D[D[D[D[D[D[D[D[Dinfo block-[K[D[D[D[D[D[D[D[D[D[D[Dinfo block-j[K[D[D[D[D[D[D[D[D[D[D[D[Dinfo block-jo[K[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block-job[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block-jobs[K | ||
32 | +(qemu) info block-jobs | ||
33 | No active jobs | ||
34 | === IO: pattern 195 | ||
35 | read 512/512 bytes at offset 3221194240 | ||
36 | diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051 | ||
37 | index XXXXXXX..XXXXXXX 100755 | ||
38 | --- a/tests/qemu-iotests/051 | ||
39 | +++ b/tests/qemu-iotests/051 | ||
40 | @@ -XXX,XX +XXX,XX @@ function do_run_qemu() | ||
41 | |||
42 | function run_qemu() | ||
43 | { | ||
44 | - do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu | _filter_generated_node_ids | ||
45 | + do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu | | ||
46 | + _filter_generated_node_ids | _filter_hmp | ||
47 | } | 15 | } |
48 | 16 | ||
49 | size=128M | 17 | +static void adjust_polling_time(AioContext *ctx, AioPolledEvent *poll, |
50 | diff --git a/tests/qemu-iotests/051.out b/tests/qemu-iotests/051.out | 18 | + int64_t block_ns) |
51 | index XXXXXXX..XXXXXXX 100644 | ||
52 | --- a/tests/qemu-iotests/051.out | ||
53 | +++ b/tests/qemu-iotests/051.out | ||
54 | @@ -XXX,XX +XXX,XX @@ QEMU X.Y.Z monitor - type 'help' for more information | ||
55 | |||
56 | Testing: -drive file=TEST_DIR/t.qcow2,driver=qcow2,backing.file.filename=TEST_DIR/t.qcow2.orig,if=none,id=drive0 -nodefaults | ||
57 | QEMU X.Y.Z monitor - type 'help' for more information | ||
58 | -(qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K | ||
59 | +(qemu) info block | ||
60 | drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) | ||
61 | Removable device: not locked, tray closed | ||
62 | Cache mode: writeback | ||
63 | Backing file: TEST_DIR/t.qcow2.orig (chain depth: 1) | ||
64 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
65 | +(qemu) quit | ||
66 | |||
67 | Testing: -drive file=TEST_DIR/t.qcow2,driver=raw,backing.file.filename=TEST_DIR/t.qcow2.orig | ||
68 | QEMU_PROG: -drive file=TEST_DIR/t.qcow2,driver=raw,backing.file.filename=TEST_DIR/t.qcow2.orig: Driver doesn't support backing files | ||
69 | @@ -XXX,XX +XXX,XX @@ QEMU_PROG: -drive file=TEST_DIR/t.qcow2,file.backing.driver=qcow2,file.backing.f | ||
70 | |||
71 | Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=on | ||
72 | QEMU X.Y.Z monitor - type 'help' for more information | ||
73 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
74 | +(qemu) quit | ||
75 | |||
76 | Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=off | ||
77 | QEMU X.Y.Z monitor - type 'help' for more information | ||
78 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
79 | +(qemu) quit | ||
80 | |||
81 | Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts= | ||
82 | QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=: Parameter 'lazy-refcounts' expects 'on' or 'off' | ||
83 | @@ -XXX,XX +XXX,XX @@ QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=on: Lazy ref | ||
84 | |||
85 | Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=off | ||
86 | QEMU X.Y.Z monitor - type 'help' for more information | ||
87 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
88 | +(qemu) quit | ||
89 | |||
90 | |||
91 | === No medium === | ||
92 | @@ -XXX,XX +XXX,XX @@ QEMU X.Y.Z monitor - type 'help' for more information | ||
93 | |||
94 | Testing: -drive file=TEST_DIR/t.qcow2,if=virtio,readonly=on | ||
95 | QEMU X.Y.Z monitor - type 'help' for more information | ||
96 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
97 | +(qemu) quit | ||
98 | |||
99 | |||
100 | === Cache modes === | ||
101 | |||
102 | Testing: -drive driver=null-co,cache=none | ||
103 | QEMU X.Y.Z monitor - type 'help' for more information | ||
104 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
105 | +(qemu) quit | ||
106 | |||
107 | Testing: -drive driver=null-co,cache=directsync | ||
108 | QEMU X.Y.Z monitor - type 'help' for more information | ||
109 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
110 | +(qemu) quit | ||
111 | |||
112 | Testing: -drive driver=null-co,cache=writeback | ||
113 | QEMU X.Y.Z monitor - type 'help' for more information | ||
114 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
115 | +(qemu) quit | ||
116 | |||
117 | Testing: -drive driver=null-co,cache=writethrough | ||
118 | QEMU X.Y.Z monitor - type 'help' for more information | ||
119 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
120 | +(qemu) quit | ||
121 | |||
122 | Testing: -drive driver=null-co,cache=unsafe | ||
123 | QEMU X.Y.Z monitor - type 'help' for more information | ||
124 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
125 | +(qemu) quit | ||
126 | |||
127 | Testing: -drive driver=null-co,cache=invalid_value | ||
128 | QEMU_PROG: -drive driver=null-co,cache=invalid_value: invalid cache option | ||
129 | |||
130 | Testing: -drive file=TEST_DIR/t.qcow2,cache=writeback,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0 -nodefaults | ||
131 | QEMU X.Y.Z monitor - type 'help' for more information | ||
132 | -(qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K | ||
133 | +(qemu) info block | ||
134 | drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) | ||
135 | Removable device: not locked, tray closed | ||
136 | Cache mode: writeback | ||
137 | Backing file: TEST_DIR/t.qcow2.base (chain depth: 1) | ||
138 | -(qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K[D[D[D[D[D[D[D[D[D[Dinfo block [K[D[D[D[D[D[D[D[D[D[D[Dinfo block f[K[D[D[D[D[D[D[D[D[D[D[D[Dinfo block fi[K[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block fil[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block file[K | ||
139 | +(qemu) info block file | ||
140 | |||
141 | file: TEST_DIR/t.qcow2 (file) | ||
142 | Cache mode: writeback | ||
143 | -(qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K[D[D[D[D[D[D[D[D[D[Dinfo block [K[D[D[D[D[D[D[D[D[D[D[Dinfo block b[K[D[D[D[D[D[D[D[D[D[D[D[Dinfo block ba[K[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block bac[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block back[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backi[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backin[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing[K | ||
144 | +(qemu) info block backing | ||
145 | backing: TEST_DIR/t.qcow2.base (qcow2, read-only) | ||
146 | Cache mode: writeback, ignore flushes | ||
147 | -(qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K[D[D[D[D[D[D[D[D[D[Dinfo block [K[D[D[D[D[D[D[D[D[D[D[Dinfo block b[K[D[D[D[D[D[D[D[D[D[D[D[Dinfo block ba[K[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block bac[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block back[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backi[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backin[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing-[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing-f[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing-fi[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinf | ||
148 | o block backing-fil[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing-file[K | ||
149 | +(qemu) info block backing-file | ||
150 | |||
151 | backing-file: TEST_DIR/t.qcow2.base (file, read-only) | ||
152 | Cache mode: writeback, ignore flushes | ||
153 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
154 | +(qemu) quit | ||
155 | |||
156 | Testing: -drive file=TEST_DIR/t.qcow2,cache=writethrough,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0 -nodefaults | ||
157 | QEMU X.Y.Z monitor - type 'help' for more information | ||
158 | -(qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K | ||
159 | +(qemu) info block | ||
160 | drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) | ||
161 | Removable device: not locked, tray closed | ||
162 | Cache mode: writethrough | ||
163 | Backing file: TEST_DIR/t.qcow2.base (chain depth: 1) | ||
164 | -(qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K[D[D[D[D[D[D[D[D[D[Dinfo block [K[D[D[D[D[D[D[D[D[D[D[Dinfo block f[K[D[D[D[D[D[D[D[D[D[D[D[Dinfo block fi[K[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block fil[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block file[K | ||
165 | +(qemu) info block file | ||
166 | |||
167 | file: TEST_DIR/t.qcow2 (file) | ||
168 | Cache mode: writeback | ||
169 | -(qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K[D[D[D[D[D[D[D[D[D[Dinfo block [K[D[D[D[D[D[D[D[D[D[D[Dinfo block b[K[D[D[D[D[D[D[D[D[D[D[D[Dinfo block ba[K[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block bac[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block back[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backi[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backin[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing[K | ||
170 | +(qemu) info block backing | ||
171 | backing: TEST_DIR/t.qcow2.base (qcow2, read-only) | ||
172 | Cache mode: writeback, ignore flushes | ||
173 | -(qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K[D[D[D[D[D[D[D[D[D[Dinfo block [K[D[D[D[D[D[D[D[D[D[D[Dinfo block b[K[D[D[D[D[D[D[D[D[D[D[D[Dinfo block ba[K[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block bac[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block back[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backi[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backin[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing-[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing-f[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing-fi[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinf | ||
174 | o block backing-fil[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing-file[K | ||
175 | +(qemu) info block backing-file | ||
176 | |||
177 | backing-file: TEST_DIR/t.qcow2.base (file, read-only) | ||
178 | Cache mode: writeback, ignore flushes | ||
179 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
180 | +(qemu) quit | ||
181 | |||
182 | Testing: -drive file=TEST_DIR/t.qcow2,cache=unsafe,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0 -nodefaults | ||
183 | QEMU X.Y.Z monitor - type 'help' for more information | ||
184 | -(qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K | ||
185 | +(qemu) info block | ||
186 | drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) | ||
187 | Removable device: not locked, tray closed | ||
188 | Cache mode: writeback, ignore flushes | ||
189 | Backing file: TEST_DIR/t.qcow2.base (chain depth: 1) | ||
190 | -(qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K[D[D[D[D[D[D[D[D[D[Dinfo block [K[D[D[D[D[D[D[D[D[D[D[Dinfo block f[K[D[D[D[D[D[D[D[D[D[D[D[Dinfo block fi[K[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block fil[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block file[K | ||
191 | +(qemu) info block file | ||
192 | |||
193 | file: TEST_DIR/t.qcow2 (file) | ||
194 | Cache mode: writeback, ignore flushes | ||
195 | -(qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K[D[D[D[D[D[D[D[D[D[Dinfo block [K[D[D[D[D[D[D[D[D[D[D[Dinfo block b[K[D[D[D[D[D[D[D[D[D[D[D[Dinfo block ba[K[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block bac[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block back[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backi[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backin[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing[K | ||
196 | +(qemu) info block backing | ||
197 | backing: TEST_DIR/t.qcow2.base (qcow2, read-only) | ||
198 | Cache mode: writeback, ignore flushes | ||
199 | -(qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K[D[D[D[D[D[D[D[D[D[Dinfo block [K[D[D[D[D[D[D[D[D[D[D[Dinfo block b[K[D[D[D[D[D[D[D[D[D[D[D[Dinfo block ba[K[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block bac[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block back[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backi[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backin[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing-[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing-f[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing-fi[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinf | ||
200 | o block backing-fil[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing-file[K | ||
201 | +(qemu) info block backing-file | ||
202 | |||
203 | backing-file: TEST_DIR/t.qcow2.base (file, read-only) | ||
204 | Cache mode: writeback, ignore flushes | ||
205 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
206 | +(qemu) quit | ||
207 | |||
208 | Testing: -drive file=TEST_DIR/t.qcow2,cache=invalid_value,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0 -nodefaults | ||
209 | QEMU_PROG: -drive file=TEST_DIR/t.qcow2,cache=invalid_value,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0: invalid cache option | ||
210 | @@ -XXX,XX +XXX,XX @@ QEMU_PROG: -drive file=TEST_DIR/t.qcow2,cache=invalid_value,backing.file.filenam | ||
211 | |||
212 | Testing: -drive file=TEST_DIR/t.qcow2,file.driver=file | ||
213 | QEMU X.Y.Z monitor - type 'help' for more information | ||
214 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
215 | +(qemu) quit | ||
216 | |||
217 | |||
218 | === Leaving out required options === | ||
219 | @@ -XXX,XX +XXX,XX @@ QEMU_PROG: -drive file=TEST_DIR/t.qcow2,throttling.bps-total=-5: bps/iops/max va | ||
220 | |||
221 | Testing: -drive file=TEST_DIR/t.qcow2,bps=0 | ||
222 | QEMU X.Y.Z monitor - type 'help' for more information | ||
223 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
224 | +(qemu) quit | ||
225 | |||
226 | Testing: -drive file=TEST_DIR/t.qcow2,bps=1 | ||
227 | QEMU X.Y.Z monitor - type 'help' for more information | ||
228 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
229 | +(qemu) quit | ||
230 | |||
231 | Testing: -drive file=TEST_DIR/t.qcow2,bps=1000000000000000 | ||
232 | QEMU X.Y.Z monitor - type 'help' for more information | ||
233 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
234 | +(qemu) quit | ||
235 | |||
236 | Testing: -drive file=TEST_DIR/t.qcow2,bps=1000000000000001 | ||
237 | QEMU_PROG: -drive file=TEST_DIR/t.qcow2,bps=1000000000000001: bps/iops/max values must be within [0, 1000000000000000] | ||
238 | @@ -XXX,XX +XXX,XX @@ QEMU_PROG: -drive file.filename=foo:bar: Could not open 'foo:bar': No such file | ||
239 | |||
240 | Testing: -hda file:TEST_DIR/t.qcow2 | ||
241 | QEMU X.Y.Z monitor - type 'help' for more information | ||
242 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
243 | +(qemu) quit | ||
244 | |||
245 | Testing: -drive file=file:TEST_DIR/t.qcow2 | ||
246 | QEMU X.Y.Z monitor - type 'help' for more information | ||
247 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
248 | +(qemu) quit | ||
249 | |||
250 | Testing: -drive file.filename=file:TEST_DIR/t.qcow2 | ||
251 | QEMU_PROG: -drive file.filename=file:TEST_DIR/t.qcow2: Could not open 'file:TEST_DIR/t.qcow2': No such file or directory | ||
252 | @@ -XXX,XX +XXX,XX @@ wrote 4096/4096 bytes at offset 0 | ||
253 | 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
254 | Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=drive0 -snapshot | ||
255 | QEMU X.Y.Z monitor - type 'help' for more information | ||
256 | -(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io d[K[D[D[D[D[D[D[D[D[Dqemu-io dr[K[D[D[D[D[D[D[D[D[D[Dqemu-io dri[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io driv[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqem | ||
257 | u-io drive0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x2[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0[K[D | ||
258 | [D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k"[K | ||
259 | +(qemu) qemu-io drive0 "write -P 0x22 0 4k" | ||
260 | wrote 4096/4096 bytes at offset 0 | ||
261 | 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
262 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
263 | +(qemu) quit | ||
264 | |||
265 | Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on,if=none,id=drive0 | ||
266 | QEMU X.Y.Z monitor - type 'help' for more information | ||
267 | -(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io d[K[D[D[D[D[D[D[D[D[Dqemu-io dr[K[D[D[D[D[D[D[D[D[D[Dqemu-io dri[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io driv[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqem | ||
268 | u-io drive0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x2[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0[K[D | ||
269 | [D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k"[K | ||
270 | +(qemu) qemu-io drive0 "write -P 0x22 0 4k" | ||
271 | wrote 4096/4096 bytes at offset 0 | ||
272 | 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
273 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
274 | +(qemu) quit | ||
275 | |||
276 | Testing: -drive file.filename=TEST_DIR/t.qcow2,driver=qcow2,snapshot=on,if=none,id=drive0 | ||
277 | QEMU X.Y.Z monitor - type 'help' for more information | ||
278 | -(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io d[K[D[D[D[D[D[D[D[D[Dqemu-io dr[K[D[D[D[D[D[D[D[D[D[Dqemu-io dri[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io driv[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqem | ||
279 | u-io drive0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x2[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0[K[D | ||
280 | [D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k"[K | ||
281 | +(qemu) qemu-io drive0 "write -P 0x22 0 4k" | ||
282 | wrote 4096/4096 bytes at offset 0 | ||
283 | 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
284 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
285 | +(qemu) quit | ||
286 | |||
287 | Testing: -drive file.filename=TEST_DIR/t.qcow2,driver=qcow2,if=none,id=drive0 -snapshot | ||
288 | QEMU X.Y.Z monitor - type 'help' for more information | ||
289 | -(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io d[K[D[D[D[D[D[D[D[D[Dqemu-io dr[K[D[D[D[D[D[D[D[D[D[Dqemu-io dri[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io driv[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqem | ||
290 | u-io drive0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x2[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0[K[D | ||
291 | [D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k"[K | ||
292 | +(qemu) qemu-io drive0 "write -P 0x22 0 4k" | ||
293 | wrote 4096/4096 bytes at offset 0 | ||
294 | 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
295 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
296 | +(qemu) quit | ||
297 | |||
298 | Testing: -drive file=file:TEST_DIR/t.qcow2,if=none,id=drive0 -snapshot | ||
299 | QEMU X.Y.Z monitor - type 'help' for more information | ||
300 | -(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io d[K[D[D[D[D[D[D[D[D[Dqemu-io dr[K[D[D[D[D[D[D[D[D[D[Dqemu-io dri[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io driv[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqem | ||
301 | u-io drive0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x2[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0[K[D | ||
302 | [D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k"[K | ||
303 | +(qemu) qemu-io drive0 "write -P 0x22 0 4k" | ||
304 | wrote 4096/4096 bytes at offset 0 | ||
305 | 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
306 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
307 | +(qemu) quit | ||
308 | |||
309 | Testing: -drive file=file:TEST_DIR/t.qcow2,snapshot=on,if=none,id=drive0 | ||
310 | QEMU X.Y.Z monitor - type 'help' for more information | ||
311 | -(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io d[K[D[D[D[D[D[D[D[D[Dqemu-io dr[K[D[D[D[D[D[D[D[D[D[Dqemu-io dri[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io driv[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqem | ||
312 | u-io drive0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x2[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0[K[D | ||
313 | [D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k"[K | ||
314 | +(qemu) qemu-io drive0 "write -P 0x22 0 4k" | ||
315 | wrote 4096/4096 bytes at offset 0 | ||
316 | 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
317 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
318 | +(qemu) quit | ||
319 | |||
320 | Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=drive0 -snapshot | ||
321 | QEMU X.Y.Z monitor - type 'help' for more information | ||
322 | -(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io d[K[D[D[D[D[D[D[D[D[Dqemu-io dr[K[D[D[D[D[D[D[D[D[D[Dqemu-io dri[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io driv[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqem | ||
323 | u-io drive0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x2[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0[K[D | ||
324 | [D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k"[K | ||
325 | +(qemu) qemu-io drive0 "write -P 0x22 0 4k" | ||
326 | wrote 4096/4096 bytes at offset 0 | ||
327 | 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
328 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
329 | +(qemu) quit | ||
330 | |||
331 | Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on,if=none,id=drive0 | ||
332 | QEMU X.Y.Z monitor - type 'help' for more information | ||
333 | -(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io d[K[D[D[D[D[D[D[D[D[Dqemu-io dr[K[D[D[D[D[D[D[D[D[D[Dqemu-io dri[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io driv[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqem | ||
334 | u-io drive0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x2[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0[K[D | ||
335 | [D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k"[K | ||
336 | +(qemu) qemu-io drive0 "write -P 0x22 0 4k" | ||
337 | wrote 4096/4096 bytes at offset 0 | ||
338 | 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
339 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
340 | +(qemu) quit | ||
341 | |||
342 | read 4096/4096 bytes at offset 0 | ||
343 | 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
344 | Testing: -drive file=TEST_DIR/t.qcow2,snapshot=off,if=none,id=drive0 | ||
345 | QEMU X.Y.Z monitor - type 'help' for more information | ||
346 | -(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io d[K[D[D[D[D[D[D[D[D[Dqemu-io dr[K[D[D[D[D[D[D[D[D[D[Dqemu-io dri[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io driv[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqem | ||
347 | u-io drive0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x2[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0[K[D | ||
348 | [D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k"[K | ||
349 | +(qemu) qemu-io drive0 "write -P 0x22 0 4k" | ||
350 | wrote 4096/4096 bytes at offset 0 | ||
351 | 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
352 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
353 | +(qemu) quit | ||
354 | |||
355 | read 4096/4096 bytes at offset 0 | ||
356 | 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
357 | Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on,if=none,id=drive0 | ||
358 | QEMU X.Y.Z monitor - type 'help' for more information | ||
359 | -(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io d[K[D[D[D[D[D[D[D[D[Dqemu-io dr[K[D[D[D[D[D[D[D[D[D[Dqemu-io dri[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io driv[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqem | ||
360 | u-io drive0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x3[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x33[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x33 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x33 0[K[D | ||
361 | [D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x33 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x33 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x33 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x33 0 4k"[K | ||
362 | +(qemu) qemu-io drive0 "write -P 0x33 0 4k" | ||
363 | wrote 4096/4096 bytes at offset 0 | ||
364 | 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
365 | -(qemu) c[K[Dco[K[D[Dcom[K[D[D[Dcomm[K[D[D[D[Dcommi[K[D[D[D[D[Dcommit[K[D[D[D[D[D[Dcommit [K[D[D[D[D[D[D[Dcommit d[K[D[D[D[D[D[D[D[Dcommit dr[K[D[D[D[D[D[D[D[D[Dcommit dri[K[D[D[D[D[D[D[D[D[D[Dcommit driv[K[D[D[D[D[D[D[D[D[D[D[Dcommit drive[K[D[D[D[D[D[D[D[D[D[D[D[Dcommit drive0[K | ||
366 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
367 | +(qemu) commit drive0 | ||
368 | +(qemu) quit | ||
369 | |||
370 | read 4096/4096 bytes at offset 0 | ||
371 | 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
372 | diff --git a/tests/qemu-iotests/051.pc.out b/tests/qemu-iotests/051.pc.out | ||
373 | index XXXXXXX..XXXXXXX 100644 | ||
374 | --- a/tests/qemu-iotests/051.pc.out | ||
375 | +++ b/tests/qemu-iotests/051.pc.out | ||
376 | @@ -XXX,XX +XXX,XX @@ QEMU X.Y.Z monitor - type 'help' for more information | ||
377 | |||
378 | Testing: -drive file=TEST_DIR/t.qcow2,driver=qcow2,backing.file.filename=TEST_DIR/t.qcow2.orig,if=none,id=drive0 -nodefaults | ||
379 | QEMU X.Y.Z monitor - type 'help' for more information | ||
380 | -(qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K | ||
381 | +(qemu) info block | ||
382 | drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) | ||
383 | Removable device: not locked, tray closed | ||
384 | Cache mode: writeback | ||
385 | Backing file: TEST_DIR/t.qcow2.orig (chain depth: 1) | ||
386 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
387 | +(qemu) quit | ||
388 | |||
389 | Testing: -drive file=TEST_DIR/t.qcow2,driver=raw,backing.file.filename=TEST_DIR/t.qcow2.orig | ||
390 | QEMU_PROG: -drive file=TEST_DIR/t.qcow2,driver=raw,backing.file.filename=TEST_DIR/t.qcow2.orig: Driver doesn't support backing files | ||
391 | @@ -XXX,XX +XXX,XX @@ QEMU_PROG: -drive file=TEST_DIR/t.qcow2,file.backing.driver=qcow2,file.backing.f | ||
392 | |||
393 | Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=on | ||
394 | QEMU X.Y.Z monitor - type 'help' for more information | ||
395 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
396 | +(qemu) quit | ||
397 | |||
398 | Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=off | ||
399 | QEMU X.Y.Z monitor - type 'help' for more information | ||
400 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
401 | +(qemu) quit | ||
402 | |||
403 | Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts= | ||
404 | QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=: Parameter 'lazy-refcounts' expects 'on' or 'off' | ||
405 | @@ -XXX,XX +XXX,XX @@ QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=on: Lazy ref | ||
406 | |||
407 | Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=off | ||
408 | QEMU X.Y.Z monitor - type 'help' for more information | ||
409 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
410 | +(qemu) quit | ||
411 | |||
412 | |||
413 | === No medium === | ||
414 | |||
415 | Testing: -drive if=floppy | ||
416 | QEMU X.Y.Z monitor - type 'help' for more information | ||
417 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
418 | +(qemu) quit | ||
419 | |||
420 | Testing: -drive if=ide,media=cdrom | ||
421 | QEMU X.Y.Z monitor - type 'help' for more information | ||
422 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
423 | +(qemu) quit | ||
424 | |||
425 | Testing: -drive if=scsi,media=cdrom | ||
426 | QEMU X.Y.Z monitor - type 'help' for more information | ||
427 | (qemu) QEMU_PROG: -drive if=scsi,media=cdrom: warning: bus=0,unit=0 is deprecated with this machine type | ||
428 | -q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
429 | +quit | ||
430 | |||
431 | Testing: -drive if=ide | ||
432 | QEMU X.Y.Z monitor - type 'help' for more information | ||
433 | @@ -XXX,XX +XXX,XX @@ QEMU X.Y.Z monitor - type 'help' for more information | ||
434 | |||
435 | Testing: -drive if=none,id=disk -device ide-cd,drive=disk | ||
436 | QEMU X.Y.Z monitor - type 'help' for more information | ||
437 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
438 | +(qemu) quit | ||
439 | |||
440 | Testing: -drive if=none,id=disk -device lsi53c895a -device scsi-cd,drive=disk | ||
441 | QEMU X.Y.Z monitor - type 'help' for more information | ||
442 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
443 | +(qemu) quit | ||
444 | |||
445 | Testing: -drive if=none,id=disk -device ide-drive,drive=disk | ||
446 | QEMU X.Y.Z monitor - type 'help' for more information | ||
447 | @@ -XXX,XX +XXX,XX @@ QEMU X.Y.Z monitor - type 'help' for more information | ||
448 | |||
449 | Testing: -drive file=TEST_DIR/t.qcow2,if=floppy,readonly=on | ||
450 | QEMU X.Y.Z monitor - type 'help' for more information | ||
451 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
452 | +(qemu) quit | ||
453 | |||
454 | Testing: -drive file=TEST_DIR/t.qcow2,if=ide,media=cdrom,readonly=on | ||
455 | QEMU X.Y.Z monitor - type 'help' for more information | ||
456 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
457 | +(qemu) quit | ||
458 | |||
459 | Testing: -drive file=TEST_DIR/t.qcow2,if=scsi,media=cdrom,readonly=on | ||
460 | QEMU X.Y.Z monitor - type 'help' for more information | ||
461 | (qemu) QEMU_PROG: -drive file=TEST_DIR/t.qcow2,if=scsi,media=cdrom,readonly=on: warning: bus=0,unit=0 is deprecated with this machine type | ||
462 | -q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
463 | +quit | ||
464 | |||
465 | Testing: -drive file=TEST_DIR/t.qcow2,if=ide,readonly=on | ||
466 | QEMU X.Y.Z monitor - type 'help' for more information | ||
467 | @@ -XXX,XX +XXX,XX @@ QEMU_PROG: Initialization of device ide-hd failed: Device initialization failed. | ||
468 | Testing: -drive file=TEST_DIR/t.qcow2,if=scsi,readonly=on | ||
469 | QEMU X.Y.Z monitor - type 'help' for more information | ||
470 | (qemu) QEMU_PROG: -drive file=TEST_DIR/t.qcow2,if=scsi,readonly=on: warning: bus=0,unit=0 is deprecated with this machine type | ||
471 | -q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
472 | +quit | ||
473 | |||
474 | Testing: -drive file=TEST_DIR/t.qcow2,if=virtio,readonly=on | ||
475 | QEMU X.Y.Z monitor - type 'help' for more information | ||
476 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
477 | +(qemu) quit | ||
478 | |||
479 | Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device ide-cd,drive=disk | ||
480 | QEMU X.Y.Z monitor - type 'help' for more information | ||
481 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
482 | +(qemu) quit | ||
483 | |||
484 | Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device lsi53c895a -device scsi-cd,drive=disk | ||
485 | QEMU X.Y.Z monitor - type 'help' for more information | ||
486 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
487 | +(qemu) quit | ||
488 | |||
489 | Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device ide-drive,drive=disk | ||
490 | QEMU X.Y.Z monitor - type 'help' for more information | ||
491 | @@ -XXX,XX +XXX,XX @@ QEMU_PROG: -device ide-hd,drive=disk: Device initialization failed. | ||
492 | |||
493 | Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device lsi53c895a -device scsi-disk,drive=disk | ||
494 | QEMU X.Y.Z monitor - type 'help' for more information | ||
495 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
496 | +(qemu) quit | ||
497 | |||
498 | Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device lsi53c895a -device scsi-hd,drive=disk | ||
499 | QEMU X.Y.Z monitor - type 'help' for more information | ||
500 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
501 | +(qemu) quit | ||
502 | |||
503 | |||
504 | === Cache modes === | ||
505 | |||
506 | Testing: -drive driver=null-co,cache=none | ||
507 | QEMU X.Y.Z monitor - type 'help' for more information | ||
508 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
509 | +(qemu) quit | ||
510 | |||
511 | Testing: -drive driver=null-co,cache=directsync | ||
512 | QEMU X.Y.Z monitor - type 'help' for more information | ||
513 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
514 | +(qemu) quit | ||
515 | |||
516 | Testing: -drive driver=null-co,cache=writeback | ||
517 | QEMU X.Y.Z monitor - type 'help' for more information | ||
518 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
519 | +(qemu) quit | ||
520 | |||
521 | Testing: -drive driver=null-co,cache=writethrough | ||
522 | QEMU X.Y.Z monitor - type 'help' for more information | ||
523 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
524 | +(qemu) quit | ||
525 | |||
526 | Testing: -drive driver=null-co,cache=unsafe | ||
527 | QEMU X.Y.Z monitor - type 'help' for more information | ||
528 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
529 | +(qemu) quit | ||
530 | |||
531 | Testing: -drive driver=null-co,cache=invalid_value | ||
532 | QEMU_PROG: -drive driver=null-co,cache=invalid_value: invalid cache option | ||
533 | |||
534 | Testing: -drive file=TEST_DIR/t.qcow2,cache=writeback,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0 -nodefaults | ||
535 | QEMU X.Y.Z monitor - type 'help' for more information | ||
536 | -(qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K | ||
537 | +(qemu) info block | ||
538 | drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) | ||
539 | Removable device: not locked, tray closed | ||
540 | Cache mode: writeback | ||
541 | Backing file: TEST_DIR/t.qcow2.base (chain depth: 1) | ||
542 | -(qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K[D[D[D[D[D[D[D[D[D[Dinfo block [K[D[D[D[D[D[D[D[D[D[D[Dinfo block f[K[D[D[D[D[D[D[D[D[D[D[D[Dinfo block fi[K[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block fil[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block file[K | ||
543 | +(qemu) info block file | ||
544 | |||
545 | file: TEST_DIR/t.qcow2 (file) | ||
546 | Cache mode: writeback | ||
547 | -(qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K[D[D[D[D[D[D[D[D[D[Dinfo block [K[D[D[D[D[D[D[D[D[D[D[Dinfo block b[K[D[D[D[D[D[D[D[D[D[D[D[Dinfo block ba[K[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block bac[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block back[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backi[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backin[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing[K | ||
548 | +(qemu) info block backing | ||
549 | backing: TEST_DIR/t.qcow2.base (qcow2, read-only) | ||
550 | Cache mode: writeback, ignore flushes | ||
551 | -(qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K[D[D[D[D[D[D[D[D[D[Dinfo block [K[D[D[D[D[D[D[D[D[D[D[Dinfo block b[K[D[D[D[D[D[D[D[D[D[D[D[Dinfo block ba[K[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block bac[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block back[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backi[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backin[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing-[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing-f[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing-fi[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinf | ||
552 | o block backing-fil[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing-file[K | ||
553 | +(qemu) info block backing-file | ||
554 | |||
555 | backing-file: TEST_DIR/t.qcow2.base (file, read-only) | ||
556 | Cache mode: writeback, ignore flushes | ||
557 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
558 | +(qemu) quit | ||
559 | |||
560 | Testing: -drive file=TEST_DIR/t.qcow2,cache=writethrough,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0 -nodefaults | ||
561 | QEMU X.Y.Z monitor - type 'help' for more information | ||
562 | -(qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K | ||
563 | +(qemu) info block | ||
564 | drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) | ||
565 | Removable device: not locked, tray closed | ||
566 | Cache mode: writethrough | ||
567 | Backing file: TEST_DIR/t.qcow2.base (chain depth: 1) | ||
568 | -(qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K[D[D[D[D[D[D[D[D[D[Dinfo block [K[D[D[D[D[D[D[D[D[D[D[Dinfo block f[K[D[D[D[D[D[D[D[D[D[D[D[Dinfo block fi[K[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block fil[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block file[K | ||
569 | +(qemu) info block file | ||
570 | |||
571 | file: TEST_DIR/t.qcow2 (file) | ||
572 | Cache mode: writeback | ||
573 | -(qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K[D[D[D[D[D[D[D[D[D[Dinfo block [K[D[D[D[D[D[D[D[D[D[D[Dinfo block b[K[D[D[D[D[D[D[D[D[D[D[D[Dinfo block ba[K[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block bac[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block back[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backi[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backin[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing[K | ||
574 | +(qemu) info block backing | ||
575 | backing: TEST_DIR/t.qcow2.base (qcow2, read-only) | ||
576 | Cache mode: writeback, ignore flushes | ||
577 | -(qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K[D[D[D[D[D[D[D[D[D[Dinfo block [K[D[D[D[D[D[D[D[D[D[D[Dinfo block b[K[D[D[D[D[D[D[D[D[D[D[D[Dinfo block ba[K[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block bac[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block back[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backi[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backin[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing-[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing-f[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing-fi[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinf | ||
578 | o block backing-fil[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing-file[K | ||
579 | +(qemu) info block backing-file | ||
580 | |||
581 | backing-file: TEST_DIR/t.qcow2.base (file, read-only) | ||
582 | Cache mode: writeback, ignore flushes | ||
583 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
584 | +(qemu) quit | ||
585 | |||
586 | Testing: -drive file=TEST_DIR/t.qcow2,cache=unsafe,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0 -nodefaults | ||
587 | QEMU X.Y.Z monitor - type 'help' for more information | ||
588 | -(qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K | ||
589 | +(qemu) info block | ||
590 | drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) | ||
591 | Removable device: not locked, tray closed | ||
592 | Cache mode: writeback, ignore flushes | ||
593 | Backing file: TEST_DIR/t.qcow2.base (chain depth: 1) | ||
594 | -(qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K[D[D[D[D[D[D[D[D[D[Dinfo block [K[D[D[D[D[D[D[D[D[D[D[Dinfo block f[K[D[D[D[D[D[D[D[D[D[D[D[Dinfo block fi[K[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block fil[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block file[K | ||
595 | +(qemu) info block file | ||
596 | |||
597 | file: TEST_DIR/t.qcow2 (file) | ||
598 | Cache mode: writeback, ignore flushes | ||
599 | -(qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K[D[D[D[D[D[D[D[D[D[Dinfo block [K[D[D[D[D[D[D[D[D[D[D[Dinfo block b[K[D[D[D[D[D[D[D[D[D[D[D[Dinfo block ba[K[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block bac[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block back[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backi[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backin[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing[K | ||
600 | +(qemu) info block backing | ||
601 | backing: TEST_DIR/t.qcow2.base (qcow2, read-only) | ||
602 | Cache mode: writeback, ignore flushes | ||
603 | -(qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K[D[D[D[D[D[D[D[D[D[Dinfo block [K[D[D[D[D[D[D[D[D[D[D[Dinfo block b[K[D[D[D[D[D[D[D[D[D[D[D[Dinfo block ba[K[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block bac[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block back[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backi[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backin[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing-[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing-f[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing-fi[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinf | ||
604 | o block backing-fil[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing-file[K | ||
605 | +(qemu) info block backing-file | ||
606 | |||
607 | backing-file: TEST_DIR/t.qcow2.base (file, read-only) | ||
608 | Cache mode: writeback, ignore flushes | ||
609 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
610 | +(qemu) quit | ||
611 | |||
612 | Testing: -drive file=TEST_DIR/t.qcow2,cache=invalid_value,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0 -nodefaults | ||
613 | QEMU_PROG: -drive file=TEST_DIR/t.qcow2,cache=invalid_value,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0: invalid cache option | ||
614 | @@ -XXX,XX +XXX,XX @@ QEMU_PROG: -drive file=TEST_DIR/t.qcow2,cache=invalid_value,backing.file.filenam | ||
615 | |||
616 | Testing: -drive file=TEST_DIR/t.qcow2,file.driver=file | ||
617 | QEMU X.Y.Z monitor - type 'help' for more information | ||
618 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
619 | +(qemu) quit | ||
620 | |||
621 | |||
622 | === Leaving out required options === | ||
623 | @@ -XXX,XX +XXX,XX @@ QEMU_PROG: -drive file=TEST_DIR/t.qcow2,throttling.bps-total=-5: bps/iops/max va | ||
624 | |||
625 | Testing: -drive file=TEST_DIR/t.qcow2,bps=0 | ||
626 | QEMU X.Y.Z monitor - type 'help' for more information | ||
627 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
628 | +(qemu) quit | ||
629 | |||
630 | Testing: -drive file=TEST_DIR/t.qcow2,bps=1 | ||
631 | QEMU X.Y.Z monitor - type 'help' for more information | ||
632 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
633 | +(qemu) quit | ||
634 | |||
635 | Testing: -drive file=TEST_DIR/t.qcow2,bps=1000000000000000 | ||
636 | QEMU X.Y.Z monitor - type 'help' for more information | ||
637 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
638 | +(qemu) quit | ||
639 | |||
640 | Testing: -drive file=TEST_DIR/t.qcow2,bps=1000000000000001 | ||
641 | QEMU_PROG: -drive file=TEST_DIR/t.qcow2,bps=1000000000000001: bps/iops/max values must be within [0, 1000000000000000] | ||
642 | @@ -XXX,XX +XXX,XX @@ QEMU_PROG: -drive file.filename=foo:bar: Could not open 'foo:bar': No such file | ||
643 | |||
644 | Testing: -hda file:TEST_DIR/t.qcow2 | ||
645 | QEMU X.Y.Z monitor - type 'help' for more information | ||
646 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
647 | +(qemu) quit | ||
648 | |||
649 | Testing: -drive file=file:TEST_DIR/t.qcow2 | ||
650 | QEMU X.Y.Z monitor - type 'help' for more information | ||
651 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
652 | +(qemu) quit | ||
653 | |||
654 | Testing: -drive file.filename=file:TEST_DIR/t.qcow2 | ||
655 | QEMU_PROG: -drive file.filename=file:TEST_DIR/t.qcow2: Could not open 'file:TEST_DIR/t.qcow2': No such file or directory | ||
656 | @@ -XXX,XX +XXX,XX @@ wrote 4096/4096 bytes at offset 0 | ||
657 | 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
658 | Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=drive0 -snapshot | ||
659 | QEMU X.Y.Z monitor - type 'help' for more information | ||
660 | -(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io d[K[D[D[D[D[D[D[D[D[Dqemu-io dr[K[D[D[D[D[D[D[D[D[D[Dqemu-io dri[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io driv[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqem | ||
661 | u-io drive0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x2[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0[K[D | ||
662 | [D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k"[K | ||
663 | +(qemu) qemu-io drive0 "write -P 0x22 0 4k" | ||
664 | wrote 4096/4096 bytes at offset 0 | ||
665 | 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
666 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
667 | +(qemu) quit | ||
668 | |||
669 | Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on,if=none,id=drive0 | ||
670 | QEMU X.Y.Z monitor - type 'help' for more information | ||
671 | -(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io d[K[D[D[D[D[D[D[D[D[Dqemu-io dr[K[D[D[D[D[D[D[D[D[D[Dqemu-io dri[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io driv[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqem | ||
672 | u-io drive0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x2[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0[K[D | ||
673 | [D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k"[K | ||
674 | +(qemu) qemu-io drive0 "write -P 0x22 0 4k" | ||
675 | wrote 4096/4096 bytes at offset 0 | ||
676 | 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
677 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
678 | +(qemu) quit | ||
679 | |||
680 | Testing: -drive file.filename=TEST_DIR/t.qcow2,driver=qcow2,snapshot=on,if=none,id=drive0 | ||
681 | QEMU X.Y.Z monitor - type 'help' for more information | ||
682 | -(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io d[K[D[D[D[D[D[D[D[D[Dqemu-io dr[K[D[D[D[D[D[D[D[D[D[Dqemu-io dri[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io driv[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqem | ||
683 | u-io drive0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x2[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0[K[D | ||
684 | [D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k"[K | ||
685 | +(qemu) qemu-io drive0 "write -P 0x22 0 4k" | ||
686 | wrote 4096/4096 bytes at offset 0 | ||
687 | 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
688 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
689 | +(qemu) quit | ||
690 | |||
691 | Testing: -drive file.filename=TEST_DIR/t.qcow2,driver=qcow2,if=none,id=drive0 -snapshot | ||
692 | QEMU X.Y.Z monitor - type 'help' for more information | ||
693 | -(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io d[K[D[D[D[D[D[D[D[D[Dqemu-io dr[K[D[D[D[D[D[D[D[D[D[Dqemu-io dri[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io driv[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqem | ||
694 | u-io drive0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x2[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0[K[D | ||
695 | [D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k"[K | ||
696 | +(qemu) qemu-io drive0 "write -P 0x22 0 4k" | ||
697 | wrote 4096/4096 bytes at offset 0 | ||
698 | 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
699 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
700 | +(qemu) quit | ||
701 | |||
702 | Testing: -drive file=file:TEST_DIR/t.qcow2,if=none,id=drive0 -snapshot | ||
703 | QEMU X.Y.Z monitor - type 'help' for more information | ||
704 | -(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io d[K[D[D[D[D[D[D[D[D[Dqemu-io dr[K[D[D[D[D[D[D[D[D[D[Dqemu-io dri[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io driv[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqem | ||
705 | u-io drive0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x2[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0[K[D | ||
706 | [D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k"[K | ||
707 | +(qemu) qemu-io drive0 "write -P 0x22 0 4k" | ||
708 | wrote 4096/4096 bytes at offset 0 | ||
709 | 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
710 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
711 | +(qemu) quit | ||
712 | |||
713 | Testing: -drive file=file:TEST_DIR/t.qcow2,snapshot=on,if=none,id=drive0 | ||
714 | QEMU X.Y.Z monitor - type 'help' for more information | ||
715 | -(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io d[K[D[D[D[D[D[D[D[D[Dqemu-io dr[K[D[D[D[D[D[D[D[D[D[Dqemu-io dri[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io driv[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqem | ||
716 | u-io drive0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x2[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0[K[D | ||
717 | [D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k"[K | ||
718 | +(qemu) qemu-io drive0 "write -P 0x22 0 4k" | ||
719 | wrote 4096/4096 bytes at offset 0 | ||
720 | 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
721 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
722 | +(qemu) quit | ||
723 | |||
724 | Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=drive0 -snapshot | ||
725 | QEMU X.Y.Z monitor - type 'help' for more information | ||
726 | -(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io d[K[D[D[D[D[D[D[D[D[Dqemu-io dr[K[D[D[D[D[D[D[D[D[D[Dqemu-io dri[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io driv[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqem | ||
727 | u-io drive0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x2[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0[K[D | ||
728 | [D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k"[K | ||
729 | +(qemu) qemu-io drive0 "write -P 0x22 0 4k" | ||
730 | wrote 4096/4096 bytes at offset 0 | ||
731 | 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
732 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
733 | +(qemu) quit | ||
734 | |||
735 | Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on,if=none,id=drive0 | ||
736 | QEMU X.Y.Z monitor - type 'help' for more information | ||
737 | -(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io d[K[D[D[D[D[D[D[D[D[Dqemu-io dr[K[D[D[D[D[D[D[D[D[D[Dqemu-io dri[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io driv[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqem | ||
738 | u-io drive0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x2[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0[K[D | ||
739 | [D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k"[K | ||
740 | +(qemu) qemu-io drive0 "write -P 0x22 0 4k" | ||
741 | wrote 4096/4096 bytes at offset 0 | ||
742 | 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
743 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
744 | +(qemu) quit | ||
745 | |||
746 | read 4096/4096 bytes at offset 0 | ||
747 | 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
748 | Testing: -drive file=TEST_DIR/t.qcow2,snapshot=off,if=none,id=drive0 | ||
749 | QEMU X.Y.Z monitor - type 'help' for more information | ||
750 | -(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io d[K[D[D[D[D[D[D[D[D[Dqemu-io dr[K[D[D[D[D[D[D[D[D[D[Dqemu-io dri[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io driv[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqem | ||
751 | u-io drive0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x2[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0[K[D | ||
752 | [D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k"[K | ||
753 | +(qemu) qemu-io drive0 "write -P 0x22 0 4k" | ||
754 | wrote 4096/4096 bytes at offset 0 | ||
755 | 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
756 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
757 | +(qemu) quit | ||
758 | |||
759 | read 4096/4096 bytes at offset 0 | ||
760 | 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
761 | Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on,if=none,id=drive0 | ||
762 | QEMU X.Y.Z monitor - type 'help' for more information | ||
763 | -(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io d[K[D[D[D[D[D[D[D[D[Dqemu-io dr[K[D[D[D[D[D[D[D[D[D[Dqemu-io dri[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io driv[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqem | ||
764 | u-io drive0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x3[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x33[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x33 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x33 0[K[D | ||
765 | [D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x33 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x33 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x33 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x33 0 4k"[K | ||
766 | +(qemu) qemu-io drive0 "write -P 0x33 0 4k" | ||
767 | wrote 4096/4096 bytes at offset 0 | ||
768 | 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
769 | -(qemu) c[K[Dco[K[D[Dcom[K[D[D[Dcomm[K[D[D[D[Dcommi[K[D[D[D[D[Dcommit[K[D[D[D[D[D[Dcommit [K[D[D[D[D[D[D[Dcommit d[K[D[D[D[D[D[D[D[Dcommit dr[K[D[D[D[D[D[D[D[D[Dcommit dri[K[D[D[D[D[D[D[D[D[D[Dcommit driv[K[D[D[D[D[D[D[D[D[D[D[Dcommit drive[K[D[D[D[D[D[D[D[D[D[D[D[Dcommit drive0[K | ||
770 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
771 | +(qemu) commit drive0 | ||
772 | +(qemu) quit | ||
773 | |||
774 | read 4096/4096 bytes at offset 0 | ||
775 | 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
776 | diff --git a/tests/qemu-iotests/068 b/tests/qemu-iotests/068 | ||
777 | index XXXXXXX..XXXXXXX 100755 | ||
778 | --- a/tests/qemu-iotests/068 | ||
779 | +++ b/tests/qemu-iotests/068 | ||
780 | @@ -XXX,XX +XXX,XX @@ esac | ||
781 | # Give qemu some time to boot before saving the VM state | ||
782 | bash -c 'sleep 1; echo -e "savevm 0\nquit"' |\ | ||
783 | $QEMU $platform_parm -nographic -monitor stdio -serial none -hda "$TEST_IMG" |\ | ||
784 | - _filter_qemu | ||
785 | + _filter_qemu | _filter_hmp | ||
786 | # Now try to continue from that VM state (this should just work) | ||
787 | echo quit |\ | ||
788 | $QEMU $platform_parm -nographic -monitor stdio -serial none -hda "$TEST_IMG" -loadvm 0 |\ | ||
789 | - _filter_qemu | ||
790 | + _filter_qemu | _filter_hmp | ||
791 | |||
792 | # success, all done | ||
793 | echo "*** done" | ||
794 | diff --git a/tests/qemu-iotests/068.out b/tests/qemu-iotests/068.out | ||
795 | index XXXXXXX..XXXXXXX 100644 | ||
796 | --- a/tests/qemu-iotests/068.out | ||
797 | +++ b/tests/qemu-iotests/068.out | ||
798 | @@ -XXX,XX +XXX,XX @@ QA output created by 068 | ||
799 | |||
800 | Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=131072 | ||
801 | QEMU X.Y.Z monitor - type 'help' for more information | ||
802 | -(qemu) s[K[Dsa[K[D[Dsav[K[D[D[Dsave[K[D[D[D[Dsavev[K[D[D[D[D[Dsavevm[K[D[D[D[D[D[Dsavevm [K[D[D[D[D[D[D[Dsavevm 0[K | ||
803 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
804 | +(qemu) savevm 0 | ||
805 | +(qemu) quit | ||
806 | QEMU X.Y.Z monitor - type 'help' for more information | ||
807 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
808 | +(qemu) quit | ||
809 | *** done | ||
810 | diff --git a/tests/qemu-iotests/130.out b/tests/qemu-iotests/130.out | ||
811 | index XXXXXXX..XXXXXXX 100644 | ||
812 | --- a/tests/qemu-iotests/130.out | ||
813 | +++ b/tests/qemu-iotests/130.out | ||
814 | @@ -XXX,XX +XXX,XX @@ virtual size: 64M (67108864 bytes) | ||
815 | === HMP commit === | ||
816 | |||
817 | QEMU X.Y.Z monitor - type 'help' for more information | ||
818 | -(qemu) c[K[Dco[K[D[Dcom[K[D[D[Dcomm[K[D[D[D[Dcommi[K[D[D[D[D[Dcommit[K[D[D[D[D[D[Dcommit [K[D[D[D[D[D[D[Dcommit t[K[D[D[D[D[D[D[D[Dcommit te[K[D[D[D[D[D[D[D[D[Dcommit tes[K[D[D[D[D[D[D[D[D[D[Dcommit test[K[D[D[D[D[D[D[D[D[D[D[Dcommit testd[K[D[D[D[D[D[D[D[D[D[D[D[Dcommit testdi[K[D[D[D[D[D[D[D[D[D[D[D[D[Dcommit testdis[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dcommit testdisk[K | ||
819 | +(qemu) commit testdisk | ||
820 | (qemu) | ||
821 | image: TEST_DIR/t.IMGFMT | ||
822 | file format: IMGFMT | ||
823 | virtual size: 64M (67108864 bytes) | ||
824 | Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.orig backing_fmt=raw | ||
825 | QEMU X.Y.Z monitor - type 'help' for more information | ||
826 | -(qemu) c[K[Dco[K[D[Dcom[K[D[D[Dcomm[K[D[D[D[Dcommi[K[D[D[D[D[Dcommit[K[D[D[D[D[D[Dcommit [K[D[D[D[D[D[D[Dcommit t[K[D[D[D[D[D[D[D[Dcommit te[K[D[D[D[D[D[D[D[D[Dcommit tes[K[D[D[D[D[D[D[D[D[D[Dcommit test[K[D[D[D[D[D[D[D[D[D[D[Dcommit testd[K[D[D[D[D[D[D[D[D[D[D[D[Dcommit testdi[K[D[D[D[D[D[D[D[D[D[D[D[D[Dcommit testdis[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dcommit testdisk[K | ||
827 | +(qemu) commit testdisk | ||
828 | (qemu) | ||
829 | image: TEST_DIR/t.IMGFMT | ||
830 | file format: IMGFMT | ||
831 | diff --git a/tests/qemu-iotests/142 b/tests/qemu-iotests/142 | ||
832 | index XXXXXXX..XXXXXXX 100755 | ||
833 | --- a/tests/qemu-iotests/142 | ||
834 | +++ b/tests/qemu-iotests/142 | ||
835 | @@ -XXX,XX +XXX,XX @@ function do_run_qemu() | ||
836 | |||
837 | function run_qemu() | ||
838 | { | ||
839 | - do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu | ||
840 | + do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu | _filter_hmp | ||
841 | } | ||
842 | |||
843 | size=128M | ||
844 | diff --git a/tests/qemu-iotests/142.out b/tests/qemu-iotests/142.out | ||
845 | index XXXXXXX..XXXXXXX 100644 | ||
846 | --- a/tests/qemu-iotests/142.out | ||
847 | +++ b/tests/qemu-iotests/142.out | ||
848 | @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/ | ||
849 | |||
850 | Testing: -drive file=TEST_DIR/t.qcow2,cache=none | ||
851 | QEMU X.Y.Z monitor - type 'help' for more information | ||
852 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
853 | +(qemu) quit | ||
854 | |||
855 | Testing: -drive file=TEST_DIR/t.qcow2,cache=directsync | ||
856 | QEMU X.Y.Z monitor - type 'help' for more information | ||
857 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
858 | +(qemu) quit | ||
859 | |||
860 | Testing: -drive file=TEST_DIR/t.qcow2,cache=writeback | ||
861 | QEMU X.Y.Z monitor - type 'help' for more information | ||
862 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
863 | +(qemu) quit | ||
864 | |||
865 | Testing: -drive file=TEST_DIR/t.qcow2,cache=writethrough | ||
866 | QEMU X.Y.Z monitor - type 'help' for more information | ||
867 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
868 | +(qemu) quit | ||
869 | |||
870 | Testing: -drive file=TEST_DIR/t.qcow2,cache=unsafe | ||
871 | QEMU X.Y.Z monitor - type 'help' for more information | ||
872 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
873 | +(qemu) quit | ||
874 | |||
875 | Testing: -drive file=TEST_DIR/t.qcow2,cache=invalid_value | ||
876 | QEMU_PROG: -drive file=TEST_DIR/t.qcow2,cache=invalid_value: invalid cache option | ||
877 | diff --git a/tests/qemu-iotests/145 b/tests/qemu-iotests/145 | ||
878 | index XXXXXXX..XXXXXXX 100755 | ||
879 | --- a/tests/qemu-iotests/145 | ||
880 | +++ b/tests/qemu-iotests/145 | ||
881 | @@ -XXX,XX +XXX,XX @@ _supported_proto generic | ||
882 | _supported_os Linux | ||
883 | |||
884 | _make_test_img 1M | ||
885 | -echo quit | $QEMU -nographic -hda "$TEST_IMG" -incoming 'exec:true' -snapshot -serial none -monitor stdio | _filter_qemu | ||
886 | +echo quit | $QEMU -nographic -hda "$TEST_IMG" -incoming 'exec:true' -snapshot -serial none -monitor stdio | | ||
887 | + _filter_qemu | _filter_hmp | ||
888 | |||
889 | # success, all done | ||
890 | echo "*** done" | ||
891 | diff --git a/tests/qemu-iotests/145.out b/tests/qemu-iotests/145.out | ||
892 | index XXXXXXX..XXXXXXX 100644 | ||
893 | --- a/tests/qemu-iotests/145.out | ||
894 | +++ b/tests/qemu-iotests/145.out | ||
895 | @@ -XXX,XX +XXX,XX @@ | ||
896 | QA output created by 145 | ||
897 | Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 | ||
898 | QEMU X.Y.Z monitor - type 'help' for more information | ||
899 | -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K | ||
900 | +(qemu) quit | ||
901 | *** done | ||
902 | diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter | ||
903 | index XXXXXXX..XXXXXXX 100644 | ||
904 | --- a/tests/qemu-iotests/common.filter | ||
905 | +++ b/tests/qemu-iotests/common.filter | ||
906 | @@ -XXX,XX +XXX,XX @@ _filter_qmp() | ||
907 | -e ' QMP_VERSION' | ||
908 | } | ||
909 | |||
910 | +# readline makes HMP command strings so long that git complains | ||
911 | +_filter_hmp() | ||
912 | +{ | 19 | +{ |
913 | + sed -e $'s/^\\((qemu) \\)\\?.*\e\\[D/\\1/g' \ | 20 | + if (block_ns <= poll->ns) { |
914 | + -e $'s/\e\\[K//g' | 21 | + /* This is the sweet spot, no adjustment needed */ |
22 | + } else if (block_ns > ctx->poll_max_ns) { | ||
23 | + /* We'd have to poll for too long, poll less */ | ||
24 | + int64_t old = poll->ns; | ||
25 | + | ||
26 | + if (ctx->poll_shrink) { | ||
27 | + poll->ns /= ctx->poll_shrink; | ||
28 | + } else { | ||
29 | + poll->ns = 0; | ||
30 | + } | ||
31 | + | ||
32 | + trace_poll_shrink(ctx, old, poll->ns); | ||
33 | + } else if (poll->ns < ctx->poll_max_ns && | ||
34 | + block_ns < ctx->poll_max_ns) { | ||
35 | + /* There is room to grow, poll longer */ | ||
36 | + int64_t old = poll->ns; | ||
37 | + int64_t grow = ctx->poll_grow; | ||
38 | + | ||
39 | + if (grow == 0) { | ||
40 | + grow = 2; | ||
41 | + } | ||
42 | + | ||
43 | + if (poll->ns) { | ||
44 | + poll->ns *= grow; | ||
45 | + } else { | ||
46 | + poll->ns = 4000; /* start polling at 4 microseconds */ | ||
47 | + } | ||
48 | + | ||
49 | + if (poll->ns > ctx->poll_max_ns) { | ||
50 | + poll->ns = ctx->poll_max_ns; | ||
51 | + } | ||
52 | + | ||
53 | + trace_poll_grow(ctx, old, poll->ns); | ||
54 | + } | ||
915 | +} | 55 | +} |
916 | + | 56 | + |
917 | # replace block job offset | 57 | bool aio_poll(AioContext *ctx, bool blocking) |
918 | _filter_block_job_offset() | ||
919 | { | 58 | { |
920 | diff --git a/tests/qemu-iotests/common.qemu b/tests/qemu-iotests/common.qemu | 59 | AioHandlerList ready_list = QLIST_HEAD_INITIALIZER(ready_list); |
921 | index XXXXXXX..XXXXXXX 100644 | 60 | @@ -XXX,XX +XXX,XX @@ bool aio_poll(AioContext *ctx, bool blocking) |
922 | --- a/tests/qemu-iotests/common.qemu | 61 | /* Adjust polling time */ |
923 | +++ b/tests/qemu-iotests/common.qemu | 62 | if (ctx->poll_max_ns) { |
924 | @@ -XXX,XX +XXX,XX @@ function _timed_wait_for() | 63 | int64_t block_ns = qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - start; |
925 | do | 64 | - |
926 | if [ -z "${silent}" ]; then | 65 | - if (block_ns <= ctx->poll.ns) { |
927 | echo "${resp}" | _filter_testdir | _filter_qemu \ | 66 | - /* This is the sweet spot, no adjustment needed */ |
928 | - | _filter_qemu_io | _filter_qmp | 67 | - } else if (block_ns > ctx->poll_max_ns) { |
929 | + | _filter_qemu_io | _filter_qmp | _filter_hmp | 68 | - /* We'd have to poll for too long, poll less */ |
930 | fi | 69 | - int64_t old = ctx->poll.ns; |
931 | grep -q "${*}" < <(echo ${resp}) | 70 | - |
932 | if [ $? -eq 0 ]; then | 71 | - if (ctx->poll_shrink) { |
933 | @@ -XXX,XX +XXX,XX @@ function _cleanup_qemu() | 72 | - ctx->poll.ns /= ctx->poll_shrink; |
934 | 73 | - } else { | |
935 | if [ -n "${wait}" ]; then | 74 | - ctx->poll.ns = 0; |
936 | cat <&${QEMU_OUT[$i]} | _filter_testdir | _filter_qemu \ | 75 | - } |
937 | - | _filter_qemu_io | _filter_qmp | 76 | - |
938 | + | _filter_qemu_io | _filter_qmp | _filter_hmp | 77 | - trace_poll_shrink(ctx, old, ctx->poll.ns); |
939 | fi | 78 | - } else if (ctx->poll.ns < ctx->poll_max_ns && |
940 | rm -f "${QEMU_FIFO_IN}_${i}" "${QEMU_FIFO_OUT}_${i}" | 79 | - block_ns < ctx->poll_max_ns) { |
941 | eval "exec ${QEMU_IN[$i]}<&-" # close file descriptors | 80 | - /* There is room to grow, poll longer */ |
81 | - int64_t old = ctx->poll.ns; | ||
82 | - int64_t grow = ctx->poll_grow; | ||
83 | - | ||
84 | - if (grow == 0) { | ||
85 | - grow = 2; | ||
86 | - } | ||
87 | - | ||
88 | - if (ctx->poll.ns) { | ||
89 | - ctx->poll.ns *= grow; | ||
90 | - } else { | ||
91 | - ctx->poll.ns = 4000; /* start polling at 4 microseconds */ | ||
92 | - } | ||
93 | - | ||
94 | - if (ctx->poll.ns > ctx->poll_max_ns) { | ||
95 | - ctx->poll.ns = ctx->poll_max_ns; | ||
96 | - } | ||
97 | - | ||
98 | - trace_poll_grow(ctx, old, ctx->poll.ns); | ||
99 | - } | ||
100 | + adjust_polling_time(ctx, &ctx->poll, block_ns); | ||
101 | } | ||
102 | |||
103 | progress |= aio_bh_poll(ctx); | ||
942 | -- | 104 | -- |
943 | 1.8.3.1 | 105 | 2.48.1 |
944 | |||
945 | diff view generated by jsdifflib |
1 | From: Eric Blake <eblake@redhat.com> | 1 | Adaptive polling has a big problem: It doesn't consider that an event |
---|---|---|---|
2 | loop can wait for many different events that may have very different | ||
3 | typical latencies. | ||
2 | 4 | ||
3 | As mentioned in commit 0c1bd46, we ignored requests to | 5 | For example, think of a guest that tends to send a new I/O request soon |
4 | discard the trailing cluster of an unaligned image. While | 6 | after the previous I/O request completes, but the storage on the host is |
5 | discard is an advisory operation from the guest standpoint, | 7 | rather slow. In this case, getting the new request from guest quickly |
6 | (and we are therefore free to ignore any request), our | 8 | means that polling is enabled, but the next thing is performing the I/O |
7 | qcow2 implementation exploits the fact that a discarded | 9 | request on the backend, which is slow and disables polling again for the |
8 | cluster reads back as 0. As long as we discard on cluster | 10 | next guest request. This means that in such a scenario, polling could |
9 | boundaries, we are fine; but that means we could observe | 11 | help for every other event, but is only ever enabled when it can't |
10 | non-zero data leaked at the tail of an unaligned image. | 12 | succeed. |
11 | 13 | ||
12 | Enhance iotest 66 to cover this case, and fix the implementation | 14 | In order to fix this, keep a separate AioPolledEvent for each |
13 | to honor a discard request on the final partial cluster. | 15 | AioHandler. We will then know that the backend file descriptor always |
16 | has a high latency and isn't worth polling for, but we also know that | ||
17 | the guest is always fast and we should poll for it. This solves at least | ||
18 | half of the problem, we can now keep polling for those cases where it | ||
19 | makes sense and get the improved performance from it. | ||
14 | 20 | ||
15 | Signed-off-by: Eric Blake <eblake@redhat.com> | 21 | Since the event loop doesn't know which event will be next, we still do |
16 | Message-id: 20170407013709.18440-1-eblake@redhat.com | 22 | some unnecessary polling while we're waiting for the slow disk. I made |
17 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 23 | some attempts to be more clever than just randomly growing and shrinking |
24 | the polling time, and even to let callers be explicit about when they | ||
25 | expect a new event, but so far this hasn't resulted in improved | ||
26 | performance or even caused performance regressions. For now, let's just | ||
27 | fix the part that is easy enough to fix, we can revisit the rest later. | ||
28 | |||
29 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
30 | Message-ID: <20250307221634.71951-6-kwolf@redhat.com> | ||
31 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
32 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
18 | --- | 33 | --- |
19 | block/qcow2.c | 7 ++++++- | 34 | include/block/aio.h | 1 - |
20 | tests/qemu-iotests/066 | 12 +++++++----- | 35 | util/aio-posix.h | 1 + |
21 | tests/qemu-iotests/066.out | 12 ++++++++---- | 36 | util/aio-posix.c | 26 ++++++++++++++++++++++---- |
22 | 3 files changed, 21 insertions(+), 10 deletions(-) | 37 | util/async.c | 2 -- |
38 | 4 files changed, 23 insertions(+), 7 deletions(-) | ||
23 | 39 | ||
24 | diff --git a/block/qcow2.c b/block/qcow2.c | 40 | diff --git a/include/block/aio.h b/include/block/aio.h |
25 | index XXXXXXX..XXXXXXX 100644 | 41 | index XXXXXXX..XXXXXXX 100644 |
26 | --- a/block/qcow2.c | 42 | --- a/include/block/aio.h |
27 | +++ b/block/qcow2.c | 43 | +++ b/include/block/aio.h |
28 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pdiscard(BlockDriverState *bs, | 44 | @@ -XXX,XX +XXX,XX @@ struct AioContext { |
29 | 45 | int poll_disable_cnt; | |
30 | if (!QEMU_IS_ALIGNED(offset | count, s->cluster_size)) { | 46 | |
31 | assert(count < s->cluster_size); | 47 | /* Polling mode parameters */ |
32 | - return -ENOTSUP; | 48 | - AioPolledEvent poll; |
33 | + /* Ignore partial clusters, except for the special case of the | 49 | int64_t poll_max_ns; /* maximum polling time in nanoseconds */ |
34 | + * complete partial cluster at the end of an unaligned file */ | 50 | int64_t poll_grow; /* polling time growth factor */ |
35 | + if (!QEMU_IS_ALIGNED(offset, s->cluster_size) || | 51 | int64_t poll_shrink; /* polling time shrink factor */ |
36 | + offset + count != bs->total_sectors * BDRV_SECTOR_SIZE) { | 52 | diff --git a/util/aio-posix.h b/util/aio-posix.h |
37 | + return -ENOTSUP; | 53 | index XXXXXXX..XXXXXXX 100644 |
54 | --- a/util/aio-posix.h | ||
55 | +++ b/util/aio-posix.h | ||
56 | @@ -XXX,XX +XXX,XX @@ struct AioHandler { | ||
57 | #endif | ||
58 | int64_t poll_idle_timeout; /* when to stop userspace polling */ | ||
59 | bool poll_ready; /* has polling detected an event? */ | ||
60 | + AioPolledEvent poll; | ||
61 | }; | ||
62 | |||
63 | /* Add a handler to a ready list */ | ||
64 | diff --git a/util/aio-posix.c b/util/aio-posix.c | ||
65 | index XXXXXXX..XXXXXXX 100644 | ||
66 | --- a/util/aio-posix.c | ||
67 | +++ b/util/aio-posix.c | ||
68 | @@ -XXX,XX +XXX,XX @@ static bool run_poll_handlers(AioContext *ctx, AioHandlerList *ready_list, | ||
69 | static bool try_poll_mode(AioContext *ctx, AioHandlerList *ready_list, | ||
70 | int64_t *timeout) | ||
71 | { | ||
72 | + AioHandler *node; | ||
73 | int64_t max_ns; | ||
74 | |||
75 | if (QLIST_EMPTY_RCU(&ctx->poll_aio_handlers)) { | ||
76 | return false; | ||
77 | } | ||
78 | |||
79 | - max_ns = qemu_soonest_timeout(*timeout, ctx->poll.ns); | ||
80 | + max_ns = 0; | ||
81 | + QLIST_FOREACH(node, &ctx->poll_aio_handlers, node_poll) { | ||
82 | + max_ns = MAX(max_ns, node->poll.ns); | ||
83 | + } | ||
84 | + max_ns = qemu_soonest_timeout(*timeout, max_ns); | ||
85 | + | ||
86 | if (max_ns && !ctx->fdmon_ops->need_wait(ctx)) { | ||
87 | /* | ||
88 | * Enable poll mode. It pairs with the poll_set_started() in | ||
89 | @@ -XXX,XX +XXX,XX @@ bool aio_poll(AioContext *ctx, bool blocking) | ||
90 | |||
91 | /* Adjust polling time */ | ||
92 | if (ctx->poll_max_ns) { | ||
93 | + AioHandler *node; | ||
94 | int64_t block_ns = qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - start; | ||
95 | - adjust_polling_time(ctx, &ctx->poll, block_ns); | ||
96 | + | ||
97 | + QLIST_FOREACH(node, &ctx->poll_aio_handlers, node_poll) { | ||
98 | + if (QLIST_IS_INSERTED(node, node_ready)) { | ||
99 | + adjust_polling_time(ctx, &node->poll, block_ns); | ||
100 | + } | ||
38 | + } | 101 | + } |
39 | } | 102 | } |
40 | 103 | ||
41 | qemu_co_mutex_lock(&s->lock); | 104 | progress |= aio_bh_poll(ctx); |
42 | diff --git a/tests/qemu-iotests/066 b/tests/qemu-iotests/066 | 105 | @@ -XXX,XX +XXX,XX @@ void aio_context_use_g_source(AioContext *ctx) |
43 | index XXXXXXX..XXXXXXX 100755 | 106 | void aio_context_set_poll_params(AioContext *ctx, int64_t max_ns, |
44 | --- a/tests/qemu-iotests/066 | 107 | int64_t grow, int64_t shrink, Error **errp) |
45 | +++ b/tests/qemu-iotests/066 | 108 | { |
46 | @@ -XXX,XX +XXX,XX @@ _supported_fmt qcow2 | 109 | + AioHandler *node; |
47 | _supported_proto generic | 110 | + |
48 | _supported_os Linux | 111 | + qemu_lockcnt_inc(&ctx->list_lock); |
49 | 112 | + QLIST_FOREACH(node, &ctx->aio_handlers, node) { | |
50 | +# Intentionally create an unaligned image | 113 | + node->poll.ns = 0; |
51 | IMGOPTS="compat=1.1" | 114 | + } |
52 | -IMG_SIZE=64M | 115 | + qemu_lockcnt_dec(&ctx->list_lock); |
53 | +IMG_SIZE=$((64 * 1024 * 1024 + 512)) | 116 | + |
54 | 117 | /* No thread synchronization here, it doesn't matter if an incorrect value | |
55 | echo | 118 | * is used once. |
56 | -echo "=== Testing snapshotting an image with zero clusters ===" | 119 | */ |
57 | +echo "=== Testing cluster discards ===" | 120 | - ctx->poll.ns = 0; |
58 | echo | 121 | - |
59 | _make_test_img $IMG_SIZE | 122 | ctx->poll_max_ns = max_ns; |
60 | -# Write some normal clusters, zero them (creating preallocated zero clusters) | 123 | ctx->poll_grow = grow; |
61 | -# and discard those | 124 | ctx->poll_shrink = shrink; |
62 | -$QEMU_IO -c "write 0 256k" -c "write -z 0 256k" -c "discard 0 256k" "$TEST_IMG" \ | 125 | diff --git a/util/async.c b/util/async.c |
63 | +# Write some normal clusters, zero some of them (creating preallocated | ||
64 | +# zero clusters) and discard everything. Everything should now read as 0. | ||
65 | +$QEMU_IO -c "write 0 256k" -c "write -z 0 256k" -c "write 64M 512" \ | ||
66 | + -c "discard 0 $IMG_SIZE" -c "read -P 0 0 $IMG_SIZE" "$TEST_IMG" \ | ||
67 | | _filter_qemu_io | ||
68 | # Check the image (there shouldn't be any leaks) | ||
69 | _check_test_img | ||
70 | diff --git a/tests/qemu-iotests/066.out b/tests/qemu-iotests/066.out | ||
71 | index XXXXXXX..XXXXXXX 100644 | 126 | index XXXXXXX..XXXXXXX 100644 |
72 | --- a/tests/qemu-iotests/066.out | 127 | --- a/util/async.c |
73 | +++ b/tests/qemu-iotests/066.out | 128 | +++ b/util/async.c |
74 | @@ -XXX,XX +XXX,XX @@ | 129 | @@ -XXX,XX +XXX,XX @@ AioContext *aio_context_new(Error **errp) |
75 | QA output created by 066 | 130 | qemu_rec_mutex_init(&ctx->lock); |
76 | 131 | timerlistgroup_init(&ctx->tlg, aio_timerlist_notify, ctx); | |
77 | -=== Testing snapshotting an image with zero clusters === | 132 | |
78 | +=== Testing cluster discards === | 133 | - ctx->poll.ns = 0; |
79 | 134 | - | |
80 | -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 | 135 | ctx->poll_max_ns = 0; |
81 | +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67109376 | 136 | ctx->poll_grow = 0; |
82 | wrote 262144/262144 bytes at offset 0 | 137 | ctx->poll_shrink = 0; |
83 | 256 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
84 | wrote 262144/262144 bytes at offset 0 | ||
85 | 256 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
86 | -discard 262144/262144 bytes at offset 0 | ||
87 | -256 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
88 | +wrote 512/512 bytes at offset 67108864 | ||
89 | +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
90 | +discard 67109376/67109376 bytes at offset 0 | ||
91 | +64 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
92 | +read 67109376/67109376 bytes at offset 0 | ||
93 | +64 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
94 | No errors were found on the image. | ||
95 | *** done | ||
96 | -- | 138 | -- |
97 | 1.8.3.1 | 139 | 2.48.1 |
98 | |||
99 | diff view generated by jsdifflib |
1 | Commit d35ff5e6 ('block: Ignore guest dev permissions during incoming | 1 | aio_dispatch_handler() adds handlers to ctx->poll_aio_handlers if |
---|---|---|---|
2 | migration') added blk_resume_after_migration() to the precopy migration | 2 | polling should be enabled. If we call adjust_polling_time() for all |
3 | path, but neglected to add it to the duplicated code that is used for | 3 | polling handlers before this, new polling handlers are still left at |
4 | postcopy migration. This means that the guest device doesn't request the | 4 | poll->ns = 0 and polling is only actually enabled after the next event. |
5 | necessary permissions, which ultimately led to failing assertions. | 5 | Move the adjust_polling_time() call after aio_dispatch_handler(). |
6 | 6 | ||
7 | Add the missing blk_resume_after_migration() to the postcopy path. | 7 | This fixes test-nested-aio-poll, which expects that polling becomes |
8 | effective the first time around. | ||
8 | 9 | ||
9 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
10 | Reviewed-by: Eric Blake <eblake@redhat.com> | 11 | Message-ID: <20250311141912.135657-1-kwolf@redhat.com> |
12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
11 | --- | 13 | --- |
12 | migration/savevm.c | 8 ++++++++ | 14 | util/aio-posix.c | 28 +++++++++++++++++----------- |
13 | 1 file changed, 8 insertions(+) | 15 | 1 file changed, 17 insertions(+), 11 deletions(-) |
14 | 16 | ||
15 | diff --git a/migration/savevm.c b/migration/savevm.c | 17 | diff --git a/util/aio-posix.c b/util/aio-posix.c |
16 | index XXXXXXX..XXXXXXX 100644 | 18 | index XXXXXXX..XXXXXXX 100644 |
17 | --- a/migration/savevm.c | 19 | --- a/util/aio-posix.c |
18 | +++ b/migration/savevm.c | 20 | +++ b/util/aio-posix.c |
19 | @@ -XXX,XX +XXX,XX @@ static void loadvm_postcopy_handle_run_bh(void *opaque) | 21 | @@ -XXX,XX +XXX,XX @@ |
20 | error_report_err(local_err); | 22 | /* Stop userspace polling on a handler if it isn't active for some time */ |
23 | #define POLL_IDLE_INTERVAL_NS (7 * NANOSECONDS_PER_SECOND) | ||
24 | |||
25 | +static void adjust_polling_time(AioContext *ctx, AioPolledEvent *poll, | ||
26 | + int64_t block_ns); | ||
27 | + | ||
28 | bool aio_poll_disabled(AioContext *ctx) | ||
29 | { | ||
30 | return qatomic_read(&ctx->poll_disable_cnt); | ||
31 | @@ -XXX,XX +XXX,XX @@ static bool aio_dispatch_handler(AioContext *ctx, AioHandler *node) | ||
32 | * scanning all handlers with aio_dispatch_handlers(). | ||
33 | */ | ||
34 | static bool aio_dispatch_ready_handlers(AioContext *ctx, | ||
35 | - AioHandlerList *ready_list) | ||
36 | + AioHandlerList *ready_list, | ||
37 | + int64_t block_ns) | ||
38 | { | ||
39 | bool progress = false; | ||
40 | AioHandler *node; | ||
41 | @@ -XXX,XX +XXX,XX @@ static bool aio_dispatch_ready_handlers(AioContext *ctx, | ||
42 | while ((node = QLIST_FIRST(ready_list))) { | ||
43 | QLIST_REMOVE(node, node_ready); | ||
44 | progress = aio_dispatch_handler(ctx, node) || progress; | ||
45 | + | ||
46 | + /* | ||
47 | + * Adjust polling time only after aio_dispatch_handler(), which can | ||
48 | + * add the handler to ctx->poll_aio_handlers. | ||
49 | + */ | ||
50 | + if (ctx->poll_max_ns && QLIST_IS_INSERTED(node, node_poll)) { | ||
51 | + adjust_polling_time(ctx, &node->poll, block_ns); | ||
52 | + } | ||
21 | } | 53 | } |
22 | 54 | ||
23 | + /* If we get an error here, just don't restart the VM yet. */ | 55 | return progress; |
24 | + blk_resume_after_migration(&local_err); | 56 | @@ -XXX,XX +XXX,XX @@ bool aio_poll(AioContext *ctx, bool blocking) |
25 | + if (local_err) { | 57 | bool use_notify_me; |
26 | + error_free(local_err); | 58 | int64_t timeout; |
27 | + local_err = NULL; | 59 | int64_t start = 0; |
28 | + autostart = false; | 60 | + int64_t block_ns = 0; |
29 | + } | 61 | |
30 | + | 62 | /* |
31 | trace_loadvm_postcopy_handle_run_cpu_sync(); | 63 | * There cannot be two concurrent aio_poll calls for the same AioContext (or |
32 | cpu_synchronize_all_post_init(); | 64 | @@ -XXX,XX +XXX,XX @@ bool aio_poll(AioContext *ctx, bool blocking) |
65 | |||
66 | aio_notify_accept(ctx); | ||
67 | |||
68 | - /* Adjust polling time */ | ||
69 | + /* Calculate blocked time for adaptive polling */ | ||
70 | if (ctx->poll_max_ns) { | ||
71 | - AioHandler *node; | ||
72 | - int64_t block_ns = qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - start; | ||
73 | - | ||
74 | - QLIST_FOREACH(node, &ctx->poll_aio_handlers, node_poll) { | ||
75 | - if (QLIST_IS_INSERTED(node, node_ready)) { | ||
76 | - adjust_polling_time(ctx, &node->poll, block_ns); | ||
77 | - } | ||
78 | - } | ||
79 | + block_ns = qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - start; | ||
80 | } | ||
81 | |||
82 | progress |= aio_bh_poll(ctx); | ||
83 | - progress |= aio_dispatch_ready_handlers(ctx, &ready_list); | ||
84 | + progress |= aio_dispatch_ready_handlers(ctx, &ready_list, block_ns); | ||
85 | |||
86 | aio_free_deleted_handlers(ctx); | ||
33 | 87 | ||
34 | -- | 88 | -- |
35 | 1.8.3.1 | 89 | 2.48.1 |
36 | |||
37 | diff view generated by jsdifflib |
1 | From: Thomas Huth <thuth@redhat.com> | 1 | From: Thomas Huth <thuth@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | If the user needs to specify the disk geometry, the corresponding | 3 | qsd-migrate is currently only working for raw, qcow2 and qed. |
4 | parameters of the "-device ide-hd" option should be used instead. | 4 | Other formats are failing, e.g. because they don't support migration. |
5 | "-hdachs" is considered as deprecated and might be removed soon. | 5 | Thus let's limit this test to the three usable formats now. |
6 | 6 | ||
7 | Suggested-by: Kevin Wolf <kwolf@redhat.com> | ||
7 | Signed-off-by: Thomas Huth <thuth@redhat.com> | 8 | Signed-off-by: Thomas Huth <thuth@redhat.com> |
8 | Reviewed-by: Eric Blake <eblake@redhat.com> | 9 | Message-ID: <20250224214058.205889-1-thuth@redhat.com> |
10 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
9 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
10 | --- | 12 | --- |
11 | qemu-options.hx | 4 ++-- | 13 | tests/qemu-iotests/tests/qsd-migrate | 2 +- |
12 | vl.c | 2 ++ | 14 | 1 file changed, 1 insertion(+), 1 deletion(-) |
13 | 2 files changed, 4 insertions(+), 2 deletions(-) | ||
14 | 15 | ||
15 | diff --git a/qemu-options.hx b/qemu-options.hx | 16 | diff --git a/tests/qemu-iotests/tests/qsd-migrate b/tests/qemu-iotests/tests/qsd-migrate |
16 | index XXXXXXX..XXXXXXX 100644 | 17 | index XXXXXXX..XXXXXXX 100755 |
17 | --- a/qemu-options.hx | 18 | --- a/tests/qemu-iotests/tests/qsd-migrate |
18 | +++ b/qemu-options.hx | 19 | +++ b/tests/qemu-iotests/tests/qsd-migrate |
19 | @@ -XXX,XX +XXX,XX @@ STEXI | 20 | @@ -XXX,XX +XXX,XX @@ import iotests |
20 | Force hard disk 0 physical geometry (1 <= @var{c} <= 16383, 1 <= | 21 | |
21 | @var{h} <= 16, 1 <= @var{s} <= 63) and optionally force the BIOS | 22 | from iotests import filter_qemu_io, filter_qtest |
22 | translation mode (@var{t}=none, lba or auto). Usually QEMU can guess | 23 | |
23 | -all those parameters. This option is useful for old MS-DOS disk | 24 | -iotests.script_initialize(supported_fmts=['generic'], |
24 | -images. | 25 | +iotests.script_initialize(supported_fmts=['qcow2', 'qed', 'raw'], |
25 | +all those parameters. This option is deprecated, please use | 26 | supported_protocols=['file'], |
26 | +@code{-device ide-hd,cyls=c,heads=h,secs=s,...} instead. | 27 | supported_platforms=['linux']) |
27 | ETEXI | 28 | |
28 | |||
29 | DEF("fsdev", HAS_ARG, QEMU_OPTION_fsdev, | ||
30 | diff --git a/vl.c b/vl.c | ||
31 | index XXXXXXX..XXXXXXX 100644 | ||
32 | --- a/vl.c | ||
33 | +++ b/vl.c | ||
34 | @@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv, char **envp) | ||
35 | } | ||
36 | } | ||
37 | } | ||
38 | + error_report("'-hdachs' is deprecated, please use '-device" | ||
39 | + " ide-hd,cyls=c,heads=h,secs=s,...' instead"); | ||
40 | break; | ||
41 | case QEMU_OPTION_numa: | ||
42 | opts = qemu_opts_parse_noisily(qemu_find_opts("numa"), | ||
43 | -- | 29 | -- |
44 | 1.8.3.1 | 30 | 2.48.1 |
45 | |||
46 | diff view generated by jsdifflib |
1 | From: Stefan Hajnoczi <stefanha@redhat.com> | ||
---|---|---|---|
2 | |||
3 | Commit 71544d30a6f8 ("scsi: push request restart to SCSIDevice") removed | ||
4 | the only user of SCSIDiskState->bh. | ||
5 | |||
6 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
7 | Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> | ||
8 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
9 | Message-ID: <20250311132616.1049687-2-stefanha@redhat.com> | ||
1 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
2 | --- | 11 | --- |
3 | block/file-win32.c | 1 - | 12 | hw/scsi/scsi-disk.c | 1 - |
4 | 1 file changed, 1 deletion(-) | 13 | 1 file changed, 1 deletion(-) |
5 | 14 | ||
6 | diff --git a/block/file-win32.c b/block/file-win32.c | 15 | diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c |
7 | index XXXXXXX..XXXXXXX 100644 | 16 | index XXXXXXX..XXXXXXX 100644 |
8 | --- a/block/file-win32.c | 17 | --- a/hw/scsi/scsi-disk.c |
9 | +++ b/block/file-win32.c | 18 | +++ b/hw/scsi/scsi-disk.c |
10 | @@ -XXX,XX +XXX,XX @@ | 19 | @@ -XXX,XX +XXX,XX @@ struct SCSIDiskState { |
11 | #include "qemu/osdep.h" | 20 | uint64_t max_unmap_size; |
12 | #include "qapi/error.h" | 21 | uint64_t max_io_size; |
13 | #include "qemu/cutils.h" | 22 | uint32_t quirks; |
14 | -#include "qemu/timer.h" | 23 | - QEMUBH *bh; |
15 | #include "block/block_int.h" | 24 | char *version; |
16 | #include "qemu/module.h" | 25 | char *serial; |
17 | #include "block/raw-aio.h" | 26 | char *vendor; |
18 | -- | 27 | -- |
19 | 1.8.3.1 | 28 | 2.48.1 |
20 | 29 | ||
21 | 30 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Max Reitz <mreitz@redhat.com> | ||
2 | 1 | ||
3 | This reverts commit e3e0003a8f6570aba1421ef99a0b383a43371a74. | ||
4 | |||
5 | This commit was necessary for the 2.9 release because we were unable to | ||
6 | fix the underlying issue(s) in time. However, we will be for 2.10. | ||
7 | |||
8 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
9 | Acked-by: Fam Zheng <famz@redhat.com> | ||
10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
11 | --- | ||
12 | block.c | 6 +----- | ||
13 | block/io.c | 12 ++---------- | ||
14 | 2 files changed, 3 insertions(+), 15 deletions(-) | ||
15 | |||
16 | diff --git a/block.c b/block.c | ||
17 | index XXXXXXX..XXXXXXX 100644 | ||
18 | --- a/block.c | ||
19 | +++ b/block.c | ||
20 | @@ -XXX,XX +XXX,XX @@ int bdrv_truncate(BdrvChild *child, int64_t offset) | ||
21 | BlockDriver *drv = bs->drv; | ||
22 | int ret; | ||
23 | |||
24 | - /* FIXME: Some format block drivers use this function instead of implicitly | ||
25 | - * growing their file by writing beyond its end. | ||
26 | - * See bdrv_aligned_pwritev() for an explanation why we currently | ||
27 | - * cannot assert this permission in that case. */ | ||
28 | - // assert(child->perm & BLK_PERM_RESIZE); | ||
29 | + assert(child->perm & BLK_PERM_RESIZE); | ||
30 | |||
31 | if (!drv) | ||
32 | return -ENOMEDIUM; | ||
33 | diff --git a/block/io.c b/block/io.c | ||
34 | index XXXXXXX..XXXXXXX 100644 | ||
35 | --- a/block/io.c | ||
36 | +++ b/block/io.c | ||
37 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child, | ||
38 | assert(!waited || !req->serialising); | ||
39 | assert(req->overlap_offset <= offset); | ||
40 | assert(offset + bytes <= req->overlap_offset + req->overlap_bytes); | ||
41 | - /* FIXME: Block migration uses the BlockBackend of the guest device at a | ||
42 | - * point when it has not yet taken write permissions. This will be | ||
43 | - * fixed by a future patch, but for now we have to bypass this | ||
44 | - * assertion for block migration to work. */ | ||
45 | - // assert(child->perm & BLK_PERM_WRITE); | ||
46 | - /* FIXME: Because of the above, we also cannot guarantee that all format | ||
47 | - * BDS take the BLK_PERM_RESIZE permission on their file BDS, since | ||
48 | - * they are not obligated to do so if they do not have any parent | ||
49 | - * that has taken the permission to write to them. */ | ||
50 | - // assert(end_sector <= bs->total_sectors || child->perm & BLK_PERM_RESIZE); | ||
51 | + assert(child->perm & BLK_PERM_WRITE); | ||
52 | + assert(end_sector <= bs->total_sectors || child->perm & BLK_PERM_RESIZE); | ||
53 | |||
54 | ret = notifier_with_return_list_notify(&bs->before_write_notifiers, req); | ||
55 | |||
56 | -- | ||
57 | 1.8.3.1 | ||
58 | |||
59 | diff view generated by jsdifflib |
1 | From: Max Reitz <mreitz@redhat.com> | 1 | From: Stefan Hajnoczi <stefanha@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | After storing the creation options for the new image into @opts, we | 3 | In the past a single AioContext was used for block I/O and it was |
4 | fetch some things for our own information, like the backing file name, | 4 | fetched using blk_get_aio_context(). Nowadays the block layer supports |
5 | or whether to use encryption or preallocation. | 5 | running I/O from any AioContext and multiple AioContexts at the same |
6 | time. Remove the dma_blk_io() AioContext argument and use the current | ||
7 | AioContext instead. | ||
6 | 8 | ||
7 | With the -n parameter, there will not be any creation options; this is | 9 | This makes calling the function easier and enables multiple IOThreads to |
8 | not too bad because this just means that querying a NULL @opts will | 10 | use dma_blk_io() concurrently for the same block device. |
9 | always return the default value. | ||
10 | 11 | ||
11 | However, we also use @opts for the --object options. Therefore, @opts is | 12 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> |
12 | not necessarily NULL if -n was specified; instead, it may contain those | 13 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> |
13 | options. In practice, this probably does not cause any problems because | 14 | Message-ID: <20250311132616.1049687-3-stefanha@redhat.com> |
14 | there most likely is no object that supports any of the parameters we | ||
15 | query here, but this is neither something we should rely on nor does | ||
16 | this variable reuse make the code very nice to read. | ||
17 | |||
18 | Therefore, just use a separate variable for the --object options. | ||
19 | |||
20 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
21 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
22 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 15 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
23 | --- | 16 | --- |
24 | qemu-img.c | 10 ++++++---- | 17 | include/system/dma.h | 3 +-- |
25 | 1 file changed, 6 insertions(+), 4 deletions(-) | 18 | hw/ide/core.c | 3 +-- |
19 | hw/ide/macio.c | 3 +-- | ||
20 | hw/scsi/scsi-disk.c | 6 ++---- | ||
21 | system/dma-helpers.c | 8 ++++---- | ||
22 | 5 files changed, 9 insertions(+), 14 deletions(-) | ||
26 | 23 | ||
27 | diff --git a/qemu-img.c b/qemu-img.c | 24 | diff --git a/include/system/dma.h b/include/system/dma.h |
28 | index XXXXXXX..XXXXXXX 100644 | 25 | index XXXXXXX..XXXXXXX 100644 |
29 | --- a/qemu-img.c | 26 | --- a/include/system/dma.h |
30 | +++ b/qemu-img.c | 27 | +++ b/include/system/dma.h |
31 | @@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv) | 28 | @@ -XXX,XX +XXX,XX @@ typedef BlockAIOCB *DMAIOFunc(int64_t offset, QEMUIOVector *iov, |
32 | case 'W': | 29 | BlockCompletionFunc *cb, void *cb_opaque, |
33 | s.wr_in_order = false; | 30 | void *opaque); |
34 | break; | 31 | |
35 | - case OPTION_OBJECT: | 32 | -BlockAIOCB *dma_blk_io(AioContext *ctx, |
36 | - opts = qemu_opts_parse_noisily(&qemu_object_opts, | 33 | - QEMUSGList *sg, uint64_t offset, uint32_t align, |
37 | - optarg, true); | 34 | +BlockAIOCB *dma_blk_io(QEMUSGList *sg, uint64_t offset, uint32_t align, |
38 | - if (!opts) { | 35 | DMAIOFunc *io_func, void *io_func_opaque, |
39 | + case OPTION_OBJECT: { | 36 | BlockCompletionFunc *cb, void *opaque, DMADirection dir); |
40 | + QemuOpts *object_opts; | 37 | BlockAIOCB *dma_blk_read(BlockBackend *blk, |
41 | + object_opts = qemu_opts_parse_noisily(&qemu_object_opts, | 38 | diff --git a/hw/ide/core.c b/hw/ide/core.c |
42 | + optarg, true); | 39 | index XXXXXXX..XXXXXXX 100644 |
43 | + if (!object_opts) { | 40 | --- a/hw/ide/core.c |
44 | goto fail_getopt; | 41 | +++ b/hw/ide/core.c |
45 | } | 42 | @@ -XXX,XX +XXX,XX @@ static void ide_dma_cb(void *opaque, int ret) |
46 | break; | 43 | BDRV_SECTOR_SIZE, ide_dma_cb, s); |
47 | + } | 44 | break; |
48 | case OPTION_IMAGE_OPTS: | 45 | case IDE_DMA_TRIM: |
49 | image_opts = true; | 46 | - s->bus->dma->aiocb = dma_blk_io(blk_get_aio_context(s->blk), |
50 | break; | 47 | - &s->sg, offset, BDRV_SECTOR_SIZE, |
48 | + s->bus->dma->aiocb = dma_blk_io(&s->sg, offset, BDRV_SECTOR_SIZE, | ||
49 | ide_issue_trim, s, ide_dma_cb, s, | ||
50 | DMA_DIRECTION_TO_DEVICE); | ||
51 | break; | ||
52 | diff --git a/hw/ide/macio.c b/hw/ide/macio.c | ||
53 | index XXXXXXX..XXXXXXX 100644 | ||
54 | --- a/hw/ide/macio.c | ||
55 | +++ b/hw/ide/macio.c | ||
56 | @@ -XXX,XX +XXX,XX @@ static void pmac_ide_transfer_cb(void *opaque, int ret) | ||
57 | pmac_ide_transfer_cb, io); | ||
58 | break; | ||
59 | case IDE_DMA_TRIM: | ||
60 | - s->bus->dma->aiocb = dma_blk_io(blk_get_aio_context(s->blk), &s->sg, | ||
61 | - offset, 0x1, ide_issue_trim, s, | ||
62 | + s->bus->dma->aiocb = dma_blk_io(&s->sg, offset, 0x1, ide_issue_trim, s, | ||
63 | pmac_ide_transfer_cb, io, | ||
64 | DMA_DIRECTION_TO_DEVICE); | ||
65 | break; | ||
66 | diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c | ||
67 | index XXXXXXX..XXXXXXX 100644 | ||
68 | --- a/hw/scsi/scsi-disk.c | ||
69 | +++ b/hw/scsi/scsi-disk.c | ||
70 | @@ -XXX,XX +XXX,XX @@ static void scsi_do_read(SCSIDiskReq *r, int ret) | ||
71 | if (r->req.sg) { | ||
72 | dma_acct_start(s->qdev.conf.blk, &r->acct, r->req.sg, BLOCK_ACCT_READ); | ||
73 | r->req.residual -= r->req.sg->size; | ||
74 | - r->req.aiocb = dma_blk_io(blk_get_aio_context(s->qdev.conf.blk), | ||
75 | - r->req.sg, r->sector << BDRV_SECTOR_BITS, | ||
76 | + r->req.aiocb = dma_blk_io(r->req.sg, r->sector << BDRV_SECTOR_BITS, | ||
77 | BDRV_SECTOR_SIZE, | ||
78 | sdc->dma_readv, r, scsi_dma_complete, r, | ||
79 | DMA_DIRECTION_FROM_DEVICE); | ||
80 | @@ -XXX,XX +XXX,XX @@ static void scsi_write_data(SCSIRequest *req) | ||
81 | if (r->req.sg) { | ||
82 | dma_acct_start(s->qdev.conf.blk, &r->acct, r->req.sg, BLOCK_ACCT_WRITE); | ||
83 | r->req.residual -= r->req.sg->size; | ||
84 | - r->req.aiocb = dma_blk_io(blk_get_aio_context(s->qdev.conf.blk), | ||
85 | - r->req.sg, r->sector << BDRV_SECTOR_BITS, | ||
86 | + r->req.aiocb = dma_blk_io(r->req.sg, r->sector << BDRV_SECTOR_BITS, | ||
87 | BDRV_SECTOR_SIZE, | ||
88 | sdc->dma_writev, r, scsi_dma_complete, r, | ||
89 | DMA_DIRECTION_TO_DEVICE); | ||
90 | diff --git a/system/dma-helpers.c b/system/dma-helpers.c | ||
91 | index XXXXXXX..XXXXXXX 100644 | ||
92 | --- a/system/dma-helpers.c | ||
93 | +++ b/system/dma-helpers.c | ||
94 | @@ -XXX,XX +XXX,XX @@ static const AIOCBInfo dma_aiocb_info = { | ||
95 | .cancel_async = dma_aio_cancel, | ||
96 | }; | ||
97 | |||
98 | -BlockAIOCB *dma_blk_io(AioContext *ctx, | ||
99 | +BlockAIOCB *dma_blk_io( | ||
100 | QEMUSGList *sg, uint64_t offset, uint32_t align, | ||
101 | DMAIOFunc *io_func, void *io_func_opaque, | ||
102 | BlockCompletionFunc *cb, | ||
103 | @@ -XXX,XX +XXX,XX @@ BlockAIOCB *dma_blk_io(AioContext *ctx, | ||
104 | |||
105 | dbs->acb = NULL; | ||
106 | dbs->sg = sg; | ||
107 | - dbs->ctx = ctx; | ||
108 | + dbs->ctx = qemu_get_current_aio_context(); | ||
109 | dbs->offset = offset; | ||
110 | dbs->align = align; | ||
111 | dbs->sg_cur_index = 0; | ||
112 | @@ -XXX,XX +XXX,XX @@ BlockAIOCB *dma_blk_read(BlockBackend *blk, | ||
113 | QEMUSGList *sg, uint64_t offset, uint32_t align, | ||
114 | void (*cb)(void *opaque, int ret), void *opaque) | ||
115 | { | ||
116 | - return dma_blk_io(blk_get_aio_context(blk), sg, offset, align, | ||
117 | + return dma_blk_io(sg, offset, align, | ||
118 | dma_blk_read_io_func, blk, cb, opaque, | ||
119 | DMA_DIRECTION_FROM_DEVICE); | ||
120 | } | ||
121 | @@ -XXX,XX +XXX,XX @@ BlockAIOCB *dma_blk_write(BlockBackend *blk, | ||
122 | QEMUSGList *sg, uint64_t offset, uint32_t align, | ||
123 | void (*cb)(void *opaque, int ret), void *opaque) | ||
124 | { | ||
125 | - return dma_blk_io(blk_get_aio_context(blk), sg, offset, align, | ||
126 | + return dma_blk_io(sg, offset, align, | ||
127 | dma_blk_write_io_func, blk, cb, opaque, | ||
128 | DMA_DIRECTION_TO_DEVICE); | ||
129 | } | ||
51 | -- | 130 | -- |
52 | 1.8.3.1 | 131 | 2.48.1 |
53 | |||
54 | diff view generated by jsdifflib |
1 | From: Max Reitz <mreitz@redhat.com> | 1 | From: Stefan Hajnoczi <stefanha@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Reproducer: | 3 | Until now, a SCSIDevice's I/O requests have run in a single AioContext. |
4 | $ ./qemu-img info '' | 4 | In order to support multiple IOThreads it will be necessary to move to |
5 | qemu-img: ./block.c:1008: bdrv_open_driver: Assertion | 5 | the concept of a per-SCSIRequest AioContext. |
6 | `!drv->bdrv_needs_filename || bs->filename[0]' failed. | ||
7 | [1] 26105 abort (core dumped) ./qemu-img info '' | ||
8 | 6 | ||
9 | This patch fixes this to be: | 7 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> |
10 | $ ./qemu-img info '' | 8 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> |
11 | qemu-img: Could not open '': The 'file' block driver requires a file | 9 | Message-ID: <20250311132616.1049687-4-stefanha@redhat.com> |
12 | name | ||
13 | |||
14 | Cc: qemu-stable <qemu-stable@nongnu.org> | ||
15 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
16 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
17 | Reviewed-by: Fam Zheng <famz@redhat.com> | ||
18 | Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org> | ||
19 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
20 | --- | 11 | --- |
21 | block.c | 2 +- | 12 | include/hw/scsi/scsi.h | 1 + |
22 | 1 file changed, 1 insertion(+), 1 deletion(-) | 13 | hw/scsi/scsi-bus.c | 1 + |
14 | hw/scsi/scsi-disk.c | 17 ++++++----------- | ||
15 | 3 files changed, 8 insertions(+), 11 deletions(-) | ||
23 | 16 | ||
24 | diff --git a/block.c b/block.c | 17 | diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h |
25 | index XXXXXXX..XXXXXXX 100644 | 18 | index XXXXXXX..XXXXXXX 100644 |
26 | --- a/block.c | 19 | --- a/include/hw/scsi/scsi.h |
27 | +++ b/block.c | 20 | +++ b/include/hw/scsi/scsi.h |
28 | @@ -XXX,XX +XXX,XX @@ static int bdrv_open_common(BlockDriverState *bs, BlockBackend *file, | 21 | @@ -XXX,XX +XXX,XX @@ struct SCSIRequest { |
29 | filename = qdict_get_try_str(options, "filename"); | 22 | SCSIBus *bus; |
23 | SCSIDevice *dev; | ||
24 | const SCSIReqOps *ops; | ||
25 | + AioContext *ctx; | ||
26 | uint32_t refcount; | ||
27 | uint32_t tag; | ||
28 | uint32_t lun; | ||
29 | diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c | ||
30 | index XXXXXXX..XXXXXXX 100644 | ||
31 | --- a/hw/scsi/scsi-bus.c | ||
32 | +++ b/hw/scsi/scsi-bus.c | ||
33 | @@ -XXX,XX +XXX,XX @@ invalid_opcode: | ||
34 | } | ||
30 | } | 35 | } |
31 | 36 | ||
32 | - if (drv->bdrv_needs_filename && !filename) { | 37 | + req->ctx = qemu_get_current_aio_context(); |
33 | + if (drv->bdrv_needs_filename && (!filename || !filename[0])) { | 38 | req->cmd = cmd; |
34 | error_setg(errp, "The '%s' block driver requires a file name", | 39 | req->residual = req->cmd.xfer; |
35 | drv->format_name); | 40 | |
36 | ret = -EINVAL; | 41 | diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c |
42 | index XXXXXXX..XXXXXXX 100644 | ||
43 | --- a/hw/scsi/scsi-disk.c | ||
44 | +++ b/hw/scsi/scsi-disk.c | ||
45 | @@ -XXX,XX +XXX,XX @@ static void scsi_aio_complete(void *opaque, int ret) | ||
46 | SCSIDiskReq *r = (SCSIDiskReq *)opaque; | ||
47 | SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); | ||
48 | |||
49 | - /* The request must only run in the BlockBackend's AioContext */ | ||
50 | - assert(blk_get_aio_context(s->qdev.conf.blk) == | ||
51 | - qemu_get_current_aio_context()); | ||
52 | + /* The request must run in its AioContext */ | ||
53 | + assert(r->req.ctx == qemu_get_current_aio_context()); | ||
54 | |||
55 | assert(r->req.aiocb != NULL); | ||
56 | r->req.aiocb = NULL; | ||
57 | @@ -XXX,XX +XXX,XX @@ static void scsi_dma_complete(void *opaque, int ret) | ||
58 | |||
59 | static void scsi_read_complete_noio(SCSIDiskReq *r, int ret) | ||
60 | { | ||
61 | - SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); | ||
62 | uint32_t n; | ||
63 | |||
64 | - /* The request must only run in the BlockBackend's AioContext */ | ||
65 | - assert(blk_get_aio_context(s->qdev.conf.blk) == | ||
66 | - qemu_get_current_aio_context()); | ||
67 | + /* The request must run in its AioContext */ | ||
68 | + assert(r->req.ctx == qemu_get_current_aio_context()); | ||
69 | |||
70 | assert(r->req.aiocb == NULL); | ||
71 | if (scsi_disk_req_check_error(r, ret, ret > 0)) { | ||
72 | @@ -XXX,XX +XXX,XX @@ static void scsi_read_data(SCSIRequest *req) | ||
73 | |||
74 | static void scsi_write_complete_noio(SCSIDiskReq *r, int ret) | ||
75 | { | ||
76 | - SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); | ||
77 | uint32_t n; | ||
78 | |||
79 | - /* The request must only run in the BlockBackend's AioContext */ | ||
80 | - assert(blk_get_aio_context(s->qdev.conf.blk) == | ||
81 | - qemu_get_current_aio_context()); | ||
82 | + /* The request must run in its AioContext */ | ||
83 | + assert(r->req.ctx == qemu_get_current_aio_context()); | ||
84 | |||
85 | assert (r->req.aiocb == NULL); | ||
86 | if (scsi_disk_req_check_error(r, ret, ret > 0)) { | ||
37 | -- | 87 | -- |
38 | 1.8.3.1 | 88 | 2.48.1 |
39 | |||
40 | diff view generated by jsdifflib |
1 | From: Max Reitz <mreitz@redhat.com> | 1 | From: Stefan Hajnoczi <stefanha@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Currently we only print progress information on retrieval of SIGUSR1. | 3 | SCSIDevice keeps track of in-flight requests for device reset and Task |
4 | Some systems have a dedicated SIGINFO for this, however, so it should be | 4 | Management Functions (TMFs). The request list requires protection so |
5 | handled appropriately if it is available. | 5 | that multi-threaded SCSI emulation can be implemented in commits that |
6 | follow. | ||
6 | 7 | ||
7 | Buglink: https://bugs.launchpad.net/qemu/+bug/1662468 | 8 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> |
8 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 9 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> |
9 | Message-id: 20170207235757.2026-1-mreitz@redhat.com | 10 | Message-ID: <20250311132616.1049687-5-stefanha@redhat.com> |
10 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | 11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
11 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
12 | --- | 12 | --- |
13 | qemu-img.texi | 3 ++- | 13 | include/hw/scsi/scsi.h | 7 ++- |
14 | util/qemu-progress.c | 3 +++ | 14 | hw/scsi/scsi-bus.c | 120 +++++++++++++++++++++++++++++------------ |
15 | 2 files changed, 5 insertions(+), 1 deletion(-) | 15 | 2 files changed, 88 insertions(+), 39 deletions(-) |
16 | 16 | ||
17 | diff --git a/qemu-img.texi b/qemu-img.texi | 17 | diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h |
18 | index XXXXXXX..XXXXXXX 100644 | 18 | index XXXXXXX..XXXXXXX 100644 |
19 | --- a/qemu-img.texi | 19 | --- a/include/hw/scsi/scsi.h |
20 | +++ b/qemu-img.texi | 20 | +++ b/include/hw/scsi/scsi.h |
21 | @@ -XXX,XX +XXX,XX @@ with or without a command shows help and lists the supported formats | 21 | @@ -XXX,XX +XXX,XX @@ struct SCSIRequest { |
22 | @item -p | 22 | bool dma_started; |
23 | display progress bar (compare, convert and rebase commands only). | 23 | BlockAIOCB *aiocb; |
24 | If the @var{-p} option is not used for a command that supports it, the | 24 | QEMUSGList *sg; |
25 | -progress is reported when the process receives a @code{SIGUSR1} signal. | 25 | + |
26 | +progress is reported when the process receives a @code{SIGUSR1} or | 26 | + /* Protected by SCSIDevice->requests_lock */ |
27 | +@code{SIGINFO} signal. | 27 | QTAILQ_ENTRY(SCSIRequest) next; |
28 | @item -q | 28 | }; |
29 | Quiet mode - do not print any output (except errors). There's no progress bar | 29 | |
30 | in case both @var{-q} and @var{-p} options are used. | 30 | @@ -XXX,XX +XXX,XX @@ struct SCSIDevice |
31 | diff --git a/util/qemu-progress.c b/util/qemu-progress.c | 31 | uint8_t sense[SCSI_SENSE_BUF_SIZE]; |
32 | uint32_t sense_len; | ||
33 | |||
34 | - /* | ||
35 | - * The requests list is only accessed from the AioContext that executes | ||
36 | - * requests or from the main loop when IOThread processing is stopped. | ||
37 | - */ | ||
38 | + QemuMutex requests_lock; /* protects the requests list */ | ||
39 | QTAILQ_HEAD(, SCSIRequest) requests; | ||
40 | |||
41 | uint32_t channel; | ||
42 | diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c | ||
32 | index XXXXXXX..XXXXXXX 100644 | 43 | index XXXXXXX..XXXXXXX 100644 |
33 | --- a/util/qemu-progress.c | 44 | --- a/hw/scsi/scsi-bus.c |
34 | +++ b/util/qemu-progress.c | 45 | +++ b/hw/scsi/scsi-bus.c |
35 | @@ -XXX,XX +XXX,XX @@ static void progress_dummy_init(void) | 46 | @@ -XXX,XX +XXX,XX @@ static void scsi_device_for_each_req_sync(SCSIDevice *s, |
36 | action.sa_handler = sigusr_print; | 47 | assert(!runstate_is_running()); |
37 | action.sa_flags = 0; | 48 | assert(qemu_in_main_thread()); |
38 | sigaction(SIGUSR1, &action, NULL); | 49 | |
39 | +#ifdef SIGINFO | 50 | - QTAILQ_FOREACH_SAFE(req, &s->requests, next, next_req) { |
40 | + sigaction(SIGINFO, &action, NULL); | 51 | - fn(req, opaque); |
41 | +#endif | 52 | + /* |
53 | + * Locking is not necessary because the guest is stopped and no other | ||
54 | + * threads can be accessing the requests list, but take the lock for | ||
55 | + * consistency. | ||
56 | + */ | ||
57 | + WITH_QEMU_LOCK_GUARD(&s->requests_lock) { | ||
58 | + QTAILQ_FOREACH_SAFE(req, &s->requests, next, next_req) { | ||
59 | + fn(req, opaque); | ||
60 | + } | ||
61 | } | ||
62 | } | ||
63 | |||
64 | @@ -XXX,XX +XXX,XX @@ static void scsi_device_for_each_req_async_bh(void *opaque) | ||
65 | { | ||
66 | g_autofree SCSIDeviceForEachReqAsyncData *data = opaque; | ||
67 | SCSIDevice *s = data->s; | ||
68 | - AioContext *ctx; | ||
69 | - SCSIRequest *req; | ||
70 | - SCSIRequest *next; | ||
71 | + g_autoptr(GList) reqs = NULL; | ||
42 | 72 | ||
43 | /* | 73 | /* |
44 | * SIGUSR1 is SIG_IPI and gets blocked in qemu_init_main_loop(). In the | 74 | - * The BB cannot have changed contexts between this BH being scheduled and |
75 | - * now: BBs' AioContexts, when they have a node attached, can only be | ||
76 | - * changed via bdrv_try_change_aio_context(), in a drained section. While | ||
77 | - * we have the in-flight counter incremented, that drain must block. | ||
78 | + * Build a list of requests in this AioContext so fn() can be invoked later | ||
79 | + * outside requests_lock. | ||
80 | */ | ||
81 | - ctx = blk_get_aio_context(s->conf.blk); | ||
82 | - assert(ctx == qemu_get_current_aio_context()); | ||
83 | + WITH_QEMU_LOCK_GUARD(&s->requests_lock) { | ||
84 | + AioContext *ctx = qemu_get_current_aio_context(); | ||
85 | + SCSIRequest *req; | ||
86 | + SCSIRequest *next; | ||
87 | + | ||
88 | + QTAILQ_FOREACH_SAFE(req, &s->requests, next, next) { | ||
89 | + if (req->ctx == ctx) { | ||
90 | + scsi_req_ref(req); /* dropped after calling fn() */ | ||
91 | + reqs = g_list_prepend(reqs, req); | ||
92 | + } | ||
93 | + } | ||
94 | + } | ||
95 | |||
96 | - QTAILQ_FOREACH_SAFE(req, &s->requests, next, next) { | ||
97 | - data->fn(req, data->fn_opaque); | ||
98 | + /* Call fn() on each request */ | ||
99 | + for (GList *elem = g_list_first(reqs); elem; elem = g_list_next(elem)) { | ||
100 | + data->fn(elem->data, data->fn_opaque); | ||
101 | + scsi_req_unref(elem->data); | ||
102 | } | ||
103 | |||
104 | /* Drop the reference taken by scsi_device_for_each_req_async() */ | ||
105 | @@ -XXX,XX +XXX,XX @@ static void scsi_device_for_each_req_async_bh(void *opaque) | ||
106 | blk_dec_in_flight(s->conf.blk); | ||
107 | } | ||
108 | |||
109 | +static void scsi_device_for_each_req_async_do_ctx(gpointer key, gpointer value, | ||
110 | + gpointer user_data) | ||
111 | +{ | ||
112 | + AioContext *ctx = key; | ||
113 | + SCSIDeviceForEachReqAsyncData *params = user_data; | ||
114 | + SCSIDeviceForEachReqAsyncData *data; | ||
115 | + | ||
116 | + data = g_new(SCSIDeviceForEachReqAsyncData, 1); | ||
117 | + data->s = params->s; | ||
118 | + data->fn = params->fn; | ||
119 | + data->fn_opaque = params->fn_opaque; | ||
120 | + | ||
121 | + /* | ||
122 | + * Hold a reference to the SCSIDevice until | ||
123 | + * scsi_device_for_each_req_async_bh() finishes. | ||
124 | + */ | ||
125 | + object_ref(OBJECT(data->s)); | ||
126 | + | ||
127 | + /* Paired with scsi_device_for_each_req_async_bh() */ | ||
128 | + blk_inc_in_flight(data->s->conf.blk); | ||
129 | + | ||
130 | + aio_bh_schedule_oneshot(ctx, scsi_device_for_each_req_async_bh, data); | ||
131 | +} | ||
132 | + | ||
133 | /* | ||
134 | * Schedule @fn() to be invoked for each enqueued request in device @s. @fn() | ||
135 | - * runs in the AioContext that is executing the request. | ||
136 | + * must be thread-safe because it runs concurrently in each AioContext that is | ||
137 | + * executing a request. | ||
138 | + * | ||
139 | * Keeps the BlockBackend's in-flight counter incremented until everything is | ||
140 | * done, so draining it will settle all scheduled @fn() calls. | ||
141 | */ | ||
142 | @@ -XXX,XX +XXX,XX @@ static void scsi_device_for_each_req_async(SCSIDevice *s, | ||
143 | { | ||
144 | assert(qemu_in_main_thread()); | ||
145 | |||
146 | - SCSIDeviceForEachReqAsyncData *data = | ||
147 | - g_new(SCSIDeviceForEachReqAsyncData, 1); | ||
148 | - | ||
149 | - data->s = s; | ||
150 | - data->fn = fn; | ||
151 | - data->fn_opaque = opaque; | ||
152 | - | ||
153 | - /* | ||
154 | - * Hold a reference to the SCSIDevice until | ||
155 | - * scsi_device_for_each_req_async_bh() finishes. | ||
156 | - */ | ||
157 | - object_ref(OBJECT(s)); | ||
158 | + /* The set of AioContexts where the requests are being processed */ | ||
159 | + g_autoptr(GHashTable) aio_contexts = g_hash_table_new(NULL, NULL); | ||
160 | + WITH_QEMU_LOCK_GUARD(&s->requests_lock) { | ||
161 | + SCSIRequest *req; | ||
162 | + QTAILQ_FOREACH(req, &s->requests, next) { | ||
163 | + g_hash_table_add(aio_contexts, req->ctx); | ||
164 | + } | ||
165 | + } | ||
166 | |||
167 | - /* Paired with blk_dec_in_flight() in scsi_device_for_each_req_async_bh() */ | ||
168 | - blk_inc_in_flight(s->conf.blk); | ||
169 | - aio_bh_schedule_oneshot(blk_get_aio_context(s->conf.blk), | ||
170 | - scsi_device_for_each_req_async_bh, | ||
171 | - data); | ||
172 | + /* Schedule a BH for each AioContext */ | ||
173 | + SCSIDeviceForEachReqAsyncData params = { | ||
174 | + .s = s, | ||
175 | + .fn = fn, | ||
176 | + .fn_opaque = opaque, | ||
177 | + }; | ||
178 | + g_hash_table_foreach( | ||
179 | + aio_contexts, | ||
180 | + scsi_device_for_each_req_async_do_ctx, | ||
181 | + ¶ms | ||
182 | + ); | ||
183 | } | ||
184 | |||
185 | static void scsi_device_realize(SCSIDevice *s, Error **errp) | ||
186 | @@ -XXX,XX +XXX,XX @@ static void scsi_qdev_realize(DeviceState *qdev, Error **errp) | ||
187 | dev->lun = lun; | ||
188 | } | ||
189 | |||
190 | + qemu_mutex_init(&dev->requests_lock); | ||
191 | QTAILQ_INIT(&dev->requests); | ||
192 | scsi_device_realize(dev, &local_err); | ||
193 | if (local_err) { | ||
194 | @@ -XXX,XX +XXX,XX @@ static void scsi_qdev_unrealize(DeviceState *qdev) | ||
195 | |||
196 | scsi_device_purge_requests(dev, SENSE_CODE(NO_SENSE)); | ||
197 | |||
198 | + qemu_mutex_destroy(&dev->requests_lock); | ||
199 | + | ||
200 | scsi_device_unrealize(dev); | ||
201 | |||
202 | blockdev_mark_auto_del(dev->conf.blk); | ||
203 | @@ -XXX,XX +XXX,XX @@ static void scsi_req_enqueue_internal(SCSIRequest *req) | ||
204 | req->sg = NULL; | ||
205 | } | ||
206 | req->enqueued = true; | ||
207 | - QTAILQ_INSERT_TAIL(&req->dev->requests, req, next); | ||
208 | + | ||
209 | + WITH_QEMU_LOCK_GUARD(&req->dev->requests_lock) { | ||
210 | + QTAILQ_INSERT_TAIL(&req->dev->requests, req, next); | ||
211 | + } | ||
212 | } | ||
213 | |||
214 | int32_t scsi_req_enqueue(SCSIRequest *req) | ||
215 | @@ -XXX,XX +XXX,XX @@ static void scsi_req_dequeue(SCSIRequest *req) | ||
216 | trace_scsi_req_dequeue(req->dev->id, req->lun, req->tag); | ||
217 | req->retry = false; | ||
218 | if (req->enqueued) { | ||
219 | - QTAILQ_REMOVE(&req->dev->requests, req, next); | ||
220 | + WITH_QEMU_LOCK_GUARD(&req->dev->requests_lock) { | ||
221 | + QTAILQ_REMOVE(&req->dev->requests, req, next); | ||
222 | + } | ||
223 | req->enqueued = false; | ||
224 | scsi_req_unref(req); | ||
225 | } | ||
226 | @@ -XXX,XX +XXX,XX @@ static void scsi_device_class_init(ObjectClass *klass, void *data) | ||
227 | |||
228 | static void scsi_dev_instance_init(Object *obj) | ||
229 | { | ||
230 | - DeviceState *dev = DEVICE(obj); | ||
231 | - SCSIDevice *s = SCSI_DEVICE(dev); | ||
232 | + SCSIDevice *s = SCSI_DEVICE(obj); | ||
233 | |||
234 | device_add_bootindex_property(obj, &s->conf.bootindex, | ||
235 | "bootindex", NULL, | ||
45 | -- | 236 | -- |
46 | 1.8.3.1 | 237 | 2.48.1 |
47 | |||
48 | diff view generated by jsdifflib |
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 1 | From: Stefan Hajnoczi <stefanha@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Do not do extra call to _get_block_status() | 3 | Virtqueues are not thread-safe. Until now this was not a major issue |
4 | 4 | since all virtqueue processing happened in the same thread. The ctrl | |
5 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 5 | queue's Task Management Function (TMF) requests sometimes need the main |
6 | Message-id: 20170407113404.9351-1-vsementsov@virtuozzo.com | 6 | loop, so a BH was used to schedule the virtqueue completion back in the |
7 | Reviewed-by: John Snow <jsnow@redhat.com> | 7 | thread that has virtqueue access. |
8 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 8 | |
9 | When IOThread Virtqueue Mapping is introduced in later commits, event | ||
10 | and ctrl virtqueue accesses from other threads will become necessary. | ||
11 | Introduce an optional per-virtqueue lock so the event and ctrl | ||
12 | virtqueues can be protected in the commits that follow. | ||
13 | |||
14 | The addition of the ctrl virtqueue lock makes | ||
15 | virtio_scsi_complete_req_from_main_loop() and its BH unnecessary. | ||
16 | Instead, take the ctrl virtqueue lock from the main loop thread. | ||
17 | |||
18 | The cmd virtqueue does not have a lock because the entirety of SCSI | ||
19 | command processing happens in one thread. Only one thread accesses the | ||
20 | cmd virtqueue and a lock is unnecessary. | ||
21 | |||
22 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
23 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
24 | Message-ID: <20250311132616.1049687-6-stefanha@redhat.com> | ||
25 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
9 | --- | 26 | --- |
10 | qemu-img.c | 32 ++++++++++---------------------- | 27 | include/hw/virtio/virtio-scsi.h | 3 ++ |
11 | 1 file changed, 10 insertions(+), 22 deletions(-) | 28 | hw/scsi/virtio-scsi.c | 84 ++++++++++++++++++--------------- |
12 | 29 | 2 files changed, 49 insertions(+), 38 deletions(-) | |
13 | diff --git a/qemu-img.c b/qemu-img.c | 30 | |
31 | diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h | ||
14 | index XXXXXXX..XXXXXXX 100644 | 32 | index XXXXXXX..XXXXXXX 100644 |
15 | --- a/qemu-img.c | 33 | --- a/include/hw/virtio/virtio-scsi.h |
16 | +++ b/qemu-img.c | 34 | +++ b/include/hw/virtio/virtio-scsi.h |
17 | @@ -XXX,XX +XXX,XX @@ static int convert_iteration_sectors(ImgConvertState *s, int64_t sector_num) | 35 | @@ -XXX,XX +XXX,XX @@ struct VirtIOSCSI { |
18 | 36 | int resetting; /* written from main loop thread, read from any thread */ | |
19 | if (s->sector_next_status <= sector_num) { | 37 | bool events_dropped; |
20 | BlockDriverState *file; | 38 | |
21 | - ret = bdrv_get_block_status(blk_bs(s->src[src_cur]), | 39 | + QemuMutex ctrl_lock; /* protects ctrl_vq */ |
22 | - sector_num - src_cur_offset, | 40 | + QemuMutex event_lock; /* protects event_vq */ |
23 | - n, &n, &file); | 41 | + |
24 | + if (s->target_has_backing) { | 42 | /* |
25 | + ret = bdrv_get_block_status(blk_bs(s->src[src_cur]), | 43 | * TMFs deferred to main loop BH. These fields are protected by |
26 | + sector_num - src_cur_offset, | 44 | * tmf_bh_lock. |
27 | + n, &n, &file); | 45 | diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c |
28 | + } else { | 46 | index XXXXXXX..XXXXXXX 100644 |
29 | + ret = bdrv_get_block_status_above(blk_bs(s->src[src_cur]), NULL, | 47 | --- a/hw/scsi/virtio-scsi.c |
30 | + sector_num - src_cur_offset, | 48 | +++ b/hw/scsi/virtio-scsi.c |
31 | + n, &n, &file); | 49 | @@ -XXX,XX +XXX,XX @@ static void virtio_scsi_free_req(VirtIOSCSIReq *req) |
32 | + } | 50 | g_free(req); |
33 | if (ret < 0) { | 51 | } |
34 | return ret; | 52 | |
53 | -static void virtio_scsi_complete_req(VirtIOSCSIReq *req) | ||
54 | +static void virtio_scsi_complete_req(VirtIOSCSIReq *req, QemuMutex *vq_lock) | ||
55 | { | ||
56 | VirtIOSCSI *s = req->dev; | ||
57 | VirtQueue *vq = req->vq; | ||
58 | VirtIODevice *vdev = VIRTIO_DEVICE(s); | ||
59 | |||
60 | qemu_iovec_from_buf(&req->resp_iov, 0, &req->resp, req->resp_size); | ||
61 | + | ||
62 | + if (vq_lock) { | ||
63 | + qemu_mutex_lock(vq_lock); | ||
64 | + } | ||
65 | + | ||
66 | virtqueue_push(vq, &req->elem, req->qsgl.size + req->resp_iov.size); | ||
67 | if (s->dataplane_started && !s->dataplane_fenced) { | ||
68 | virtio_notify_irqfd(vdev, vq); | ||
69 | @@ -XXX,XX +XXX,XX @@ static void virtio_scsi_complete_req(VirtIOSCSIReq *req) | ||
70 | virtio_notify(vdev, vq); | ||
71 | } | ||
72 | |||
73 | + if (vq_lock) { | ||
74 | + qemu_mutex_unlock(vq_lock); | ||
75 | + } | ||
76 | + | ||
77 | if (req->sreq) { | ||
78 | req->sreq->hba_private = NULL; | ||
79 | scsi_req_unref(req->sreq); | ||
80 | @@ -XXX,XX +XXX,XX @@ static void virtio_scsi_complete_req(VirtIOSCSIReq *req) | ||
81 | virtio_scsi_free_req(req); | ||
82 | } | ||
83 | |||
84 | -static void virtio_scsi_complete_req_bh(void *opaque) | ||
85 | +static void virtio_scsi_bad_req(VirtIOSCSIReq *req, QemuMutex *vq_lock) | ||
86 | { | ||
87 | - VirtIOSCSIReq *req = opaque; | ||
88 | + virtio_error(VIRTIO_DEVICE(req->dev), "wrong size for virtio-scsi headers"); | ||
89 | |||
90 | - virtio_scsi_complete_req(req); | ||
91 | -} | ||
92 | + if (vq_lock) { | ||
93 | + qemu_mutex_lock(vq_lock); | ||
94 | + } | ||
95 | |||
96 | -/* | ||
97 | - * Called from virtio_scsi_do_one_tmf_bh() in main loop thread. The main loop | ||
98 | - * thread cannot touch the virtqueue since that could race with an IOThread. | ||
99 | - */ | ||
100 | -static void virtio_scsi_complete_req_from_main_loop(VirtIOSCSIReq *req) | ||
101 | -{ | ||
102 | - VirtIOSCSI *s = req->dev; | ||
103 | + virtqueue_detach_element(req->vq, &req->elem, 0); | ||
104 | |||
105 | - if (!s->ctx || s->ctx == qemu_get_aio_context()) { | ||
106 | - /* No need to schedule a BH when there is no IOThread */ | ||
107 | - virtio_scsi_complete_req(req); | ||
108 | - } else { | ||
109 | - /* Run request completion in the IOThread */ | ||
110 | - aio_wait_bh_oneshot(s->ctx, virtio_scsi_complete_req_bh, req); | ||
111 | + if (vq_lock) { | ||
112 | + qemu_mutex_unlock(vq_lock); | ||
113 | } | ||
114 | -} | ||
115 | |||
116 | -static void virtio_scsi_bad_req(VirtIOSCSIReq *req) | ||
117 | -{ | ||
118 | - virtio_error(VIRTIO_DEVICE(req->dev), "wrong size for virtio-scsi headers"); | ||
119 | - virtqueue_detach_element(req->vq, &req->elem, 0); | ||
120 | virtio_scsi_free_req(req); | ||
121 | } | ||
122 | |||
123 | @@ -XXX,XX +XXX,XX @@ static int virtio_scsi_parse_req(VirtIOSCSIReq *req, | ||
124 | return 0; | ||
125 | } | ||
126 | |||
127 | -static VirtIOSCSIReq *virtio_scsi_pop_req(VirtIOSCSI *s, VirtQueue *vq) | ||
128 | +static VirtIOSCSIReq *virtio_scsi_pop_req(VirtIOSCSI *s, VirtQueue *vq, QemuMutex *vq_lock) | ||
129 | { | ||
130 | VirtIOSCSICommon *vs = (VirtIOSCSICommon *)s; | ||
131 | VirtIOSCSIReq *req; | ||
132 | |||
133 | + if (vq_lock) { | ||
134 | + qemu_mutex_lock(vq_lock); | ||
135 | + } | ||
136 | + | ||
137 | req = virtqueue_pop(vq, sizeof(VirtIOSCSIReq) + vs->cdb_size); | ||
138 | + | ||
139 | + if (vq_lock) { | ||
140 | + qemu_mutex_unlock(vq_lock); | ||
141 | + } | ||
142 | + | ||
143 | if (!req) { | ||
144 | return NULL; | ||
145 | } | ||
146 | @@ -XXX,XX +XXX,XX @@ static void virtio_scsi_cancel_notify(Notifier *notifier, void *data) | ||
147 | |||
148 | trace_virtio_scsi_tmf_resp(virtio_scsi_get_lun(req->req.tmf.lun), | ||
149 | req->req.tmf.tag, req->resp.tmf.response); | ||
150 | - virtio_scsi_complete_req(req); | ||
151 | + virtio_scsi_complete_req(req, &req->dev->ctrl_lock); | ||
152 | } | ||
153 | g_free(n); | ||
154 | } | ||
155 | @@ -XXX,XX +XXX,XX @@ static void virtio_scsi_do_one_tmf_bh(VirtIOSCSIReq *req) | ||
156 | |||
157 | out: | ||
158 | object_unref(OBJECT(d)); | ||
159 | - virtio_scsi_complete_req_from_main_loop(req); | ||
160 | + virtio_scsi_complete_req(req, &s->ctrl_lock); | ||
161 | } | ||
162 | |||
163 | /* Some TMFs must be processed from the main loop thread */ | ||
164 | @@ -XXX,XX +XXX,XX @@ static void virtio_scsi_reset_tmf_bh(VirtIOSCSI *s) | ||
165 | |||
166 | /* SAM-6 6.3.2 Hard reset */ | ||
167 | req->resp.tmf.response = VIRTIO_SCSI_S_TARGET_FAILURE; | ||
168 | - virtio_scsi_complete_req(req); | ||
169 | + virtio_scsi_complete_req(req, &req->dev->ctrl_lock); | ||
170 | } | ||
171 | } | ||
172 | |||
173 | @@ -XXX,XX +XXX,XX @@ static void virtio_scsi_handle_ctrl_req(VirtIOSCSI *s, VirtIOSCSIReq *req) | ||
174 | |||
175 | if (iov_to_buf(req->elem.out_sg, req->elem.out_num, 0, | ||
176 | &type, sizeof(type)) < sizeof(type)) { | ||
177 | - virtio_scsi_bad_req(req); | ||
178 | + virtio_scsi_bad_req(req, &s->ctrl_lock); | ||
179 | return; | ||
180 | } | ||
181 | |||
182 | @@ -XXX,XX +XXX,XX @@ static void virtio_scsi_handle_ctrl_req(VirtIOSCSI *s, VirtIOSCSIReq *req) | ||
183 | if (type == VIRTIO_SCSI_T_TMF) { | ||
184 | if (virtio_scsi_parse_req(req, sizeof(VirtIOSCSICtrlTMFReq), | ||
185 | sizeof(VirtIOSCSICtrlTMFResp)) < 0) { | ||
186 | - virtio_scsi_bad_req(req); | ||
187 | + virtio_scsi_bad_req(req, &s->ctrl_lock); | ||
188 | return; | ||
189 | } else { | ||
190 | r = virtio_scsi_do_tmf(s, req); | ||
191 | @@ -XXX,XX +XXX,XX @@ static void virtio_scsi_handle_ctrl_req(VirtIOSCSI *s, VirtIOSCSIReq *req) | ||
192 | type == VIRTIO_SCSI_T_AN_SUBSCRIBE) { | ||
193 | if (virtio_scsi_parse_req(req, sizeof(VirtIOSCSICtrlANReq), | ||
194 | sizeof(VirtIOSCSICtrlANResp)) < 0) { | ||
195 | - virtio_scsi_bad_req(req); | ||
196 | + virtio_scsi_bad_req(req, &s->ctrl_lock); | ||
197 | return; | ||
198 | } else { | ||
199 | req->req.an.event_requested = | ||
200 | @@ -XXX,XX +XXX,XX @@ static void virtio_scsi_handle_ctrl_req(VirtIOSCSI *s, VirtIOSCSIReq *req) | ||
201 | type == VIRTIO_SCSI_T_AN_SUBSCRIBE) | ||
202 | trace_virtio_scsi_an_resp(virtio_scsi_get_lun(req->req.an.lun), | ||
203 | req->resp.an.response); | ||
204 | - virtio_scsi_complete_req(req); | ||
205 | + virtio_scsi_complete_req(req, &s->ctrl_lock); | ||
206 | } else { | ||
207 | assert(r == -EINPROGRESS); | ||
208 | } | ||
209 | @@ -XXX,XX +XXX,XX @@ static void virtio_scsi_handle_ctrl_vq(VirtIOSCSI *s, VirtQueue *vq) | ||
210 | { | ||
211 | VirtIOSCSIReq *req; | ||
212 | |||
213 | - while ((req = virtio_scsi_pop_req(s, vq))) { | ||
214 | + while ((req = virtio_scsi_pop_req(s, vq, &s->ctrl_lock))) { | ||
215 | virtio_scsi_handle_ctrl_req(s, req); | ||
216 | } | ||
217 | } | ||
218 | @@ -XXX,XX +XXX,XX @@ static void virtio_scsi_complete_cmd_req(VirtIOSCSIReq *req) | ||
219 | * in virtio_scsi_command_complete. | ||
220 | */ | ||
221 | req->resp_size = sizeof(VirtIOSCSICmdResp); | ||
222 | - virtio_scsi_complete_req(req); | ||
223 | + virtio_scsi_complete_req(req, NULL); | ||
224 | } | ||
225 | |||
226 | static void virtio_scsi_command_failed(SCSIRequest *r) | ||
227 | @@ -XXX,XX +XXX,XX @@ static int virtio_scsi_handle_cmd_req_prepare(VirtIOSCSI *s, VirtIOSCSIReq *req) | ||
228 | virtio_scsi_fail_cmd_req(req); | ||
229 | return -ENOTSUP; | ||
230 | } else { | ||
231 | - virtio_scsi_bad_req(req); | ||
232 | + virtio_scsi_bad_req(req, NULL); | ||
233 | return -EINVAL; | ||
35 | } | 234 | } |
36 | @@ -XXX,XX +XXX,XX @@ static int convert_iteration_sectors(ImgConvertState *s, int64_t sector_num) | 235 | } |
37 | s->status = BLK_ZERO; | 236 | @@ -XXX,XX +XXX,XX @@ static void virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq) |
38 | } else if (ret & BDRV_BLOCK_DATA) { | 237 | virtio_queue_set_notification(vq, 0); |
39 | s->status = BLK_DATA; | ||
40 | - } else if (!s->target_has_backing) { | ||
41 | - /* Without a target backing file we must copy over the contents of | ||
42 | - * the backing file as well. */ | ||
43 | - /* Check block status of the backing file chain to avoid | ||
44 | - * needlessly reading zeroes and limiting the iteration to the | ||
45 | - * buffer size */ | ||
46 | - ret = bdrv_get_block_status_above(blk_bs(s->src[src_cur]), NULL, | ||
47 | - sector_num - src_cur_offset, | ||
48 | - n, &n, &file); | ||
49 | - if (ret < 0) { | ||
50 | - return ret; | ||
51 | - } | ||
52 | - | ||
53 | - if (ret & BDRV_BLOCK_ZERO) { | ||
54 | - s->status = BLK_ZERO; | ||
55 | - } else { | ||
56 | - s->status = BLK_DATA; | ||
57 | - } | ||
58 | } else { | ||
59 | - s->status = BLK_BACKING_FILE; | ||
60 | + s->status = s->target_has_backing ? BLK_BACKING_FILE : BLK_DATA; | ||
61 | } | 238 | } |
62 | 239 | ||
63 | s->sector_next_status = sector_num + n; | 240 | - while ((req = virtio_scsi_pop_req(s, vq))) { |
241 | + while ((req = virtio_scsi_pop_req(s, vq, NULL))) { | ||
242 | ret = virtio_scsi_handle_cmd_req_prepare(s, req); | ||
243 | if (!ret) { | ||
244 | QTAILQ_INSERT_TAIL(&reqs, req, next); | ||
245 | @@ -XXX,XX +XXX,XX @@ static void virtio_scsi_push_event(VirtIOSCSI *s, | ||
246 | return; | ||
247 | } | ||
248 | |||
249 | - req = virtio_scsi_pop_req(s, vs->event_vq); | ||
250 | + req = virtio_scsi_pop_req(s, vs->event_vq, &s->event_lock); | ||
251 | if (!req) { | ||
252 | s->events_dropped = true; | ||
253 | return; | ||
254 | @@ -XXX,XX +XXX,XX @@ static void virtio_scsi_push_event(VirtIOSCSI *s, | ||
255 | } | ||
256 | |||
257 | if (virtio_scsi_parse_req(req, 0, sizeof(VirtIOSCSIEvent))) { | ||
258 | - virtio_scsi_bad_req(req); | ||
259 | + virtio_scsi_bad_req(req, &s->event_lock); | ||
260 | return; | ||
261 | } | ||
262 | |||
263 | @@ -XXX,XX +XXX,XX @@ static void virtio_scsi_push_event(VirtIOSCSI *s, | ||
264 | } | ||
265 | trace_virtio_scsi_event(virtio_scsi_get_lun(evt->lun), event, reason); | ||
266 | |||
267 | - virtio_scsi_complete_req(req); | ||
268 | + virtio_scsi_complete_req(req, &s->event_lock); | ||
269 | } | ||
270 | |||
271 | static void virtio_scsi_handle_event_vq(VirtIOSCSI *s, VirtQueue *vq) | ||
272 | @@ -XXX,XX +XXX,XX @@ static void virtio_scsi_device_realize(DeviceState *dev, Error **errp) | ||
273 | Error *err = NULL; | ||
274 | |||
275 | QTAILQ_INIT(&s->tmf_bh_list); | ||
276 | + qemu_mutex_init(&s->ctrl_lock); | ||
277 | + qemu_mutex_init(&s->event_lock); | ||
278 | qemu_mutex_init(&s->tmf_bh_lock); | ||
279 | |||
280 | virtio_scsi_common_realize(dev, | ||
281 | @@ -XXX,XX +XXX,XX @@ static void virtio_scsi_device_unrealize(DeviceState *dev) | ||
282 | qbus_set_hotplug_handler(BUS(&s->bus), NULL); | ||
283 | virtio_scsi_common_unrealize(dev); | ||
284 | qemu_mutex_destroy(&s->tmf_bh_lock); | ||
285 | + qemu_mutex_destroy(&s->event_lock); | ||
286 | + qemu_mutex_destroy(&s->ctrl_lock); | ||
287 | } | ||
288 | |||
289 | static const Property virtio_scsi_properties[] = { | ||
64 | -- | 290 | -- |
65 | 1.8.3.1 | 291 | 2.48.1 |
66 | |||
67 | diff view generated by jsdifflib |
1 | From: Max Reitz <mreitz@redhat.com> | 1 | From: Stefan Hajnoczi <stefanha@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | It does not make much sense to use a backing image for the target when | 3 | The block layer can invoke the resize callback from any AioContext that |
4 | you concatenate multiple images (because then there is no correspondence | 4 | is processing requests. The virtqueue is already protected but the |
5 | between the source images' backing files and the target's); but it was | 5 | events_dropped field also needs to be protected against races. Cover it |
6 | still possible to give one by using -o backing_file=X instead of -B X. | 6 | using the event virtqueue lock because it is closely associated with |
7 | accesses to the virtqueue. | ||
7 | 8 | ||
8 | Fix this by moving the check. | 9 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> |
9 | 10 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | |
10 | (Also, change the error message because -B is not the only way to | 11 | Message-ID: <20250311132616.1049687-7-stefanha@redhat.com> |
11 | specify the backing file, evidently.) | ||
12 | |||
13 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
14 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
15 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
16 | --- | 13 | --- |
17 | qemu-img.c | 13 +++++++------ | 14 | include/hw/virtio/virtio-scsi.h | 3 ++- |
18 | tests/qemu-iotests/122.out | 4 ++-- | 15 | hw/scsi/virtio-scsi.c | 29 ++++++++++++++++++++--------- |
19 | 2 files changed, 9 insertions(+), 8 deletions(-) | 16 | 2 files changed, 22 insertions(+), 10 deletions(-) |
20 | 17 | ||
21 | diff --git a/qemu-img.c b/qemu-img.c | 18 | diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h |
22 | index XXXXXXX..XXXXXXX 100644 | 19 | index XXXXXXX..XXXXXXX 100644 |
23 | --- a/qemu-img.c | 20 | --- a/include/hw/virtio/virtio-scsi.h |
24 | +++ b/qemu-img.c | 21 | +++ b/include/hw/virtio/virtio-scsi.h |
25 | @@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv) | 22 | @@ -XXX,XX +XXX,XX @@ struct VirtIOSCSI { |
23 | |||
24 | SCSIBus bus; | ||
25 | int resetting; /* written from main loop thread, read from any thread */ | ||
26 | + | ||
27 | + QemuMutex event_lock; /* protects event_vq and events_dropped */ | ||
28 | bool events_dropped; | ||
29 | |||
30 | QemuMutex ctrl_lock; /* protects ctrl_vq */ | ||
31 | - QemuMutex event_lock; /* protects event_vq */ | ||
32 | |||
33 | /* | ||
34 | * TMFs deferred to main loop BH. These fields are protected by | ||
35 | diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c | ||
36 | index XXXXXXX..XXXXXXX 100644 | ||
37 | --- a/hw/scsi/virtio-scsi.c | ||
38 | +++ b/hw/scsi/virtio-scsi.c | ||
39 | @@ -XXX,XX +XXX,XX @@ static void virtio_scsi_reset(VirtIODevice *vdev) | ||
40 | |||
41 | vs->sense_size = VIRTIO_SCSI_SENSE_DEFAULT_SIZE; | ||
42 | vs->cdb_size = VIRTIO_SCSI_CDB_DEFAULT_SIZE; | ||
43 | - s->events_dropped = false; | ||
44 | + | ||
45 | + WITH_QEMU_LOCK_GUARD(&s->event_lock) { | ||
46 | + s->events_dropped = false; | ||
47 | + } | ||
48 | } | ||
49 | |||
50 | typedef struct { | ||
51 | @@ -XXX,XX +XXX,XX @@ static void virtio_scsi_push_event(VirtIOSCSI *s, | ||
26 | } | 52 | } |
27 | 53 | ||
28 | 54 | req = virtio_scsi_pop_req(s, vs->event_vq, &s->event_lock); | |
29 | - if (s.src_num > 1 && out_baseimg) { | 55 | - if (!req) { |
30 | - error_report("-B makes no sense when concatenating multiple input " | 56 | - s->events_dropped = true; |
31 | - "images"); | 57 | - return; |
32 | - goto fail_getopt; | ||
33 | - } | 58 | - } |
34 | - | 59 | + WITH_QEMU_LOCK_GUARD(&s->event_lock) { |
35 | /* ret is still -EINVAL until here */ | 60 | + if (!req) { |
36 | ret = bdrv_parse_cache_mode(src_cache, &src_flags, &src_writethrough); | 61 | + s->events_dropped = true; |
37 | if (ret < 0) { | 62 | + return; |
38 | @@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv) | 63 | + } |
64 | |||
65 | - if (s->events_dropped) { | ||
66 | - event |= VIRTIO_SCSI_T_EVENTS_MISSED; | ||
67 | - s->events_dropped = false; | ||
68 | + if (s->events_dropped) { | ||
69 | + event |= VIRTIO_SCSI_T_EVENTS_MISSED; | ||
70 | + s->events_dropped = false; | ||
71 | + } | ||
39 | } | 72 | } |
40 | s.target_has_backing = (bool) out_baseimg; | 73 | |
41 | 74 | if (virtio_scsi_parse_req(req, 0, sizeof(VirtIOSCSIEvent))) { | |
42 | + if (s.src_num > 1 && out_baseimg) { | 75 | @@ -XXX,XX +XXX,XX @@ static void virtio_scsi_push_event(VirtIOSCSI *s, |
43 | + error_report("Having a backing file for the target makes no sense when " | 76 | |
44 | + "concatenating multiple input images"); | 77 | static void virtio_scsi_handle_event_vq(VirtIOSCSI *s, VirtQueue *vq) |
45 | + ret = -1; | 78 | { |
46 | + goto out; | 79 | - if (s->events_dropped) { |
80 | + bool events_dropped; | ||
81 | + | ||
82 | + WITH_QEMU_LOCK_GUARD(&s->event_lock) { | ||
83 | + events_dropped = s->events_dropped; | ||
47 | + } | 84 | + } |
48 | + | 85 | + |
49 | /* Check if compression is supported */ | 86 | + if (events_dropped) { |
50 | if (s.compressed) { | 87 | VirtIOSCSIEventInfo info = { |
51 | bool encryption = | 88 | .event = VIRTIO_SCSI_T_NO_EVENT, |
52 | diff --git a/tests/qemu-iotests/122.out b/tests/qemu-iotests/122.out | 89 | }; |
53 | index XXXXXXX..XXXXXXX 100644 | ||
54 | --- a/tests/qemu-iotests/122.out | ||
55 | +++ b/tests/qemu-iotests/122.out | ||
56 | @@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 4194304 | ||
57 | 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
58 | read 65536/65536 bytes at offset 8388608 | ||
59 | 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
60 | -qemu-img: -B makes no sense when concatenating multiple input images | ||
61 | -qemu-img: -B makes no sense when concatenating multiple input images | ||
62 | +qemu-img: Having a backing file for the target makes no sense when concatenating multiple input images | ||
63 | +qemu-img: Having a backing file for the target makes no sense when concatenating multiple input images | ||
64 | |||
65 | === Compression with misaligned allocations and image sizes === | ||
66 | |||
67 | -- | 90 | -- |
68 | 1.8.3.1 | 91 | 2.48.1 |
69 | |||
70 | diff view generated by jsdifflib |
1 | From: Max Reitz <mreitz@redhat.com> | 1 | From: Stefan Hajnoczi <stefanha@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Add an Error parameter to the block drivers' bdrv_truncate() interface. | 3 | With IOThread Virtqueue Mapping there will be multiple AioContexts |
4 | If a block driver does not set this in case of an error, the generic | 4 | processing SCSI requests. scsi_req_cancel() and other SCSI request |
5 | bdrv_truncate() implementation will do so. | 5 | operations must be performed from the AioContext where the request is |
6 | 6 | running. | |
7 | Where it is obvious, this patch also makes some block drivers set this | 7 | |
8 | value. | 8 | Introduce a virtio_scsi_defer_tmf_to_aio_context() function and the |
9 | 9 | necessary VirtIOSCSIReq->remaining refcount infrastructure to move the | |
10 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 10 | TMF code into the AioContext where the request is running. |
11 | Message-id: 20170328205129.15138-4-mreitz@redhat.com | 11 | |
12 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | 12 | For the time being there is still just one AioContext: the main loop or |
13 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 13 | the IOThread. When the iothread-vq-mapping parameter is added in a later |
14 | patch this will be changed to per-virtqueue AioContexts. | ||
15 | |||
16 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
17 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
18 | Message-ID: <20250311132616.1049687-8-stefanha@redhat.com> | ||
19 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
14 | --- | 20 | --- |
15 | block.c | 4 ++-- | 21 | hw/scsi/virtio-scsi.c | 270 ++++++++++++++++++++++++++++++++---------- |
16 | block/blkdebug.c | 4 ++-- | 22 | 1 file changed, 206 insertions(+), 64 deletions(-) |
17 | block/crypto.c | 5 +++-- | 23 | |
18 | block/file-posix.c | 2 +- | 24 | diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c |
19 | block/file-win32.c | 6 +++--- | ||
20 | block/gluster.c | 3 ++- | ||
21 | block/iscsi.c | 4 ++-- | ||
22 | block/nfs.c | 2 +- | ||
23 | block/qcow2.c | 8 ++++---- | ||
24 | block/qed.c | 2 +- | ||
25 | block/raw-format.c | 4 ++-- | ||
26 | block/rbd.c | 2 +- | ||
27 | block/sheepdog.c | 14 ++++++-------- | ||
28 | include/block/block_int.h | 2 +- | ||
29 | 14 files changed, 31 insertions(+), 31 deletions(-) | ||
30 | |||
31 | diff --git a/block.c b/block.c | ||
32 | index XXXXXXX..XXXXXXX 100644 | 25 | index XXXXXXX..XXXXXXX 100644 |
33 | --- a/block.c | 26 | --- a/hw/scsi/virtio-scsi.c |
34 | +++ b/block.c | 27 | +++ b/hw/scsi/virtio-scsi.c |
35 | @@ -XXX,XX +XXX,XX @@ int bdrv_truncate(BdrvChild *child, int64_t offset, Error **errp) | 28 | @@ -XXX,XX +XXX,XX @@ typedef struct VirtIOSCSIReq { |
36 | return -EACCES; | 29 | /* Used for two-stage request submission and TMFs deferred to BH */ |
37 | } | 30 | QTAILQ_ENTRY(VirtIOSCSIReq) next; |
38 | 31 | ||
39 | - ret = drv->bdrv_truncate(bs, offset); | 32 | - /* Used for cancellation of request during TMFs */ |
40 | + ret = drv->bdrv_truncate(bs, offset, errp); | 33 | + /* Used for cancellation of request during TMFs. Atomic. */ |
41 | if (ret == 0) { | 34 | int remaining; |
42 | ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS); | 35 | |
43 | bdrv_dirty_bitmap_truncate(bs); | 36 | SCSIRequest *sreq; |
44 | bdrv_parent_cb_resize(bs); | 37 | @@ -XXX,XX +XXX,XX @@ typedef struct { |
45 | ++bs->write_gen; | 38 | VirtIOSCSIReq *tmf_req; |
46 | - } else { | 39 | } VirtIOSCSICancelNotifier; |
47 | + } else if (errp && !*errp) { | 40 | |
48 | error_setg_errno(errp, -ret, "Failed to resize image"); | 41 | +static void virtio_scsi_tmf_dec_remaining(VirtIOSCSIReq *tmf) |
49 | } | 42 | +{ |
50 | return ret; | 43 | + if (qatomic_fetch_dec(&tmf->remaining) == 1) { |
51 | diff --git a/block/blkdebug.c b/block/blkdebug.c | 44 | + trace_virtio_scsi_tmf_resp(virtio_scsi_get_lun(tmf->req.tmf.lun), |
52 | index XXXXXXX..XXXXXXX 100644 | 45 | + tmf->req.tmf.tag, tmf->resp.tmf.response); |
53 | --- a/block/blkdebug.c | 46 | + |
54 | +++ b/block/blkdebug.c | 47 | + virtio_scsi_complete_req(tmf, &tmf->dev->ctrl_lock); |
55 | @@ -XXX,XX +XXX,XX @@ static int64_t blkdebug_getlength(BlockDriverState *bs) | 48 | + } |
56 | return bdrv_getlength(bs->file->bs); | 49 | +} |
50 | + | ||
51 | static void virtio_scsi_cancel_notify(Notifier *notifier, void *data) | ||
52 | { | ||
53 | VirtIOSCSICancelNotifier *n = container_of(notifier, | ||
54 | VirtIOSCSICancelNotifier, | ||
55 | notifier); | ||
56 | |||
57 | - if (--n->tmf_req->remaining == 0) { | ||
58 | - VirtIOSCSIReq *req = n->tmf_req; | ||
59 | - | ||
60 | - trace_virtio_scsi_tmf_resp(virtio_scsi_get_lun(req->req.tmf.lun), | ||
61 | - req->req.tmf.tag, req->resp.tmf.response); | ||
62 | - virtio_scsi_complete_req(req, &req->dev->ctrl_lock); | ||
63 | - } | ||
64 | + virtio_scsi_tmf_dec_remaining(n->tmf_req); | ||
65 | g_free(n); | ||
57 | } | 66 | } |
58 | 67 | ||
59 | -static int blkdebug_truncate(BlockDriverState *bs, int64_t offset) | 68 | @@ -XXX,XX +XXX,XX @@ static void virtio_scsi_reset_tmf_bh(VirtIOSCSI *s) |
60 | +static int blkdebug_truncate(BlockDriverState *bs, int64_t offset, Error **errp) | ||
61 | { | ||
62 | - return bdrv_truncate(bs->file, offset, NULL); | ||
63 | + return bdrv_truncate(bs->file, offset, errp); | ||
64 | } | ||
65 | |||
66 | static void blkdebug_refresh_filename(BlockDriverState *bs, QDict *options) | ||
67 | diff --git a/block/crypto.c b/block/crypto.c | ||
68 | index XXXXXXX..XXXXXXX 100644 | ||
69 | --- a/block/crypto.c | ||
70 | +++ b/block/crypto.c | ||
71 | @@ -XXX,XX +XXX,XX @@ static int block_crypto_create_generic(QCryptoBlockFormat format, | ||
72 | return ret; | ||
73 | } | ||
74 | |||
75 | -static int block_crypto_truncate(BlockDriverState *bs, int64_t offset) | ||
76 | +static int block_crypto_truncate(BlockDriverState *bs, int64_t offset, | ||
77 | + Error **errp) | ||
78 | { | ||
79 | BlockCrypto *crypto = bs->opaque; | ||
80 | size_t payload_offset = | ||
81 | @@ -XXX,XX +XXX,XX @@ static int block_crypto_truncate(BlockDriverState *bs, int64_t offset) | ||
82 | |||
83 | offset += payload_offset; | ||
84 | |||
85 | - return bdrv_truncate(bs->file, offset, NULL); | ||
86 | + return bdrv_truncate(bs->file, offset, errp); | ||
87 | } | ||
88 | |||
89 | static void block_crypto_close(BlockDriverState *bs) | ||
90 | diff --git a/block/file-posix.c b/block/file-posix.c | ||
91 | index XXXXXXX..XXXXXXX 100644 | ||
92 | --- a/block/file-posix.c | ||
93 | +++ b/block/file-posix.c | ||
94 | @@ -XXX,XX +XXX,XX @@ static void raw_close(BlockDriverState *bs) | ||
95 | } | 69 | } |
96 | } | 70 | } |
97 | 71 | ||
98 | -static int raw_truncate(BlockDriverState *bs, int64_t offset) | 72 | -static void virtio_scsi_defer_tmf_to_bh(VirtIOSCSIReq *req) |
99 | +static int raw_truncate(BlockDriverState *bs, int64_t offset, Error **errp) | 73 | +static void virtio_scsi_defer_tmf_to_main_loop(VirtIOSCSIReq *req) |
100 | { | 74 | { |
101 | BDRVRawState *s = bs->opaque; | 75 | VirtIOSCSI *s = req->dev; |
102 | struct stat st; | 76 | |
103 | diff --git a/block/file-win32.c b/block/file-win32.c | 77 | @@ -XXX,XX +XXX,XX @@ static void virtio_scsi_defer_tmf_to_bh(VirtIOSCSIReq *req) |
104 | index XXXXXXX..XXXXXXX 100644 | ||
105 | --- a/block/file-win32.c | ||
106 | +++ b/block/file-win32.c | ||
107 | @@ -XXX,XX +XXX,XX @@ static void raw_close(BlockDriverState *bs) | ||
108 | } | 78 | } |
109 | } | 79 | } |
110 | 80 | ||
111 | -static int raw_truncate(BlockDriverState *bs, int64_t offset) | 81 | +static void virtio_scsi_tmf_cancel_req(VirtIOSCSIReq *tmf, SCSIRequest *r) |
112 | +static int raw_truncate(BlockDriverState *bs, int64_t offset, Error **errp) | 82 | +{ |
83 | + VirtIOSCSICancelNotifier *notifier; | ||
84 | + | ||
85 | + assert(r->ctx == qemu_get_current_aio_context()); | ||
86 | + | ||
87 | + /* Decremented in virtio_scsi_cancel_notify() */ | ||
88 | + qatomic_inc(&tmf->remaining); | ||
89 | + | ||
90 | + notifier = g_new(VirtIOSCSICancelNotifier, 1); | ||
91 | + notifier->notifier.notify = virtio_scsi_cancel_notify; | ||
92 | + notifier->tmf_req = tmf; | ||
93 | + scsi_req_cancel_async(r, ¬ifier->notifier); | ||
94 | +} | ||
95 | + | ||
96 | +/* Execute a TMF on the requests in the current AioContext */ | ||
97 | +static void virtio_scsi_do_tmf_aio_context(void *opaque) | ||
98 | +{ | ||
99 | + AioContext *ctx = qemu_get_current_aio_context(); | ||
100 | + VirtIOSCSIReq *tmf = opaque; | ||
101 | + VirtIOSCSI *s = tmf->dev; | ||
102 | + SCSIDevice *d = virtio_scsi_device_get(s, tmf->req.tmf.lun); | ||
103 | + SCSIRequest *r; | ||
104 | + bool match_tag; | ||
105 | + | ||
106 | + if (!d) { | ||
107 | + tmf->resp.tmf.response = VIRTIO_SCSI_S_BAD_TARGET; | ||
108 | + virtio_scsi_tmf_dec_remaining(tmf); | ||
109 | + return; | ||
110 | + } | ||
111 | + | ||
112 | + /* | ||
113 | + * This function could handle other subtypes that need to be processed in | ||
114 | + * the request's AioContext in the future, but for now only request | ||
115 | + * cancelation subtypes are performed here. | ||
116 | + */ | ||
117 | + switch (tmf->req.tmf.subtype) { | ||
118 | + case VIRTIO_SCSI_T_TMF_ABORT_TASK: | ||
119 | + match_tag = true; | ||
120 | + break; | ||
121 | + case VIRTIO_SCSI_T_TMF_ABORT_TASK_SET: | ||
122 | + case VIRTIO_SCSI_T_TMF_CLEAR_TASK_SET: | ||
123 | + match_tag = false; | ||
124 | + break; | ||
125 | + default: | ||
126 | + g_assert_not_reached(); | ||
127 | + } | ||
128 | + | ||
129 | + WITH_QEMU_LOCK_GUARD(&d->requests_lock) { | ||
130 | + QTAILQ_FOREACH(r, &d->requests, next) { | ||
131 | + VirtIOSCSIReq *cmd_req = r->hba_private; | ||
132 | + assert(cmd_req); /* request has hba_private while enqueued */ | ||
133 | + | ||
134 | + if (r->ctx != ctx) { | ||
135 | + continue; | ||
136 | + } | ||
137 | + if (match_tag && cmd_req->req.cmd.tag != tmf->req.tmf.tag) { | ||
138 | + continue; | ||
139 | + } | ||
140 | + virtio_scsi_tmf_cancel_req(tmf, r); | ||
141 | + } | ||
142 | + } | ||
143 | + | ||
144 | + /* Incremented by virtio_scsi_do_tmf() */ | ||
145 | + virtio_scsi_tmf_dec_remaining(tmf); | ||
146 | + | ||
147 | + object_unref(d); | ||
148 | +} | ||
149 | + | ||
150 | +static void dummy_bh(void *opaque) | ||
151 | +{ | ||
152 | + /* Do nothing */ | ||
153 | +} | ||
154 | + | ||
155 | +/* | ||
156 | + * Wait for pending virtio_scsi_defer_tmf_to_aio_context() BHs. | ||
157 | + */ | ||
158 | +static void virtio_scsi_flush_defer_tmf_to_aio_context(VirtIOSCSI *s) | ||
159 | +{ | ||
160 | + GLOBAL_STATE_CODE(); | ||
161 | + | ||
162 | + assert(!s->dataplane_started); | ||
163 | + | ||
164 | + if (s->ctx) { | ||
165 | + /* Our BH only runs after previously scheduled BHs */ | ||
166 | + aio_wait_bh_oneshot(s->ctx, dummy_bh, NULL); | ||
167 | + } | ||
168 | +} | ||
169 | + | ||
170 | +/* | ||
171 | + * Run the TMF in a specific AioContext, handling only requests in that | ||
172 | + * AioContext. This is necessary because requests can run in different | ||
173 | + * AioContext and it is only possible to cancel them from the AioContext where | ||
174 | + * they are running. | ||
175 | + */ | ||
176 | +static void virtio_scsi_defer_tmf_to_aio_context(VirtIOSCSIReq *tmf, | ||
177 | + AioContext *ctx) | ||
178 | +{ | ||
179 | + /* Decremented in virtio_scsi_do_tmf_aio_context() */ | ||
180 | + qatomic_inc(&tmf->remaining); | ||
181 | + | ||
182 | + /* See virtio_scsi_flush_defer_tmf_to_aio_context() cleanup during reset */ | ||
183 | + aio_bh_schedule_oneshot(ctx, virtio_scsi_do_tmf_aio_context, tmf); | ||
184 | +} | ||
185 | + | ||
186 | +/* | ||
187 | + * Returns the AioContext for a given TMF's tag field or NULL. Note that the | ||
188 | + * request identified by the tag may have completed by the time you can execute | ||
189 | + * a BH in the AioContext, so don't assume the request still exists in your BH. | ||
190 | + */ | ||
191 | +static AioContext *find_aio_context_for_tmf_tag(SCSIDevice *d, | ||
192 | + VirtIOSCSIReq *tmf) | ||
193 | +{ | ||
194 | + WITH_QEMU_LOCK_GUARD(&d->requests_lock) { | ||
195 | + SCSIRequest *r; | ||
196 | + SCSIRequest *next; | ||
197 | + | ||
198 | + QTAILQ_FOREACH_SAFE(r, &d->requests, next, next) { | ||
199 | + VirtIOSCSIReq *cmd_req = r->hba_private; | ||
200 | + | ||
201 | + /* hba_private is non-NULL while the request is enqueued */ | ||
202 | + assert(cmd_req); | ||
203 | + | ||
204 | + if (cmd_req->req.cmd.tag == tmf->req.tmf.tag) { | ||
205 | + return r->ctx; | ||
206 | + } | ||
207 | + } | ||
208 | + } | ||
209 | + return NULL; | ||
210 | +} | ||
211 | + | ||
212 | /* Return 0 if the request is ready to be completed and return to guest; | ||
213 | * -EINPROGRESS if the request is submitted and will be completed later, in the | ||
214 | * case of async cancellation. */ | ||
215 | @@ -XXX,XX +XXX,XX @@ static int virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req) | ||
113 | { | 216 | { |
114 | BDRVRawState *s = bs->opaque; | 217 | SCSIDevice *d = virtio_scsi_device_get(s, req->req.tmf.lun); |
115 | LONG low, high; | 218 | SCSIRequest *r, *next; |
116 | @@ -XXX,XX +XXX,XX @@ static int raw_truncate(BlockDriverState *bs, int64_t offset) | 219 | + AioContext *ctx; |
117 | */ | 220 | int ret = 0; |
118 | dwPtrLow = SetFilePointer(s->hfile, low, &high, FILE_BEGIN); | 221 | |
119 | if (dwPtrLow == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) { | 222 | virtio_scsi_ctx_check(s, d); |
120 | - fprintf(stderr, "SetFilePointer error: %lu\n", GetLastError()); | 223 | @@ -XXX,XX +XXX,XX @@ static int virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req) |
121 | + error_setg_win32(errp, GetLastError(), "SetFilePointer error"); | 224 | req->req.tmf.tag, req->req.tmf.subtype); |
122 | return -EIO; | 225 | |
123 | } | 226 | switch (req->req.tmf.subtype) { |
124 | if (SetEndOfFile(s->hfile) == 0) { | 227 | - case VIRTIO_SCSI_T_TMF_ABORT_TASK: |
125 | - fprintf(stderr, "SetEndOfFile error: %lu\n", GetLastError()); | 228 | - case VIRTIO_SCSI_T_TMF_QUERY_TASK: |
126 | + error_setg_win32(errp, GetLastError(), "SetEndOfFile error"); | 229 | + case VIRTIO_SCSI_T_TMF_ABORT_TASK: { |
127 | return -EIO; | 230 | if (!d) { |
128 | } | 231 | goto fail; |
129 | return 0; | 232 | } |
130 | diff --git a/block/gluster.c b/block/gluster.c | 233 | if (d->lun != virtio_scsi_get_lun(req->req.tmf.lun)) { |
131 | index XXXXXXX..XXXXXXX 100644 | 234 | goto incorrect_lun; |
132 | --- a/block/gluster.c | 235 | } |
133 | +++ b/block/gluster.c | 236 | - QTAILQ_FOREACH_SAFE(r, &d->requests, next, next) { |
134 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int qemu_gluster_co_rw(BlockDriverState *bs, | 237 | - VirtIOSCSIReq *cmd_req = r->hba_private; |
135 | return acb.ret; | 238 | - if (cmd_req && cmd_req->req.cmd.tag == req->req.tmf.tag) { |
136 | } | 239 | - break; |
137 | 240 | - } | |
138 | -static int qemu_gluster_truncate(BlockDriverState *bs, int64_t offset) | 241 | + |
139 | +static int qemu_gluster_truncate(BlockDriverState *bs, int64_t offset, | 242 | + ctx = find_aio_context_for_tmf_tag(d, req); |
140 | + Error **errp) | 243 | + if (ctx) { |
141 | { | 244 | + virtio_scsi_defer_tmf_to_aio_context(req, ctx); |
142 | int ret; | 245 | + ret = -EINPROGRESS; |
143 | BDRVGlusterState *s = bs->opaque; | 246 | } |
144 | diff --git a/block/iscsi.c b/block/iscsi.c | 247 | - if (r) { |
145 | index XXXXXXX..XXXXXXX 100644 | 248 | - /* |
146 | --- a/block/iscsi.c | 249 | - * Assert that the request has not been completed yet, we |
147 | +++ b/block/iscsi.c | 250 | - * check for it in the loop above. |
148 | @@ -XXX,XX +XXX,XX @@ static void iscsi_reopen_commit(BDRVReopenState *reopen_state) | 251 | - */ |
149 | } | 252 | - assert(r->hba_private); |
150 | } | 253 | - if (req->req.tmf.subtype == VIRTIO_SCSI_T_TMF_QUERY_TASK) { |
151 | 254 | - /* "If the specified command is present in the task set, then | |
152 | -static int iscsi_truncate(BlockDriverState *bs, int64_t offset) | 255 | - * return a service response set to FUNCTION SUCCEEDED". |
153 | +static int iscsi_truncate(BlockDriverState *bs, int64_t offset, Error **errp) | 256 | - */ |
154 | { | 257 | - req->resp.tmf.response = VIRTIO_SCSI_S_FUNCTION_SUCCEEDED; |
155 | IscsiLun *iscsilun = bs->opaque; | 258 | - } else { |
156 | Error *local_err = NULL; | 259 | - VirtIOSCSICancelNotifier *notifier; |
157 | @@ -XXX,XX +XXX,XX @@ static int iscsi_truncate(BlockDriverState *bs, int64_t offset) | 260 | - |
158 | 261 | - req->remaining = 1; | |
159 | iscsi_readcapacity_sync(iscsilun, &local_err); | 262 | - notifier = g_new(VirtIOSCSICancelNotifier, 1); |
160 | if (local_err != NULL) { | 263 | - notifier->tmf_req = req; |
161 | - error_free(local_err); | 264 | - notifier->notifier.notify = virtio_scsi_cancel_notify; |
162 | + error_propagate(errp, local_err); | 265 | - scsi_req_cancel_async(r, ¬ifier->notifier); |
163 | return -EIO; | 266 | - ret = -EINPROGRESS; |
164 | } | 267 | + break; |
165 | 268 | + } | |
166 | diff --git a/block/nfs.c b/block/nfs.c | 269 | + |
167 | index XXXXXXX..XXXXXXX 100644 | 270 | + case VIRTIO_SCSI_T_TMF_QUERY_TASK: |
168 | --- a/block/nfs.c | 271 | + if (!d) { |
169 | +++ b/block/nfs.c | 272 | + goto fail; |
170 | @@ -XXX,XX +XXX,XX @@ static int64_t nfs_get_allocated_file_size(BlockDriverState *bs) | 273 | + } |
171 | return (task.ret < 0 ? task.ret : st.st_blocks * 512); | 274 | + if (d->lun != virtio_scsi_get_lun(req->req.tmf.lun)) { |
172 | } | 275 | + goto incorrect_lun; |
173 | 276 | + } | |
174 | -static int nfs_file_truncate(BlockDriverState *bs, int64_t offset) | 277 | + |
175 | +static int nfs_file_truncate(BlockDriverState *bs, int64_t offset, Error **errp) | 278 | + WITH_QEMU_LOCK_GUARD(&d->requests_lock) { |
176 | { | 279 | + QTAILQ_FOREACH(r, &d->requests, next) { |
177 | NFSClient *client = bs->opaque; | 280 | + VirtIOSCSIReq *cmd_req = r->hba_private; |
178 | return nfs_ftruncate(client->context, client->fh, offset); | 281 | + assert(cmd_req); /* request has hba_private while enqueued */ |
179 | diff --git a/block/qcow2.c b/block/qcow2.c | 282 | + |
180 | index XXXXXXX..XXXXXXX 100644 | 283 | + if (cmd_req->req.cmd.tag == req->req.tmf.tag) { |
181 | --- a/block/qcow2.c | 284 | + /* |
182 | +++ b/block/qcow2.c | 285 | + * "If the specified command is present in the task set, |
183 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pdiscard(BlockDriverState *bs, | 286 | + * then return a service response set to FUNCTION |
184 | return ret; | 287 | + * SUCCEEDED". |
185 | } | 288 | + */ |
186 | 289 | + req->resp.tmf.response = VIRTIO_SCSI_S_FUNCTION_SUCCEEDED; | |
187 | -static int qcow2_truncate(BlockDriverState *bs, int64_t offset) | 290 | + } |
188 | +static int qcow2_truncate(BlockDriverState *bs, int64_t offset, Error **errp) | 291 | } |
189 | { | 292 | } |
190 | BDRVQcow2State *s = bs->opaque; | 293 | break; |
191 | int64_t new_l1_size; | 294 | |
192 | int ret; | 295 | case VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET: |
193 | 296 | case VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET: | |
194 | if (offset & 511) { | 297 | - virtio_scsi_defer_tmf_to_bh(req); |
195 | - error_report("The new size must be a multiple of 512"); | 298 | + virtio_scsi_defer_tmf_to_main_loop(req); |
196 | + error_setg(errp, "The new size must be a multiple of 512"); | 299 | ret = -EINPROGRESS; |
197 | return -EINVAL; | 300 | break; |
198 | } | 301 | |
199 | 302 | case VIRTIO_SCSI_T_TMF_ABORT_TASK_SET: | |
200 | /* cannot proceed if image has snapshots */ | 303 | - case VIRTIO_SCSI_T_TMF_CLEAR_TASK_SET: |
201 | if (s->nb_snapshots) { | 304 | + case VIRTIO_SCSI_T_TMF_CLEAR_TASK_SET: { |
202 | - error_report("Can't resize an image which has snapshots"); | 305 | + if (!d) { |
203 | + error_setg(errp, "Can't resize an image which has snapshots"); | 306 | + goto fail; |
204 | return -ENOTSUP; | 307 | + } |
205 | } | 308 | + if (d->lun != virtio_scsi_get_lun(req->req.tmf.lun)) { |
206 | 309 | + goto incorrect_lun; | |
207 | /* shrinking is currently not supported */ | 310 | + } |
208 | if (offset < bs->total_sectors * 512) { | 311 | + |
209 | - error_report("qcow2 doesn't support shrinking images yet"); | 312 | + qatomic_inc(&req->remaining); |
210 | + error_setg(errp, "qcow2 doesn't support shrinking images yet"); | 313 | + |
211 | return -ENOTSUP; | 314 | + ctx = s->ctx ?: qemu_get_aio_context(); |
212 | } | 315 | + virtio_scsi_defer_tmf_to_aio_context(req, ctx); |
213 | 316 | + | |
214 | diff --git a/block/qed.c b/block/qed.c | 317 | + virtio_scsi_tmf_dec_remaining(req); |
215 | index XXXXXXX..XXXXXXX 100644 | 318 | + ret = -EINPROGRESS; |
216 | --- a/block/qed.c | 319 | + break; |
217 | +++ b/block/qed.c | 320 | + } |
218 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_qed_co_pwrite_zeroes(BlockDriverState *bs, | 321 | + |
219 | return cb.ret; | 322 | case VIRTIO_SCSI_T_TMF_QUERY_TASK_SET: |
220 | } | 323 | if (!d) { |
221 | 324 | goto fail; | |
222 | -static int bdrv_qed_truncate(BlockDriverState *bs, int64_t offset) | 325 | @@ -XXX,XX +XXX,XX @@ static int virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req) |
223 | +static int bdrv_qed_truncate(BlockDriverState *bs, int64_t offset, Error **errp) | 326 | goto incorrect_lun; |
224 | { | 327 | } |
225 | BDRVQEDState *s = bs->opaque; | 328 | |
226 | uint64_t old_image_size; | 329 | - /* Add 1 to "remaining" until virtio_scsi_do_tmf returns. |
227 | diff --git a/block/raw-format.c b/block/raw-format.c | 330 | - * This way, if the bus starts calling back to the notifiers |
228 | index XXXXXXX..XXXXXXX 100644 | 331 | - * even before we finish the loop, virtio_scsi_cancel_notify |
229 | --- a/block/raw-format.c | 332 | - * will not complete the TMF too early. |
230 | +++ b/block/raw-format.c | 333 | - */ |
231 | @@ -XXX,XX +XXX,XX @@ static void raw_refresh_limits(BlockDriverState *bs, Error **errp) | 334 | - req->remaining = 1; |
232 | } | 335 | - QTAILQ_FOREACH_SAFE(r, &d->requests, next, next) { |
233 | } | 336 | - if (r->hba_private) { |
234 | 337 | - if (req->req.tmf.subtype == VIRTIO_SCSI_T_TMF_QUERY_TASK_SET) { | |
235 | -static int raw_truncate(BlockDriverState *bs, int64_t offset) | 338 | - /* "If there is any command present in the task set, then |
236 | +static int raw_truncate(BlockDriverState *bs, int64_t offset, Error **errp) | 339 | - * return a service response set to FUNCTION SUCCEEDED". |
237 | { | 340 | - */ |
238 | BDRVRawState *s = bs->opaque; | 341 | - req->resp.tmf.response = VIRTIO_SCSI_S_FUNCTION_SUCCEEDED; |
239 | 342 | - break; | |
240 | @@ -XXX,XX +XXX,XX @@ static int raw_truncate(BlockDriverState *bs, int64_t offset) | 343 | - } else { |
241 | 344 | - VirtIOSCSICancelNotifier *notifier; | |
242 | s->size = offset; | 345 | - |
243 | offset += s->offset; | 346 | - req->remaining++; |
244 | - return bdrv_truncate(bs->file, offset, NULL); | 347 | - notifier = g_new(VirtIOSCSICancelNotifier, 1); |
245 | + return bdrv_truncate(bs->file, offset, errp); | 348 | - notifier->notifier.notify = virtio_scsi_cancel_notify; |
246 | } | 349 | - notifier->tmf_req = req; |
247 | 350 | - scsi_req_cancel_async(r, ¬ifier->notifier); | |
248 | static int raw_media_changed(BlockDriverState *bs) | 351 | - } |
249 | diff --git a/block/rbd.c b/block/rbd.c | 352 | + WITH_QEMU_LOCK_GUARD(&d->requests_lock) { |
250 | index XXXXXXX..XXXXXXX 100644 | 353 | + QTAILQ_FOREACH_SAFE(r, &d->requests, next, next) { |
251 | --- a/block/rbd.c | 354 | + /* Request has hba_private while enqueued */ |
252 | +++ b/block/rbd.c | 355 | + assert(r->hba_private); |
253 | @@ -XXX,XX +XXX,XX @@ static int64_t qemu_rbd_getlength(BlockDriverState *bs) | 356 | + |
254 | return info.size; | 357 | + /* |
255 | } | 358 | + * "If there is any command present in the task set, then |
256 | 359 | + * return a service response set to FUNCTION SUCCEEDED". | |
257 | -static int qemu_rbd_truncate(BlockDriverState *bs, int64_t offset) | 360 | + */ |
258 | +static int qemu_rbd_truncate(BlockDriverState *bs, int64_t offset, Error **errp) | 361 | + req->resp.tmf.response = VIRTIO_SCSI_S_FUNCTION_SUCCEEDED; |
259 | { | 362 | + break; |
260 | BDRVRBDState *s = bs->opaque; | 363 | } |
261 | int r; | 364 | } |
262 | diff --git a/block/sheepdog.c b/block/sheepdog.c | 365 | - if (--req->remaining > 0) { |
263 | index XXXXXXX..XXXXXXX 100644 | 366 | - ret = -EINPROGRESS; |
264 | --- a/block/sheepdog.c | 367 | - } |
265 | +++ b/block/sheepdog.c | 368 | break; |
266 | @@ -XXX,XX +XXX,XX @@ static int64_t sd_getlength(BlockDriverState *bs) | 369 | |
267 | return s->inode.vdi_size; | 370 | case VIRTIO_SCSI_T_TMF_CLEAR_ACA: |
268 | } | 371 | @@ -XXX,XX +XXX,XX @@ static void virtio_scsi_reset(VirtIODevice *vdev) |
269 | 372 | assert(!s->dataplane_started); | |
270 | -static int sd_truncate(BlockDriverState *bs, int64_t offset) | 373 | |
271 | +static int sd_truncate(BlockDriverState *bs, int64_t offset, Error **errp) | 374 | virtio_scsi_reset_tmf_bh(s); |
272 | { | 375 | + virtio_scsi_flush_defer_tmf_to_aio_context(s); |
273 | - Error *local_err = NULL; | 376 | |
274 | BDRVSheepdogState *s = bs->opaque; | 377 | qatomic_inc(&s->resetting); |
275 | int ret, fd; | 378 | bus_cold_reset(BUS(&s->bus)); |
276 | unsigned int datalen; | ||
277 | @@ -XXX,XX +XXX,XX @@ static int sd_truncate(BlockDriverState *bs, int64_t offset) | ||
278 | |||
279 | max_vdi_size = (UINT64_C(1) << s->inode.block_size_shift) * MAX_DATA_OBJS; | ||
280 | if (offset < s->inode.vdi_size) { | ||
281 | - error_report("shrinking is not supported"); | ||
282 | + error_setg(errp, "shrinking is not supported"); | ||
283 | return -EINVAL; | ||
284 | } else if (offset > max_vdi_size) { | ||
285 | - error_report("too big image size"); | ||
286 | + error_setg(errp, "too big image size"); | ||
287 | return -EINVAL; | ||
288 | } | ||
289 | |||
290 | - fd = connect_to_sdog(s, &local_err); | ||
291 | + fd = connect_to_sdog(s, errp); | ||
292 | if (fd < 0) { | ||
293 | - error_report_err(local_err); | ||
294 | return fd; | ||
295 | } | ||
296 | |||
297 | @@ -XXX,XX +XXX,XX @@ static int sd_truncate(BlockDriverState *bs, int64_t offset) | ||
298 | close(fd); | ||
299 | |||
300 | if (ret < 0) { | ||
301 | - error_report("failed to update an inode."); | ||
302 | + error_setg_errno(errp, -ret, "failed to update an inode"); | ||
303 | } | ||
304 | |||
305 | return ret; | ||
306 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int sd_co_writev(BlockDriverState *bs, int64_t sector_num, | ||
307 | BDRVSheepdogState *s = bs->opaque; | ||
308 | |||
309 | if (offset > s->inode.vdi_size) { | ||
310 | - ret = sd_truncate(bs, offset); | ||
311 | + ret = sd_truncate(bs, offset, NULL); | ||
312 | if (ret < 0) { | ||
313 | return ret; | ||
314 | } | ||
315 | diff --git a/include/block/block_int.h b/include/block/block_int.h | ||
316 | index XXXXXXX..XXXXXXX 100644 | ||
317 | --- a/include/block/block_int.h | ||
318 | +++ b/include/block/block_int.h | ||
319 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | ||
320 | int coroutine_fn (*bdrv_co_flush_to_os)(BlockDriverState *bs); | ||
321 | |||
322 | const char *protocol_name; | ||
323 | - int (*bdrv_truncate)(BlockDriverState *bs, int64_t offset); | ||
324 | + int (*bdrv_truncate)(BlockDriverState *bs, int64_t offset, Error **errp); | ||
325 | |||
326 | int64_t (*bdrv_getlength)(BlockDriverState *bs); | ||
327 | bool has_variable_length; | ||
328 | -- | 379 | -- |
329 | 1.8.3.1 | 380 | 2.48.1 |
330 | |||
331 | diff view generated by jsdifflib |
1 | From: Fam Zheng <famz@redhat.com> | 1 | From: Stefan Hajnoczi <stefanha@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Mirror calculates job len from current I/O progress: | 3 | This is the cleanup function that must be called after |
4 | apply_iothread_vq_mapping() succeeds. virtio-scsi will need this | ||
5 | function too, so extract it. | ||
4 | 6 | ||
5 | s->common.len = s->common.offset + | 7 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> |
6 | (cnt + s->sectors_in_flight) * BDRV_SECTOR_SIZE; | 8 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> |
7 | 9 | Message-ID: <20250311132616.1049687-9-stefanha@redhat.com> | |
8 | The final "len" of a failed mirror job in iotests 109 depends on the | ||
9 | subtle timing of the completion of read and write issued in the first | ||
10 | mirror iteration. The second iteration may or may not have run when the | ||
11 | I/O error happens, resulting in non-deterministic output of the | ||
12 | BLOCK_JOB_COMPLETED event text. | ||
13 | |||
14 | Similar to what was done in a752e4786, filter out the field to make the | ||
15 | test robust. | ||
16 | |||
17 | Signed-off-by: Fam Zheng <famz@redhat.com> | ||
18 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
19 | Tested-by: Eric Blake <eblake@redhat.com> | ||
20 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
21 | --- | 11 | --- |
22 | tests/qemu-iotests/109 | 6 ++++-- | 12 | hw/block/virtio-blk.c | 27 +++++++++++++++++++++------ |
23 | tests/qemu-iotests/109.out | 20 ++++++++++---------- | 13 | 1 file changed, 21 insertions(+), 6 deletions(-) |
24 | tests/qemu-iotests/common.filter | 6 ++++++ | ||
25 | 3 files changed, 20 insertions(+), 12 deletions(-) | ||
26 | 14 | ||
27 | diff --git a/tests/qemu-iotests/109 b/tests/qemu-iotests/109 | 15 | diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c |
28 | index XXXXXXX..XXXXXXX 100755 | ||
29 | --- a/tests/qemu-iotests/109 | ||
30 | +++ b/tests/qemu-iotests/109 | ||
31 | @@ -XXX,XX +XXX,XX @@ for fmt in qcow qcow2 qed vdi vmdk vpc; do | ||
32 | |||
33 | # This first test should fail: The image format was probed, we may not | ||
34 | # write an image header at the start of the image | ||
35 | - run_qemu "$TEST_IMG" "$TEST_IMG.src" "" "BLOCK_JOB_ERROR" | ||
36 | + run_qemu "$TEST_IMG" "$TEST_IMG.src" "" "BLOCK_JOB_ERROR" | | ||
37 | + _filter_block_job_len | ||
38 | $QEMU_IO -c 'read -P 0 0 64k' "$TEST_IMG" | _filter_qemu_io | ||
39 | |||
40 | |||
41 | @@ -XXX,XX +XXX,XX @@ for sample_img in empty.bochs iotest-dirtylog-10G-4M.vhdx parallels-v1 \ | ||
42 | _make_test_img 64M | ||
43 | bzcat "$SAMPLE_IMG_DIR/$sample_img.bz2" > "$TEST_IMG.src" | ||
44 | |||
45 | - run_qemu "$TEST_IMG" "$TEST_IMG.src" "" "BLOCK_JOB_ERROR" | _filter_block_job_offset | ||
46 | + run_qemu "$TEST_IMG" "$TEST_IMG.src" "" "BLOCK_JOB_ERROR" | | ||
47 | + _filter_block_job_offset | _filter_block_job_len | ||
48 | $QEMU_IO -c 'read -P 0 0 64k' "$TEST_IMG" | _filter_qemu_io | ||
49 | |||
50 | run_qemu "$TEST_IMG" "$TEST_IMG.src" "'format': 'raw'," "BLOCK_JOB_READY" | ||
51 | diff --git a/tests/qemu-iotests/109.out b/tests/qemu-iotests/109.out | ||
52 | index XXXXXXX..XXXXXXX 100644 | 16 | index XXXXXXX..XXXXXXX 100644 |
53 | --- a/tests/qemu-iotests/109.out | 17 | --- a/hw/block/virtio-blk.c |
54 | +++ b/tests/qemu-iotests/109.out | 18 | +++ b/hw/block/virtio-blk.c |
55 | @@ -XXX,XX +XXX,XX @@ Automatically detecting the format is dangerous for raw images, write operations | 19 | @@ -XXX,XX +XXX,XX @@ validate_iothread_vq_mapping_list(IOThreadVirtQueueMappingList *list, |
56 | Specify the 'raw' format explicitly to remove the restrictions. | 20 | * Fill in the AioContext for each virtqueue in the @vq_aio_context array given |
57 | {"return": {}} | 21 | * the iothread-vq-mapping parameter in @iothread_vq_mapping_list. |
58 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}} | 22 | * |
59 | -{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 65536, "offset": 0, "speed": 0, "type": "mirror", "error": "Operation not permitted"}} | 23 | + * cleanup_iothread_vq_mapping() must be called to free IOThread object |
60 | +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": LEN, "offset": 0, "speed": 0, "type": "mirror", "error": "Operation not permitted"}} | 24 | + * references after this function returns success. |
61 | {"return": []} | 25 | + * |
62 | read 65536/65536 bytes at offset 0 | 26 | * Returns: %true on success, %false on failure. |
63 | 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | 27 | **/ |
64 | @@ -XXX,XX +XXX,XX @@ Automatically detecting the format is dangerous for raw images, write operations | 28 | static bool apply_iothread_vq_mapping( |
65 | Specify the 'raw' format explicitly to remove the restrictions. | 29 | @@ -XXX,XX +XXX,XX @@ static bool apply_iothread_vq_mapping( |
66 | {"return": {}} | 30 | return true; |
67 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}} | ||
68 | -{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 197120, "offset": 512, "speed": 0, "type": "mirror", "error": "Operation not permitted"}} | ||
69 | +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": LEN, "offset": 512, "speed": 0, "type": "mirror", "error": "Operation not permitted"}} | ||
70 | {"return": []} | ||
71 | read 65536/65536 bytes at offset 0 | ||
72 | 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
73 | @@ -XXX,XX +XXX,XX @@ Automatically detecting the format is dangerous for raw images, write operations | ||
74 | Specify the 'raw' format explicitly to remove the restrictions. | ||
75 | {"return": {}} | ||
76 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}} | ||
77 | -{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 327680, "offset": 262144, "speed": 0, "type": "mirror", "error": "Operation not permitted"}} | ||
78 | +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": LEN, "offset": 262144, "speed": 0, "type": "mirror", "error": "Operation not permitted"}} | ||
79 | {"return": []} | ||
80 | read 65536/65536 bytes at offset 0 | ||
81 | 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
82 | @@ -XXX,XX +XXX,XX @@ Automatically detecting the format is dangerous for raw images, write operations | ||
83 | Specify the 'raw' format explicitly to remove the restrictions. | ||
84 | {"return": {}} | ||
85 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}} | ||
86 | -{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 65536, "offset": 0, "speed": 0, "type": "mirror", "error": "Operation not permitted"}} | ||
87 | +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": LEN, "offset": 0, "speed": 0, "type": "mirror", "error": "Operation not permitted"}} | ||
88 | {"return": []} | ||
89 | read 65536/65536 bytes at offset 0 | ||
90 | 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
91 | @@ -XXX,XX +XXX,XX @@ Automatically detecting the format is dangerous for raw images, write operations | ||
92 | Specify the 'raw' format explicitly to remove the restrictions. | ||
93 | {"return": {}} | ||
94 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}} | ||
95 | -{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 65536, "offset": 0, "speed": 0, "type": "mirror", "error": "Operation not permitted"}} | ||
96 | +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": LEN, "offset": 0, "speed": 0, "type": "mirror", "error": "Operation not permitted"}} | ||
97 | {"return": []} | ||
98 | read 65536/65536 bytes at offset 0 | ||
99 | 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
100 | @@ -XXX,XX +XXX,XX @@ Automatically detecting the format is dangerous for raw images, write operations | ||
101 | Specify the 'raw' format explicitly to remove the restrictions. | ||
102 | {"return": {}} | ||
103 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}} | ||
104 | -{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 65536, "offset": 0, "speed": 0, "type": "mirror", "error": "Operation not permitted"}} | ||
105 | +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": LEN, "offset": 0, "speed": 0, "type": "mirror", "error": "Operation not permitted"}} | ||
106 | {"return": []} | ||
107 | read 65536/65536 bytes at offset 0 | ||
108 | 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
109 | @@ -XXX,XX +XXX,XX @@ Automatically detecting the format is dangerous for raw images, write operations | ||
110 | Specify the 'raw' format explicitly to remove the restrictions. | ||
111 | {"return": {}} | ||
112 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}} | ||
113 | -{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 65536, "offset": OFFSET, "speed": 0, "type": "mirror", "error": "Operation not permitted"}} | ||
114 | +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": LEN, "offset": OFFSET, "speed": 0, "type": "mirror", "error": "Operation not permitted"}} | ||
115 | {"return": []} | ||
116 | read 65536/65536 bytes at offset 0 | ||
117 | 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
118 | @@ -XXX,XX +XXX,XX @@ Automatically detecting the format is dangerous for raw images, write operations | ||
119 | Specify the 'raw' format explicitly to remove the restrictions. | ||
120 | {"return": {}} | ||
121 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}} | ||
122 | -{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 31457280, "offset": OFFSET, "speed": 0, "type": "mirror", "error": "Operation not permitted"}} | ||
123 | +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": LEN, "offset": OFFSET, "speed": 0, "type": "mirror", "error": "Operation not permitted"}} | ||
124 | {"return": []} | ||
125 | read 65536/65536 bytes at offset 0 | ||
126 | 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
127 | @@ -XXX,XX +XXX,XX @@ Automatically detecting the format is dangerous for raw images, write operations | ||
128 | Specify the 'raw' format explicitly to remove the restrictions. | ||
129 | {"return": {}} | ||
130 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}} | ||
131 | -{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 327680, "offset": OFFSET, "speed": 0, "type": "mirror", "error": "Operation not permitted"}} | ||
132 | +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": LEN, "offset": OFFSET, "speed": 0, "type": "mirror", "error": "Operation not permitted"}} | ||
133 | {"return": []} | ||
134 | read 65536/65536 bytes at offset 0 | ||
135 | 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
136 | @@ -XXX,XX +XXX,XX @@ Automatically detecting the format is dangerous for raw images, write operations | ||
137 | Specify the 'raw' format explicitly to remove the restrictions. | ||
138 | {"return": {}} | ||
139 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}} | ||
140 | -{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 65536, "offset": OFFSET, "speed": 0, "type": "mirror", "error": "Operation not permitted"}} | ||
141 | +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": LEN, "offset": OFFSET, "speed": 0, "type": "mirror", "error": "Operation not permitted"}} | ||
142 | {"return": []} | ||
143 | read 65536/65536 bytes at offset 0 | ||
144 | 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
145 | diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter | ||
146 | index XXXXXXX..XXXXXXX 100644 | ||
147 | --- a/tests/qemu-iotests/common.filter | ||
148 | +++ b/tests/qemu-iotests/common.filter | ||
149 | @@ -XXX,XX +XXX,XX @@ _filter_block_job_offset() | ||
150 | sed -e 's/, "offset": [0-9]\+,/, "offset": OFFSET,/' | ||
151 | } | 31 | } |
152 | 32 | ||
153 | +# replace block job len | 33 | +/** |
154 | +_filter_block_job_len() | 34 | + * cleanup_iothread_vq_mapping: |
35 | + * @list: The mapping of virtqueues to IOThreads. | ||
36 | + * | ||
37 | + * Release IOThread object references that were acquired by | ||
38 | + * apply_iothread_vq_mapping(). | ||
39 | + */ | ||
40 | +static void cleanup_iothread_vq_mapping(IOThreadVirtQueueMappingList *list) | ||
155 | +{ | 41 | +{ |
156 | + sed -e 's/, "len": [0-9]\+,/, "len": LEN,/g' | 42 | + IOThreadVirtQueueMappingList *node; |
43 | + | ||
44 | + for (node = list; node; node = node->next) { | ||
45 | + IOThread *iothread = iothread_by_id(node->value->iothread); | ||
46 | + object_unref(OBJECT(iothread)); | ||
47 | + } | ||
157 | +} | 48 | +} |
158 | + | 49 | + |
159 | # replace driver-specific options in the "Formatting..." line | 50 | /* Context: BQL held */ |
160 | _filter_img_create() | 51 | static bool virtio_blk_vq_aio_context_init(VirtIOBlock *s, Error **errp) |
161 | { | 52 | { |
53 | @@ -XXX,XX +XXX,XX @@ static void virtio_blk_vq_aio_context_cleanup(VirtIOBlock *s) | ||
54 | assert(!s->ioeventfd_started); | ||
55 | |||
56 | if (conf->iothread_vq_mapping_list) { | ||
57 | - IOThreadVirtQueueMappingList *node; | ||
58 | - | ||
59 | - for (node = conf->iothread_vq_mapping_list; node; node = node->next) { | ||
60 | - IOThread *iothread = iothread_by_id(node->value->iothread); | ||
61 | - object_unref(OBJECT(iothread)); | ||
62 | - } | ||
63 | + cleanup_iothread_vq_mapping(conf->iothread_vq_mapping_list); | ||
64 | } | ||
65 | |||
66 | if (conf->iothread) { | ||
162 | -- | 67 | -- |
163 | 1.8.3.1 | 68 | 2.48.1 |
164 | |||
165 | diff view generated by jsdifflib |
1 | From: Max Reitz <mreitz@redhat.com> | 1 | From: Stefan Hajnoczi <stefanha@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | The block layer takes care of removing the bs->file child if the block | 3 | Use noun_verb() function naming instead of verb_noun() because the |
4 | driver's bdrv_open()/bdrv_file_open() implementation fails. The block | 4 | former is the most common naming style for APIs. The next commit will |
5 | driver therefore does not need to do so, and indeed should not unless it | 5 | move these functions into a header file so that virtio-scsi can call |
6 | sets bs->file to NULL afterwards -- because if this is not done, the | 6 | them. |
7 | bdrv_unref_child() in bdrv_open_inherit() will dereference the freed | ||
8 | memory block at bs->file afterwards, which is not good. | ||
9 | 7 | ||
10 | We can now decide whether to add a "bs->file = NULL;" after each of the | 8 | Shorten iothread_vq_mapping_apply()'s iothread_vq_mapping_list argument |
11 | offending bdrv_unref_child() invocations, or just drop them altogether. | 9 | to just "list" like in the other functions. |
12 | The latter is simpler, so let's do that. | ||
13 | 10 | ||
14 | Cc: qemu-stable <qemu-stable@nongnu.org> | 11 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> |
15 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 12 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> |
16 | Reviewed-by: Eric Blake <eblake@redhat.com> | 13 | Message-ID: <20250311132616.1049687-10-stefanha@redhat.com> |
17 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
18 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 14 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
19 | --- | 15 | --- |
20 | block/blkdebug.c | 4 +--- | 16 | hw/block/virtio-blk.c | 33 ++++++++++++++++----------------- |
21 | block/blkreplay.c | 3 --- | 17 | 1 file changed, 16 insertions(+), 17 deletions(-) |
22 | block/blkverify.c | 3 --- | ||
23 | 3 files changed, 1 insertion(+), 9 deletions(-) | ||
24 | 18 | ||
25 | diff --git a/block/blkdebug.c b/block/blkdebug.c | 19 | diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c |
26 | index XXXXXXX..XXXXXXX 100644 | 20 | index XXXXXXX..XXXXXXX 100644 |
27 | --- a/block/blkdebug.c | 21 | --- a/hw/block/virtio-blk.c |
28 | +++ b/block/blkdebug.c | 22 | +++ b/hw/block/virtio-blk.c |
29 | @@ -XXX,XX +XXX,XX @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags, | 23 | @@ -XXX,XX +XXX,XX @@ static const BlockDevOps virtio_block_ops = { |
30 | } else if (align) { | 24 | }; |
31 | error_setg(errp, "Invalid alignment"); | 25 | |
32 | ret = -EINVAL; | 26 | static bool |
33 | - goto fail_unref; | 27 | -validate_iothread_vq_mapping_list(IOThreadVirtQueueMappingList *list, |
34 | + goto out; | 28 | - uint16_t num_queues, Error **errp) |
29 | +iothread_vq_mapping_validate(IOThreadVirtQueueMappingList *list, uint16_t | ||
30 | + num_queues, Error **errp) | ||
31 | { | ||
32 | g_autofree unsigned long *vqs = bitmap_new(num_queues); | ||
33 | g_autoptr(GHashTable) iothreads = | ||
34 | @@ -XXX,XX +XXX,XX @@ validate_iothread_vq_mapping_list(IOThreadVirtQueueMappingList *list, | ||
35 | } | ||
36 | |||
37 | /** | ||
38 | - * apply_iothread_vq_mapping: | ||
39 | - * @iothread_vq_mapping_list: The mapping of virtqueues to IOThreads. | ||
40 | + * iothread_vq_mapping_apply: | ||
41 | + * @list: The mapping of virtqueues to IOThreads. | ||
42 | * @vq_aio_context: The array of AioContext pointers to fill in. | ||
43 | * @num_queues: The length of @vq_aio_context. | ||
44 | * @errp: If an error occurs, a pointer to the area to store the error. | ||
45 | * | ||
46 | * Fill in the AioContext for each virtqueue in the @vq_aio_context array given | ||
47 | - * the iothread-vq-mapping parameter in @iothread_vq_mapping_list. | ||
48 | + * the iothread-vq-mapping parameter in @list. | ||
49 | * | ||
50 | - * cleanup_iothread_vq_mapping() must be called to free IOThread object | ||
51 | + * iothread_vq_mapping_cleanup() must be called to free IOThread object | ||
52 | * references after this function returns success. | ||
53 | * | ||
54 | * Returns: %true on success, %false on failure. | ||
55 | **/ | ||
56 | -static bool apply_iothread_vq_mapping( | ||
57 | - IOThreadVirtQueueMappingList *iothread_vq_mapping_list, | ||
58 | +static bool iothread_vq_mapping_apply( | ||
59 | + IOThreadVirtQueueMappingList *list, | ||
60 | AioContext **vq_aio_context, | ||
61 | uint16_t num_queues, | ||
62 | Error **errp) | ||
63 | @@ -XXX,XX +XXX,XX @@ static bool apply_iothread_vq_mapping( | ||
64 | size_t num_iothreads = 0; | ||
65 | size_t cur_iothread = 0; | ||
66 | |||
67 | - if (!validate_iothread_vq_mapping_list(iothread_vq_mapping_list, | ||
68 | - num_queues, errp)) { | ||
69 | + if (!iothread_vq_mapping_validate(list, num_queues, errp)) { | ||
70 | return false; | ||
35 | } | 71 | } |
36 | 72 | ||
37 | ret = 0; | 73 | - for (node = iothread_vq_mapping_list; node; node = node->next) { |
38 | goto out; | 74 | + for (node = list; node; node = node->next) { |
39 | 75 | num_iothreads++; | |
40 | -fail_unref: | 76 | } |
41 | - bdrv_unref_child(bs, bs->file); | 77 | |
42 | out: | 78 | - for (node = iothread_vq_mapping_list; node; node = node->next) { |
43 | if (ret < 0) { | 79 | + for (node = list; node; node = node->next) { |
44 | g_free(s->config_file); | 80 | IOThread *iothread = iothread_by_id(node->value->iothread); |
45 | diff --git a/block/blkreplay.c b/block/blkreplay.c | 81 | AioContext *ctx = iothread_get_aio_context(iothread); |
46 | index XXXXXXX..XXXXXXX 100755 | 82 | |
47 | --- a/block/blkreplay.c | 83 | @@ -XXX,XX +XXX,XX @@ static bool apply_iothread_vq_mapping( |
48 | +++ b/block/blkreplay.c | ||
49 | @@ -XXX,XX +XXX,XX @@ static int blkreplay_open(BlockDriverState *bs, QDict *options, int flags, | ||
50 | |||
51 | ret = 0; | ||
52 | fail: | ||
53 | - if (ret < 0) { | ||
54 | - bdrv_unref_child(bs, bs->file); | ||
55 | - } | ||
56 | return ret; | ||
57 | } | 84 | } |
58 | 85 | ||
59 | diff --git a/block/blkverify.c b/block/blkverify.c | 86 | /** |
60 | index XXXXXXX..XXXXXXX 100644 | 87 | - * cleanup_iothread_vq_mapping: |
61 | --- a/block/blkverify.c | 88 | + * iothread_vq_mapping_cleanup: |
62 | +++ b/block/blkverify.c | 89 | * @list: The mapping of virtqueues to IOThreads. |
63 | @@ -XXX,XX +XXX,XX @@ static int blkverify_open(BlockDriverState *bs, QDict *options, int flags, | 90 | * |
64 | 91 | * Release IOThread object references that were acquired by | |
65 | ret = 0; | 92 | - * apply_iothread_vq_mapping(). |
66 | fail: | 93 | + * iothread_vq_mapping_apply(). |
67 | - if (ret < 0) { | 94 | */ |
68 | - bdrv_unref_child(bs, bs->file); | 95 | -static void cleanup_iothread_vq_mapping(IOThreadVirtQueueMappingList *list) |
69 | - } | 96 | +static void iothread_vq_mapping_cleanup(IOThreadVirtQueueMappingList *list) |
70 | qemu_opts_del(opts); | 97 | { |
71 | return ret; | 98 | IOThreadVirtQueueMappingList *node; |
72 | } | 99 | |
100 | @@ -XXX,XX +XXX,XX @@ static bool virtio_blk_vq_aio_context_init(VirtIOBlock *s, Error **errp) | ||
101 | s->vq_aio_context = g_new(AioContext *, conf->num_queues); | ||
102 | |||
103 | if (conf->iothread_vq_mapping_list) { | ||
104 | - if (!apply_iothread_vq_mapping(conf->iothread_vq_mapping_list, | ||
105 | + if (!iothread_vq_mapping_apply(conf->iothread_vq_mapping_list, | ||
106 | s->vq_aio_context, | ||
107 | conf->num_queues, | ||
108 | errp)) { | ||
109 | @@ -XXX,XX +XXX,XX @@ static void virtio_blk_vq_aio_context_cleanup(VirtIOBlock *s) | ||
110 | assert(!s->ioeventfd_started); | ||
111 | |||
112 | if (conf->iothread_vq_mapping_list) { | ||
113 | - cleanup_iothread_vq_mapping(conf->iothread_vq_mapping_list); | ||
114 | + iothread_vq_mapping_cleanup(conf->iothread_vq_mapping_list); | ||
115 | } | ||
116 | |||
117 | if (conf->iothread) { | ||
73 | -- | 118 | -- |
74 | 1.8.3.1 | 119 | 2.48.1 |
75 | |||
76 | diff view generated by jsdifflib |
1 | From: Stefan Hajnoczi <stefanha@redhat.com> | ||
---|---|---|---|
2 | |||
3 | The code that builds an array of AioContext pointers indexed by the | ||
4 | virtqueue is not specific to virtio-blk. virtio-scsi will need to do the | ||
5 | same thing, so extract the functions. | ||
6 | |||
7 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
8 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
9 | Message-ID: <20250311132616.1049687-11-stefanha@redhat.com> | ||
1 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
2 | Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com> | ||
3 | --- | 11 | --- |
4 | tests/qemu-iotests/181 | 119 +++++++++++++++++++++++++++++++++++++++++++++ | 12 | include/hw/virtio/iothread-vq-mapping.h | 45 ++++++++ |
5 | tests/qemu-iotests/181.out | 38 +++++++++++++++ | 13 | hw/block/virtio-blk.c | 142 +----------------------- |
6 | tests/qemu-iotests/group | 1 + | 14 | hw/virtio/iothread-vq-mapping.c | 131 ++++++++++++++++++++++ |
7 | 3 files changed, 158 insertions(+) | 15 | hw/virtio/meson.build | 1 + |
8 | create mode 100755 tests/qemu-iotests/181 | 16 | 4 files changed, 178 insertions(+), 141 deletions(-) |
9 | create mode 100644 tests/qemu-iotests/181.out | 17 | create mode 100644 include/hw/virtio/iothread-vq-mapping.h |
18 | create mode 100644 hw/virtio/iothread-vq-mapping.c | ||
10 | 19 | ||
11 | diff --git a/tests/qemu-iotests/181 b/tests/qemu-iotests/181 | 20 | diff --git a/include/hw/virtio/iothread-vq-mapping.h b/include/hw/virtio/iothread-vq-mapping.h |
12 | new file mode 100755 | ||
13 | index XXXXXXX..XXXXXXX | ||
14 | --- /dev/null | ||
15 | +++ b/tests/qemu-iotests/181 | ||
16 | @@ -XXX,XX +XXX,XX @@ | ||
17 | +#!/bin/bash | ||
18 | +# | ||
19 | +# Test postcopy live migration with shared storage | ||
20 | +# | ||
21 | +# Copyright (C) 2017 Red Hat, Inc. | ||
22 | +# | ||
23 | +# This program is free software; you can redistribute it and/or modify | ||
24 | +# it under the terms of the GNU General Public License as published by | ||
25 | +# the Free Software Foundation; either version 2 of the License, or | ||
26 | +# (at your option) any later version. | ||
27 | +# | ||
28 | +# This program is distributed in the hope that it will be useful, | ||
29 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
30 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
31 | +# GNU General Public License for more details. | ||
32 | +# | ||
33 | +# You should have received a copy of the GNU General Public License | ||
34 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
35 | +# | ||
36 | + | ||
37 | +# creator | ||
38 | +owner=kwolf@redhat.com | ||
39 | + | ||
40 | +seq=`basename $0` | ||
41 | +echo "QA output created by $seq" | ||
42 | + | ||
43 | +here=`pwd` | ||
44 | +status=1 # failure is the default! | ||
45 | + | ||
46 | +MIG_SOCKET="${TEST_DIR}/migrate" | ||
47 | + | ||
48 | +_cleanup() | ||
49 | +{ | ||
50 | + rm -f "${MIG_SOCKET}" | ||
51 | + _cleanup_test_img | ||
52 | + _cleanup_qemu | ||
53 | +} | ||
54 | +trap "_cleanup; exit \$status" 0 1 2 3 15 | ||
55 | + | ||
56 | +# get standard environment, filters and checks | ||
57 | +. ./common.rc | ||
58 | +. ./common.filter | ||
59 | +. ./common.qemu | ||
60 | + | ||
61 | +_supported_fmt generic | ||
62 | +_supported_proto generic | ||
63 | +_supported_os Linux | ||
64 | + | ||
65 | +size=64M | ||
66 | +_make_test_img $size | ||
67 | + | ||
68 | +echo | ||
69 | +echo === Starting VMs === | ||
70 | +echo | ||
71 | + | ||
72 | +qemu_comm_method="monitor" | ||
73 | + | ||
74 | +_launch_qemu \ | ||
75 | + -drive file="${TEST_IMG}",cache=${CACHEMODE},driver=$IMGFMT,id=disk | ||
76 | +src=$QEMU_HANDLE | ||
77 | + | ||
78 | +_launch_qemu \ | ||
79 | + -drive file="${TEST_IMG}",cache=${CACHEMODE},driver=$IMGFMT,id=disk \ | ||
80 | + -incoming "unix:${MIG_SOCKET}" | ||
81 | +dest=$QEMU_HANDLE | ||
82 | + | ||
83 | +echo | ||
84 | +echo === Write something on the source === | ||
85 | +echo | ||
86 | + | ||
87 | +silent= | ||
88 | +_send_qemu_cmd $src 'qemu-io disk "write -P 0x55 0 64k"' "(qemu)" | ||
89 | +_send_qemu_cmd $src "" "ops/sec" | ||
90 | +_send_qemu_cmd $src 'qemu-io disk "read -P 0x55 0 64k"' "(qemu)" | ||
91 | +_send_qemu_cmd $src "" "ops/sec" | ||
92 | + | ||
93 | +echo | ||
94 | +echo === Do postcopy migration to destination === | ||
95 | +echo | ||
96 | + | ||
97 | +# Slow down migration so much that it definitely won't finish before we can | ||
98 | +# switch to postcopy | ||
99 | +silent=yes | ||
100 | +_send_qemu_cmd $src 'migrate_set_speed 4k' "(qemu)" | ||
101 | +_send_qemu_cmd $src 'migrate_set_capability postcopy-ram on' "(qemu)" | ||
102 | +_send_qemu_cmd $src "migrate -d unix:${MIG_SOCKET}" "(qemu)" | ||
103 | +_send_qemu_cmd $src 'migrate_start_postcopy' "(qemu)" | ||
104 | + | ||
105 | +QEMU_COMM_TIMEOUT=1 qemu_cmd_repeat=10 silent=yes \ | ||
106 | + _send_qemu_cmd $src "info migrate" "completed\|failed" | ||
107 | +silent=yes _send_qemu_cmd $src "" "(qemu)" | ||
108 | + | ||
109 | +echo | ||
110 | +echo === Do some I/O on the destination === | ||
111 | +echo | ||
112 | + | ||
113 | +# It is important that we use the BlockBackend of the guest device here instead | ||
114 | +# of the node name, which would create a new BlockBackend and not test whether | ||
115 | +# the guest has the necessary permissions to access the image now | ||
116 | +silent= | ||
117 | +_send_qemu_cmd $dest 'qemu-io disk "read -P 0x55 0 64k"' "(qemu)" | ||
118 | +_send_qemu_cmd $dest "" "ops/sec" | ||
119 | +_send_qemu_cmd $dest 'qemu-io disk "write -P 0x66 1M 64k"' "(qemu)" | ||
120 | +_send_qemu_cmd $dest "" "ops/sec" | ||
121 | + | ||
122 | +echo | ||
123 | +echo === Shut down and check image === | ||
124 | +echo | ||
125 | + | ||
126 | +_send_qemu_cmd $src 'quit' "" | ||
127 | +_send_qemu_cmd $dest 'quit' "" | ||
128 | +wait=1 _cleanup_qemu | ||
129 | + | ||
130 | +_check_test_img | ||
131 | + | ||
132 | +# success, all done | ||
133 | +echo "*** done" | ||
134 | +rm -f $seq.full | ||
135 | +status=0 | ||
136 | diff --git a/tests/qemu-iotests/181.out b/tests/qemu-iotests/181.out | ||
137 | new file mode 100644 | 21 | new file mode 100644 |
138 | index XXXXXXX..XXXXXXX | 22 | index XXXXXXX..XXXXXXX |
139 | --- /dev/null | 23 | --- /dev/null |
140 | +++ b/tests/qemu-iotests/181.out | 24 | +++ b/include/hw/virtio/iothread-vq-mapping.h |
141 | @@ -XXX,XX +XXX,XX @@ | 25 | @@ -XXX,XX +XXX,XX @@ |
142 | +QA output created by 181 | 26 | +/* |
143 | +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 | 27 | + * IOThread Virtqueue Mapping |
144 | + | 28 | + * |
145 | +=== Starting VMs === | 29 | + * Copyright Red Hat, Inc |
146 | + | 30 | + * |
147 | + | 31 | + * SPDX-License-Identifier: GPL-2.0-only |
148 | +=== Write something on the source === | 32 | + */ |
149 | + | 33 | + |
150 | +QEMU X.Y.Z monitor - type 'help' for more information | 34 | +#ifndef HW_VIRTIO_IOTHREAD_VQ_MAPPING_H |
151 | +(qemu) qemu-io disk "write -P 0x55 0 64k" | 35 | +#define HW_VIRTIO_IOTHREAD_VQ_MAPPING_H |
152 | +wrote 65536/65536 bytes at offset 0 | 36 | + |
153 | +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | 37 | +#include "qapi/error.h" |
154 | +(qemu) | 38 | +#include "qapi/qapi-types-virtio.h" |
155 | +(qemu) qemu-io disk "read -P 0x55 0 64k" | 39 | + |
156 | +read 65536/65536 bytes at offset 0 | 40 | +/** |
157 | +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | 41 | + * iothread_vq_mapping_apply: |
158 | + | 42 | + * @list: The mapping of virtqueues to IOThreads. |
159 | +=== Do postcopy migration to destination === | 43 | + * @vq_aio_context: The array of AioContext pointers to fill in. |
160 | + | 44 | + * @num_queues: The length of @vq_aio_context. |
161 | + | 45 | + * @errp: If an error occurs, a pointer to the area to store the error. |
162 | +=== Do some I/O on the destination === | 46 | + * |
163 | + | 47 | + * Fill in the AioContext for each virtqueue in the @vq_aio_context array given |
164 | +QEMU X.Y.Z monitor - type 'help' for more information | 48 | + * the iothread-vq-mapping parameter in @list. |
165 | +(qemu) qemu-io disk "read -P 0x55 0 64k" | 49 | + * |
166 | +read 65536/65536 bytes at offset 0 | 50 | + * iothread_vq_mapping_cleanup() must be called to free IOThread object |
167 | +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | 51 | + * references after this function returns success. |
168 | +(qemu) | 52 | + * |
169 | +(qemu) qemu-io disk "write -P 0x66 1M 64k" | 53 | + * Returns: %true on success, %false on failure. |
170 | +wrote 65536/65536 bytes at offset 1048576 | 54 | + **/ |
171 | +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | 55 | +bool iothread_vq_mapping_apply( |
172 | + | 56 | + IOThreadVirtQueueMappingList *list, |
173 | +=== Shut down and check image === | 57 | + AioContext **vq_aio_context, |
174 | + | 58 | + uint16_t num_queues, |
175 | +(qemu) quit | 59 | + Error **errp); |
176 | +(qemu) | 60 | + |
177 | +(qemu) quit | 61 | +/** |
178 | +No errors were found on the image. | 62 | + * iothread_vq_mapping_cleanup: |
179 | +*** done | 63 | + * @list: The mapping of virtqueues to IOThreads. |
180 | diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group | 64 | + * |
65 | + * Release IOThread object references that were acquired by | ||
66 | + * iothread_vq_mapping_apply(). | ||
67 | + */ | ||
68 | +void iothread_vq_mapping_cleanup(IOThreadVirtQueueMappingList *list); | ||
69 | + | ||
70 | +#endif /* HW_VIRTIO_IOTHREAD_VQ_MAPPING_H */ | ||
71 | diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c | ||
181 | index XXXXXXX..XXXXXXX 100644 | 72 | index XXXXXXX..XXXXXXX 100644 |
182 | --- a/tests/qemu-iotests/group | 73 | --- a/hw/block/virtio-blk.c |
183 | +++ b/tests/qemu-iotests/group | 74 | +++ b/hw/block/virtio-blk.c |
184 | @@ -XXX,XX +XXX,XX @@ | 75 | @@ -XXX,XX +XXX,XX @@ |
185 | 174 auto | 76 | #endif |
186 | 175 auto quick | 77 | #include "hw/virtio/virtio-bus.h" |
187 | 176 rw auto backing | 78 | #include "migration/qemu-file-types.h" |
188 | +181 rw auto migration | 79 | +#include "hw/virtio/iothread-vq-mapping.h" |
80 | #include "hw/virtio/virtio-access.h" | ||
81 | #include "hw/virtio/virtio-blk-common.h" | ||
82 | #include "qemu/coroutine.h" | ||
83 | @@ -XXX,XX +XXX,XX @@ static const BlockDevOps virtio_block_ops = { | ||
84 | .drained_end = virtio_blk_drained_end, | ||
85 | }; | ||
86 | |||
87 | -static bool | ||
88 | -iothread_vq_mapping_validate(IOThreadVirtQueueMappingList *list, uint16_t | ||
89 | - num_queues, Error **errp) | ||
90 | -{ | ||
91 | - g_autofree unsigned long *vqs = bitmap_new(num_queues); | ||
92 | - g_autoptr(GHashTable) iothreads = | ||
93 | - g_hash_table_new(g_str_hash, g_str_equal); | ||
94 | - | ||
95 | - for (IOThreadVirtQueueMappingList *node = list; node; node = node->next) { | ||
96 | - const char *name = node->value->iothread; | ||
97 | - uint16List *vq; | ||
98 | - | ||
99 | - if (!iothread_by_id(name)) { | ||
100 | - error_setg(errp, "IOThread \"%s\" object does not exist", name); | ||
101 | - return false; | ||
102 | - } | ||
103 | - | ||
104 | - if (!g_hash_table_add(iothreads, (gpointer)name)) { | ||
105 | - error_setg(errp, | ||
106 | - "duplicate IOThread name \"%s\" in iothread-vq-mapping", | ||
107 | - name); | ||
108 | - return false; | ||
109 | - } | ||
110 | - | ||
111 | - if (node != list) { | ||
112 | - if (!!node->value->vqs != !!list->value->vqs) { | ||
113 | - error_setg(errp, "either all items in iothread-vq-mapping " | ||
114 | - "must have vqs or none of them must have it"); | ||
115 | - return false; | ||
116 | - } | ||
117 | - } | ||
118 | - | ||
119 | - for (vq = node->value->vqs; vq; vq = vq->next) { | ||
120 | - if (vq->value >= num_queues) { | ||
121 | - error_setg(errp, "vq index %u for IOThread \"%s\" must be " | ||
122 | - "less than num_queues %u in iothread-vq-mapping", | ||
123 | - vq->value, name, num_queues); | ||
124 | - return false; | ||
125 | - } | ||
126 | - | ||
127 | - if (test_and_set_bit(vq->value, vqs)) { | ||
128 | - error_setg(errp, "cannot assign vq %u to IOThread \"%s\" " | ||
129 | - "because it is already assigned", vq->value, name); | ||
130 | - return false; | ||
131 | - } | ||
132 | - } | ||
133 | - } | ||
134 | - | ||
135 | - if (list->value->vqs) { | ||
136 | - for (uint16_t i = 0; i < num_queues; i++) { | ||
137 | - if (!test_bit(i, vqs)) { | ||
138 | - error_setg(errp, | ||
139 | - "missing vq %u IOThread assignment in iothread-vq-mapping", | ||
140 | - i); | ||
141 | - return false; | ||
142 | - } | ||
143 | - } | ||
144 | - } | ||
145 | - | ||
146 | - return true; | ||
147 | -} | ||
148 | - | ||
149 | -/** | ||
150 | - * iothread_vq_mapping_apply: | ||
151 | - * @list: The mapping of virtqueues to IOThreads. | ||
152 | - * @vq_aio_context: The array of AioContext pointers to fill in. | ||
153 | - * @num_queues: The length of @vq_aio_context. | ||
154 | - * @errp: If an error occurs, a pointer to the area to store the error. | ||
155 | - * | ||
156 | - * Fill in the AioContext for each virtqueue in the @vq_aio_context array given | ||
157 | - * the iothread-vq-mapping parameter in @list. | ||
158 | - * | ||
159 | - * iothread_vq_mapping_cleanup() must be called to free IOThread object | ||
160 | - * references after this function returns success. | ||
161 | - * | ||
162 | - * Returns: %true on success, %false on failure. | ||
163 | - **/ | ||
164 | -static bool iothread_vq_mapping_apply( | ||
165 | - IOThreadVirtQueueMappingList *list, | ||
166 | - AioContext **vq_aio_context, | ||
167 | - uint16_t num_queues, | ||
168 | - Error **errp) | ||
169 | -{ | ||
170 | - IOThreadVirtQueueMappingList *node; | ||
171 | - size_t num_iothreads = 0; | ||
172 | - size_t cur_iothread = 0; | ||
173 | - | ||
174 | - if (!iothread_vq_mapping_validate(list, num_queues, errp)) { | ||
175 | - return false; | ||
176 | - } | ||
177 | - | ||
178 | - for (node = list; node; node = node->next) { | ||
179 | - num_iothreads++; | ||
180 | - } | ||
181 | - | ||
182 | - for (node = list; node; node = node->next) { | ||
183 | - IOThread *iothread = iothread_by_id(node->value->iothread); | ||
184 | - AioContext *ctx = iothread_get_aio_context(iothread); | ||
185 | - | ||
186 | - /* Released in virtio_blk_vq_aio_context_cleanup() */ | ||
187 | - object_ref(OBJECT(iothread)); | ||
188 | - | ||
189 | - if (node->value->vqs) { | ||
190 | - uint16List *vq; | ||
191 | - | ||
192 | - /* Explicit vq:IOThread assignment */ | ||
193 | - for (vq = node->value->vqs; vq; vq = vq->next) { | ||
194 | - assert(vq->value < num_queues); | ||
195 | - vq_aio_context[vq->value] = ctx; | ||
196 | - } | ||
197 | - } else { | ||
198 | - /* Round-robin vq:IOThread assignment */ | ||
199 | - for (unsigned i = cur_iothread; i < num_queues; | ||
200 | - i += num_iothreads) { | ||
201 | - vq_aio_context[i] = ctx; | ||
202 | - } | ||
203 | - } | ||
204 | - | ||
205 | - cur_iothread++; | ||
206 | - } | ||
207 | - | ||
208 | - return true; | ||
209 | -} | ||
210 | - | ||
211 | -/** | ||
212 | - * iothread_vq_mapping_cleanup: | ||
213 | - * @list: The mapping of virtqueues to IOThreads. | ||
214 | - * | ||
215 | - * Release IOThread object references that were acquired by | ||
216 | - * iothread_vq_mapping_apply(). | ||
217 | - */ | ||
218 | -static void iothread_vq_mapping_cleanup(IOThreadVirtQueueMappingList *list) | ||
219 | -{ | ||
220 | - IOThreadVirtQueueMappingList *node; | ||
221 | - | ||
222 | - for (node = list; node; node = node->next) { | ||
223 | - IOThread *iothread = iothread_by_id(node->value->iothread); | ||
224 | - object_unref(OBJECT(iothread)); | ||
225 | - } | ||
226 | -} | ||
227 | - | ||
228 | /* Context: BQL held */ | ||
229 | static bool virtio_blk_vq_aio_context_init(VirtIOBlock *s, Error **errp) | ||
230 | { | ||
231 | diff --git a/hw/virtio/iothread-vq-mapping.c b/hw/virtio/iothread-vq-mapping.c | ||
232 | new file mode 100644 | ||
233 | index XXXXXXX..XXXXXXX | ||
234 | --- /dev/null | ||
235 | +++ b/hw/virtio/iothread-vq-mapping.c | ||
236 | @@ -XXX,XX +XXX,XX @@ | ||
237 | +/* | ||
238 | + * IOThread Virtqueue Mapping | ||
239 | + * | ||
240 | + * Copyright Red Hat, Inc | ||
241 | + * | ||
242 | + * SPDX-License-Identifier: GPL-2.0-only | ||
243 | + */ | ||
244 | + | ||
245 | +#include "qemu/osdep.h" | ||
246 | +#include "system/iothread.h" | ||
247 | +#include "hw/virtio/iothread-vq-mapping.h" | ||
248 | + | ||
249 | +static bool | ||
250 | +iothread_vq_mapping_validate(IOThreadVirtQueueMappingList *list, uint16_t | ||
251 | + num_queues, Error **errp) | ||
252 | +{ | ||
253 | + g_autofree unsigned long *vqs = bitmap_new(num_queues); | ||
254 | + g_autoptr(GHashTable) iothreads = | ||
255 | + g_hash_table_new(g_str_hash, g_str_equal); | ||
256 | + | ||
257 | + for (IOThreadVirtQueueMappingList *node = list; node; node = node->next) { | ||
258 | + const char *name = node->value->iothread; | ||
259 | + uint16List *vq; | ||
260 | + | ||
261 | + if (!iothread_by_id(name)) { | ||
262 | + error_setg(errp, "IOThread \"%s\" object does not exist", name); | ||
263 | + return false; | ||
264 | + } | ||
265 | + | ||
266 | + if (!g_hash_table_add(iothreads, (gpointer)name)) { | ||
267 | + error_setg(errp, | ||
268 | + "duplicate IOThread name \"%s\" in iothread-vq-mapping", | ||
269 | + name); | ||
270 | + return false; | ||
271 | + } | ||
272 | + | ||
273 | + if (node != list) { | ||
274 | + if (!!node->value->vqs != !!list->value->vqs) { | ||
275 | + error_setg(errp, "either all items in iothread-vq-mapping " | ||
276 | + "must have vqs or none of them must have it"); | ||
277 | + return false; | ||
278 | + } | ||
279 | + } | ||
280 | + | ||
281 | + for (vq = node->value->vqs; vq; vq = vq->next) { | ||
282 | + if (vq->value >= num_queues) { | ||
283 | + error_setg(errp, "vq index %u for IOThread \"%s\" must be " | ||
284 | + "less than num_queues %u in iothread-vq-mapping", | ||
285 | + vq->value, name, num_queues); | ||
286 | + return false; | ||
287 | + } | ||
288 | + | ||
289 | + if (test_and_set_bit(vq->value, vqs)) { | ||
290 | + error_setg(errp, "cannot assign vq %u to IOThread \"%s\" " | ||
291 | + "because it is already assigned", vq->value, name); | ||
292 | + return false; | ||
293 | + } | ||
294 | + } | ||
295 | + } | ||
296 | + | ||
297 | + if (list->value->vqs) { | ||
298 | + for (uint16_t i = 0; i < num_queues; i++) { | ||
299 | + if (!test_bit(i, vqs)) { | ||
300 | + error_setg(errp, | ||
301 | + "missing vq %u IOThread assignment in iothread-vq-mapping", | ||
302 | + i); | ||
303 | + return false; | ||
304 | + } | ||
305 | + } | ||
306 | + } | ||
307 | + | ||
308 | + return true; | ||
309 | +} | ||
310 | + | ||
311 | +bool iothread_vq_mapping_apply( | ||
312 | + IOThreadVirtQueueMappingList *list, | ||
313 | + AioContext **vq_aio_context, | ||
314 | + uint16_t num_queues, | ||
315 | + Error **errp) | ||
316 | +{ | ||
317 | + IOThreadVirtQueueMappingList *node; | ||
318 | + size_t num_iothreads = 0; | ||
319 | + size_t cur_iothread = 0; | ||
320 | + | ||
321 | + if (!iothread_vq_mapping_validate(list, num_queues, errp)) { | ||
322 | + return false; | ||
323 | + } | ||
324 | + | ||
325 | + for (node = list; node; node = node->next) { | ||
326 | + num_iothreads++; | ||
327 | + } | ||
328 | + | ||
329 | + for (node = list; node; node = node->next) { | ||
330 | + IOThread *iothread = iothread_by_id(node->value->iothread); | ||
331 | + AioContext *ctx = iothread_get_aio_context(iothread); | ||
332 | + | ||
333 | + /* Released in virtio_blk_vq_aio_context_cleanup() */ | ||
334 | + object_ref(OBJECT(iothread)); | ||
335 | + | ||
336 | + if (node->value->vqs) { | ||
337 | + uint16List *vq; | ||
338 | + | ||
339 | + /* Explicit vq:IOThread assignment */ | ||
340 | + for (vq = node->value->vqs; vq; vq = vq->next) { | ||
341 | + assert(vq->value < num_queues); | ||
342 | + vq_aio_context[vq->value] = ctx; | ||
343 | + } | ||
344 | + } else { | ||
345 | + /* Round-robin vq:IOThread assignment */ | ||
346 | + for (unsigned i = cur_iothread; i < num_queues; | ||
347 | + i += num_iothreads) { | ||
348 | + vq_aio_context[i] = ctx; | ||
349 | + } | ||
350 | + } | ||
351 | + | ||
352 | + cur_iothread++; | ||
353 | + } | ||
354 | + | ||
355 | + return true; | ||
356 | +} | ||
357 | + | ||
358 | +void iothread_vq_mapping_cleanup(IOThreadVirtQueueMappingList *list) | ||
359 | +{ | ||
360 | + IOThreadVirtQueueMappingList *node; | ||
361 | + | ||
362 | + for (node = list; node; node = node->next) { | ||
363 | + IOThread *iothread = iothread_by_id(node->value->iothread); | ||
364 | + object_unref(OBJECT(iothread)); | ||
365 | + } | ||
366 | +} | ||
367 | + | ||
368 | diff --git a/hw/virtio/meson.build b/hw/virtio/meson.build | ||
369 | index XXXXXXX..XXXXXXX 100644 | ||
370 | --- a/hw/virtio/meson.build | ||
371 | +++ b/hw/virtio/meson.build | ||
372 | @@ -XXX,XX +XXX,XX @@ | ||
373 | system_virtio_ss = ss.source_set() | ||
374 | system_virtio_ss.add(files('virtio-bus.c')) | ||
375 | +system_virtio_ss.add(files('iothread-vq-mapping.c')) | ||
376 | system_virtio_ss.add(when: 'CONFIG_VIRTIO_PCI', if_true: files('virtio-pci.c')) | ||
377 | system_virtio_ss.add(when: 'CONFIG_VIRTIO_MMIO', if_true: files('virtio-mmio.c')) | ||
378 | system_virtio_ss.add(when: 'CONFIG_VIRTIO_CRYPTO', if_true: files('virtio-crypto.c')) | ||
189 | -- | 379 | -- |
190 | 1.8.3.1 | 380 | 2.48.1 |
191 | |||
192 | diff view generated by jsdifflib |
1 | From: "Denis V. Lunev" <den@openvz.org> | 1 | From: Stefan Hajnoczi <stefanha@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | tail_padding_bytes is calculated wrong. F.e. for | 3 | Allow virtio-scsi virtqueues to be assigned to different IOThreads. This |
4 | offset = 0 | 4 | makes it possible to take advantage of host multi-queue block layer |
5 | bytes = 2048 | 5 | scalability by assigning virtqueues that have affinity with vCPUs to |
6 | align = 512 | 6 | different IOThreads that have affinity with host CPUs. The same feature |
7 | we will have tail_padding_bytes = 512 which is definitely wrong. The patch | 7 | was introduced for virtio-blk in the past: |
8 | fixes that arithmetics. | 8 | https://developers.redhat.com/articles/2024/09/05/scaling-virtio-blk-disk-io-iothread-virtqueue-mapping |
9 | 9 | ||
10 | Fortunately this problem is harmless, we will have 1 extra allocation and | 10 | Here are fio randread 4k iodepth=64 results from a 4 vCPU guest with an |
11 | free thus there is no need to put this into stable. The problem is here | 11 | Intel P4800X SSD: |
12 | from the very beginning. | 12 | iothreads IOPS |
13 | ------------------------------ | ||
14 | 1 189576 | ||
15 | 2 312698 | ||
16 | 4 346744 | ||
13 | 17 | ||
14 | Signed-off-by: Denis V. Lunev <den@openvz.org> | 18 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> |
15 | CC: Stefan Hajnoczi <stefanha@redhat.com> | 19 | Message-ID: <20250311132616.1049687-12-stefanha@redhat.com> |
16 | CC: Fam Zheng <famz@redhat.com> | ||
17 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
18 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 20 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
19 | --- | 21 | --- |
20 | block/io.c | 2 +- | 22 | include/hw/virtio/virtio-scsi.h | 5 +- |
21 | 1 file changed, 1 insertion(+), 1 deletion(-) | 23 | hw/scsi/virtio-scsi-dataplane.c | 90 ++++++++++++++++++++++++--------- |
24 | hw/scsi/virtio-scsi.c | 63 ++++++++++++++--------- | ||
25 | 3 files changed, 107 insertions(+), 51 deletions(-) | ||
22 | 26 | ||
23 | diff --git a/block/io.c b/block/io.c | 27 | diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h |
24 | index XXXXXXX..XXXXXXX 100644 | 28 | index XXXXXXX..XXXXXXX 100644 |
25 | --- a/block/io.c | 29 | --- a/include/hw/virtio/virtio-scsi.h |
26 | +++ b/block/io.c | 30 | +++ b/include/hw/virtio/virtio-scsi.h |
27 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_do_zero_pwritev(BdrvChild *child, | 31 | @@ -XXX,XX +XXX,XX @@ |
32 | #include "hw/virtio/virtio.h" | ||
33 | #include "hw/scsi/scsi.h" | ||
34 | #include "chardev/char-fe.h" | ||
35 | +#include "qapi/qapi-types-virtio.h" | ||
36 | #include "system/iothread.h" | ||
37 | |||
38 | #define TYPE_VIRTIO_SCSI_COMMON "virtio-scsi-common" | ||
39 | @@ -XXX,XX +XXX,XX @@ struct VirtIOSCSIConf { | ||
40 | CharBackend chardev; | ||
41 | uint32_t boot_tpgt; | ||
42 | IOThread *iothread; | ||
43 | + IOThreadVirtQueueMappingList *iothread_vq_mapping_list; | ||
44 | }; | ||
45 | |||
46 | struct VirtIOSCSI; | ||
47 | @@ -XXX,XX +XXX,XX @@ struct VirtIOSCSI { | ||
48 | QTAILQ_HEAD(, VirtIOSCSIReq) tmf_bh_list; | ||
49 | |||
50 | /* Fields for dataplane below */ | ||
51 | - AioContext *ctx; /* one iothread per virtio-scsi-pci for now */ | ||
52 | + AioContext **vq_aio_context; /* per-virtqueue AioContext pointer */ | ||
53 | |||
54 | bool dataplane_started; | ||
55 | bool dataplane_starting; | ||
56 | @@ -XXX,XX +XXX,XX @@ void virtio_scsi_common_realize(DeviceState *dev, | ||
57 | void virtio_scsi_common_unrealize(DeviceState *dev); | ||
58 | |||
59 | void virtio_scsi_dataplane_setup(VirtIOSCSI *s, Error **errp); | ||
60 | +void virtio_scsi_dataplane_cleanup(VirtIOSCSI *s); | ||
61 | int virtio_scsi_dataplane_start(VirtIODevice *s); | ||
62 | void virtio_scsi_dataplane_stop(VirtIODevice *s); | ||
63 | |||
64 | diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c | ||
65 | index XXXXXXX..XXXXXXX 100644 | ||
66 | --- a/hw/scsi/virtio-scsi-dataplane.c | ||
67 | +++ b/hw/scsi/virtio-scsi-dataplane.c | ||
68 | @@ -XXX,XX +XXX,XX @@ | ||
69 | #include "system/block-backend.h" | ||
70 | #include "hw/scsi/scsi.h" | ||
71 | #include "scsi/constants.h" | ||
72 | +#include "hw/virtio/iothread-vq-mapping.h" | ||
73 | #include "hw/virtio/virtio-bus.h" | ||
74 | |||
75 | /* Context: BQL held */ | ||
76 | @@ -XXX,XX +XXX,XX @@ void virtio_scsi_dataplane_setup(VirtIOSCSI *s, Error **errp) | ||
77 | VirtIODevice *vdev = VIRTIO_DEVICE(s); | ||
78 | BusState *qbus = qdev_get_parent_bus(DEVICE(vdev)); | ||
79 | VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); | ||
80 | + uint16_t num_vqs = vs->conf.num_queues + VIRTIO_SCSI_VQ_NUM_FIXED; | ||
81 | |||
82 | - if (vs->conf.iothread) { | ||
83 | + if (vs->conf.iothread && vs->conf.iothread_vq_mapping_list) { | ||
84 | + error_setg(errp, | ||
85 | + "iothread and iothread-vq-mapping properties cannot be set " | ||
86 | + "at the same time"); | ||
87 | + return; | ||
88 | + } | ||
89 | + | ||
90 | + if (vs->conf.iothread || vs->conf.iothread_vq_mapping_list) { | ||
91 | if (!k->set_guest_notifiers || !k->ioeventfd_assign) { | ||
92 | error_setg(errp, | ||
93 | "device is incompatible with iothread " | ||
94 | @@ -XXX,XX +XXX,XX @@ void virtio_scsi_dataplane_setup(VirtIOSCSI *s, Error **errp) | ||
95 | error_setg(errp, "ioeventfd is required for iothread"); | ||
96 | return; | ||
97 | } | ||
98 | - s->ctx = iothread_get_aio_context(vs->conf.iothread); | ||
99 | - } else { | ||
100 | - if (!virtio_device_ioeventfd_enabled(vdev)) { | ||
101 | + } | ||
102 | + | ||
103 | + s->vq_aio_context = g_new(AioContext *, num_vqs); | ||
104 | + | ||
105 | + if (vs->conf.iothread_vq_mapping_list) { | ||
106 | + if (!iothread_vq_mapping_apply(vs->conf.iothread_vq_mapping_list, | ||
107 | + s->vq_aio_context, num_vqs, errp)) { | ||
108 | + g_free(s->vq_aio_context); | ||
109 | + s->vq_aio_context = NULL; | ||
110 | return; | ||
111 | } | ||
112 | - s->ctx = qemu_get_aio_context(); | ||
113 | + } else if (vs->conf.iothread) { | ||
114 | + AioContext *ctx = iothread_get_aio_context(vs->conf.iothread); | ||
115 | + for (uint16_t i = 0; i < num_vqs; i++) { | ||
116 | + s->vq_aio_context[i] = ctx; | ||
117 | + } | ||
118 | + | ||
119 | + /* Released in virtio_scsi_dataplane_cleanup() */ | ||
120 | + object_ref(OBJECT(vs->conf.iothread)); | ||
121 | + } else { | ||
122 | + AioContext *ctx = qemu_get_aio_context(); | ||
123 | + for (unsigned i = 0; i < num_vqs; i++) { | ||
124 | + s->vq_aio_context[i] = ctx; | ||
125 | + } | ||
126 | + } | ||
127 | +} | ||
128 | + | ||
129 | +/* Context: BQL held */ | ||
130 | +void virtio_scsi_dataplane_cleanup(VirtIOSCSI *s) | ||
131 | +{ | ||
132 | + VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s); | ||
133 | + | ||
134 | + if (vs->conf.iothread_vq_mapping_list) { | ||
135 | + iothread_vq_mapping_cleanup(vs->conf.iothread_vq_mapping_list); | ||
136 | } | ||
137 | + | ||
138 | + if (vs->conf.iothread) { | ||
139 | + object_unref(OBJECT(vs->conf.iothread)); | ||
140 | + } | ||
141 | + | ||
142 | + g_free(s->vq_aio_context); | ||
143 | + s->vq_aio_context = NULL; | ||
144 | } | ||
145 | |||
146 | static int virtio_scsi_set_host_notifier(VirtIOSCSI *s, VirtQueue *vq, int n) | ||
147 | @@ -XXX,XX +XXX,XX @@ static int virtio_scsi_set_host_notifier(VirtIOSCSI *s, VirtQueue *vq, int n) | ||
148 | } | ||
149 | |||
150 | /* Context: BH in IOThread */ | ||
151 | -static void virtio_scsi_dataplane_stop_bh(void *opaque) | ||
152 | +static void virtio_scsi_dataplane_stop_vq_bh(void *opaque) | ||
153 | { | ||
154 | - VirtIOSCSI *s = opaque; | ||
155 | - VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s); | ||
156 | + AioContext *ctx = qemu_get_current_aio_context(); | ||
157 | + VirtQueue *vq = opaque; | ||
158 | EventNotifier *host_notifier; | ||
159 | - int i; | ||
160 | |||
161 | - virtio_queue_aio_detach_host_notifier(vs->ctrl_vq, s->ctx); | ||
162 | - host_notifier = virtio_queue_get_host_notifier(vs->ctrl_vq); | ||
163 | + virtio_queue_aio_detach_host_notifier(vq, ctx); | ||
164 | + host_notifier = virtio_queue_get_host_notifier(vq); | ||
165 | |||
166 | /* | ||
167 | * Test and clear notifier after disabling event, in case poll callback | ||
168 | * didn't have time to run. | ||
169 | */ | ||
170 | virtio_queue_host_notifier_read(host_notifier); | ||
171 | - | ||
172 | - virtio_queue_aio_detach_host_notifier(vs->event_vq, s->ctx); | ||
173 | - host_notifier = virtio_queue_get_host_notifier(vs->event_vq); | ||
174 | - virtio_queue_host_notifier_read(host_notifier); | ||
175 | - | ||
176 | - for (i = 0; i < vs->conf.num_queues; i++) { | ||
177 | - virtio_queue_aio_detach_host_notifier(vs->cmd_vqs[i], s->ctx); | ||
178 | - host_notifier = virtio_queue_get_host_notifier(vs->cmd_vqs[i]); | ||
179 | - virtio_queue_host_notifier_read(host_notifier); | ||
180 | - } | ||
181 | } | ||
182 | |||
183 | /* Context: BQL held */ | ||
184 | @@ -XXX,XX +XXX,XX @@ int virtio_scsi_dataplane_start(VirtIODevice *vdev) | ||
185 | smp_wmb(); /* paired with aio_notify_accept() */ | ||
186 | |||
187 | if (s->bus.drain_count == 0) { | ||
188 | - virtio_queue_aio_attach_host_notifier(vs->ctrl_vq, s->ctx); | ||
189 | - virtio_queue_aio_attach_host_notifier_no_poll(vs->event_vq, s->ctx); | ||
190 | + virtio_queue_aio_attach_host_notifier(vs->ctrl_vq, | ||
191 | + s->vq_aio_context[0]); | ||
192 | + virtio_queue_aio_attach_host_notifier_no_poll(vs->event_vq, | ||
193 | + s->vq_aio_context[1]); | ||
194 | |||
195 | for (i = 0; i < vs->conf.num_queues; i++) { | ||
196 | - virtio_queue_aio_attach_host_notifier(vs->cmd_vqs[i], s->ctx); | ||
197 | + AioContext *ctx = s->vq_aio_context[VIRTIO_SCSI_VQ_NUM_FIXED + i]; | ||
198 | + virtio_queue_aio_attach_host_notifier(vs->cmd_vqs[i], ctx); | ||
199 | } | ||
200 | } | ||
201 | return 0; | ||
202 | @@ -XXX,XX +XXX,XX @@ void virtio_scsi_dataplane_stop(VirtIODevice *vdev) | ||
203 | s->dataplane_stopping = true; | ||
204 | |||
205 | if (s->bus.drain_count == 0) { | ||
206 | - aio_wait_bh_oneshot(s->ctx, virtio_scsi_dataplane_stop_bh, s); | ||
207 | + for (i = 0; i < vs->conf.num_queues + VIRTIO_SCSI_VQ_NUM_FIXED; i++) { | ||
208 | + VirtQueue *vq = virtio_get_queue(&vs->parent_obj, i); | ||
209 | + AioContext *ctx = s->vq_aio_context[i]; | ||
210 | + aio_wait_bh_oneshot(ctx, virtio_scsi_dataplane_stop_vq_bh, vq); | ||
211 | + } | ||
212 | } | ||
213 | |||
214 | blk_drain_all(); /* ensure there are no in-flight requests */ | ||
215 | diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c | ||
216 | index XXXXXXX..XXXXXXX 100644 | ||
217 | --- a/hw/scsi/virtio-scsi.c | ||
218 | +++ b/hw/scsi/virtio-scsi.c | ||
219 | @@ -XXX,XX +XXX,XX @@ | ||
220 | #include "hw/qdev-properties.h" | ||
221 | #include "hw/scsi/scsi.h" | ||
222 | #include "scsi/constants.h" | ||
223 | +#include "hw/virtio/iothread-vq-mapping.h" | ||
224 | #include "hw/virtio/virtio-bus.h" | ||
225 | #include "hw/virtio/virtio-access.h" | ||
226 | #include "trace.h" | ||
227 | @@ -XXX,XX +XXX,XX @@ static void virtio_scsi_cancel_notify(Notifier *notifier, void *data) | ||
228 | g_free(n); | ||
229 | } | ||
230 | |||
231 | -static inline void virtio_scsi_ctx_check(VirtIOSCSI *s, SCSIDevice *d) | ||
232 | -{ | ||
233 | - if (s->dataplane_started && d && blk_is_available(d->conf.blk)) { | ||
234 | - assert(blk_get_aio_context(d->conf.blk) == s->ctx); | ||
235 | - } | ||
236 | -} | ||
237 | - | ||
238 | static void virtio_scsi_do_one_tmf_bh(VirtIOSCSIReq *req) | ||
239 | { | ||
240 | VirtIOSCSI *s = req->dev; | ||
241 | @@ -XXX,XX +XXX,XX @@ static void virtio_scsi_flush_defer_tmf_to_aio_context(VirtIOSCSI *s) | ||
242 | |||
243 | assert(!s->dataplane_started); | ||
244 | |||
245 | - if (s->ctx) { | ||
246 | + for (uint32_t i = 0; i < s->parent_obj.conf.num_queues; i++) { | ||
247 | + AioContext *ctx = s->vq_aio_context[VIRTIO_SCSI_VQ_NUM_FIXED + i]; | ||
248 | + | ||
249 | /* Our BH only runs after previously scheduled BHs */ | ||
250 | - aio_wait_bh_oneshot(s->ctx, dummy_bh, NULL); | ||
251 | + aio_wait_bh_oneshot(ctx, dummy_bh, NULL); | ||
252 | } | ||
253 | } | ||
254 | |||
255 | @@ -XXX,XX +XXX,XX @@ static int virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req) | ||
256 | AioContext *ctx; | ||
28 | int ret = 0; | 257 | int ret = 0; |
29 | 258 | ||
30 | head_padding_bytes = offset & (align - 1); | 259 | - virtio_scsi_ctx_check(s, d); |
31 | - tail_padding_bytes = align - ((offset + bytes) & (align - 1)); | 260 | /* Here VIRTIO_SCSI_S_OK means "FUNCTION COMPLETE". */ |
32 | + tail_padding_bytes = (align - (offset + bytes)) & (align - 1); | 261 | req->resp.tmf.response = VIRTIO_SCSI_S_OK; |
33 | 262 | ||
34 | 263 | @@ -XXX,XX +XXX,XX @@ static int virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req) | |
35 | assert(flags & BDRV_REQ_ZERO_WRITE); | 264 | |
265 | case VIRTIO_SCSI_T_TMF_ABORT_TASK_SET: | ||
266 | case VIRTIO_SCSI_T_TMF_CLEAR_TASK_SET: { | ||
267 | + g_autoptr(GHashTable) aio_contexts = g_hash_table_new(NULL, NULL); | ||
268 | + | ||
269 | if (!d) { | ||
270 | goto fail; | ||
271 | } | ||
272 | @@ -XXX,XX +XXX,XX @@ static int virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req) | ||
273 | |||
274 | qatomic_inc(&req->remaining); | ||
275 | |||
276 | - ctx = s->ctx ?: qemu_get_aio_context(); | ||
277 | - virtio_scsi_defer_tmf_to_aio_context(req, ctx); | ||
278 | + for (uint32_t i = 0; i < s->parent_obj.conf.num_queues; i++) { | ||
279 | + ctx = s->vq_aio_context[VIRTIO_SCSI_VQ_NUM_FIXED + i]; | ||
280 | + | ||
281 | + if (!g_hash_table_add(aio_contexts, ctx)) { | ||
282 | + continue; /* skip previously added AioContext */ | ||
283 | + } | ||
284 | + | ||
285 | + virtio_scsi_defer_tmf_to_aio_context(req, ctx); | ||
286 | + } | ||
287 | |||
288 | virtio_scsi_tmf_dec_remaining(req); | ||
289 | ret = -EINPROGRESS; | ||
290 | @@ -XXX,XX +XXX,XX @@ static void virtio_scsi_handle_ctrl_vq(VirtIOSCSI *s, VirtQueue *vq) | ||
291 | */ | ||
292 | static bool virtio_scsi_defer_to_dataplane(VirtIOSCSI *s) | ||
293 | { | ||
294 | - if (!s->ctx || s->dataplane_started) { | ||
295 | + if (s->dataplane_started) { | ||
296 | return false; | ||
297 | } | ||
298 | + if (s->vq_aio_context[0] == qemu_get_aio_context()) { | ||
299 | + return false; /* not using IOThreads */ | ||
300 | + } | ||
301 | |||
302 | virtio_device_start_ioeventfd(&s->parent_obj.parent_obj); | ||
303 | return !s->dataplane_fenced; | ||
304 | @@ -XXX,XX +XXX,XX @@ static int virtio_scsi_handle_cmd_req_prepare(VirtIOSCSI *s, VirtIOSCSIReq *req) | ||
305 | virtio_scsi_complete_cmd_req(req); | ||
306 | return -ENOENT; | ||
307 | } | ||
308 | - virtio_scsi_ctx_check(s, d); | ||
309 | req->sreq = scsi_req_new(d, req->req.cmd.tag, | ||
310 | virtio_scsi_get_lun(req->req.cmd.lun), | ||
311 | req->req.cmd.cdb, vs->cdb_size, req); | ||
312 | @@ -XXX,XX +XXX,XX @@ static void virtio_scsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev, | ||
313 | { | ||
314 | VirtIODevice *vdev = VIRTIO_DEVICE(hotplug_dev); | ||
315 | VirtIOSCSI *s = VIRTIO_SCSI(vdev); | ||
316 | + AioContext *ctx = s->vq_aio_context[VIRTIO_SCSI_VQ_NUM_FIXED]; | ||
317 | SCSIDevice *sd = SCSI_DEVICE(dev); | ||
318 | - int ret; | ||
319 | |||
320 | - if (s->ctx && !s->dataplane_fenced) { | ||
321 | - ret = blk_set_aio_context(sd->conf.blk, s->ctx, errp); | ||
322 | - if (ret < 0) { | ||
323 | - return; | ||
324 | - } | ||
325 | + if (ctx != qemu_get_aio_context() && !s->dataplane_fenced) { | ||
326 | + /* | ||
327 | + * Try to make the BlockBackend's AioContext match ours. Ignore failure | ||
328 | + * because I/O will still work although block jobs and other users | ||
329 | + * might be slower when multiple AioContexts use a BlockBackend. | ||
330 | + */ | ||
331 | + blk_set_aio_context(sd->conf.blk, ctx, errp); | ||
332 | } | ||
333 | |||
334 | if (virtio_vdev_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG)) { | ||
335 | @@ -XXX,XX +XXX,XX @@ static void virtio_scsi_hotunplug(HotplugHandler *hotplug_dev, DeviceState *dev, | ||
336 | |||
337 | qdev_simple_device_unplug_cb(hotplug_dev, dev, errp); | ||
338 | |||
339 | - if (s->ctx) { | ||
340 | + if (s->vq_aio_context[VIRTIO_SCSI_VQ_NUM_FIXED] != qemu_get_aio_context()) { | ||
341 | /* If other users keep the BlockBackend in the iothread, that's ok */ | ||
342 | blk_set_aio_context(sd->conf.blk, qemu_get_aio_context(), NULL); | ||
343 | } | ||
344 | @@ -XXX,XX +XXX,XX @@ static void virtio_scsi_drained_begin(SCSIBus *bus) | ||
345 | |||
346 | for (uint32_t i = 0; i < total_queues; i++) { | ||
347 | VirtQueue *vq = virtio_get_queue(vdev, i); | ||
348 | - virtio_queue_aio_detach_host_notifier(vq, s->ctx); | ||
349 | + virtio_queue_aio_detach_host_notifier(vq, s->vq_aio_context[i]); | ||
350 | } | ||
351 | } | ||
352 | |||
353 | @@ -XXX,XX +XXX,XX @@ static void virtio_scsi_drained_end(SCSIBus *bus) | ||
354 | |||
355 | for (uint32_t i = 0; i < total_queues; i++) { | ||
356 | VirtQueue *vq = virtio_get_queue(vdev, i); | ||
357 | + AioContext *ctx = s->vq_aio_context[i]; | ||
358 | + | ||
359 | if (vq == vs->event_vq) { | ||
360 | - virtio_queue_aio_attach_host_notifier_no_poll(vq, s->ctx); | ||
361 | + virtio_queue_aio_attach_host_notifier_no_poll(vq, ctx); | ||
362 | } else { | ||
363 | - virtio_queue_aio_attach_host_notifier(vq, s->ctx); | ||
364 | + virtio_queue_aio_attach_host_notifier(vq, ctx); | ||
365 | } | ||
366 | } | ||
367 | } | ||
368 | @@ -XXX,XX +XXX,XX @@ void virtio_scsi_common_unrealize(DeviceState *dev) | ||
369 | virtio_cleanup(vdev); | ||
370 | } | ||
371 | |||
372 | +/* main loop */ | ||
373 | static void virtio_scsi_device_unrealize(DeviceState *dev) | ||
374 | { | ||
375 | VirtIOSCSI *s = VIRTIO_SCSI(dev); | ||
376 | |||
377 | virtio_scsi_reset_tmf_bh(s); | ||
378 | - | ||
379 | + virtio_scsi_dataplane_cleanup(s); | ||
380 | qbus_set_hotplug_handler(BUS(&s->bus), NULL); | ||
381 | virtio_scsi_common_unrealize(dev); | ||
382 | qemu_mutex_destroy(&s->tmf_bh_lock); | ||
383 | @@ -XXX,XX +XXX,XX @@ static const Property virtio_scsi_properties[] = { | ||
384 | VIRTIO_SCSI_F_CHANGE, true), | ||
385 | DEFINE_PROP_LINK("iothread", VirtIOSCSI, parent_obj.conf.iothread, | ||
386 | TYPE_IOTHREAD, IOThread *), | ||
387 | + DEFINE_PROP_IOTHREAD_VQ_MAPPING_LIST("iothread-vq-mapping", VirtIOSCSI, | ||
388 | + parent_obj.conf.iothread_vq_mapping_list), | ||
389 | }; | ||
390 | |||
391 | static const VMStateDescription vmstate_virtio_scsi = { | ||
36 | -- | 392 | -- |
37 | 1.8.3.1 | 393 | 2.48.1 |
38 | |||
39 | diff view generated by jsdifflib |
1 | From: Max Reitz <mreitz@redhat.com> | 1 | From: Stefan Hajnoczi <stefanha@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | For one thing, this allows us to drop the error message generation from | 3 | Previously the ctrl virtqueue was handled in the AioContext where SCSI |
4 | qemu-img.c and blockdev.c and instead have it unified in | 4 | requests are processed. When IOThread Virtqueue Mapping was added things |
5 | bdrv_truncate(). | 5 | become more complicated because SCSI requests could run in other |
6 | 6 | AioContexts. | |
7 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 7 | |
8 | Message-id: 20170328205129.15138-3-mreitz@redhat.com | 8 | Simplify by handling the ctrl virtqueue in the main loop where reset |
9 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | 9 | operations can be performed. Note that BHs are still used canceling SCSI |
10 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 10 | requests in their AioContexts but at least the mean loop activity |
11 | doesn't need BHs anymore. | ||
12 | |||
13 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
14 | Message-ID: <20250311132616.1049687-13-stefanha@redhat.com> | ||
15 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
11 | --- | 16 | --- |
12 | block.c | 16 ++++++++++++---- | 17 | include/hw/virtio/virtio-scsi.h | 8 -- |
13 | block/blkdebug.c | 2 +- | 18 | hw/scsi/virtio-scsi-dataplane.c | 6 ++ |
14 | block/block-backend.c | 5 +++-- | 19 | hw/scsi/virtio-scsi.c | 144 ++++++-------------------------- |
15 | block/commit.c | 5 +++-- | 20 | 3 files changed, 33 insertions(+), 125 deletions(-) |
16 | block/crypto.c | 2 +- | 21 | |
17 | block/mirror.c | 2 +- | 22 | diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h |
18 | block/parallels.c | 13 ++++++++----- | ||
19 | block/qcow.c | 6 +++--- | ||
20 | block/qcow2-refcount.c | 5 ++++- | ||
21 | block/qcow2.c | 14 +++++++++----- | ||
22 | block/qed.c | 2 +- | ||
23 | block/raw-format.c | 2 +- | ||
24 | block/vdi.c | 4 ++-- | ||
25 | block/vhdx-log.c | 2 +- | ||
26 | block/vhdx.c | 10 +++------- | ||
27 | block/vmdk.c | 13 +++---------- | ||
28 | block/vpc.c | 13 +++++++------ | ||
29 | blockdev.c | 21 +-------------------- | ||
30 | include/block/block.h | 2 +- | ||
31 | include/sysemu/block-backend.h | 2 +- | ||
32 | qemu-img.c | 17 ++++------------- | ||
33 | qemu-io-cmds.c | 5 +++-- | ||
34 | 22 files changed, 73 insertions(+), 90 deletions(-) | ||
35 | |||
36 | diff --git a/block.c b/block.c | ||
37 | index XXXXXXX..XXXXXXX 100644 | 23 | index XXXXXXX..XXXXXXX 100644 |
38 | --- a/block.c | 24 | --- a/include/hw/virtio/virtio-scsi.h |
39 | +++ b/block.c | 25 | +++ b/include/hw/virtio/virtio-scsi.h |
40 | @@ -XXX,XX +XXX,XX @@ exit: | 26 | @@ -XXX,XX +XXX,XX @@ struct VirtIOSCSI { |
41 | /** | 27 | |
42 | * Truncate file to 'offset' bytes (needed only for file protocols) | 28 | QemuMutex ctrl_lock; /* protects ctrl_vq */ |
43 | */ | 29 | |
44 | -int bdrv_truncate(BdrvChild *child, int64_t offset) | 30 | - /* |
45 | +int bdrv_truncate(BdrvChild *child, int64_t offset, Error **errp) | 31 | - * TMFs deferred to main loop BH. These fields are protected by |
46 | { | 32 | - * tmf_bh_lock. |
47 | BlockDriverState *bs = child->bs; | 33 | - */ |
48 | BlockDriver *drv = bs->drv; | 34 | - QemuMutex tmf_bh_lock; |
49 | @@ -XXX,XX +XXX,XX @@ int bdrv_truncate(BdrvChild *child, int64_t offset) | 35 | - QEMUBH *tmf_bh; |
50 | 36 | - QTAILQ_HEAD(, VirtIOSCSIReq) tmf_bh_list; | |
51 | assert(child->perm & BLK_PERM_RESIZE); | 37 | - |
52 | 38 | /* Fields for dataplane below */ | |
53 | - if (!drv) | 39 | AioContext **vq_aio_context; /* per-virtqueue AioContext pointer */ |
54 | + if (!drv) { | 40 | |
55 | + error_setg(errp, "No medium inserted"); | 41 | diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c |
56 | return -ENOMEDIUM; | ||
57 | - if (!drv->bdrv_truncate) | ||
58 | + } | ||
59 | + if (!drv->bdrv_truncate) { | ||
60 | + error_setg(errp, "Image format driver does not support resize"); | ||
61 | return -ENOTSUP; | ||
62 | - if (bs->read_only) | ||
63 | + } | ||
64 | + if (bs->read_only) { | ||
65 | + error_setg(errp, "Image is read-only"); | ||
66 | return -EACCES; | ||
67 | + } | ||
68 | |||
69 | ret = drv->bdrv_truncate(bs, offset); | ||
70 | if (ret == 0) { | ||
71 | @@ -XXX,XX +XXX,XX @@ int bdrv_truncate(BdrvChild *child, int64_t offset) | ||
72 | bdrv_dirty_bitmap_truncate(bs); | ||
73 | bdrv_parent_cb_resize(bs); | ||
74 | ++bs->write_gen; | ||
75 | + } else { | ||
76 | + error_setg_errno(errp, -ret, "Failed to resize image"); | ||
77 | } | ||
78 | return ret; | ||
79 | } | ||
80 | diff --git a/block/blkdebug.c b/block/blkdebug.c | ||
81 | index XXXXXXX..XXXXXXX 100644 | 42 | index XXXXXXX..XXXXXXX 100644 |
82 | --- a/block/blkdebug.c | 43 | --- a/hw/scsi/virtio-scsi-dataplane.c |
83 | +++ b/block/blkdebug.c | 44 | +++ b/hw/scsi/virtio-scsi-dataplane.c |
84 | @@ -XXX,XX +XXX,XX @@ static int64_t blkdebug_getlength(BlockDriverState *bs) | 45 | @@ -XXX,XX +XXX,XX @@ void virtio_scsi_dataplane_setup(VirtIOSCSI *s, Error **errp) |
85 | 46 | s->vq_aio_context[i] = ctx; | |
86 | static int blkdebug_truncate(BlockDriverState *bs, int64_t offset) | ||
87 | { | ||
88 | - return bdrv_truncate(bs->file, offset); | ||
89 | + return bdrv_truncate(bs->file, offset, NULL); | ||
90 | } | ||
91 | |||
92 | static void blkdebug_refresh_filename(BlockDriverState *bs, QDict *options) | ||
93 | diff --git a/block/block-backend.c b/block/block-backend.c | ||
94 | index XXXXXXX..XXXXXXX 100644 | ||
95 | --- a/block/block-backend.c | ||
96 | +++ b/block/block-backend.c | ||
97 | @@ -XXX,XX +XXX,XX @@ int blk_pwrite_compressed(BlockBackend *blk, int64_t offset, const void *buf, | ||
98 | BDRV_REQ_WRITE_COMPRESSED); | ||
99 | } | ||
100 | |||
101 | -int blk_truncate(BlockBackend *blk, int64_t offset) | ||
102 | +int blk_truncate(BlockBackend *blk, int64_t offset, Error **errp) | ||
103 | { | ||
104 | if (!blk_is_available(blk)) { | ||
105 | + error_setg(errp, "No medium inserted"); | ||
106 | return -ENOMEDIUM; | ||
107 | } | ||
108 | |||
109 | - return bdrv_truncate(blk->root, offset); | ||
110 | + return bdrv_truncate(blk->root, offset, errp); | ||
111 | } | ||
112 | |||
113 | static void blk_pdiscard_entry(void *opaque) | ||
114 | diff --git a/block/commit.c b/block/commit.c | ||
115 | index XXXXXXX..XXXXXXX 100644 | ||
116 | --- a/block/commit.c | ||
117 | +++ b/block/commit.c | ||
118 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn commit_run(void *opaque) | ||
119 | } | ||
120 | |||
121 | if (base_len < s->common.len) { | ||
122 | - ret = blk_truncate(s->base, s->common.len); | ||
123 | + ret = blk_truncate(s->base, s->common.len, NULL); | ||
124 | if (ret) { | ||
125 | goto out; | ||
126 | } | ||
127 | @@ -XXX,XX +XXX,XX @@ int bdrv_commit(BlockDriverState *bs) | ||
128 | * grow the backing file image if possible. If not possible, | ||
129 | * we must return an error */ | ||
130 | if (length > backing_length) { | ||
131 | - ret = blk_truncate(backing, length); | ||
132 | + ret = blk_truncate(backing, length, &local_err); | ||
133 | if (ret < 0) { | ||
134 | + error_report_err(local_err); | ||
135 | goto ro_cleanup; | ||
136 | } | 47 | } |
137 | } | 48 | } |
138 | diff --git a/block/crypto.c b/block/crypto.c | 49 | + |
50 | + /* | ||
51 | + * Always handle the ctrl virtqueue in the main loop thread where device | ||
52 | + * resets can be performed. | ||
53 | + */ | ||
54 | + s->vq_aio_context[0] = qemu_get_aio_context(); | ||
55 | } | ||
56 | |||
57 | /* Context: BQL held */ | ||
58 | diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c | ||
139 | index XXXXXXX..XXXXXXX 100644 | 59 | index XXXXXXX..XXXXXXX 100644 |
140 | --- a/block/crypto.c | 60 | --- a/hw/scsi/virtio-scsi.c |
141 | +++ b/block/crypto.c | 61 | +++ b/hw/scsi/virtio-scsi.c |
142 | @@ -XXX,XX +XXX,XX @@ static int block_crypto_truncate(BlockDriverState *bs, int64_t offset) | 62 | @@ -XXX,XX +XXX,XX @@ static void virtio_scsi_cancel_notify(Notifier *notifier, void *data) |
143 | 63 | g_free(n); | |
144 | offset += payload_offset; | ||
145 | |||
146 | - return bdrv_truncate(bs->file, offset); | ||
147 | + return bdrv_truncate(bs->file, offset, NULL); | ||
148 | } | 64 | } |
149 | 65 | ||
150 | static void block_crypto_close(BlockDriverState *bs) | 66 | -static void virtio_scsi_do_one_tmf_bh(VirtIOSCSIReq *req) |
151 | diff --git a/block/mirror.c b/block/mirror.c | 67 | -{ |
152 | index XXXXXXX..XXXXXXX 100644 | 68 | - VirtIOSCSI *s = req->dev; |
153 | --- a/block/mirror.c | 69 | - SCSIDevice *d = virtio_scsi_device_get(s, req->req.tmf.lun); |
154 | +++ b/block/mirror.c | 70 | - BusChild *kid; |
155 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn mirror_run(void *opaque) | 71 | - int target; |
156 | } | 72 | - |
157 | 73 | - switch (req->req.tmf.subtype) { | |
158 | if (s->bdev_length > base_length) { | 74 | - case VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET: |
159 | - ret = blk_truncate(s->target, s->bdev_length); | 75 | - if (!d) { |
160 | + ret = blk_truncate(s->target, s->bdev_length, NULL); | 76 | - req->resp.tmf.response = VIRTIO_SCSI_S_BAD_TARGET; |
161 | if (ret < 0) { | 77 | - goto out; |
162 | goto immediate_exit; | 78 | - } |
163 | } | 79 | - if (d->lun != virtio_scsi_get_lun(req->req.tmf.lun)) { |
164 | diff --git a/block/parallels.c b/block/parallels.c | 80 | - req->resp.tmf.response = VIRTIO_SCSI_S_INCORRECT_LUN; |
165 | index XXXXXXX..XXXXXXX 100644 | 81 | - goto out; |
166 | --- a/block/parallels.c | 82 | - } |
167 | +++ b/block/parallels.c | 83 | - qatomic_inc(&s->resetting); |
168 | @@ -XXX,XX +XXX,XX @@ static int64_t allocate_clusters(BlockDriverState *bs, int64_t sector_num, | 84 | - device_cold_reset(&d->qdev); |
169 | space << BDRV_SECTOR_BITS, 0); | 85 | - qatomic_dec(&s->resetting); |
170 | } else { | 86 | - break; |
171 | ret = bdrv_truncate(bs->file, | 87 | - |
172 | - (s->data_end + space) << BDRV_SECTOR_BITS); | 88 | - case VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET: |
173 | + (s->data_end + space) << BDRV_SECTOR_BITS, | 89 | - target = req->req.tmf.lun[1]; |
174 | + NULL); | 90 | - qatomic_inc(&s->resetting); |
175 | } | 91 | - |
176 | if (ret < 0) { | 92 | - rcu_read_lock(); |
177 | return ret; | 93 | - QTAILQ_FOREACH_RCU(kid, &s->bus.qbus.children, sibling) { |
178 | @@ -XXX,XX +XXX,XX @@ static int parallels_check(BlockDriverState *bs, BdrvCheckResult *res, | 94 | - SCSIDevice *d1 = SCSI_DEVICE(kid->child); |
179 | size - res->image_end_offset); | 95 | - if (d1->channel == 0 && d1->id == target) { |
180 | res->leaks += count; | 96 | - device_cold_reset(&d1->qdev); |
181 | if (fix & BDRV_FIX_LEAKS) { | 97 | - } |
182 | - ret = bdrv_truncate(bs->file, res->image_end_offset); | 98 | - } |
183 | + Error *local_err = NULL; | 99 | - rcu_read_unlock(); |
184 | + ret = bdrv_truncate(bs->file, res->image_end_offset, &local_err); | 100 | - |
185 | if (ret < 0) { | 101 | - qatomic_dec(&s->resetting); |
186 | + error_report_err(local_err); | 102 | - break; |
187 | res->check_errors++; | 103 | - |
188 | return ret; | 104 | - default: |
189 | } | 105 | - g_assert_not_reached(); |
190 | @@ -XXX,XX +XXX,XX @@ static int parallels_create(const char *filename, QemuOpts *opts, Error **errp) | 106 | - } |
191 | 107 | - | |
192 | blk_set_allow_write_beyond_eof(file, true); | 108 | -out: |
193 | 109 | - object_unref(OBJECT(d)); | |
194 | - ret = blk_truncate(file, 0); | 110 | - virtio_scsi_complete_req(req, &s->ctrl_lock); |
195 | + ret = blk_truncate(file, 0, errp); | 111 | -} |
196 | if (ret < 0) { | 112 | - |
197 | goto exit; | 113 | -/* Some TMFs must be processed from the main loop thread */ |
198 | } | 114 | -static void virtio_scsi_do_tmf_bh(void *opaque) |
199 | @@ -XXX,XX +XXX,XX @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags, | 115 | -{ |
200 | } | 116 | - VirtIOSCSI *s = opaque; |
201 | 117 | - QTAILQ_HEAD(, VirtIOSCSIReq) reqs = QTAILQ_HEAD_INITIALIZER(reqs); | |
202 | if (!(flags & BDRV_O_RESIZE) || !bdrv_has_zero_init(bs->file->bs) || | 118 | - VirtIOSCSIReq *req; |
203 | - bdrv_truncate(bs->file, bdrv_getlength(bs->file->bs)) != 0) { | 119 | - VirtIOSCSIReq *tmp; |
204 | + bdrv_truncate(bs->file, bdrv_getlength(bs->file->bs), NULL) != 0) { | 120 | - |
205 | s->prealloc_mode = PRL_PREALLOC_MODE_FALLOCATE; | 121 | - GLOBAL_STATE_CODE(); |
206 | } | 122 | - |
207 | 123 | - WITH_QEMU_LOCK_GUARD(&s->tmf_bh_lock) { | |
208 | @@ -XXX,XX +XXX,XX @@ static void parallels_close(BlockDriverState *bs) | 124 | - QTAILQ_FOREACH_SAFE(req, &s->tmf_bh_list, next, tmp) { |
209 | } | 125 | - QTAILQ_REMOVE(&s->tmf_bh_list, req, next); |
210 | 126 | - QTAILQ_INSERT_TAIL(&reqs, req, next); | |
211 | if (bs->open_flags & BDRV_O_RDWR) { | 127 | - } |
212 | - bdrv_truncate(bs->file, s->data_end << BDRV_SECTOR_BITS); | 128 | - |
213 | + bdrv_truncate(bs->file, s->data_end << BDRV_SECTOR_BITS, NULL); | 129 | - qemu_bh_delete(s->tmf_bh); |
214 | } | 130 | - s->tmf_bh = NULL; |
215 | 131 | - } | |
216 | g_free(s->bat_dirty_bmap); | 132 | - |
217 | diff --git a/block/qcow.c b/block/qcow.c | 133 | - QTAILQ_FOREACH_SAFE(req, &reqs, next, tmp) { |
218 | index XXXXXXX..XXXXXXX 100644 | 134 | - QTAILQ_REMOVE(&reqs, req, next); |
219 | --- a/block/qcow.c | 135 | - virtio_scsi_do_one_tmf_bh(req); |
220 | +++ b/block/qcow.c | 136 | - } |
221 | @@ -XXX,XX +XXX,XX @@ static uint64_t get_cluster_offset(BlockDriverState *bs, | 137 | -} |
222 | /* round to cluster size */ | 138 | - |
223 | cluster_offset = (cluster_offset + s->cluster_size - 1) & | 139 | -static void virtio_scsi_reset_tmf_bh(VirtIOSCSI *s) |
224 | ~(s->cluster_size - 1); | 140 | -{ |
225 | - bdrv_truncate(bs->file, cluster_offset + s->cluster_size); | 141 | - VirtIOSCSIReq *req; |
226 | + bdrv_truncate(bs->file, cluster_offset + s->cluster_size, NULL); | 142 | - VirtIOSCSIReq *tmp; |
227 | /* if encrypted, we must initialize the cluster | 143 | - |
228 | content which won't be written */ | 144 | - GLOBAL_STATE_CODE(); |
229 | if (bs->encrypted && | 145 | - |
230 | @@ -XXX,XX +XXX,XX @@ static int qcow_create(const char *filename, QemuOpts *opts, Error **errp) | 146 | - /* Called after ioeventfd has been stopped, so tmf_bh_lock is not needed */ |
231 | 147 | - if (s->tmf_bh) { | |
232 | blk_set_allow_write_beyond_eof(qcow_blk, true); | 148 | - qemu_bh_delete(s->tmf_bh); |
233 | 149 | - s->tmf_bh = NULL; | |
234 | - ret = blk_truncate(qcow_blk, 0); | 150 | - } |
235 | + ret = blk_truncate(qcow_blk, 0, errp); | 151 | - |
236 | if (ret < 0) { | 152 | - QTAILQ_FOREACH_SAFE(req, &s->tmf_bh_list, next, tmp) { |
237 | goto exit; | 153 | - QTAILQ_REMOVE(&s->tmf_bh_list, req, next); |
238 | } | 154 | - |
239 | @@ -XXX,XX +XXX,XX @@ static int qcow_make_empty(BlockDriverState *bs) | 155 | - /* SAM-6 6.3.2 Hard reset */ |
240 | if (bdrv_pwrite_sync(bs->file, s->l1_table_offset, s->l1_table, | 156 | - req->resp.tmf.response = VIRTIO_SCSI_S_TARGET_FAILURE; |
241 | l1_length) < 0) | 157 | - virtio_scsi_complete_req(req, &req->dev->ctrl_lock); |
242 | return -1; | 158 | - } |
243 | - ret = bdrv_truncate(bs->file, s->l1_table_offset + l1_length); | 159 | -} |
244 | + ret = bdrv_truncate(bs->file, s->l1_table_offset + l1_length, NULL); | 160 | - |
245 | if (ret < 0) | 161 | -static void virtio_scsi_defer_tmf_to_main_loop(VirtIOSCSIReq *req) |
246 | return ret; | 162 | -{ |
247 | 163 | - VirtIOSCSI *s = req->dev; | |
248 | diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c | 164 | - |
249 | index XXXXXXX..XXXXXXX 100644 | 165 | - WITH_QEMU_LOCK_GUARD(&s->tmf_bh_lock) { |
250 | --- a/block/qcow2-refcount.c | 166 | - QTAILQ_INSERT_TAIL(&s->tmf_bh_list, req, next); |
251 | +++ b/block/qcow2-refcount.c | 167 | - |
252 | @@ -XXX,XX +XXX,XX @@ static int check_refblocks(BlockDriverState *bs, BdrvCheckResult *res, | 168 | - if (!s->tmf_bh) { |
253 | 169 | - s->tmf_bh = qemu_bh_new(virtio_scsi_do_tmf_bh, s); | |
254 | if (fix & BDRV_FIX_ERRORS) { | 170 | - qemu_bh_schedule(s->tmf_bh); |
255 | int64_t new_nb_clusters; | 171 | - } |
256 | + Error *local_err = NULL; | 172 | - } |
257 | 173 | -} | |
258 | if (offset > INT64_MAX - s->cluster_size) { | 174 | - |
259 | ret = -EINVAL; | 175 | static void virtio_scsi_tmf_cancel_req(VirtIOSCSIReq *tmf, SCSIRequest *r) |
260 | goto resize_fail; | ||
261 | } | ||
262 | |||
263 | - ret = bdrv_truncate(bs->file, offset + s->cluster_size); | ||
264 | + ret = bdrv_truncate(bs->file, offset + s->cluster_size, | ||
265 | + &local_err); | ||
266 | if (ret < 0) { | ||
267 | + error_report_err(local_err); | ||
268 | goto resize_fail; | ||
269 | } | ||
270 | size = bdrv_getlength(bs->file->bs); | ||
271 | diff --git a/block/qcow2.c b/block/qcow2.c | ||
272 | index XXXXXXX..XXXXXXX 100644 | ||
273 | --- a/block/qcow2.c | ||
274 | +++ b/block/qcow2.c | ||
275 | @@ -XXX,XX +XXX,XX @@ static int qcow2_create2(const char *filename, int64_t total_size, | ||
276 | } | ||
277 | |||
278 | /* Okay, now that we have a valid image, let's give it the right size */ | ||
279 | - ret = blk_truncate(blk, total_size); | ||
280 | + ret = blk_truncate(blk, total_size, errp); | ||
281 | if (ret < 0) { | ||
282 | - error_setg_errno(errp, -ret, "Could not resize image"); | ||
283 | + error_prepend(errp, "Could not resize image: "); | ||
284 | goto out; | ||
285 | } | ||
286 | |||
287 | @@ -XXX,XX +XXX,XX @@ qcow2_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset, | ||
288 | /* align end of file to a sector boundary to ease reading with | ||
289 | sector based I/Os */ | ||
290 | cluster_offset = bdrv_getlength(bs->file->bs); | ||
291 | - return bdrv_truncate(bs->file, cluster_offset); | ||
292 | + return bdrv_truncate(bs->file, cluster_offset, NULL); | ||
293 | } | ||
294 | |||
295 | buf = qemu_blockalign(bs, s->cluster_size); | ||
296 | @@ -XXX,XX +XXX,XX @@ fail: | ||
297 | static int make_completely_empty(BlockDriverState *bs) | ||
298 | { | 176 | { |
299 | BDRVQcow2State *s = bs->opaque; | 177 | VirtIOSCSICancelNotifier *notifier; |
300 | + Error *local_err = NULL; | 178 | @@ -XXX,XX +XXX,XX @@ static int virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req) |
301 | int ret, l1_clusters; | 179 | break; |
302 | int64_t offset; | 180 | |
303 | uint64_t *new_reftable = NULL; | 181 | case VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET: |
304 | @@ -XXX,XX +XXX,XX @@ static int make_completely_empty(BlockDriverState *bs) | 182 | - case VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET: |
305 | goto fail; | 183 | - virtio_scsi_defer_tmf_to_main_loop(req); |
306 | } | 184 | - ret = -EINPROGRESS; |
307 | 185 | + if (!d) { | |
308 | - ret = bdrv_truncate(bs->file, (3 + l1_clusters) * s->cluster_size); | 186 | + goto fail; |
309 | + ret = bdrv_truncate(bs->file, (3 + l1_clusters) * s->cluster_size, | 187 | + } |
310 | + &local_err); | 188 | + if (d->lun != virtio_scsi_get_lun(req->req.tmf.lun)) { |
311 | if (ret < 0) { | 189 | + goto incorrect_lun; |
312 | + error_report_err(local_err); | 190 | + } |
313 | goto fail; | 191 | + qatomic_inc(&s->resetting); |
314 | } | 192 | + device_cold_reset(&d->qdev); |
315 | 193 | + qatomic_dec(&s->resetting); | |
316 | @@ -XXX,XX +XXX,XX @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, | 194 | break; |
317 | return ret; | 195 | |
318 | } | 196 | + case VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET: { |
319 | 197 | + BusChild *kid; | |
320 | - ret = blk_truncate(blk, new_size); | 198 | + int target = req->req.tmf.lun[1]; |
321 | + ret = blk_truncate(blk, new_size, &local_err); | 199 | + qatomic_inc(&s->resetting); |
322 | blk_unref(blk); | 200 | + |
323 | if (ret < 0) { | 201 | + rcu_read_lock(); |
324 | + error_report_err(local_err); | 202 | + QTAILQ_FOREACH_RCU(kid, &s->bus.qbus.children, sibling) { |
325 | return ret; | 203 | + SCSIDevice *d1 = SCSI_DEVICE(kid->child); |
326 | } | 204 | + if (d1->channel == 0 && d1->id == target) { |
327 | } | 205 | + device_cold_reset(&d1->qdev); |
328 | diff --git a/block/qed.c b/block/qed.c | 206 | + } |
329 | index XXXXXXX..XXXXXXX 100644 | 207 | + } |
330 | --- a/block/qed.c | 208 | + rcu_read_unlock(); |
331 | +++ b/block/qed.c | 209 | + |
332 | @@ -XXX,XX +XXX,XX @@ static int qed_create(const char *filename, uint32_t cluster_size, | 210 | + qatomic_dec(&s->resetting); |
333 | blk_set_allow_write_beyond_eof(blk, true); | 211 | + break; |
334 | 212 | + } | |
335 | /* File must start empty and grow, check truncate is supported */ | 213 | + |
336 | - ret = blk_truncate(blk, 0); | 214 | case VIRTIO_SCSI_T_TMF_ABORT_TASK_SET: |
337 | + ret = blk_truncate(blk, 0, errp); | 215 | case VIRTIO_SCSI_T_TMF_CLEAR_TASK_SET: { |
338 | if (ret < 0) { | 216 | g_autoptr(GHashTable) aio_contexts = g_hash_table_new(NULL, NULL); |
339 | goto out; | 217 | @@ -XXX,XX +XXX,XX @@ static void virtio_scsi_reset(VirtIODevice *vdev) |
340 | } | 218 | |
341 | diff --git a/block/raw-format.c b/block/raw-format.c | 219 | assert(!s->dataplane_started); |
342 | index XXXXXXX..XXXXXXX 100644 | 220 | |
343 | --- a/block/raw-format.c | 221 | - virtio_scsi_reset_tmf_bh(s); |
344 | +++ b/block/raw-format.c | 222 | virtio_scsi_flush_defer_tmf_to_aio_context(s); |
345 | @@ -XXX,XX +XXX,XX @@ static int raw_truncate(BlockDriverState *bs, int64_t offset) | 223 | |
346 | 224 | qatomic_inc(&s->resetting); | |
347 | s->size = offset; | 225 | @@ -XXX,XX +XXX,XX @@ static void virtio_scsi_device_realize(DeviceState *dev, Error **errp) |
348 | offset += s->offset; | 226 | VirtIOSCSI *s = VIRTIO_SCSI(dev); |
349 | - return bdrv_truncate(bs->file, offset); | 227 | Error *err = NULL; |
350 | + return bdrv_truncate(bs->file, offset, NULL); | 228 | |
229 | - QTAILQ_INIT(&s->tmf_bh_list); | ||
230 | qemu_mutex_init(&s->ctrl_lock); | ||
231 | qemu_mutex_init(&s->event_lock); | ||
232 | - qemu_mutex_init(&s->tmf_bh_lock); | ||
233 | |||
234 | virtio_scsi_common_realize(dev, | ||
235 | virtio_scsi_handle_ctrl, | ||
236 | @@ -XXX,XX +XXX,XX @@ static void virtio_scsi_device_unrealize(DeviceState *dev) | ||
237 | { | ||
238 | VirtIOSCSI *s = VIRTIO_SCSI(dev); | ||
239 | |||
240 | - virtio_scsi_reset_tmf_bh(s); | ||
241 | virtio_scsi_dataplane_cleanup(s); | ||
242 | qbus_set_hotplug_handler(BUS(&s->bus), NULL); | ||
243 | virtio_scsi_common_unrealize(dev); | ||
244 | - qemu_mutex_destroy(&s->tmf_bh_lock); | ||
245 | qemu_mutex_destroy(&s->event_lock); | ||
246 | qemu_mutex_destroy(&s->ctrl_lock); | ||
351 | } | 247 | } |
352 | |||
353 | static int raw_media_changed(BlockDriverState *bs) | ||
354 | diff --git a/block/vdi.c b/block/vdi.c | ||
355 | index XXXXXXX..XXXXXXX 100644 | ||
356 | --- a/block/vdi.c | ||
357 | +++ b/block/vdi.c | ||
358 | @@ -XXX,XX +XXX,XX @@ static int vdi_create(const char *filename, QemuOpts *opts, Error **errp) | ||
359 | } | ||
360 | |||
361 | if (image_type == VDI_TYPE_STATIC) { | ||
362 | - ret = blk_truncate(blk, offset + blocks * block_size); | ||
363 | + ret = blk_truncate(blk, offset + blocks * block_size, errp); | ||
364 | if (ret < 0) { | ||
365 | - error_setg(errp, "Failed to statically allocate %s", filename); | ||
366 | + error_prepend(errp, "Failed to statically allocate %s", filename); | ||
367 | goto exit; | ||
368 | } | ||
369 | } | ||
370 | diff --git a/block/vhdx-log.c b/block/vhdx-log.c | ||
371 | index XXXXXXX..XXXXXXX 100644 | ||
372 | --- a/block/vhdx-log.c | ||
373 | +++ b/block/vhdx-log.c | ||
374 | @@ -XXX,XX +XXX,XX @@ static int vhdx_log_flush(BlockDriverState *bs, BDRVVHDXState *s, | ||
375 | if (new_file_size % (1024*1024)) { | ||
376 | /* round up to nearest 1MB boundary */ | ||
377 | new_file_size = ((new_file_size >> 20) + 1) << 20; | ||
378 | - bdrv_truncate(bs->file, new_file_size); | ||
379 | + bdrv_truncate(bs->file, new_file_size, NULL); | ||
380 | } | ||
381 | } | ||
382 | qemu_vfree(desc_entries); | ||
383 | diff --git a/block/vhdx.c b/block/vhdx.c | ||
384 | index XXXXXXX..XXXXXXX 100644 | ||
385 | --- a/block/vhdx.c | ||
386 | +++ b/block/vhdx.c | ||
387 | @@ -XXX,XX +XXX,XX @@ static int vhdx_allocate_block(BlockDriverState *bs, BDRVVHDXState *s, | ||
388 | /* per the spec, the address for a block is in units of 1MB */ | ||
389 | *new_offset = ROUND_UP(*new_offset, 1024 * 1024); | ||
390 | |||
391 | - return bdrv_truncate(bs->file, *new_offset + s->block_size); | ||
392 | + return bdrv_truncate(bs->file, *new_offset + s->block_size, NULL); | ||
393 | } | ||
394 | |||
395 | /* | ||
396 | @@ -XXX,XX +XXX,XX @@ static int vhdx_create_bat(BlockBackend *blk, BDRVVHDXState *s, | ||
397 | if (type == VHDX_TYPE_DYNAMIC) { | ||
398 | /* All zeroes, so we can just extend the file - the end of the BAT | ||
399 | * is the furthest thing we have written yet */ | ||
400 | - ret = blk_truncate(blk, data_file_offset); | ||
401 | + ret = blk_truncate(blk, data_file_offset, errp); | ||
402 | if (ret < 0) { | ||
403 | - error_setg_errno(errp, -ret, | ||
404 | - "Failed to resize the underlying file"); | ||
405 | goto exit; | ||
406 | } | ||
407 | } else if (type == VHDX_TYPE_FIXED) { | ||
408 | - ret = blk_truncate(blk, data_file_offset + image_size); | ||
409 | + ret = blk_truncate(blk, data_file_offset + image_size, errp); | ||
410 | if (ret < 0) { | ||
411 | - error_setg_errno(errp, -ret, | ||
412 | - "Failed to resize the underlying file"); | ||
413 | goto exit; | ||
414 | } | ||
415 | } else { | ||
416 | diff --git a/block/vmdk.c b/block/vmdk.c | ||
417 | index XXXXXXX..XXXXXXX 100644 | ||
418 | --- a/block/vmdk.c | ||
419 | +++ b/block/vmdk.c | ||
420 | @@ -XXX,XX +XXX,XX @@ static int vmdk_create_extent(const char *filename, int64_t filesize, | ||
421 | blk_set_allow_write_beyond_eof(blk, true); | ||
422 | |||
423 | if (flat) { | ||
424 | - ret = blk_truncate(blk, filesize); | ||
425 | - if (ret < 0) { | ||
426 | - error_setg_errno(errp, -ret, "Could not truncate file"); | ||
427 | - } | ||
428 | + ret = blk_truncate(blk, filesize, errp); | ||
429 | goto exit; | ||
430 | } | ||
431 | magic = cpu_to_be32(VMDK4_MAGIC); | ||
432 | @@ -XXX,XX +XXX,XX @@ static int vmdk_create_extent(const char *filename, int64_t filesize, | ||
433 | goto exit; | ||
434 | } | ||
435 | |||
436 | - ret = blk_truncate(blk, le64_to_cpu(header.grain_offset) << 9); | ||
437 | + ret = blk_truncate(blk, le64_to_cpu(header.grain_offset) << 9, errp); | ||
438 | if (ret < 0) { | ||
439 | - error_setg_errno(errp, -ret, "Could not truncate file"); | ||
440 | goto exit; | ||
441 | } | ||
442 | |||
443 | @@ -XXX,XX +XXX,XX @@ static int vmdk_create(const char *filename, QemuOpts *opts, Error **errp) | ||
444 | /* bdrv_pwrite write padding zeros to align to sector, we don't need that | ||
445 | * for description file */ | ||
446 | if (desc_offset == 0) { | ||
447 | - ret = blk_truncate(new_blk, desc_len); | ||
448 | - if (ret < 0) { | ||
449 | - error_setg_errno(errp, -ret, "Could not truncate file"); | ||
450 | - } | ||
451 | + ret = blk_truncate(new_blk, desc_len, errp); | ||
452 | } | ||
453 | exit: | ||
454 | if (new_blk) { | ||
455 | diff --git a/block/vpc.c b/block/vpc.c | ||
456 | index XXXXXXX..XXXXXXX 100644 | ||
457 | --- a/block/vpc.c | ||
458 | +++ b/block/vpc.c | ||
459 | @@ -XXX,XX +XXX,XX @@ static int create_dynamic_disk(BlockBackend *blk, uint8_t *buf, | ||
460 | } | ||
461 | |||
462 | static int create_fixed_disk(BlockBackend *blk, uint8_t *buf, | ||
463 | - int64_t total_size) | ||
464 | + int64_t total_size, Error **errp) | ||
465 | { | ||
466 | int ret; | ||
467 | |||
468 | /* Add footer to total size */ | ||
469 | total_size += HEADER_SIZE; | ||
470 | |||
471 | - ret = blk_truncate(blk, total_size); | ||
472 | + ret = blk_truncate(blk, total_size, errp); | ||
473 | if (ret < 0) { | ||
474 | return ret; | ||
475 | } | ||
476 | |||
477 | ret = blk_pwrite(blk, total_size - HEADER_SIZE, buf, HEADER_SIZE, 0); | ||
478 | if (ret < 0) { | ||
479 | + error_setg_errno(errp, -ret, "Unable to write VHD header"); | ||
480 | return ret; | ||
481 | } | ||
482 | |||
483 | @@ -XXX,XX +XXX,XX @@ static int vpc_create(const char *filename, QemuOpts *opts, Error **errp) | ||
484 | |||
485 | if (disk_type == VHD_DYNAMIC) { | ||
486 | ret = create_dynamic_disk(blk, buf, total_sectors); | ||
487 | + if (ret < 0) { | ||
488 | + error_setg(errp, "Unable to create or write VHD header"); | ||
489 | + } | ||
490 | } else { | ||
491 | - ret = create_fixed_disk(blk, buf, total_size); | ||
492 | - } | ||
493 | - if (ret < 0) { | ||
494 | - error_setg(errp, "Unable to create or write VHD header"); | ||
495 | + ret = create_fixed_disk(blk, buf, total_size, errp); | ||
496 | } | ||
497 | |||
498 | out: | ||
499 | diff --git a/blockdev.c b/blockdev.c | ||
500 | index XXXXXXX..XXXXXXX 100644 | ||
501 | --- a/blockdev.c | ||
502 | +++ b/blockdev.c | ||
503 | @@ -XXX,XX +XXX,XX @@ void qmp_block_resize(bool has_device, const char *device, | ||
504 | /* complete all in-flight operations before resizing the device */ | ||
505 | bdrv_drain_all(); | ||
506 | |||
507 | - ret = blk_truncate(blk, size); | ||
508 | - switch (ret) { | ||
509 | - case 0: | ||
510 | - break; | ||
511 | - case -ENOMEDIUM: | ||
512 | - error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, device); | ||
513 | - break; | ||
514 | - case -ENOTSUP: | ||
515 | - error_setg(errp, QERR_UNSUPPORTED); | ||
516 | - break; | ||
517 | - case -EACCES: | ||
518 | - error_setg(errp, "Device '%s' is read only", device); | ||
519 | - break; | ||
520 | - case -EBUSY: | ||
521 | - error_setg(errp, QERR_DEVICE_IN_USE, device); | ||
522 | - break; | ||
523 | - default: | ||
524 | - error_setg_errno(errp, -ret, "Could not resize"); | ||
525 | - break; | ||
526 | - } | ||
527 | + ret = blk_truncate(blk, size, errp); | ||
528 | |||
529 | out: | ||
530 | blk_unref(blk); | ||
531 | diff --git a/include/block/block.h b/include/block/block.h | ||
532 | index XXXXXXX..XXXXXXX 100644 | ||
533 | --- a/include/block/block.h | ||
534 | +++ b/include/block/block.h | ||
535 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs, | ||
536 | const char *backing_file); | ||
537 | int bdrv_get_backing_file_depth(BlockDriverState *bs); | ||
538 | void bdrv_refresh_filename(BlockDriverState *bs); | ||
539 | -int bdrv_truncate(BdrvChild *child, int64_t offset); | ||
540 | +int bdrv_truncate(BdrvChild *child, int64_t offset, Error **errp); | ||
541 | int64_t bdrv_nb_sectors(BlockDriverState *bs); | ||
542 | int64_t bdrv_getlength(BlockDriverState *bs); | ||
543 | int64_t bdrv_get_allocated_file_size(BlockDriverState *bs); | ||
544 | diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h | ||
545 | index XXXXXXX..XXXXXXX 100644 | ||
546 | --- a/include/sysemu/block-backend.h | ||
547 | +++ b/include/sysemu/block-backend.h | ||
548 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn blk_co_pwrite_zeroes(BlockBackend *blk, int64_t offset, | ||
549 | int count, BdrvRequestFlags flags); | ||
550 | int blk_pwrite_compressed(BlockBackend *blk, int64_t offset, const void *buf, | ||
551 | int count); | ||
552 | -int blk_truncate(BlockBackend *blk, int64_t offset); | ||
553 | +int blk_truncate(BlockBackend *blk, int64_t offset, Error **errp); | ||
554 | int blk_pdiscard(BlockBackend *blk, int64_t offset, int count); | ||
555 | int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf, | ||
556 | int64_t pos, int size); | ||
557 | diff --git a/qemu-img.c b/qemu-img.c | ||
558 | index XXXXXXX..XXXXXXX 100644 | ||
559 | --- a/qemu-img.c | ||
560 | +++ b/qemu-img.c | ||
561 | @@ -XXX,XX +XXX,XX @@ static int img_resize(int argc, char **argv) | ||
562 | goto out; | ||
563 | } | ||
564 | |||
565 | - ret = blk_truncate(blk, total_size); | ||
566 | - switch (ret) { | ||
567 | - case 0: | ||
568 | + ret = blk_truncate(blk, total_size, &err); | ||
569 | + if (!ret) { | ||
570 | qprintf(quiet, "Image resized.\n"); | ||
571 | - break; | ||
572 | - case -ENOTSUP: | ||
573 | - error_report("This image does not support resize"); | ||
574 | - break; | ||
575 | - case -EACCES: | ||
576 | - error_report("Image is read-only"); | ||
577 | - break; | ||
578 | - default: | ||
579 | - error_report("Error resizing image: %s", strerror(-ret)); | ||
580 | - break; | ||
581 | + } else { | ||
582 | + error_report_err(err); | ||
583 | } | ||
584 | out: | ||
585 | blk_unref(blk); | ||
586 | diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c | ||
587 | index XXXXXXX..XXXXXXX 100644 | ||
588 | --- a/qemu-io-cmds.c | ||
589 | +++ b/qemu-io-cmds.c | ||
590 | @@ -XXX,XX +XXX,XX @@ static const cmdinfo_t flush_cmd = { | ||
591 | |||
592 | static int truncate_f(BlockBackend *blk, int argc, char **argv) | ||
593 | { | ||
594 | + Error *local_err = NULL; | ||
595 | int64_t offset; | ||
596 | int ret; | ||
597 | |||
598 | @@ -XXX,XX +XXX,XX @@ static int truncate_f(BlockBackend *blk, int argc, char **argv) | ||
599 | return 0; | ||
600 | } | ||
601 | |||
602 | - ret = blk_truncate(blk, offset); | ||
603 | + ret = blk_truncate(blk, offset, &local_err); | ||
604 | if (ret < 0) { | ||
605 | - printf("truncate: %s\n", strerror(-ret)); | ||
606 | + error_report_err(local_err); | ||
607 | return 0; | ||
608 | } | ||
609 | |||
610 | -- | 248 | -- |
611 | 1.8.3.1 | 249 | 2.48.1 |
612 | |||
613 | diff view generated by jsdifflib |
1 | From: Peter Lieven <pl@kamp.de> | 1 | From: Stefan Hajnoczi <stefanha@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | img_convert has been around before there was an ImgConvertState or | 3 | Peter Krempa and Kevin Wolf observed that iothread-vq-mapping is |
4 | a block backend, but it has never been modified to directly use | 4 | confusing to use because the control and event virtqueues have a fixed |
5 | these structs. Change this by parsing parameters directly into | 5 | location before the command virtqueues but need to be treated |
6 | the ImgConvertState and directly use BlockBackend where possible. | 6 | differently. |
7 | Furthermore variable initialization has been reworked and sorted. | ||
8 | 7 | ||
9 | Signed-off-by: Peter Lieven <pl@kamp.de> | 8 | Only expose the command virtqueues via iothread-vq-mapping so that the |
10 | Reviewed-by: Eric Blake <eblake@redhat.com> | 9 | command-line parameter is intuitive: it controls where SCSI requests are |
10 | processed. | ||
11 | |||
12 | The control virtqueue needs to be hardcoded to the main loop thread for | ||
13 | technical reasons anyway. Kevin also pointed out that it's better to | ||
14 | place the event virtqueue in the main loop thread since its no poll | ||
15 | behavior would prevent polling if assigned to an IOThread. | ||
16 | |||
17 | This change is its own commit to avoid squashing the previous commit. | ||
18 | |||
19 | Suggested-by: Kevin Wolf <kwolf@redhat.com> | ||
20 | Suggested-by: Peter Krempa <pkrempa@redhat.com> | ||
21 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
22 | Message-ID: <20250311132616.1049687-14-stefanha@redhat.com> | ||
11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 23 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
12 | --- | 24 | --- |
13 | qemu-img.c | 201 +++++++++++++++++++++++++------------------------------------ | 25 | hw/scsi/virtio-scsi-dataplane.c | 33 ++++++++++++++++++++------------- |
14 | 1 file changed, 81 insertions(+), 120 deletions(-) | 26 | 1 file changed, 20 insertions(+), 13 deletions(-) |
15 | 27 | ||
16 | diff --git a/qemu-img.c b/qemu-img.c | 28 | diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c |
17 | index XXXXXXX..XXXXXXX 100644 | 29 | index XXXXXXX..XXXXXXX 100644 |
18 | --- a/qemu-img.c | 30 | --- a/hw/scsi/virtio-scsi-dataplane.c |
19 | +++ b/qemu-img.c | 31 | +++ b/hw/scsi/virtio-scsi-dataplane.c |
20 | @@ -XXX,XX +XXX,XX @@ typedef struct ImgConvertState { | 32 | @@ -XXX,XX +XXX,XX @@ void virtio_scsi_dataplane_setup(VirtIOSCSI *s, Error **errp) |
21 | int min_sparse; | 33 | VirtIODevice *vdev = VIRTIO_DEVICE(s); |
22 | size_t cluster_sectors; | 34 | BusState *qbus = qdev_get_parent_bus(DEVICE(vdev)); |
23 | size_t buf_sectors; | 35 | VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); |
24 | - int num_coroutines; | 36 | - uint16_t num_vqs = vs->conf.num_queues + VIRTIO_SCSI_VQ_NUM_FIXED; |
25 | + long num_coroutines; | 37 | |
26 | int running_coroutines; | 38 | if (vs->conf.iothread && vs->conf.iothread_vq_mapping_list) { |
27 | Coroutine *co[MAX_COROUTINES]; | 39 | error_setg(errp, |
28 | int64_t wait_sector_num[MAX_COROUTINES]; | 40 | @@ -XXX,XX +XXX,XX @@ void virtio_scsi_dataplane_setup(VirtIOSCSI *s, Error **errp) |
29 | @@ -XXX,XX +XXX,XX @@ static int convert_do_copy(ImgConvertState *s) | ||
30 | |||
31 | static int img_convert(int argc, char **argv) | ||
32 | { | ||
33 | - int c, bs_n, bs_i, compress, cluster_sectors, skip_create; | ||
34 | - int64_t ret = 0; | ||
35 | - int progress = 0, flags, src_flags; | ||
36 | - bool writethrough, src_writethrough; | ||
37 | - const char *fmt, *out_fmt, *cache, *src_cache, *out_baseimg, *out_filename; | ||
38 | + int c, bs_i, flags, src_flags = 0; | ||
39 | + const char *fmt = NULL, *out_fmt = "raw", *cache = "unsafe", | ||
40 | + *src_cache = BDRV_DEFAULT_CACHE, *out_baseimg = NULL, | ||
41 | + *out_filename, *out_baseimg_param, *snapshot_name = NULL; | ||
42 | BlockDriver *drv, *proto_drv; | ||
43 | - BlockBackend **blk = NULL, *out_blk = NULL; | ||
44 | - BlockDriverState **bs = NULL, *out_bs = NULL; | ||
45 | - int64_t total_sectors; | ||
46 | - int64_t *bs_sectors = NULL; | ||
47 | - size_t bufsectors = IO_BUF_SIZE / BDRV_SECTOR_SIZE; | ||
48 | BlockDriverInfo bdi; | ||
49 | - QemuOpts *opts = NULL; | ||
50 | + BlockDriverState *out_bs; | ||
51 | + QemuOpts *opts = NULL, *sn_opts = NULL; | ||
52 | QemuOptsList *create_opts = NULL; | ||
53 | - const char *out_baseimg_param; | ||
54 | char *options = NULL; | ||
55 | - const char *snapshot_name = NULL; | ||
56 | - int min_sparse = 8; /* Need at least 4k of zeros for sparse detection */ | ||
57 | - bool quiet = false; | ||
58 | Error *local_err = NULL; | ||
59 | - QemuOpts *sn_opts = NULL; | ||
60 | - ImgConvertState state; | ||
61 | - bool image_opts = false; | ||
62 | - bool wr_in_order = true; | ||
63 | - long num_coroutines = 8; | ||
64 | + bool writethrough, src_writethrough, quiet = false, image_opts = false, | ||
65 | + skip_create = false, progress = false; | ||
66 | + int64_t ret = -EINVAL; | ||
67 | + | ||
68 | + ImgConvertState s = (ImgConvertState) { | ||
69 | + /* Need at least 4k of zeros for sparse detection */ | ||
70 | + .min_sparse = 8, | ||
71 | + .buf_sectors = IO_BUF_SIZE / BDRV_SECTOR_SIZE, | ||
72 | + .wr_in_order = true, | ||
73 | + .num_coroutines = 8, | ||
74 | + }; | ||
75 | |||
76 | - fmt = NULL; | ||
77 | - out_fmt = "raw"; | ||
78 | - cache = "unsafe"; | ||
79 | - src_cache = BDRV_DEFAULT_CACHE; | ||
80 | - out_baseimg = NULL; | ||
81 | - compress = 0; | ||
82 | - skip_create = 0; | ||
83 | for(;;) { | ||
84 | static const struct option long_options[] = { | ||
85 | {"help", no_argument, 0, 'h'}, | ||
86 | @@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv) | ||
87 | out_baseimg = optarg; | ||
88 | break; | ||
89 | case 'c': | ||
90 | - compress = 1; | ||
91 | + s.compressed = true; | ||
92 | break; | ||
93 | case 'e': | ||
94 | error_report("option -e is deprecated, please use \'-o " | ||
95 | "encryption\' instead!"); | ||
96 | - ret = -1; | ||
97 | goto fail_getopt; | ||
98 | case '6': | ||
99 | error_report("option -6 is deprecated, please use \'-o " | ||
100 | "compat6\' instead!"); | ||
101 | - ret = -1; | ||
102 | goto fail_getopt; | ||
103 | case 'o': | ||
104 | if (!is_valid_option_list(optarg)) { | ||
105 | error_report("Invalid option list: %s", optarg); | ||
106 | - ret = -1; | ||
107 | goto fail_getopt; | ||
108 | } | ||
109 | if (!options) { | ||
110 | @@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv) | ||
111 | if (!sn_opts) { | ||
112 | error_report("Failed in parsing snapshot param '%s'", | ||
113 | optarg); | ||
114 | - ret = -1; | ||
115 | goto fail_getopt; | ||
116 | } | ||
117 | } else { | ||
118 | @@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv) | ||
119 | sval = cvtnum(optarg); | ||
120 | if (sval < 0) { | ||
121 | error_report("Invalid minimum zero buffer size for sparse output specified"); | ||
122 | - ret = -1; | ||
123 | goto fail_getopt; | ||
124 | } | ||
125 | |||
126 | - min_sparse = sval / BDRV_SECTOR_SIZE; | ||
127 | + s.min_sparse = sval / BDRV_SECTOR_SIZE; | ||
128 | break; | ||
129 | } | ||
130 | case 'p': | ||
131 | - progress = 1; | ||
132 | + progress = true; | ||
133 | break; | ||
134 | case 't': | ||
135 | cache = optarg; | ||
136 | @@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv) | ||
137 | quiet = true; | ||
138 | break; | ||
139 | case 'n': | ||
140 | - skip_create = 1; | ||
141 | + skip_create = true; | ||
142 | break; | ||
143 | case 'm': | ||
144 | - if (qemu_strtol(optarg, NULL, 0, &num_coroutines) || | ||
145 | - num_coroutines < 1 || num_coroutines > MAX_COROUTINES) { | ||
146 | + if (qemu_strtol(optarg, NULL, 0, &s.num_coroutines) || | ||
147 | + s.num_coroutines < 1 || s.num_coroutines > MAX_COROUTINES) { | ||
148 | error_report("Invalid number of coroutines. Allowed number of" | ||
149 | " coroutines is between 1 and %d", MAX_COROUTINES); | ||
150 | - ret = -1; | ||
151 | goto fail_getopt; | ||
152 | } | ||
153 | break; | ||
154 | case 'W': | ||
155 | - wr_in_order = false; | ||
156 | + s.wr_in_order = false; | ||
157 | break; | ||
158 | case OPTION_OBJECT: | ||
159 | opts = qemu_opts_parse_noisily(&qemu_object_opts, | ||
160 | @@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv) | ||
161 | goto fail_getopt; | ||
162 | } | ||
163 | |||
164 | - if (!wr_in_order && compress) { | ||
165 | + if (!s.wr_in_order && s.compressed) { | ||
166 | error_report("Out of order write and compress are mutually exclusive"); | ||
167 | - ret = -1; | ||
168 | goto fail_getopt; | ||
169 | } | ||
170 | |||
171 | - /* Initialize before goto out */ | ||
172 | - if (quiet) { | ||
173 | - progress = 0; | ||
174 | - } | ||
175 | - qemu_progress_init(progress, 1.0); | ||
176 | - | ||
177 | - bs_n = argc - optind - 1; | ||
178 | - out_filename = bs_n >= 1 ? argv[argc - 1] : NULL; | ||
179 | + s.src_num = argc - optind - 1; | ||
180 | + out_filename = s.src_num >= 1 ? argv[argc - 1] : NULL; | ||
181 | |||
182 | if (options && has_help_option(options)) { | ||
183 | ret = print_block_option_help(out_filename, out_fmt); | ||
184 | - goto out; | ||
185 | + goto fail_getopt; | ||
186 | } | ||
187 | |||
188 | - if (bs_n < 1) { | ||
189 | - error_exit("Must specify image file name"); | ||
190 | + if (s.src_num < 1) { | ||
191 | + error_report("Must specify image file name"); | ||
192 | + goto fail_getopt; | ||
193 | } | ||
194 | |||
195 | |||
196 | - if (bs_n > 1 && out_baseimg) { | ||
197 | + if (s.src_num > 1 && out_baseimg) { | ||
198 | error_report("-B makes no sense when concatenating multiple input " | ||
199 | "images"); | ||
200 | - ret = -1; | ||
201 | - goto out; | ||
202 | + goto fail_getopt; | ||
203 | } | ||
204 | |||
205 | - src_flags = 0; | ||
206 | + /* ret is still -EINVAL until here */ | ||
207 | ret = bdrv_parse_cache_mode(src_cache, &src_flags, &src_writethrough); | ||
208 | if (ret < 0) { | ||
209 | error_report("Invalid source cache option: %s", src_cache); | ||
210 | - goto out; | ||
211 | + goto fail_getopt; | ||
212 | } | ||
213 | |||
214 | + /* Initialize before goto out */ | ||
215 | + if (quiet) { | ||
216 | + progress = false; | ||
217 | + } | ||
218 | + qemu_progress_init(progress, 1.0); | ||
219 | qemu_progress_print(0, 100); | ||
220 | |||
221 | - blk = g_new0(BlockBackend *, bs_n); | ||
222 | - bs = g_new0(BlockDriverState *, bs_n); | ||
223 | - bs_sectors = g_new(int64_t, bs_n); | ||
224 | + s.src = g_new0(BlockBackend *, s.src_num); | ||
225 | + s.src_sectors = g_new(int64_t, s.src_num); | ||
226 | |||
227 | - total_sectors = 0; | ||
228 | - for (bs_i = 0; bs_i < bs_n; bs_i++) { | ||
229 | - blk[bs_i] = img_open(image_opts, argv[optind + bs_i], | ||
230 | - fmt, src_flags, src_writethrough, quiet); | ||
231 | - if (!blk[bs_i]) { | ||
232 | + for (bs_i = 0; bs_i < s.src_num; bs_i++) { | ||
233 | + s.src[bs_i] = img_open(image_opts, argv[optind + bs_i], | ||
234 | + fmt, src_flags, src_writethrough, quiet); | ||
235 | + if (!s.src[bs_i]) { | ||
236 | ret = -1; | ||
237 | goto out; | ||
238 | } | ||
239 | - bs[bs_i] = blk_bs(blk[bs_i]); | ||
240 | - bs_sectors[bs_i] = blk_nb_sectors(blk[bs_i]); | ||
241 | - if (bs_sectors[bs_i] < 0) { | ||
242 | + s.src_sectors[bs_i] = blk_nb_sectors(s.src[bs_i]); | ||
243 | + if (s.src_sectors[bs_i] < 0) { | ||
244 | error_report("Could not get size of %s: %s", | ||
245 | - argv[optind + bs_i], strerror(-bs_sectors[bs_i])); | ||
246 | + argv[optind + bs_i], strerror(-s.src_sectors[bs_i])); | ||
247 | ret = -1; | ||
248 | goto out; | ||
249 | } | ||
250 | - total_sectors += bs_sectors[bs_i]; | ||
251 | + s.total_sectors += s.src_sectors[bs_i]; | ||
252 | } | ||
253 | |||
254 | if (sn_opts) { | ||
255 | - bdrv_snapshot_load_tmp(bs[0], | ||
256 | + bdrv_snapshot_load_tmp(blk_bs(s.src[0]), | ||
257 | qemu_opt_get(sn_opts, SNAPSHOT_OPT_ID), | ||
258 | qemu_opt_get(sn_opts, SNAPSHOT_OPT_NAME), | ||
259 | &local_err); | ||
260 | } else if (snapshot_name != NULL) { | ||
261 | - if (bs_n > 1) { | ||
262 | + if (s.src_num > 1) { | ||
263 | error_report("No support for concatenating multiple snapshot"); | ||
264 | ret = -1; | ||
265 | goto out; | ||
266 | } | ||
267 | |||
268 | - bdrv_snapshot_load_tmp_by_id_or_name(bs[0], snapshot_name, &local_err); | ||
269 | + bdrv_snapshot_load_tmp_by_id_or_name(blk_bs(s.src[0]), snapshot_name, | ||
270 | + &local_err); | ||
271 | } | ||
272 | if (local_err) { | ||
273 | error_reportf_err(local_err, "Failed to load snapshot: "); | ||
274 | @@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv) | ||
275 | } | ||
276 | } | ||
277 | |||
278 | - qemu_opt_set_number(opts, BLOCK_OPT_SIZE, total_sectors * 512, | ||
279 | + qemu_opt_set_number(opts, BLOCK_OPT_SIZE, s.total_sectors * 512, | ||
280 | &error_abort); | ||
281 | ret = add_old_style_options(out_fmt, opts, out_baseimg, NULL); | ||
282 | if (ret < 0) { | ||
283 | @@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv) | ||
284 | if (out_baseimg_param) { | ||
285 | out_baseimg = out_baseimg_param; | ||
286 | } | ||
287 | + s.target_has_backing = (bool) out_baseimg; | ||
288 | |||
289 | /* Check if compression is supported */ | ||
290 | - if (compress) { | ||
291 | + if (s.compressed) { | ||
292 | bool encryption = | ||
293 | qemu_opt_get_bool(opts, BLOCK_OPT_ENCRYPT, false); | ||
294 | const char *preallocation = | ||
295 | @@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv) | ||
296 | } | 41 | } |
297 | } | 42 | } |
298 | 43 | ||
299 | - flags = min_sparse ? (BDRV_O_RDWR | BDRV_O_UNMAP) : BDRV_O_RDWR; | 44 | - s->vq_aio_context = g_new(AioContext *, num_vqs); |
300 | + flags = s.min_sparse ? (BDRV_O_RDWR | BDRV_O_UNMAP) : BDRV_O_RDWR; | 45 | + s->vq_aio_context = g_new(AioContext *, vs->conf.num_queues + |
301 | ret = bdrv_parse_cache_mode(cache, &flags, &writethrough); | 46 | + VIRTIO_SCSI_VQ_NUM_FIXED); |
302 | if (ret < 0) { | 47 | + |
303 | error_report("Invalid cache option: %s", cache); | 48 | + /* |
304 | @@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv) | 49 | + * Handle the ctrl virtqueue in the main loop thread where device resets |
305 | * the bdrv_create() call which takes different params. | 50 | + * can be performed. |
306 | * Not critical right now, so fix can wait... | 51 | + */ |
307 | */ | 52 | + s->vq_aio_context[0] = qemu_get_aio_context(); |
308 | - out_blk = img_open_file(out_filename, out_fmt, flags, writethrough, quiet); | 53 | + |
309 | - if (!out_blk) { | 54 | + /* |
310 | + s.target = img_open_file(out_filename, out_fmt, flags, writethrough, quiet); | 55 | + * Handle the event virtqueue in the main loop thread where its no_poll |
311 | + if (!s.target) { | 56 | + * behavior won't stop IOThread polling. |
312 | ret = -1; | 57 | + */ |
313 | goto out; | 58 | + s->vq_aio_context[1] = qemu_get_aio_context(); |
314 | } | 59 | |
315 | - out_bs = blk_bs(out_blk); | 60 | if (vs->conf.iothread_vq_mapping_list) { |
316 | + out_bs = blk_bs(s.target); | 61 | if (!iothread_vq_mapping_apply(vs->conf.iothread_vq_mapping_list, |
317 | 62 | - s->vq_aio_context, num_vqs, errp)) { | |
318 | /* increase bufsectors from the default 4096 (2M) if opt_transfer | 63 | + &s->vq_aio_context[VIRTIO_SCSI_VQ_NUM_FIXED], |
319 | * or discard_alignment of the out_bs is greater. Limit to 32768 (16MB) | 64 | + vs->conf.num_queues, errp)) { |
320 | * as maximum. */ | 65 | g_free(s->vq_aio_context); |
321 | - bufsectors = MIN(32768, | 66 | s->vq_aio_context = NULL; |
322 | - MAX(bufsectors, | 67 | return; |
323 | - MAX(out_bs->bl.opt_transfer >> BDRV_SECTOR_BITS, | 68 | } |
324 | - out_bs->bl.pdiscard_alignment >> | 69 | } else if (vs->conf.iothread) { |
325 | - BDRV_SECTOR_BITS))); | 70 | AioContext *ctx = iothread_get_aio_context(vs->conf.iothread); |
326 | + s.buf_sectors = MIN(32768, | 71 | - for (uint16_t i = 0; i < num_vqs; i++) { |
327 | + MAX(s.buf_sectors, | 72 | - s->vq_aio_context[i] = ctx; |
328 | + MAX(out_bs->bl.opt_transfer >> BDRV_SECTOR_BITS, | 73 | + for (uint16_t i = 0; i < vs->conf.num_queues; i++) { |
329 | + out_bs->bl.pdiscard_alignment >> | 74 | + s->vq_aio_context[VIRTIO_SCSI_VQ_NUM_FIXED + i] = ctx; |
330 | + BDRV_SECTOR_BITS))); | 75 | } |
331 | 76 | ||
332 | if (skip_create) { | 77 | /* Released in virtio_scsi_dataplane_cleanup() */ |
333 | - int64_t output_sectors = blk_nb_sectors(out_blk); | 78 | object_ref(OBJECT(vs->conf.iothread)); |
334 | + int64_t output_sectors = blk_nb_sectors(s.target); | 79 | } else { |
335 | if (output_sectors < 0) { | 80 | AioContext *ctx = qemu_get_aio_context(); |
336 | error_report("unable to get output image length: %s", | 81 | - for (unsigned i = 0; i < num_vqs; i++) { |
337 | strerror(-output_sectors)); | 82 | - s->vq_aio_context[i] = ctx; |
338 | ret = -1; | 83 | + for (unsigned i = 0; i < vs->conf.num_queues; i++) { |
339 | goto out; | 84 | + s->vq_aio_context[VIRTIO_SCSI_VQ_NUM_FIXED + i] = ctx; |
340 | - } else if (output_sectors < total_sectors) { | ||
341 | + } else if (output_sectors < s.total_sectors) { | ||
342 | error_report("output file is smaller than input file"); | ||
343 | ret = -1; | ||
344 | goto out; | ||
345 | } | 85 | } |
346 | } | 86 | } |
347 | |||
348 | - cluster_sectors = 0; | ||
349 | ret = bdrv_get_info(out_bs, &bdi); | ||
350 | if (ret < 0) { | ||
351 | - if (compress) { | ||
352 | + if (s.compressed) { | ||
353 | error_report("could not get block driver info"); | ||
354 | goto out; | ||
355 | } | ||
356 | } else { | ||
357 | - compress = compress || bdi.needs_compressed_writes; | ||
358 | - cluster_sectors = bdi.cluster_size / BDRV_SECTOR_SIZE; | ||
359 | - } | ||
360 | - | 87 | - |
361 | - state = (ImgConvertState) { | 88 | - /* |
362 | - .src = blk, | 89 | - * Always handle the ctrl virtqueue in the main loop thread where device |
363 | - .src_sectors = bs_sectors, | 90 | - * resets can be performed. |
364 | - .src_num = bs_n, | 91 | - */ |
365 | - .total_sectors = total_sectors, | 92 | - s->vq_aio_context[0] = qemu_get_aio_context(); |
366 | - .target = out_blk, | ||
367 | - .compressed = compress, | ||
368 | - .target_has_backing = (bool) out_baseimg, | ||
369 | - .min_sparse = min_sparse, | ||
370 | - .cluster_sectors = cluster_sectors, | ||
371 | - .buf_sectors = bufsectors, | ||
372 | - .wr_in_order = wr_in_order, | ||
373 | - .num_coroutines = num_coroutines, | ||
374 | - }; | ||
375 | - ret = convert_do_copy(&state); | ||
376 | + s.compressed = s.compressed || bdi.needs_compressed_writes; | ||
377 | + s.cluster_sectors = bdi.cluster_size / BDRV_SECTOR_SIZE; | ||
378 | + } | ||
379 | |||
380 | + ret = convert_do_copy(&s); | ||
381 | out: | ||
382 | if (!ret) { | ||
383 | qemu_progress_print(100, 0); | ||
384 | @@ -XXX,XX +XXX,XX @@ out: | ||
385 | qemu_opts_del(opts); | ||
386 | qemu_opts_free(create_opts); | ||
387 | qemu_opts_del(sn_opts); | ||
388 | - blk_unref(out_blk); | ||
389 | - g_free(bs); | ||
390 | - if (blk) { | ||
391 | - for (bs_i = 0; bs_i < bs_n; bs_i++) { | ||
392 | - blk_unref(blk[bs_i]); | ||
393 | + blk_unref(s.target); | ||
394 | + if (s.src) { | ||
395 | + for (bs_i = 0; bs_i < s.src_num; bs_i++) { | ||
396 | + blk_unref(s.src[bs_i]); | ||
397 | } | ||
398 | - g_free(blk); | ||
399 | + g_free(s.src); | ||
400 | } | ||
401 | - g_free(bs_sectors); | ||
402 | + g_free(s.src_sectors); | ||
403 | fail_getopt: | ||
404 | g_free(options); | ||
405 | |||
406 | - if (ret) { | ||
407 | - return 1; | ||
408 | - } | ||
409 | - return 0; | ||
410 | + return !!ret; | ||
411 | } | 93 | } |
412 | 94 | ||
413 | 95 | /* Context: BQL held */ | |
414 | -- | 96 | -- |
415 | 1.8.3.1 | 97 | 2.48.1 |
416 | |||
417 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Max Reitz <mreitz@redhat.com> | ||
2 | 1 | ||
3 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
4 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
5 | Reviewed-by: Fam Zheng <famz@redhat.com> | ||
6 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
7 | --- | ||
8 | tests/qemu-iotests/051 | 1 + | ||
9 | tests/qemu-iotests/051.out | 3 +++ | ||
10 | tests/qemu-iotests/051.pc.out | 3 +++ | ||
11 | 3 files changed, 7 insertions(+) | ||
12 | |||
13 | diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051 | ||
14 | index XXXXXXX..XXXXXXX 100755 | ||
15 | --- a/tests/qemu-iotests/051 | ||
16 | +++ b/tests/qemu-iotests/051 | ||
17 | @@ -XXX,XX +XXX,XX @@ echo === Leaving out required options === | ||
18 | echo | ||
19 | |||
20 | run_qemu -drive driver=file | ||
21 | +run_qemu -drive driver=file,filename= | ||
22 | run_qemu -drive driver=nbd | ||
23 | run_qemu -drive driver=raw | ||
24 | run_qemu -drive file.driver=file | ||
25 | diff --git a/tests/qemu-iotests/051.out b/tests/qemu-iotests/051.out | ||
26 | index XXXXXXX..XXXXXXX 100644 | ||
27 | --- a/tests/qemu-iotests/051.out | ||
28 | +++ b/tests/qemu-iotests/051.out | ||
29 | @@ -XXX,XX +XXX,XX @@ QEMU X.Y.Z monitor - type 'help' for more information | ||
30 | Testing: -drive driver=file | ||
31 | QEMU_PROG: -drive driver=file: The 'file' block driver requires a file name | ||
32 | |||
33 | +Testing: -drive driver=file,filename= | ||
34 | +QEMU_PROG: -drive driver=file,filename=: The 'file' block driver requires a file name | ||
35 | + | ||
36 | Testing: -drive driver=nbd | ||
37 | QEMU_PROG: -drive driver=nbd: NBD server address missing | ||
38 | |||
39 | diff --git a/tests/qemu-iotests/051.pc.out b/tests/qemu-iotests/051.pc.out | ||
40 | index XXXXXXX..XXXXXXX 100644 | ||
41 | --- a/tests/qemu-iotests/051.pc.out | ||
42 | +++ b/tests/qemu-iotests/051.pc.out | ||
43 | @@ -XXX,XX +XXX,XX @@ QEMU X.Y.Z monitor - type 'help' for more information | ||
44 | Testing: -drive driver=file | ||
45 | QEMU_PROG: -drive driver=file: The 'file' block driver requires a file name | ||
46 | |||
47 | +Testing: -drive driver=file,filename= | ||
48 | +QEMU_PROG: -drive driver=file,filename=: The 'file' block driver requires a file name | ||
49 | + | ||
50 | Testing: -drive driver=nbd | ||
51 | QEMU_PROG: -drive driver=nbd: NBD server address missing | ||
52 | |||
53 | -- | ||
54 | 1.8.3.1 | ||
55 | |||
56 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | We test for the presence of perl and bc and save their path in the | ||
2 | variables PERL_PROG and BC_PROG, but never actually make use of them. | ||
3 | Remove the checks and assignments so qemu-iotests can run even when | ||
4 | bc isn't installed. | ||
5 | 1 | ||
6 | Reported-by: Yash Mankad <ymankad@redhat.com> | ||
7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
8 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
9 | Reviewed-by: Fam Zheng <famz@redhat.com> | ||
10 | --- | ||
11 | tests/qemu-iotests/common.config | 6 ------ | ||
12 | 1 file changed, 6 deletions(-) | ||
13 | |||
14 | diff --git a/tests/qemu-iotests/common.config b/tests/qemu-iotests/common.config | ||
15 | index XXXXXXX..XXXXXXX 100644 | ||
16 | --- a/tests/qemu-iotests/common.config | ||
17 | +++ b/tests/qemu-iotests/common.config | ||
18 | @@ -XXX,XX +XXX,XX @@ _fatal() | ||
19 | exit 1 | ||
20 | } | ||
21 | |||
22 | -export PERL_PROG="`set_prog_path perl`" | ||
23 | -[ "$PERL_PROG" = "" ] && _fatal "perl not found" | ||
24 | - | ||
25 | export AWK_PROG="`set_prog_path awk`" | ||
26 | [ "$AWK_PROG" = "" ] && _fatal "awk not found" | ||
27 | |||
28 | export SED_PROG="`set_prog_path sed`" | ||
29 | [ "$SED_PROG" = "" ] && _fatal "sed not found" | ||
30 | |||
31 | -export BC_PROG="`set_prog_path bc`" | ||
32 | -[ "$BC_PROG" = "" ] && _fatal "bc not found" | ||
33 | - | ||
34 | export PS_ALL_FLAGS="-ef" | ||
35 | |||
36 | if [ -z "$QEMU_PROG" ]; then | ||
37 | -- | ||
38 | 1.8.3.1 | ||
39 | |||
40 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | It is unused. | ||
2 | 1 | ||
3 | Suggested-by: Fam Zheng <famz@redhat.com> | ||
4 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
5 | Reviewed-by: Max Reitz <mreitz@redhat.com> | ||
6 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
7 | Reviewed-by: Fam Zheng <famz@redhat.com> | ||
8 | --- | ||
9 | tests/qemu-iotests/common.config | 18 ------------------ | ||
10 | 1 file changed, 18 deletions(-) | ||
11 | |||
12 | diff --git a/tests/qemu-iotests/common.config b/tests/qemu-iotests/common.config | ||
13 | index XXXXXXX..XXXXXXX 100644 | ||
14 | --- a/tests/qemu-iotests/common.config | ||
15 | +++ b/tests/qemu-iotests/common.config | ||
16 | @@ -XXX,XX +XXX,XX @@ fi | ||
17 | |||
18 | export SAMPLE_IMG_DIR | ||
19 | |||
20 | -_readlink() | ||
21 | -{ | ||
22 | - if [ $# -ne 1 ]; then | ||
23 | - echo "Usage: _readlink filename" 1>&2 | ||
24 | - exit 1 | ||
25 | - fi | ||
26 | - | ||
27 | - perl -e "\$in=\"$1\";" -e ' | ||
28 | - $lnk = readlink($in); | ||
29 | - if ($lnk =~ m!^/.*!) { | ||
30 | - print "$lnk\n"; | ||
31 | - } | ||
32 | - else { | ||
33 | - chomp($dir = `dirname $in`); | ||
34 | - print "$dir/$lnk\n"; | ||
35 | - }' | ||
36 | -} | ||
37 | - | ||
38 | # make sure this script returns success | ||
39 | true | ||
40 | -- | ||
41 | 1.8.3.1 | ||
42 | |||
43 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Max Reitz <mreitz@redhat.com> | ||
2 | 1 | ||
3 | There is no reason for the qemu-nbd server used for tests not to accept | ||
4 | an arbitrary number of clients. In fact, test 181 will require it to | ||
5 | accept two clients at the same time (and thus it fails before this | ||
6 | patch). | ||
7 | |||
8 | This patch updates common.rc to launch qemu-nbd with -e 42 which should | ||
9 | be enough for all of our current and future tests. | ||
10 | |||
11 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
12 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
13 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
14 | --- | ||
15 | tests/qemu-iotests/common.rc | 4 +++- | ||
16 | 1 file changed, 3 insertions(+), 1 deletion(-) | ||
17 | |||
18 | diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc | ||
19 | index XXXXXXX..XXXXXXX 100644 | ||
20 | --- a/tests/qemu-iotests/common.rc | ||
21 | +++ b/tests/qemu-iotests/common.rc | ||
22 | @@ -XXX,XX +XXX,XX @@ _make_test_img() | ||
23 | |||
24 | # Start an NBD server on the image file, which is what we'll be talking to | ||
25 | if [ $IMGPROTO = "nbd" ]; then | ||
26 | - eval "$QEMU_NBD -v -t -b 127.0.0.1 -p 10810 -f $IMGFMT $TEST_IMG_FILE >/dev/null &" | ||
27 | + # Pass a sufficiently high number to -e that should be enough for all | ||
28 | + # tests | ||
29 | + eval "$QEMU_NBD -v -t -b 127.0.0.1 -p 10810 -f $IMGFMT -e 42 $TEST_IMG_FILE >/dev/null &" | ||
30 | sleep 1 # FIXME: qemu-nbd needs to be listening before we continue | ||
31 | fi | ||
32 | |||
33 | -- | ||
34 | 1.8.3.1 | ||
35 | |||
36 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Eric Blake <eblake@redhat.com> | ||
2 | 1 | ||
3 | s/refcout/refcount/ | ||
4 | |||
5 | CC: qemu-trivial@nongnu.org | ||
6 | Signed-off-by: Eric Blake <eblake@redhat.com> | ||
7 | Reviewed-by: Laurent Vivier <lvivier@redhat.com> | ||
8 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
9 | --- | ||
10 | tests/qemu-iotests/026 | 2 +- | ||
11 | tests/qemu-iotests/026.out | 2 +- | ||
12 | tests/qemu-iotests/026.out.nocache | 2 +- | ||
13 | 3 files changed, 3 insertions(+), 3 deletions(-) | ||
14 | |||
15 | diff --git a/tests/qemu-iotests/026 b/tests/qemu-iotests/026 | ||
16 | index XXXXXXX..XXXXXXX 100755 | ||
17 | --- a/tests/qemu-iotests/026 | ||
18 | +++ b/tests/qemu-iotests/026 | ||
19 | @@ -XXX,XX +XXX,XX @@ done | ||
20 | |||
21 | |||
22 | echo | ||
23 | -echo === Refcout table growth tests === | ||
24 | +echo === Refcount table growth tests === | ||
25 | echo | ||
26 | CLUSTER_SIZE=512 | ||
27 | |||
28 | diff --git a/tests/qemu-iotests/026.out b/tests/qemu-iotests/026.out | ||
29 | index XXXXXXX..XXXXXXX 100644 | ||
30 | --- a/tests/qemu-iotests/026.out | ||
31 | +++ b/tests/qemu-iotests/026.out | ||
32 | @@ -XXX,XX +XXX,XX @@ Event: cluster_alloc; errno: 28; imm: off; once: off; write -b | ||
33 | write failed: No space left on device | ||
34 | No errors were found on the image. | ||
35 | |||
36 | -=== Refcout table growth tests === | ||
37 | +=== Refcount table growth tests === | ||
38 | |||
39 | Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 | ||
40 | |||
41 | diff --git a/tests/qemu-iotests/026.out.nocache b/tests/qemu-iotests/026.out.nocache | ||
42 | index XXXXXXX..XXXXXXX 100644 | ||
43 | --- a/tests/qemu-iotests/026.out.nocache | ||
44 | +++ b/tests/qemu-iotests/026.out.nocache | ||
45 | @@ -XXX,XX +XXX,XX @@ Event: cluster_alloc; errno: 28; imm: off; once: off; write -b | ||
46 | write failed: No space left on device | ||
47 | No errors were found on the image. | ||
48 | |||
49 | -=== Refcout table growth tests === | ||
50 | +=== Refcount table growth tests === | ||
51 | |||
52 | Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 | ||
53 | |||
54 | -- | ||
55 | 1.8.3.1 | ||
56 | |||
57 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Max Reitz <mreitz@redhat.com> | ||
2 | 1 | ||
3 | This patch makes vhdx_create() always set errp in case of an error. It | ||
4 | also adds errp parameters to vhdx_create_bat() and | ||
5 | vhdx_create_new_region_table() so we can pass on the error object | ||
6 | generated by blk_truncate() as of a future commit. | ||
7 | |||
8 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
9 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
10 | Message-id: 20170328205129.15138-2-mreitz@redhat.com | ||
11 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
12 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
13 | --- | ||
14 | block/vhdx.c | 23 +++++++++++++++++++---- | ||
15 | 1 file changed, 19 insertions(+), 4 deletions(-) | ||
16 | |||
17 | diff --git a/block/vhdx.c b/block/vhdx.c | ||
18 | index XXXXXXX..XXXXXXX 100644 | ||
19 | --- a/block/vhdx.c | ||
20 | +++ b/block/vhdx.c | ||
21 | @@ -XXX,XX +XXX,XX @@ exit: | ||
22 | static int vhdx_create_bat(BlockBackend *blk, BDRVVHDXState *s, | ||
23 | uint64_t image_size, VHDXImageType type, | ||
24 | bool use_zero_blocks, uint64_t file_offset, | ||
25 | - uint32_t length) | ||
26 | + uint32_t length, Error **errp) | ||
27 | { | ||
28 | int ret = 0; | ||
29 | uint64_t data_file_offset; | ||
30 | @@ -XXX,XX +XXX,XX @@ static int vhdx_create_bat(BlockBackend *blk, BDRVVHDXState *s, | ||
31 | * is the furthest thing we have written yet */ | ||
32 | ret = blk_truncate(blk, data_file_offset); | ||
33 | if (ret < 0) { | ||
34 | + error_setg_errno(errp, -ret, | ||
35 | + "Failed to resize the underlying file"); | ||
36 | goto exit; | ||
37 | } | ||
38 | } else if (type == VHDX_TYPE_FIXED) { | ||
39 | ret = blk_truncate(blk, data_file_offset + image_size); | ||
40 | if (ret < 0) { | ||
41 | + error_setg_errno(errp, -ret, | ||
42 | + "Failed to resize the underlying file"); | ||
43 | goto exit; | ||
44 | } | ||
45 | } else { | ||
46 | + error_setg(errp, "Unsupported image type"); | ||
47 | ret = -ENOTSUP; | ||
48 | goto exit; | ||
49 | } | ||
50 | @@ -XXX,XX +XXX,XX @@ static int vhdx_create_bat(BlockBackend *blk, BDRVVHDXState *s, | ||
51 | /* for a fixed file, the default BAT entry is not zero */ | ||
52 | s->bat = g_try_malloc0(length); | ||
53 | if (length && s->bat == NULL) { | ||
54 | + error_setg(errp, "Failed to allocate memory for the BAT"); | ||
55 | ret = -ENOMEM; | ||
56 | goto exit; | ||
57 | } | ||
58 | @@ -XXX,XX +XXX,XX @@ static int vhdx_create_bat(BlockBackend *blk, BDRVVHDXState *s, | ||
59 | } | ||
60 | ret = blk_pwrite(blk, file_offset, s->bat, length, 0); | ||
61 | if (ret < 0) { | ||
62 | + error_setg_errno(errp, -ret, "Failed to write the BAT"); | ||
63 | goto exit; | ||
64 | } | ||
65 | } | ||
66 | @@ -XXX,XX +XXX,XX @@ static int vhdx_create_new_region_table(BlockBackend *blk, | ||
67 | uint32_t log_size, | ||
68 | bool use_zero_blocks, | ||
69 | VHDXImageType type, | ||
70 | - uint64_t *metadata_offset) | ||
71 | + uint64_t *metadata_offset, | ||
72 | + Error **errp) | ||
73 | { | ||
74 | int ret = 0; | ||
75 | uint32_t offset = 0; | ||
76 | @@ -XXX,XX +XXX,XX @@ static int vhdx_create_new_region_table(BlockBackend *blk, | ||
77 | /* The region table gives us the data we need to create the BAT, | ||
78 | * so do that now */ | ||
79 | ret = vhdx_create_bat(blk, s, image_size, type, use_zero_blocks, | ||
80 | - bat_file_offset, bat_length); | ||
81 | + bat_file_offset, bat_length, errp); | ||
82 | if (ret < 0) { | ||
83 | goto exit; | ||
84 | } | ||
85 | @@ -XXX,XX +XXX,XX @@ static int vhdx_create_new_region_table(BlockBackend *blk, | ||
86 | ret = blk_pwrite(blk, VHDX_REGION_TABLE_OFFSET, buffer, | ||
87 | VHDX_HEADER_BLOCK_SIZE, 0); | ||
88 | if (ret < 0) { | ||
89 | + error_setg_errno(errp, -ret, "Failed to write first region table"); | ||
90 | goto exit; | ||
91 | } | ||
92 | |||
93 | ret = blk_pwrite(blk, VHDX_REGION_TABLE2_OFFSET, buffer, | ||
94 | VHDX_HEADER_BLOCK_SIZE, 0); | ||
95 | if (ret < 0) { | ||
96 | + error_setg_errno(errp, -ret, "Failed to write second region table"); | ||
97 | goto exit; | ||
98 | } | ||
99 | |||
100 | @@ -XXX,XX +XXX,XX @@ static int vhdx_create(const char *filename, QemuOpts *opts, Error **errp) | ||
101 | ret = -ENOTSUP; | ||
102 | goto exit; | ||
103 | } else { | ||
104 | + error_setg(errp, "Invalid subformat '%s'", type); | ||
105 | ret = -EINVAL; | ||
106 | goto exit; | ||
107 | } | ||
108 | @@ -XXX,XX +XXX,XX @@ static int vhdx_create(const char *filename, QemuOpts *opts, Error **errp) | ||
109 | ret = blk_pwrite(blk, VHDX_FILE_ID_OFFSET, &signature, sizeof(signature), | ||
110 | 0); | ||
111 | if (ret < 0) { | ||
112 | + error_setg_errno(errp, -ret, "Failed to write file signature"); | ||
113 | goto delete_and_exit; | ||
114 | } | ||
115 | if (creator) { | ||
116 | ret = blk_pwrite(blk, VHDX_FILE_ID_OFFSET + sizeof(signature), | ||
117 | creator, creator_items * sizeof(gunichar2), 0); | ||
118 | if (ret < 0) { | ||
119 | + error_setg_errno(errp, -ret, "Failed to write creator field"); | ||
120 | goto delete_and_exit; | ||
121 | } | ||
122 | } | ||
123 | @@ -XXX,XX +XXX,XX @@ static int vhdx_create(const char *filename, QemuOpts *opts, Error **errp) | ||
124 | /* Creates (B),(C) */ | ||
125 | ret = vhdx_create_new_headers(blk, image_size, log_size); | ||
126 | if (ret < 0) { | ||
127 | + error_setg_errno(errp, -ret, "Failed to write image headers"); | ||
128 | goto delete_and_exit; | ||
129 | } | ||
130 | |||
131 | /* Creates (D),(E),(G) explicitly. (F) created as by-product */ | ||
132 | ret = vhdx_create_new_region_table(blk, image_size, block_size, 512, | ||
133 | log_size, use_zero_blocks, image_type, | ||
134 | - &metadata_offset); | ||
135 | + &metadata_offset, errp); | ||
136 | if (ret < 0) { | ||
137 | goto delete_and_exit; | ||
138 | } | ||
139 | @@ -XXX,XX +XXX,XX @@ static int vhdx_create(const char *filename, QemuOpts *opts, Error **errp) | ||
140 | ret = vhdx_create_new_metadata(blk, image_size, block_size, 512, | ||
141 | metadata_offset, image_type); | ||
142 | if (ret < 0) { | ||
143 | + error_setg_errno(errp, -ret, "Failed to initialize metadata"); | ||
144 | goto delete_and_exit; | ||
145 | } | ||
146 | |||
147 | -- | ||
148 | 1.8.3.1 | ||
149 | |||
150 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Klim Kireev <proffk@virtuozzo.mipt.ru> | ||
2 | 1 | ||
3 | Signed-off-by: Klim Kireev <proffk@virtuozzo.mipt.ru> | ||
4 | Signed-off-by: Denis V. Lunev <den@openvz.org> | ||
5 | CC: Kevin Wolf <kwolf@redhat.com> | ||
6 | CC: Max Reitz <mreitz@redhat.com> | ||
7 | Message-id: 1491405505-31620-2-git-send-email-den@openvz.org | ||
8 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
9 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
10 | --- | ||
11 | include/block/block_int.h | 6 +++--- | ||
12 | 1 file changed, 3 insertions(+), 3 deletions(-) | ||
13 | |||
14 | diff --git a/include/block/block_int.h b/include/block/block_int.h | ||
15 | index XXXXXXX..XXXXXXX 100644 | ||
16 | --- a/include/block/block_int.h | ||
17 | +++ b/include/block/block_int.h | ||
18 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | ||
19 | * Returns 0 for completed check, -errno for internal errors. | ||
20 | * The check results are stored in result. | ||
21 | */ | ||
22 | - int (*bdrv_check)(BlockDriverState* bs, BdrvCheckResult *result, | ||
23 | + int (*bdrv_check)(BlockDriverState *bs, BdrvCheckResult *result, | ||
24 | BdrvCheckMode fix); | ||
25 | |||
26 | int (*bdrv_amend_options)(BlockDriverState *bs, QemuOpts *opts, | ||
27 | @@ -XXX,XX +XXX,XX @@ struct BdrvChildRole { | ||
28 | /* Returns a name that is supposedly more useful for human users than the | ||
29 | * node name for identifying the node in question (in particular, a BB | ||
30 | * name), or NULL if the parent can't provide a better name. */ | ||
31 | - const char* (*get_name)(BdrvChild *child); | ||
32 | + const char *(*get_name)(BdrvChild *child); | ||
33 | |||
34 | /* Returns a malloced string that describes the parent of the child for a | ||
35 | * human reader. This could be a node-name, BlockBackend name, qdev ID or | ||
36 | * QOM path of the device owning the BlockBackend, job type and ID etc. The | ||
37 | * caller is responsible for freeing the memory. */ | ||
38 | - char* (*get_parent_desc)(BdrvChild *child); | ||
39 | + char *(*get_parent_desc)(BdrvChild *child); | ||
40 | |||
41 | /* | ||
42 | * If this pair of functions is implemented, the parent doesn't issue new | ||
43 | -- | ||
44 | 1.8.3.1 | ||
45 | |||
46 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Lidong Chen <lidongchen@tencent.com> | ||
2 | 1 | ||
3 | When the buffer is zero, blk_co_pwrite_zeroes is more effective than | ||
4 | blk_co_pwritev with BDRV_REQ_WRITE_COMPRESSED. This patch can reduce | ||
5 | the time for converting qcow2 images with lots of zero data. | ||
6 | |||
7 | Signed-off-by: Lidong Chen <lidongchen@tencent.com> | ||
8 | Message-id: 1493261907-18734-1-git-send-email-lidongchen@tencent.com | ||
9 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
10 | --- | ||
11 | qemu-img.c | 44 ++++++++++++++------------------------------ | ||
12 | 1 file changed, 14 insertions(+), 30 deletions(-) | ||
13 | |||
14 | diff --git a/qemu-img.c b/qemu-img.c | ||
15 | index XXXXXXX..XXXXXXX 100644 | ||
16 | --- a/qemu-img.c | ||
17 | +++ b/qemu-img.c | ||
18 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn convert_co_write(ImgConvertState *s, int64_t sector_num, | ||
19 | |||
20 | while (nb_sectors > 0) { | ||
21 | int n = nb_sectors; | ||
22 | + BdrvRequestFlags flags = s->compressed ? BDRV_REQ_WRITE_COMPRESSED : 0; | ||
23 | + | ||
24 | switch (status) { | ||
25 | case BLK_BACKING_FILE: | ||
26 | /* If we have a backing file, leave clusters unallocated that are | ||
27 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn convert_co_write(ImgConvertState *s, int64_t sector_num, | ||
28 | break; | ||
29 | |||
30 | case BLK_DATA: | ||
31 | - /* We must always write compressed clusters as a whole, so don't | ||
32 | - * try to find zeroed parts in the buffer. We can only save the | ||
33 | - * write if the buffer is completely zeroed and we're allowed to | ||
34 | - * keep the target sparse. */ | ||
35 | - if (s->compressed) { | ||
36 | - if (s->has_zero_init && s->min_sparse && | ||
37 | - buffer_is_zero(buf, n * BDRV_SECTOR_SIZE)) | ||
38 | - { | ||
39 | - assert(!s->target_has_backing); | ||
40 | - break; | ||
41 | - } | ||
42 | - | ||
43 | - iov.iov_base = buf; | ||
44 | - iov.iov_len = n << BDRV_SECTOR_BITS; | ||
45 | - qemu_iovec_init_external(&qiov, &iov, 1); | ||
46 | - | ||
47 | - ret = blk_co_pwritev(s->target, sector_num << BDRV_SECTOR_BITS, | ||
48 | - n << BDRV_SECTOR_BITS, &qiov, | ||
49 | - BDRV_REQ_WRITE_COMPRESSED); | ||
50 | - if (ret < 0) { | ||
51 | - return ret; | ||
52 | - } | ||
53 | - break; | ||
54 | - } | ||
55 | - | ||
56 | - /* If there is real non-zero data or we're told to keep the target | ||
57 | - * fully allocated (-S 0), we must write it. Otherwise we can treat | ||
58 | - * it as zero sectors. */ | ||
59 | + /* If we're told to keep the target fully allocated (-S 0) or there | ||
60 | + * is real non-zero data, we must write it. Otherwise we can treat | ||
61 | + * it as zero sectors. | ||
62 | + * Compressed clusters need to be written as a whole, so in that | ||
63 | + * case we can only save the write if the buffer is completely | ||
64 | + * zeroed. */ | ||
65 | if (!s->min_sparse || | ||
66 | - is_allocated_sectors_min(buf, n, &n, s->min_sparse)) | ||
67 | + (!s->compressed && | ||
68 | + is_allocated_sectors_min(buf, n, &n, s->min_sparse)) || | ||
69 | + (s->compressed && | ||
70 | + !buffer_is_zero(buf, n * BDRV_SECTOR_SIZE))) | ||
71 | { | ||
72 | iov.iov_base = buf; | ||
73 | iov.iov_len = n << BDRV_SECTOR_BITS; | ||
74 | qemu_iovec_init_external(&qiov, &iov, 1); | ||
75 | |||
76 | ret = blk_co_pwritev(s->target, sector_num << BDRV_SECTOR_BITS, | ||
77 | - n << BDRV_SECTOR_BITS, &qiov, 0); | ||
78 | + n << BDRV_SECTOR_BITS, &qiov, flags); | ||
79 | if (ret < 0) { | ||
80 | return ret; | ||
81 | } | ||
82 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn convert_co_write(ImgConvertState *s, int64_t sector_num, | ||
83 | |||
84 | case BLK_ZERO: | ||
85 | if (s->has_zero_init) { | ||
86 | + assert(!s->target_has_backing); | ||
87 | break; | ||
88 | } | ||
89 | ret = blk_co_pwrite_zeroes(s->target, | ||
90 | -- | ||
91 | 1.8.3.1 | ||
92 | |||
93 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: John Snow <jsnow@redhat.com> | ||
2 | 1 | ||
3 | Split the help text to highlight the groups of options | ||
4 | a little better, carving out a clear "format" and | ||
5 | "protocols" section. | ||
6 | |||
7 | Signed-off-by: John Snow <jsnow@redhat.com> | ||
8 | Message-id: 20170427205100.9505-2-jsnow@redhat.com | ||
9 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
10 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
11 | --- | ||
12 | tests/qemu-iotests/common | 8 ++++++-- | ||
13 | 1 file changed, 6 insertions(+), 2 deletions(-) | ||
14 | |||
15 | diff --git a/tests/qemu-iotests/common b/tests/qemu-iotests/common | ||
16 | index XXXXXXX..XXXXXXX 100644 | ||
17 | --- a/tests/qemu-iotests/common | ||
18 | +++ b/tests/qemu-iotests/common | ||
19 | @@ -XXX,XX +XXX,XX @@ common options | ||
20 | -v verbose | ||
21 | -d debug | ||
22 | |||
23 | -check options | ||
24 | +image format options | ||
25 | -raw test raw (default) | ||
26 | -bochs test bochs | ||
27 | -cloop test cloop | ||
28 | @@ -XXX,XX +XXX,XX @@ check options | ||
29 | -vpc test vpc | ||
30 | -vhdx test vhdx | ||
31 | -vmdk test vmdk | ||
32 | + -luks test luks | ||
33 | + | ||
34 | +image protocol options | ||
35 | -file test file (default) | ||
36 | -rbd test rbd | ||
37 | -sheepdog test sheepdog | ||
38 | -nbd test nbd | ||
39 | -ssh test ssh | ||
40 | -nfs test nfs | ||
41 | - -luks test luks | ||
42 | -vxhs test vxhs | ||
43 | + | ||
44 | +other options | ||
45 | -xdiff graphical mode diff | ||
46 | -nocache use O_DIRECT on backing file | ||
47 | -misalign misalign memory allocations | ||
48 | -- | ||
49 | 1.8.3.1 | ||
50 | |||
51 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: John Snow <jsnow@redhat.com> | ||
2 | 1 | ||
3 | If you are running out-of-tree, the -x option to exclude | ||
4 | a certain iotest is broken. | ||
5 | |||
6 | Replace porcelain usage of ls with a sturdier awk command. | ||
7 | |||
8 | Reviewed-by: Fam Zheng <famz@redhat.com> | ||
9 | Signed-off-by: John Snow <jsnow@redhat.com> | ||
10 | Message-id: 20170427205100.9505-3-jsnow@redhat.com | ||
11 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
12 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
13 | --- | ||
14 | tests/qemu-iotests/common | 3 ++- | ||
15 | 1 file changed, 2 insertions(+), 1 deletion(-) | ||
16 | |||
17 | diff --git a/tests/qemu-iotests/common b/tests/qemu-iotests/common | ||
18 | index XXXXXXX..XXXXXXX 100644 | ||
19 | --- a/tests/qemu-iotests/common | ||
20 | +++ b/tests/qemu-iotests/common | ||
21 | @@ -XXX,XX +XXX,XX @@ s/ .*//p | ||
22 | elif $xgroup | ||
23 | then | ||
24 | # arg after -x | ||
25 | - [ ! -s $tmp.list ] && ls [0-9][0-9][0-9] [0-9][0-9][0-9][0-9] >$tmp.list 2>/dev/null | ||
26 | + # Populate $tmp.list with all tests | ||
27 | + awk '/^[0-9]{3,}/ {print $1}' "${source_iotests}/group" > $tmp.list 2>/dev/null | ||
28 | group_list=`sed -n <"$source_iotests/group" -e 's/$/ /' -e "/^[0-9][0-9][0-9].* $r /"'{ | ||
29 | s/ .*//p | ||
30 | }'` | ||
31 | -- | ||
32 | 1.8.3.1 | ||
33 | |||
34 | diff view generated by jsdifflib |