1 | The following changes since commit ac5f7bf8e208cd7893dbb1a9520559e569a4677c: | 1 | The following changes since commit 005ad32358f12fe9313a4a01918a55e60d4f39e5: |
---|---|---|---|
2 | 2 | ||
3 | Merge tag 'migration-20230424-pull-request' of https://gitlab.com/juan.quintela/qemu into staging (2023-04-24 15:00:39 +0100) | 3 | Merge tag 'pull-tpm-2023-09-12-3' of https://github.com/stefanberger/qemu-tpm into staging (2023-09-13 13:41:57 -0400) |
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 | https://repo.or.cz/qemu/kevin.git tags/for-upstream |
8 | 8 | ||
9 | for you to fetch changes up to 8c1e8fb2e7fc2cbeb57703e143965a4cd3ad301a: | 9 | for you to fetch changes up to 5d96864b73225ee61b0dad7e928f0cddf14270fc: |
10 | 10 | ||
11 | block/monitor: Fix crash when executing HMP commit (2023-04-25 15:11:57 +0200) | 11 | block-coroutine-wrapper: use qemu_get_current_aio_context() (2023-09-15 15:49:14 +0200) |
12 | 12 | ||
13 | ---------------------------------------------------------------- | 13 | ---------------------------------------------------------------- |
14 | Block layer patches | 14 | Block layer patches |
15 | 15 | ||
16 | - Protect BlockBackend.queued_requests with its own lock | 16 | - Graph locking part 4 (node management) |
17 | - Switch to AIO_WAIT_WHILE_UNLOCKED() where possible | 17 | - qemu-img map: report compressed data blocks |
18 | - AioContext removal: LinuxAioState/LuringState/ThreadPool | 18 | - block-backend: process I/O in the current AioContext |
19 | - Add more coroutine_fn annotations, use bdrv/blk_co_* | ||
20 | - Fix crash when execute hmp_commit | ||
21 | 19 | ||
22 | ---------------------------------------------------------------- | 20 | ---------------------------------------------------------------- |
23 | Emanuele Giuseppe Esposito (4): | 21 | Andrey Drobyshev via (2): |
24 | linux-aio: use LinuxAioState from the running thread | 22 | block: add BDRV_BLOCK_COMPRESSED flag for bdrv_block_status() |
25 | io_uring: use LuringState from the running thread | 23 | qemu-img: map: report compressed data blocks |
26 | thread-pool: use ThreadPool from the running thread | ||
27 | thread-pool: avoid passing the pool parameter every time | ||
28 | 24 | ||
29 | Paolo Bonzini (9): | 25 | Kevin Wolf (21): |
30 | vvfat: mark various functions as coroutine_fn | 26 | block: Remove unused BlockReopenQueueEntry.perms_checked |
31 | blkdebug: add missing coroutine_fn annotation | 27 | preallocate: Factor out preallocate_truncate_to_real_size() |
32 | mirror: make mirror_flush a coroutine_fn, do not use co_wrappers | 28 | preallocate: Don't poll during permission updates |
33 | nbd: mark more coroutine_fns, do not use co_wrappers | 29 | block: Take AioContext lock for bdrv_append() more consistently |
34 | 9pfs: mark more coroutine_fns | 30 | block: Introduce bdrv_schedule_unref() |
35 | qemu-pr-helper: mark more coroutine_fns | 31 | block-coroutine-wrapper: Add no_co_wrapper_bdrv_wrlock functions |
36 | tests: mark more coroutine_fns | 32 | block-coroutine-wrapper: Allow arbitrary parameter names |
37 | qcow2: mark various functions as coroutine_fn and GRAPH_RDLOCK | 33 | block: Mark bdrv_replace_child_noperm() GRAPH_WRLOCK |
38 | vmdk: make vmdk_is_cid_valid a coroutine_fn | 34 | block: Mark bdrv_replace_child_tran() GRAPH_WRLOCK |
35 | block: Mark bdrv_attach_child_common() GRAPH_WRLOCK | ||
36 | block: Call transaction callbacks with lock held | ||
37 | block: Mark bdrv_attach_child() GRAPH_WRLOCK | ||
38 | block: Mark bdrv_parent_perms_conflict() and callers GRAPH_RDLOCK | ||
39 | block: Mark bdrv_get_cumulative_perm() and callers GRAPH_RDLOCK | ||
40 | block: Mark bdrv_child_perm() GRAPH_RDLOCK | ||
41 | block: Mark bdrv_parent_cb_change_media() GRAPH_RDLOCK | ||
42 | block: Take graph rdlock in bdrv_drop_intermediate() | ||
43 | block: Take graph rdlock in bdrv_change_aio_context() | ||
44 | block: Mark bdrv_root_unref_child() GRAPH_WRLOCK | ||
45 | block: Mark bdrv_unref_child() GRAPH_WRLOCK | ||
46 | block: Mark bdrv_add/del_child() and caller GRAPH_WRLOCK | ||
39 | 47 | ||
40 | Stefan Hajnoczi (10): | 48 | Stefan Hajnoczi (5): |
41 | block: make BlockBackend->quiesce_counter atomic | 49 | block: remove AIOCBInfo->get_aio_context() |
42 | block: make BlockBackend->disable_request_queuing atomic | 50 | test-bdrv-drain: avoid race with BH in IOThread drain test |
43 | block: protect BlockBackend->queued_requests with a lock | 51 | block-backend: process I/O in the current AioContext |
44 | block: don't acquire AioContext lock in bdrv_drain_all() | 52 | block-backend: process zoned requests in the current AioContext |
45 | block: convert blk_exp_close_all_type() to AIO_WAIT_WHILE_UNLOCKED() | 53 | block-coroutine-wrapper: use qemu_get_current_aio_context() |
46 | block: convert bdrv_graph_wrlock() to AIO_WAIT_WHILE_UNLOCKED() | ||
47 | block: convert bdrv_drain_all_begin() to AIO_WAIT_WHILE_UNLOCKED() | ||
48 | hmp: convert handle_hmp_command() to AIO_WAIT_WHILE_UNLOCKED() | ||
49 | monitor: convert monitor_cleanup() to AIO_WAIT_WHILE_UNLOCKED() | ||
50 | block: add missing coroutine_fn to bdrv_sum_allocated_file_size() | ||
51 | 54 | ||
52 | Wang Liang (1): | 55 | qapi/block-core.json | 6 +- |
53 | block/monitor: Fix crash when executing HMP commit | 56 | include/block/aio.h | 1 - |
54 | 57 | include/block/block-common.h | 7 + | |
55 | Wilfred Mallawa (1): | 58 | include/block/block-global-state.h | 32 +- |
56 | include/block: fixup typos | 59 | include/block/block-io.h | 1 - |
57 | 60 | include/block/block_int-common.h | 34 +- | |
58 | block/qcow2.h | 15 +++++----- | 61 | include/block/block_int-global-state.h | 14 +- |
59 | hw/9pfs/9p.h | 4 +-- | 62 | include/sysemu/block-backend-global-state.h | 4 +- |
60 | include/block/aio-wait.h | 2 +- | 63 | block.c | 348 +++++++--- |
61 | include/block/aio.h | 8 ------ | 64 | block/blklogwrites.c | 4 + |
62 | include/block/block_int-common.h | 2 +- | 65 | block/blkverify.c | 2 + |
63 | include/block/raw-aio.h | 33 +++++++++++++++------- | 66 | block/block-backend.c | 64 +- |
64 | include/block/thread-pool.h | 15 ++++++---- | 67 | block/copy-before-write.c | 10 +- |
65 | include/sysemu/block-backend-io.h | 5 ++++ | 68 | block/crypto.c | 6 +- |
66 | backends/tpm/tpm_backend.c | 4 +-- | 69 | block/graph-lock.c | 26 +- |
67 | block.c | 2 +- | 70 | block/io.c | 23 +- |
68 | block/blkdebug.c | 4 +-- | 71 | block/mirror.c | 8 + |
69 | block/block-backend.c | 45 ++++++++++++++++++------------ | 72 | block/preallocate.c | 133 ++-- |
70 | block/export/export.c | 2 +- | 73 | block/qcow.c | 5 +- |
71 | block/file-posix.c | 45 ++++++++++++------------------ | 74 | block/qcow2.c | 7 +- |
72 | block/file-win32.c | 4 +-- | 75 | block/quorum.c | 23 +- |
73 | block/graph-lock.c | 2 +- | 76 | block/replication.c | 9 + |
74 | block/io.c | 2 +- | 77 | block/snapshot.c | 2 + |
75 | block/io_uring.c | 23 ++++++++++------ | 78 | block/stream.c | 20 +- |
76 | block/linux-aio.c | 29 ++++++++++++-------- | 79 | block/vmdk.c | 15 + |
77 | block/mirror.c | 4 +-- | 80 | blockdev.c | 23 +- |
78 | block/monitor/block-hmp-cmds.c | 10 ++++--- | 81 | blockjob.c | 2 + |
79 | block/qcow2-bitmap.c | 2 +- | 82 | hw/nvme/ctrl.c | 7 - |
80 | block/qcow2-cluster.c | 21 ++++++++------ | 83 | qemu-img.c | 8 +- |
81 | block/qcow2-refcount.c | 8 +++--- | 84 | softmmu/dma-helpers.c | 8 - |
82 | block/qcow2-snapshot.c | 25 +++++++++-------- | 85 | tests/unit/test-bdrv-drain.c | 31 +- |
83 | block/qcow2-threads.c | 3 +- | 86 | tests/unit/test-bdrv-graph-mod.c | 20 + |
84 | block/qcow2.c | 27 +++++++++--------- | 87 | tests/unit/test-block-iothread.c | 3 + |
85 | block/vmdk.c | 2 +- | 88 | util/thread-pool.c | 8 - |
86 | block/vvfat.c | 58 ++++++++++++++++++++------------------- | 89 | scripts/block-coroutine-wrapper.py | 24 +- |
87 | hw/9pfs/codir.c | 6 ++-- | 90 | tests/qemu-iotests/051.pc.out | 6 +- |
88 | hw/9pfs/coth.c | 3 +- | 91 | tests/qemu-iotests/122.out | 84 +-- |
89 | hw/ppc/spapr_nvdimm.c | 6 ++-- | 92 | tests/qemu-iotests/146.out | 780 +++++++++++------------ |
90 | hw/virtio/virtio-pmem.c | 3 +- | 93 | tests/qemu-iotests/154.out | 194 +++--- |
91 | monitor/hmp.c | 2 +- | 94 | tests/qemu-iotests/179.out | 178 +++--- |
92 | monitor/monitor.c | 4 +-- | 95 | tests/qemu-iotests/209.out | 4 +- |
93 | nbd/server.c | 48 ++++++++++++++++---------------- | 96 | tests/qemu-iotests/221.out | 16 +- |
94 | scsi/pr-manager.c | 3 +- | 97 | tests/qemu-iotests/223.out | 60 +- |
95 | scsi/qemu-pr-helper.c | 25 ++++++++--------- | 98 | tests/qemu-iotests/241.out | 10 +- |
96 | tests/unit/test-thread-pool.c | 14 ++++------ | 99 | tests/qemu-iotests/244.out | 24 +- |
97 | util/thread-pool.c | 25 ++++++++--------- | 100 | tests/qemu-iotests/252.out | 10 +- |
98 | 40 files changed, 283 insertions(+), 262 deletions(-) | 101 | tests/qemu-iotests/253.out | 20 +- |
102 | tests/qemu-iotests/274.out | 48 +- | ||
103 | tests/qemu-iotests/tests/nbd-qemu-allocation.out | 16 +- | ||
104 | tests/qemu-iotests/tests/qemu-img-bitmaps.out | 24 +- | ||
105 | 50 files changed, 1376 insertions(+), 1036 deletions(-) | diff view generated by jsdifflib |
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | 1 | This field has been unused since commit 72373e40fbc ('block: |
---|---|---|---|
2 | bdrv_reopen_multiple: refresh permissions on updated graph'). | ||
3 | Remove it. | ||
2 | 4 | ||
3 | Remove usage of aio_context_acquire by always submitting asynchronous | 5 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
4 | AIO to the current thread's LuringState. | 6 | Reviewed-by: Eric Blake <eblake@redhat.com> |
5 | 7 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | |
6 | In order to prevent mistakes from the caller side, avoid passing LuringState | ||
7 | in luring_io_{plug/unplug} and luring_co_submit, and document the functions | ||
8 | to make clear that they work in the current thread's AioContext. | ||
9 | |||
10 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
11 | Message-Id: <20230203131731.851116-3-eesposit@redhat.com> | ||
12 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
13 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | 8 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> |
9 | Message-ID: <20230911094620.45040-2-kwolf@redhat.com> | ||
14 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
15 | --- | 11 | --- |
16 | include/block/aio.h | 4 ---- | 12 | block.c | 1 - |
17 | include/block/raw-aio.h | 15 +++++++++++---- | 13 | 1 file changed, 1 deletion(-) |
18 | block/file-posix.c | 12 ++++-------- | ||
19 | block/io_uring.c | 23 +++++++++++++++-------- | ||
20 | 4 files changed, 30 insertions(+), 24 deletions(-) | ||
21 | 14 | ||
22 | diff --git a/include/block/aio.h b/include/block/aio.h | 15 | diff --git a/block.c b/block.c |
23 | index XXXXXXX..XXXXXXX 100644 | 16 | index XXXXXXX..XXXXXXX 100644 |
24 | --- a/include/block/aio.h | 17 | --- a/block.c |
25 | +++ b/include/block/aio.h | 18 | +++ b/block.c |
26 | @@ -XXX,XX +XXX,XX @@ struct AioContext { | 19 | @@ -XXX,XX +XXX,XX @@ static int bdrv_fill_options(QDict **options, const char *filename, |
27 | struct LinuxAioState *linux_aio; | 20 | |
28 | #endif | 21 | typedef struct BlockReopenQueueEntry { |
29 | #ifdef CONFIG_LINUX_IO_URING | 22 | bool prepared; |
30 | - /* | 23 | - bool perms_checked; |
31 | - * State for Linux io_uring. Uses aio_context_acquire/release for | 24 | BDRVReopenState state; |
32 | - * locking. | 25 | QTAILQ_ENTRY(BlockReopenQueueEntry) entry; |
33 | - */ | 26 | } BlockReopenQueueEntry; |
34 | struct LuringState *linux_io_uring; | ||
35 | |||
36 | /* State for file descriptor monitoring using Linux io_uring */ | ||
37 | diff --git a/include/block/raw-aio.h b/include/block/raw-aio.h | ||
38 | index XXXXXXX..XXXXXXX 100644 | ||
39 | --- a/include/block/raw-aio.h | ||
40 | +++ b/include/block/raw-aio.h | ||
41 | @@ -XXX,XX +XXX,XX @@ void laio_io_unplug(uint64_t dev_max_batch); | ||
42 | typedef struct LuringState LuringState; | ||
43 | LuringState *luring_init(Error **errp); | ||
44 | void luring_cleanup(LuringState *s); | ||
45 | -int coroutine_fn luring_co_submit(BlockDriverState *bs, LuringState *s, int fd, | ||
46 | - uint64_t offset, QEMUIOVector *qiov, int type); | ||
47 | + | ||
48 | +/* luring_co_submit: submit I/O requests in the thread's current AioContext. */ | ||
49 | +int coroutine_fn luring_co_submit(BlockDriverState *bs, int fd, uint64_t offset, | ||
50 | + QEMUIOVector *qiov, int type); | ||
51 | void luring_detach_aio_context(LuringState *s, AioContext *old_context); | ||
52 | void luring_attach_aio_context(LuringState *s, AioContext *new_context); | ||
53 | -void luring_io_plug(BlockDriverState *bs, LuringState *s); | ||
54 | -void luring_io_unplug(BlockDriverState *bs, LuringState *s); | ||
55 | + | ||
56 | +/* | ||
57 | + * luring_io_plug/unplug work in the thread's current AioContext, therefore the | ||
58 | + * caller must ensure that they are paired in the same IOThread. | ||
59 | + */ | ||
60 | +void luring_io_plug(void); | ||
61 | +void luring_io_unplug(void); | ||
62 | #endif | ||
63 | |||
64 | #ifdef _WIN32 | ||
65 | diff --git a/block/file-posix.c b/block/file-posix.c | ||
66 | index XXXXXXX..XXXXXXX 100644 | ||
67 | --- a/block/file-posix.c | ||
68 | +++ b/block/file-posix.c | ||
69 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_prw(BlockDriverState *bs, uint64_t offset, | ||
70 | type |= QEMU_AIO_MISALIGNED; | ||
71 | #ifdef CONFIG_LINUX_IO_URING | ||
72 | } else if (s->use_linux_io_uring) { | ||
73 | - LuringState *aio = aio_get_linux_io_uring(bdrv_get_aio_context(bs)); | ||
74 | assert(qiov->size == bytes); | ||
75 | - return luring_co_submit(bs, aio, s->fd, offset, qiov, type); | ||
76 | + return luring_co_submit(bs, s->fd, offset, qiov, type); | ||
77 | #endif | ||
78 | #ifdef CONFIG_LINUX_AIO | ||
79 | } else if (s->use_linux_aio) { | ||
80 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn raw_co_io_plug(BlockDriverState *bs) | ||
81 | #endif | ||
82 | #ifdef CONFIG_LINUX_IO_URING | ||
83 | if (s->use_linux_io_uring) { | ||
84 | - LuringState *aio = aio_get_linux_io_uring(bdrv_get_aio_context(bs)); | ||
85 | - luring_io_plug(bs, aio); | ||
86 | + luring_io_plug(); | ||
87 | } | ||
88 | #endif | ||
89 | } | ||
90 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn raw_co_io_unplug(BlockDriverState *bs) | ||
91 | #endif | ||
92 | #ifdef CONFIG_LINUX_IO_URING | ||
93 | if (s->use_linux_io_uring) { | ||
94 | - LuringState *aio = aio_get_linux_io_uring(bdrv_get_aio_context(bs)); | ||
95 | - luring_io_unplug(bs, aio); | ||
96 | + luring_io_unplug(); | ||
97 | } | ||
98 | #endif | ||
99 | } | ||
100 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_flush_to_disk(BlockDriverState *bs) | ||
101 | |||
102 | #ifdef CONFIG_LINUX_IO_URING | ||
103 | if (s->use_linux_io_uring) { | ||
104 | - LuringState *aio = aio_get_linux_io_uring(bdrv_get_aio_context(bs)); | ||
105 | - return luring_co_submit(bs, aio, s->fd, 0, NULL, QEMU_AIO_FLUSH); | ||
106 | + return luring_co_submit(bs, s->fd, 0, NULL, QEMU_AIO_FLUSH); | ||
107 | } | ||
108 | #endif | ||
109 | return raw_thread_pool_submit(bs, handle_aiocb_flush, &acb); | ||
110 | diff --git a/block/io_uring.c b/block/io_uring.c | ||
111 | index XXXXXXX..XXXXXXX 100644 | ||
112 | --- a/block/io_uring.c | ||
113 | +++ b/block/io_uring.c | ||
114 | @@ -XXX,XX +XXX,XX @@ | ||
115 | #include "qapi/error.h" | ||
116 | #include "trace.h" | ||
117 | |||
118 | +/* Only used for assertions. */ | ||
119 | +#include "qemu/coroutine_int.h" | ||
120 | + | ||
121 | /* io_uring ring size */ | ||
122 | #define MAX_ENTRIES 128 | ||
123 | |||
124 | @@ -XXX,XX +XXX,XX @@ typedef struct LuringState { | ||
125 | |||
126 | struct io_uring ring; | ||
127 | |||
128 | - /* io queue for submit at batch. Protected by AioContext lock. */ | ||
129 | + /* No locking required, only accessed from AioContext home thread */ | ||
130 | LuringQueue io_q; | ||
131 | |||
132 | - /* I/O completion processing. Only runs in I/O thread. */ | ||
133 | QEMUBH *completion_bh; | ||
134 | } LuringState; | ||
135 | |||
136 | @@ -XXX,XX +XXX,XX @@ end: | ||
137 | * eventually runs later. Coroutines cannot be entered recursively | ||
138 | * so avoid doing that! | ||
139 | */ | ||
140 | + assert(luringcb->co->ctx == s->aio_context); | ||
141 | if (!qemu_coroutine_entered(luringcb->co)) { | ||
142 | aio_co_wake(luringcb->co); | ||
143 | } | ||
144 | @@ -XXX,XX +XXX,XX @@ static int ioq_submit(LuringState *s) | ||
145 | |||
146 | static void luring_process_completions_and_submit(LuringState *s) | ||
147 | { | ||
148 | - aio_context_acquire(s->aio_context); | ||
149 | luring_process_completions(s); | ||
150 | |||
151 | if (!s->io_q.plugged && s->io_q.in_queue > 0) { | ||
152 | ioq_submit(s); | ||
153 | } | ||
154 | - aio_context_release(s->aio_context); | ||
155 | } | ||
156 | |||
157 | static void qemu_luring_completion_bh(void *opaque) | ||
158 | @@ -XXX,XX +XXX,XX @@ static void ioq_init(LuringQueue *io_q) | ||
159 | io_q->blocked = false; | ||
160 | } | ||
161 | |||
162 | -void luring_io_plug(BlockDriverState *bs, LuringState *s) | ||
163 | +void luring_io_plug(void) | ||
164 | { | ||
165 | + AioContext *ctx = qemu_get_current_aio_context(); | ||
166 | + LuringState *s = aio_get_linux_io_uring(ctx); | ||
167 | trace_luring_io_plug(s); | ||
168 | s->io_q.plugged++; | ||
169 | } | ||
170 | |||
171 | -void luring_io_unplug(BlockDriverState *bs, LuringState *s) | ||
172 | +void luring_io_unplug(void) | ||
173 | { | ||
174 | + AioContext *ctx = qemu_get_current_aio_context(); | ||
175 | + LuringState *s = aio_get_linux_io_uring(ctx); | ||
176 | assert(s->io_q.plugged); | ||
177 | trace_luring_io_unplug(s, s->io_q.blocked, s->io_q.plugged, | ||
178 | s->io_q.in_queue, s->io_q.in_flight); | ||
179 | @@ -XXX,XX +XXX,XX @@ static int luring_do_submit(int fd, LuringAIOCB *luringcb, LuringState *s, | ||
180 | return 0; | ||
181 | } | ||
182 | |||
183 | -int coroutine_fn luring_co_submit(BlockDriverState *bs, LuringState *s, int fd, | ||
184 | - uint64_t offset, QEMUIOVector *qiov, int type) | ||
185 | +int coroutine_fn luring_co_submit(BlockDriverState *bs, int fd, uint64_t offset, | ||
186 | + QEMUIOVector *qiov, int type) | ||
187 | { | ||
188 | int ret; | ||
189 | + AioContext *ctx = qemu_get_current_aio_context(); | ||
190 | + LuringState *s = aio_get_linux_io_uring(ctx); | ||
191 | LuringAIOCB luringcb = { | ||
192 | .co = qemu_coroutine_self(), | ||
193 | .ret = -EINPROGRESS, | ||
194 | -- | 27 | -- |
195 | 2.40.0 | 28 | 2.41.0 | diff view generated by jsdifflib |
1 | From: Paolo Bonzini <pbonzini@redhat.com> | 1 | It's essentially the same code in preallocate_check_perm() and |
---|---|---|---|
2 | preallocate_close(), except that the latter ignores errors. | ||
2 | 3 | ||
3 | Functions that can do I/O are prime candidates for being coroutine_fns. Make the | 4 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
4 | change for those that are themselves called only from coroutine_fns. | 5 | Reviewed-by: Eric Blake <eblake@redhat.com> |
5 | 6 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | |
6 | In addition, coroutine_fns should do I/O using bdrv_co_*() functions, for | 7 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> |
7 | which it is required to hold the BlockDriverState graph lock. So also nnotate | 8 | Message-ID: <20230911094620.45040-3-kwolf@redhat.com> |
8 | functions on the I/O path with TSA attributes, making it possible to | ||
9 | switch them to use bdrv_co_*() functions. | ||
10 | |||
11 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> | ||
12 | Message-Id: <20230309084456.304669-2-pbonzini@redhat.com> | ||
13 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
14 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 9 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
15 | --- | 10 | --- |
16 | block/vvfat.c | 58 ++++++++++++++++++++++++++------------------------- | 11 | block/preallocate.c | 48 +++++++++++++++++++++------------------------ |
17 | 1 file changed, 30 insertions(+), 28 deletions(-) | 12 | 1 file changed, 22 insertions(+), 26 deletions(-) |
18 | 13 | ||
19 | diff --git a/block/vvfat.c b/block/vvfat.c | 14 | diff --git a/block/preallocate.c b/block/preallocate.c |
20 | index XXXXXXX..XXXXXXX 100644 | 15 | index XXXXXXX..XXXXXXX 100644 |
21 | --- a/block/vvfat.c | 16 | --- a/block/preallocate.c |
22 | +++ b/block/vvfat.c | 17 | +++ b/block/preallocate.c |
23 | @@ -XXX,XX +XXX,XX @@ static BDRVVVFATState *vvv = NULL; | 18 | @@ -XXX,XX +XXX,XX @@ static int preallocate_open(BlockDriverState *bs, QDict *options, int flags, |
24 | #endif | ||
25 | |||
26 | static int enable_write_target(BlockDriverState *bs, Error **errp); | ||
27 | -static int is_consistent(BDRVVVFATState *s); | ||
28 | +static int coroutine_fn is_consistent(BDRVVVFATState *s); | ||
29 | |||
30 | static QemuOptsList runtime_opts = { | ||
31 | .name = "vvfat", | ||
32 | @@ -XXX,XX +XXX,XX @@ static void print_mapping(const mapping_t* mapping) | ||
33 | } | ||
34 | #endif | ||
35 | |||
36 | -static int vvfat_read(BlockDriverState *bs, int64_t sector_num, | ||
37 | - uint8_t *buf, int nb_sectors) | ||
38 | +static int coroutine_fn GRAPH_RDLOCK | ||
39 | +vvfat_read(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, int nb_sectors) | ||
40 | { | ||
41 | BDRVVVFATState *s = bs->opaque; | ||
42 | int i; | ||
43 | @@ -XXX,XX +XXX,XX @@ static int vvfat_read(BlockDriverState *bs, int64_t sector_num, | ||
44 | DLOG(fprintf(stderr, "sectors %" PRId64 "+%" PRId64 | ||
45 | " allocated\n", sector_num, | ||
46 | n >> BDRV_SECTOR_BITS)); | ||
47 | - if (bdrv_pread(s->qcow, sector_num * BDRV_SECTOR_SIZE, n, | ||
48 | - buf + i * 0x200, 0) < 0) { | ||
49 | + if (bdrv_co_pread(s->qcow, sector_num * BDRV_SECTOR_SIZE, n, | ||
50 | + buf + i * 0x200, 0) < 0) { | ||
51 | return -1; | ||
52 | } | ||
53 | i += (n >> BDRV_SECTOR_BITS) - 1; | ||
54 | @@ -XXX,XX +XXX,XX @@ static int vvfat_read(BlockDriverState *bs, int64_t sector_num, | ||
55 | return 0; | 19 | return 0; |
56 | } | 20 | } |
57 | 21 | ||
58 | -static int coroutine_fn | 22 | -static void preallocate_close(BlockDriverState *bs) |
59 | +static int coroutine_fn GRAPH_RDLOCK | 23 | +static int preallocate_truncate_to_real_size(BlockDriverState *bs, Error **errp) |
60 | vvfat_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
61 | QEMUIOVector *qiov, BdrvRequestFlags flags) | ||
62 | { | 24 | { |
63 | @@ -XXX,XX +XXX,XX @@ static inline uint32_t modified_fat_get(BDRVVVFATState* s, | 25 | - int ret; |
26 | BDRVPreallocateState *s = bs->opaque; | ||
27 | - | ||
28 | - if (s->data_end < 0) { | ||
29 | - return; | ||
30 | - } | ||
31 | + int ret; | ||
32 | |||
33 | if (s->file_end < 0) { | ||
34 | s->file_end = bdrv_getlength(bs->file->bs); | ||
35 | if (s->file_end < 0) { | ||
36 | - return; | ||
37 | + error_setg_errno(errp, -s->file_end, "Failed to get file length"); | ||
38 | + return s->file_end; | ||
39 | } | ||
40 | } | ||
41 | |||
42 | if (s->data_end < s->file_end) { | ||
43 | ret = bdrv_truncate(bs->file, s->data_end, true, PREALLOC_MODE_OFF, 0, | ||
44 | NULL); | ||
45 | - s->file_end = ret < 0 ? ret : s->data_end; | ||
46 | + if (ret < 0) { | ||
47 | + error_setg_errno(errp, -ret, "Failed to drop preallocation"); | ||
48 | + s->file_end = ret; | ||
49 | + return ret; | ||
50 | + } | ||
51 | + s->file_end = s->data_end; | ||
52 | + } | ||
53 | + | ||
54 | + return 0; | ||
55 | +} | ||
56 | + | ||
57 | +static void preallocate_close(BlockDriverState *bs) | ||
58 | +{ | ||
59 | + BDRVPreallocateState *s = bs->opaque; | ||
60 | + | ||
61 | + if (s->data_end >= 0) { | ||
62 | + preallocate_truncate_to_real_size(bs, NULL); | ||
64 | } | 63 | } |
65 | } | 64 | } |
66 | 65 | ||
67 | -static inline bool cluster_was_modified(BDRVVVFATState *s, | 66 | @@ -XXX,XX +XXX,XX @@ static int preallocate_check_perm(BlockDriverState *bs, |
68 | - uint32_t cluster_num) | 67 | * We should truncate in check_perm, as in set_perm bs->file->perm will |
69 | +static inline bool coroutine_fn GRAPH_RDLOCK | 68 | * be already changed, and we should not violate it. |
70 | +cluster_was_modified(BDRVVVFATState *s, uint32_t cluster_num) | 69 | */ |
71 | { | 70 | - if (s->file_end < 0) { |
72 | int was_modified = 0; | 71 | - s->file_end = bdrv_getlength(bs->file->bs); |
73 | int i; | 72 | - if (s->file_end < 0) { |
74 | @@ -XXX,XX +XXX,XX @@ typedef enum { | 73 | - error_setg(errp, "Failed to get file length"); |
75 | * Further, the files/directories handled by this function are | 74 | - return s->file_end; |
76 | * assumed to be *not* deleted (and *only* those). | 75 | - } |
77 | */ | 76 | - } |
78 | -static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s, | 77 | - |
79 | - direntry_t* direntry, const char* path) | 78 | - if (s->data_end < s->file_end) { |
80 | +static uint32_t coroutine_fn GRAPH_RDLOCK | 79 | - int ret = bdrv_truncate(bs->file, s->data_end, true, |
81 | +get_cluster_count_for_direntry(BDRVVVFATState* s, direntry_t* direntry, const char* path) | 80 | - PREALLOC_MODE_OFF, 0, NULL); |
82 | { | 81 | - if (ret < 0) { |
83 | /* | 82 | - error_setg(errp, "Failed to drop preallocation"); |
84 | * This is a little bit tricky: | 83 | - s->file_end = ret; |
85 | @@ -XXX,XX +XXX,XX @@ static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s, | 84 | - return ret; |
86 | if (res) { | 85 | - } |
87 | return -1; | 86 | - s->file_end = s->data_end; |
88 | } | 87 | - } |
89 | - res = bdrv_pwrite(s->qcow, offset * BDRV_SECTOR_SIZE, | 88 | + return preallocate_truncate_to_real_size(bs, errp); |
90 | - BDRV_SECTOR_SIZE, s->cluster_buffer, | 89 | } |
91 | - 0); | 90 | |
92 | + res = bdrv_co_pwrite(s->qcow, offset * BDRV_SECTOR_SIZE, | ||
93 | + BDRV_SECTOR_SIZE, s->cluster_buffer, | ||
94 | + 0); | ||
95 | if (res < 0) { | ||
96 | return -2; | ||
97 | } | ||
98 | @@ -XXX,XX +XXX,XX @@ static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s, | ||
99 | * It returns 0 upon inconsistency or error, and the number of clusters | ||
100 | * used by the directory, its subdirectories and their files. | ||
101 | */ | ||
102 | -static int check_directory_consistency(BDRVVVFATState *s, | ||
103 | - int cluster_num, const char* path) | ||
104 | +static int coroutine_fn GRAPH_RDLOCK | ||
105 | +check_directory_consistency(BDRVVVFATState *s, int cluster_num, const char* path) | ||
106 | { | ||
107 | int ret = 0; | ||
108 | unsigned char* cluster = g_malloc(s->cluster_size); | ||
109 | @@ -XXX,XX +XXX,XX @@ DLOG(fprintf(stderr, "check direntry %d:\n", i); print_direntry(direntries + i)) | ||
110 | } | ||
111 | |||
112 | /* returns 1 on success */ | ||
113 | -static int is_consistent(BDRVVVFATState* s) | ||
114 | +static int coroutine_fn GRAPH_RDLOCK | ||
115 | +is_consistent(BDRVVVFATState* s) | ||
116 | { | ||
117 | int i, check; | ||
118 | int used_clusters_count = 0; | ||
119 | @@ -XXX,XX +XXX,XX @@ static int commit_mappings(BDRVVVFATState* s, | ||
120 | return 0; | 91 | return 0; |
121 | } | ||
122 | |||
123 | -static int commit_direntries(BDRVVVFATState* s, | ||
124 | - int dir_index, int parent_mapping_index) | ||
125 | +static int coroutine_fn GRAPH_RDLOCK | ||
126 | +commit_direntries(BDRVVVFATState* s, int dir_index, int parent_mapping_index) | ||
127 | { | ||
128 | direntry_t* direntry = array_get(&(s->directory), dir_index); | ||
129 | uint32_t first_cluster = dir_index == 0 ? 0 : begin_of_direntry(direntry); | ||
130 | @@ -XXX,XX +XXX,XX @@ static int commit_direntries(BDRVVVFATState* s, | ||
131 | |||
132 | /* commit one file (adjust contents, adjust mapping), | ||
133 | return first_mapping_index */ | ||
134 | -static int commit_one_file(BDRVVVFATState* s, | ||
135 | - int dir_index, uint32_t offset) | ||
136 | +static int coroutine_fn GRAPH_RDLOCK | ||
137 | +commit_one_file(BDRVVVFATState* s, int dir_index, uint32_t offset) | ||
138 | { | ||
139 | direntry_t* direntry = array_get(&(s->directory), dir_index); | ||
140 | uint32_t c = begin_of_direntry(direntry); | ||
141 | @@ -XXX,XX +XXX,XX @@ static int handle_renames_and_mkdirs(BDRVVVFATState* s) | ||
142 | /* | ||
143 | * TODO: make sure that the short name is not matching *another* file | ||
144 | */ | ||
145 | -static int handle_commits(BDRVVVFATState* s) | ||
146 | +static int coroutine_fn GRAPH_RDLOCK handle_commits(BDRVVVFATState* s) | ||
147 | { | ||
148 | int i, fail = 0; | ||
149 | |||
150 | @@ -XXX,XX +XXX,XX @@ static int handle_deletes(BDRVVVFATState* s) | ||
151 | * - recurse direntries from root (using bs->bdrv_pread) | ||
152 | * - delete files corresponding to mappings marked as deleted | ||
153 | */ | ||
154 | -static int do_commit(BDRVVVFATState* s) | ||
155 | +static int coroutine_fn GRAPH_RDLOCK do_commit(BDRVVVFATState* s) | ||
156 | { | ||
157 | int ret = 0; | ||
158 | |||
159 | @@ -XXX,XX +XXX,XX @@ DLOG(checkpoint()); | ||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | -static int try_commit(BDRVVVFATState* s) | ||
164 | +static int coroutine_fn GRAPH_RDLOCK try_commit(BDRVVVFATState* s) | ||
165 | { | ||
166 | vvfat_close_current_file(s); | ||
167 | DLOG(checkpoint()); | ||
168 | @@ -XXX,XX +XXX,XX @@ DLOG(checkpoint()); | ||
169 | return do_commit(s); | ||
170 | } | ||
171 | |||
172 | -static int vvfat_write(BlockDriverState *bs, int64_t sector_num, | ||
173 | - const uint8_t *buf, int nb_sectors) | ||
174 | +static int coroutine_fn GRAPH_RDLOCK | ||
175 | +vvfat_write(BlockDriverState *bs, int64_t sector_num, | ||
176 | + const uint8_t *buf, int nb_sectors) | ||
177 | { | ||
178 | BDRVVVFATState *s = bs->opaque; | ||
179 | int i, ret; | ||
180 | @@ -XXX,XX +XXX,XX @@ DLOG(checkpoint()); | ||
181 | * Use qcow backend. Commit later. | ||
182 | */ | ||
183 | DLOG(fprintf(stderr, "Write to qcow backend: %d + %d\n", (int)sector_num, nb_sectors)); | ||
184 | - ret = bdrv_pwrite(s->qcow, sector_num * BDRV_SECTOR_SIZE, | ||
185 | - nb_sectors * BDRV_SECTOR_SIZE, buf, 0); | ||
186 | + ret = bdrv_co_pwrite(s->qcow, sector_num * BDRV_SECTOR_SIZE, | ||
187 | + nb_sectors * BDRV_SECTOR_SIZE, buf, 0); | ||
188 | if (ret < 0) { | ||
189 | fprintf(stderr, "Error writing to qcow backend\n"); | ||
190 | return ret; | ||
191 | @@ -XXX,XX +XXX,XX @@ DLOG(checkpoint()); | ||
192 | return 0; | ||
193 | } | ||
194 | |||
195 | -static int coroutine_fn | ||
196 | +static int coroutine_fn GRAPH_RDLOCK | ||
197 | vvfat_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
198 | QEMUIOVector *qiov, BdrvRequestFlags flags) | ||
199 | { | ||
200 | -- | 92 | -- |
201 | 2.40.0 | 93 | 2.41.0 | diff view generated by jsdifflib |
1 | From: Paolo Bonzini <pbonzini@redhat.com> | 1 | When the permission related BlockDriver callbacks are called, we are in |
---|---|---|---|
2 | 2 | the middle of an operation traversing the block graph. Polling in such a | |
3 | do_sgio can suspend via the coroutine function thread_pool_submit_co, so it | 3 | place is a very bad idea because the graph could change in unexpected |
4 | has to be coroutine_fn as well---and the same is true of all its direct and | 4 | ways. In the future, callers will also hold the graph lock, which is |
5 | indirect callers. | 5 | likely to turn polling into a deadlock. |
6 | 6 | ||
7 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> | 7 | So we need to get rid of calls to functions like bdrv_getlength() or |
8 | Message-Id: <20230309084456.304669-7-pbonzini@redhat.com> | 8 | bdrv_truncate() there as these functions poll internally. They are |
9 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | 9 | currently used so that when no parent has write/resize permissions on |
10 | the image any more, the preallocate filter drops the extra preallocated | ||
11 | area in the image file and gives up write/resize permissions itself. | ||
12 | |||
13 | In order to achieve this without polling in .bdrv_check_perm, don't | ||
14 | immediately truncate the image, but only schedule a BH to do so. The | ||
15 | filter keeps the write/resize permissions a bit longer now until the BH | ||
16 | has executed. | ||
17 | |||
18 | There is one case in which delaying doesn't work: Reopening the image | ||
19 | read-only. In this case, bs->file will likely be reopened read-only, | ||
20 | too, so keeping write permissions a bit longer on it doesn't work. But | ||
21 | we can already cover this case in preallocate_reopen_prepare() and not | ||
22 | rely on the permission updates for it. | ||
23 | |||
24 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
25 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
26 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
27 | Message-ID: <20230911094620.45040-4-kwolf@redhat.com> | ||
10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 28 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
11 | --- | 29 | --- |
12 | scsi/qemu-pr-helper.c | 22 +++++++++++----------- | 30 | block/preallocate.c | 89 +++++++++++++++++++++++++++++++++++---------- |
13 | 1 file changed, 11 insertions(+), 11 deletions(-) | 31 | 1 file changed, 69 insertions(+), 20 deletions(-) |
14 | 32 | ||
15 | diff --git a/scsi/qemu-pr-helper.c b/scsi/qemu-pr-helper.c | 33 | diff --git a/block/preallocate.c b/block/preallocate.c |
16 | index XXXXXXX..XXXXXXX 100644 | 34 | index XXXXXXX..XXXXXXX 100644 |
17 | --- a/scsi/qemu-pr-helper.c | 35 | --- a/block/preallocate.c |
18 | +++ b/scsi/qemu-pr-helper.c | 36 | +++ b/block/preallocate.c |
19 | @@ -XXX,XX +XXX,XX @@ static int do_sgio_worker(void *opaque) | 37 | @@ -XXX,XX +XXX,XX @@ typedef struct BDRVPreallocateState { |
20 | return status; | 38 | * be invalid (< 0) when we don't have both exclusive BLK_PERM_RESIZE and |
39 | * BLK_PERM_WRITE permissions on file child. | ||
40 | */ | ||
41 | + | ||
42 | + /* Gives up the resize permission on children when parents don't need it */ | ||
43 | + QEMUBH *drop_resize_bh; | ||
44 | } BDRVPreallocateState; | ||
45 | |||
46 | +static int preallocate_drop_resize(BlockDriverState *bs, Error **errp); | ||
47 | +static void preallocate_drop_resize_bh(void *opaque); | ||
48 | + | ||
49 | #define PREALLOCATE_OPT_PREALLOC_ALIGN "prealloc-align" | ||
50 | #define PREALLOCATE_OPT_PREALLOC_SIZE "prealloc-size" | ||
51 | static QemuOptsList runtime_opts = { | ||
52 | @@ -XXX,XX +XXX,XX @@ static int preallocate_open(BlockDriverState *bs, QDict *options, int flags, | ||
53 | * For this to work, mark them invalid. | ||
54 | */ | ||
55 | s->file_end = s->zero_start = s->data_end = -EINVAL; | ||
56 | + s->drop_resize_bh = qemu_bh_new(preallocate_drop_resize_bh, bs); | ||
57 | |||
58 | ret = bdrv_open_file_child(NULL, options, "file", bs, errp); | ||
59 | if (ret < 0) { | ||
60 | @@ -XXX,XX +XXX,XX @@ static void preallocate_close(BlockDriverState *bs) | ||
61 | { | ||
62 | BDRVPreallocateState *s = bs->opaque; | ||
63 | |||
64 | + qemu_bh_cancel(s->drop_resize_bh); | ||
65 | + qemu_bh_delete(s->drop_resize_bh); | ||
66 | + | ||
67 | if (s->data_end >= 0) { | ||
68 | preallocate_truncate_to_real_size(bs, NULL); | ||
69 | } | ||
70 | @@ -XXX,XX +XXX,XX @@ static int preallocate_reopen_prepare(BDRVReopenState *reopen_state, | ||
71 | BlockReopenQueue *queue, Error **errp) | ||
72 | { | ||
73 | PreallocateOpts *opts = g_new0(PreallocateOpts, 1); | ||
74 | + int ret; | ||
75 | |||
76 | if (!preallocate_absorb_opts(opts, reopen_state->options, | ||
77 | reopen_state->bs->file->bs, errp)) { | ||
78 | @@ -XXX,XX +XXX,XX @@ static int preallocate_reopen_prepare(BDRVReopenState *reopen_state, | ||
79 | return -EINVAL; | ||
80 | } | ||
81 | |||
82 | + /* | ||
83 | + * Drop the preallocation already here if reopening read-only. The child | ||
84 | + * might also be reopened read-only and then scheduling a BH during the | ||
85 | + * permission update is too late. | ||
86 | + */ | ||
87 | + if ((reopen_state->flags & BDRV_O_RDWR) == 0) { | ||
88 | + ret = preallocate_drop_resize(reopen_state->bs, errp); | ||
89 | + if (ret < 0) { | ||
90 | + g_free(opts); | ||
91 | + return ret; | ||
92 | + } | ||
93 | + } | ||
94 | + | ||
95 | reopen_state->opaque = opts; | ||
96 | |||
97 | return 0; | ||
98 | @@ -XXX,XX +XXX,XX @@ preallocate_co_getlength(BlockDriverState *bs) | ||
99 | return ret; | ||
21 | } | 100 | } |
22 | 101 | ||
23 | -static int do_sgio(int fd, const uint8_t *cdb, uint8_t *sense, | 102 | -static int preallocate_check_perm(BlockDriverState *bs, |
24 | - uint8_t *buf, int *sz, int dir) | 103 | - uint64_t perm, uint64_t shared, Error **errp) |
25 | +static int coroutine_fn do_sgio(int fd, const uint8_t *cdb, uint8_t *sense, | 104 | +static int preallocate_drop_resize(BlockDriverState *bs, Error **errp) |
26 | + uint8_t *buf, int *sz, int dir) | 105 | { |
27 | { | 106 | BDRVPreallocateState *s = bs->opaque; |
28 | int r; | 107 | + int ret; |
29 | 108 | ||
30 | @@ -XXX,XX +XXX,XX @@ static SCSISense mpath_generic_sense(int r) | 109 | - if (s->data_end >= 0 && !can_write_resize(perm)) { |
31 | } | 110 | - /* |
111 | - * Lose permissions. | ||
112 | - * We should truncate in check_perm, as in set_perm bs->file->perm will | ||
113 | - * be already changed, and we should not violate it. | ||
114 | - */ | ||
115 | - return preallocate_truncate_to_real_size(bs, errp); | ||
116 | + if (s->data_end < 0) { | ||
117 | + return 0; | ||
118 | + } | ||
119 | + | ||
120 | + /* | ||
121 | + * Before switching children to be read-only, truncate them to remove | ||
122 | + * the preallocation and let them have the real size. | ||
123 | + */ | ||
124 | + ret = preallocate_truncate_to_real_size(bs, errp); | ||
125 | + if (ret < 0) { | ||
126 | + return ret; | ||
127 | } | ||
128 | |||
129 | + /* | ||
130 | + * We'll drop our permissions and will allow other users to take write and | ||
131 | + * resize permissions (see preallocate_child_perm). Anyone will be able to | ||
132 | + * change the child, so mark all states invalid. We'll regain control if a | ||
133 | + * parent requests write access again. | ||
134 | + */ | ||
135 | + s->data_end = s->file_end = s->zero_start = -EINVAL; | ||
136 | + | ||
137 | + bdrv_graph_rdlock_main_loop(); | ||
138 | + bdrv_child_refresh_perms(bs, bs->file, NULL); | ||
139 | + bdrv_graph_rdunlock_main_loop(); | ||
140 | + | ||
141 | return 0; | ||
32 | } | 142 | } |
33 | 143 | ||
34 | -static int mpath_reconstruct_sense(int fd, int r, uint8_t *sense) | 144 | +static void preallocate_drop_resize_bh(void *opaque) |
35 | +static int coroutine_fn mpath_reconstruct_sense(int fd, int r, uint8_t *sense) | 145 | +{ |
36 | { | 146 | + /* |
37 | switch (r) { | 147 | + * In case of errors, we'll simply keep the exclusive lock on the image |
38 | case MPATH_PR_SUCCESS: | 148 | + * indefinitely. |
39 | @@ -XXX,XX +XXX,XX @@ static int mpath_reconstruct_sense(int fd, int r, uint8_t *sense) | 149 | + */ |
150 | + preallocate_drop_resize(opaque, NULL); | ||
151 | +} | ||
152 | + | ||
153 | static void preallocate_set_perm(BlockDriverState *bs, | ||
154 | uint64_t perm, uint64_t shared) | ||
155 | { | ||
156 | BDRVPreallocateState *s = bs->opaque; | ||
157 | |||
158 | if (can_write_resize(perm)) { | ||
159 | + qemu_bh_cancel(s->drop_resize_bh); | ||
160 | if (s->data_end < 0) { | ||
161 | s->data_end = s->file_end = s->zero_start = | ||
162 | - bdrv_getlength(bs->file->bs); | ||
163 | + bs->file->bs->total_sectors * BDRV_SECTOR_SIZE; | ||
164 | } | ||
165 | } else { | ||
166 | - /* | ||
167 | - * We drop our permissions, as well as allow shared | ||
168 | - * permissions (see preallocate_child_perm), anyone will be able to | ||
169 | - * change the child, so mark all states invalid. We'll regain control if | ||
170 | - * get good permissions back. | ||
171 | - */ | ||
172 | - s->data_end = s->file_end = s->zero_start = -EINVAL; | ||
173 | + qemu_bh_schedule(s->drop_resize_bh); | ||
40 | } | 174 | } |
41 | } | 175 | } |
42 | 176 | ||
43 | -static int multipath_pr_in(int fd, const uint8_t *cdb, uint8_t *sense, | 177 | @@ -XXX,XX +XXX,XX @@ static void preallocate_child_perm(BlockDriverState *bs, BdrvChild *c, |
44 | - uint8_t *data, int sz) | 178 | BdrvChildRole role, BlockReopenQueue *reopen_queue, |
45 | +static int coroutine_fn multipath_pr_in(int fd, const uint8_t *cdb, uint8_t *sense, | 179 | uint64_t perm, uint64_t shared, uint64_t *nperm, uint64_t *nshared) |
46 | + uint8_t *data, int sz) | 180 | { |
47 | { | 181 | + BDRVPreallocateState *s = bs->opaque; |
48 | int rq_servact = cdb[1]; | 182 | + |
49 | struct prin_resp resp; | 183 | bdrv_default_perms(bs, c, role, reopen_queue, perm, shared, nperm, nshared); |
50 | @@ -XXX,XX +XXX,XX @@ static int multipath_pr_in(int fd, const uint8_t *cdb, uint8_t *sense, | 184 | |
51 | return mpath_reconstruct_sense(fd, r, sense); | 185 | - if (can_write_resize(perm)) { |
52 | } | 186 | - /* This should come by default, but let's enforce: */ |
53 | 187 | + /* | |
54 | -static int multipath_pr_out(int fd, const uint8_t *cdb, uint8_t *sense, | 188 | + * We need exclusive write and resize permissions on the child not only when |
55 | - const uint8_t *param, int sz) | 189 | + * the parent can write to it, but also after the parent gave up write |
56 | +static int coroutine_fn multipath_pr_out(int fd, const uint8_t *cdb, uint8_t *sense, | 190 | + * permissions until preallocate_drop_resize() has completed. |
57 | + const uint8_t *param, int sz) | 191 | + */ |
58 | { | 192 | + if (can_write_resize(perm) || s->data_end != -EINVAL) { |
59 | int rq_servact = cdb[1]; | 193 | *nperm |= BLK_PERM_WRITE | BLK_PERM_RESIZE; |
60 | int rq_scope = cdb[2] >> 4; | 194 | |
61 | @@ -XXX,XX +XXX,XX @@ static int multipath_pr_out(int fd, const uint8_t *cdb, uint8_t *sense, | 195 | /* |
62 | } | 196 | @@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_preallocate_filter = { |
63 | #endif | 197 | .bdrv_co_flush = preallocate_co_flush, |
64 | 198 | .bdrv_co_truncate = preallocate_co_truncate, | |
65 | -static int do_pr_in(int fd, const uint8_t *cdb, uint8_t *sense, | 199 | |
66 | - uint8_t *data, int *resp_sz) | 200 | - .bdrv_check_perm = preallocate_check_perm, |
67 | +static int coroutine_fn do_pr_in(int fd, const uint8_t *cdb, uint8_t *sense, | 201 | .bdrv_set_perm = preallocate_set_perm, |
68 | + uint8_t *data, int *resp_sz) | 202 | .bdrv_child_perm = preallocate_child_perm, |
69 | { | ||
70 | #ifdef CONFIG_MPATH | ||
71 | if (is_mpath(fd)) { | ||
72 | @@ -XXX,XX +XXX,XX @@ static int do_pr_in(int fd, const uint8_t *cdb, uint8_t *sense, | ||
73 | SG_DXFER_FROM_DEV); | ||
74 | } | ||
75 | |||
76 | -static int do_pr_out(int fd, const uint8_t *cdb, uint8_t *sense, | ||
77 | - const uint8_t *param, int sz) | ||
78 | +static int coroutine_fn do_pr_out(int fd, const uint8_t *cdb, uint8_t *sense, | ||
79 | + const uint8_t *param, int sz) | ||
80 | { | ||
81 | int resp_sz; | ||
82 | 203 | ||
83 | -- | 204 | -- |
84 | 2.40.0 | 205 | 2.41.0 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | The documentation for bdrv_append() says that the caller must hold the | ||
2 | AioContext lock for bs_top. Change all callers to actually adhere to the | ||
3 | contract. | ||
1 | 4 | ||
5 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
6 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
7 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
8 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
9 | Message-ID: <20230911094620.45040-5-kwolf@redhat.com> | ||
10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
11 | --- | ||
12 | tests/unit/test-bdrv-drain.c | 3 +++ | ||
13 | tests/unit/test-bdrv-graph-mod.c | 6 ++++++ | ||
14 | tests/unit/test-block-iothread.c | 3 +++ | ||
15 | 3 files changed, 12 insertions(+) | ||
16 | |||
17 | diff --git a/tests/unit/test-bdrv-drain.c b/tests/unit/test-bdrv-drain.c | ||
18 | index XXXXXXX..XXXXXXX 100644 | ||
19 | --- a/tests/unit/test-bdrv-drain.c | ||
20 | +++ b/tests/unit/test-bdrv-drain.c | ||
21 | @@ -XXX,XX +XXX,XX @@ static void test_append_to_drained(void) | ||
22 | g_assert_cmpint(base_s->drain_count, ==, 1); | ||
23 | g_assert_cmpint(base->in_flight, ==, 0); | ||
24 | |||
25 | + aio_context_acquire(qemu_get_aio_context()); | ||
26 | bdrv_append(overlay, base, &error_abort); | ||
27 | + aio_context_release(qemu_get_aio_context()); | ||
28 | + | ||
29 | g_assert_cmpint(base->in_flight, ==, 0); | ||
30 | g_assert_cmpint(overlay->in_flight, ==, 0); | ||
31 | |||
32 | diff --git a/tests/unit/test-bdrv-graph-mod.c b/tests/unit/test-bdrv-graph-mod.c | ||
33 | index XXXXXXX..XXXXXXX 100644 | ||
34 | --- a/tests/unit/test-bdrv-graph-mod.c | ||
35 | +++ b/tests/unit/test-bdrv-graph-mod.c | ||
36 | @@ -XXX,XX +XXX,XX @@ static void test_update_perm_tree(void) | ||
37 | bdrv_attach_child(filter, bs, "child", &child_of_bds, | ||
38 | BDRV_CHILD_DATA, &error_abort); | ||
39 | |||
40 | + aio_context_acquire(qemu_get_aio_context()); | ||
41 | ret = bdrv_append(filter, bs, NULL); | ||
42 | g_assert_cmpint(ret, <, 0); | ||
43 | + aio_context_release(qemu_get_aio_context()); | ||
44 | |||
45 | bdrv_unref(filter); | ||
46 | blk_unref(root); | ||
47 | @@ -XXX,XX +XXX,XX @@ static void test_should_update_child(void) | ||
48 | g_assert(target->backing->bs == bs); | ||
49 | bdrv_attach_child(filter, target, "target", &child_of_bds, | ||
50 | BDRV_CHILD_DATA, &error_abort); | ||
51 | + aio_context_acquire(qemu_get_aio_context()); | ||
52 | bdrv_append(filter, bs, &error_abort); | ||
53 | + aio_context_release(qemu_get_aio_context()); | ||
54 | g_assert(target->backing->bs == bs); | ||
55 | |||
56 | bdrv_unref(filter); | ||
57 | @@ -XXX,XX +XXX,XX @@ static void test_append_greedy_filter(void) | ||
58 | BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, | ||
59 | &error_abort); | ||
60 | |||
61 | + aio_context_acquire(qemu_get_aio_context()); | ||
62 | bdrv_append(fl, base, &error_abort); | ||
63 | + aio_context_release(qemu_get_aio_context()); | ||
64 | bdrv_unref(fl); | ||
65 | bdrv_unref(top); | ||
66 | } | ||
67 | diff --git a/tests/unit/test-block-iothread.c b/tests/unit/test-block-iothread.c | ||
68 | index XXXXXXX..XXXXXXX 100644 | ||
69 | --- a/tests/unit/test-block-iothread.c | ||
70 | +++ b/tests/unit/test-block-iothread.c | ||
71 | @@ -XXX,XX +XXX,XX @@ static void test_propagate_mirror(void) | ||
72 | &error_abort); | ||
73 | |||
74 | /* Start a mirror job */ | ||
75 | + aio_context_acquire(main_ctx); | ||
76 | mirror_start("job0", src, target, NULL, JOB_DEFAULT, 0, 0, 0, | ||
77 | MIRROR_SYNC_MODE_NONE, MIRROR_OPEN_BACKING_CHAIN, false, | ||
78 | BLOCKDEV_ON_ERROR_REPORT, BLOCKDEV_ON_ERROR_REPORT, | ||
79 | false, "filter_node", MIRROR_COPY_MODE_BACKGROUND, | ||
80 | &error_abort); | ||
81 | + aio_context_release(main_ctx); | ||
82 | + | ||
83 | WITH_JOB_LOCK_GUARD() { | ||
84 | job = job_get_locked("job0"); | ||
85 | } | ||
86 | -- | ||
87 | 2.41.0 | diff view generated by jsdifflib |
1 | From: Stefan Hajnoczi <stefanha@redhat.com> | 1 | bdrv_unref() is called by a lot of places that need to hold the graph |
---|---|---|---|
2 | lock (it naturally happens in the context of operations that change the | ||
3 | graph). However, bdrv_unref() takes the graph writer lock internally, so | ||
4 | it can't actually be called while already holding a graph lock without | ||
5 | causing a deadlock. | ||
2 | 6 | ||
3 | The following conversion is safe and does not change behavior: | 7 | bdrv_unref() also can't just become GRAPH_WRLOCK because it drains the |
8 | node before closing it, and draining requires that the graph is | ||
9 | unlocked. | ||
4 | 10 | ||
5 | GLOBAL_STATE_CODE(); | 11 | The solution is to defer deleting the node until we don't hold the lock |
6 | ... | 12 | any more and draining is possible again. |
7 | - AIO_WAIT_WHILE(qemu_get_aio_context(), ...); | ||
8 | + AIO_WAIT_WHILE_UNLOCKED(NULL, ...); | ||
9 | 13 | ||
10 | Since we're in GLOBAL_STATE_CODE(), qemu_get_aio_context() is our home | 14 | Note that keeping images open for longer than necessary can create |
11 | thread's AioContext. Thus AIO_WAIT_WHILE() does not unlock the | 15 | problems, too: You can't open an image again before it is really closed |
12 | AioContext: | 16 | (if image locking didn't prevent it, it would cause corruption). |
17 | Reopening an image immediately happens at least during bdrv_open() and | ||
18 | bdrv_co_create(). | ||
13 | 19 | ||
14 | if (ctx_ && in_aio_context_home_thread(ctx_)) { \ | 20 | In order to solve this problem, make sure to run the deferred unref in |
15 | while ((cond)) { \ | 21 | bdrv_graph_wrunlock(), i.e. the first possible place where we can drain |
16 | aio_poll(ctx_, true); \ | 22 | again. This is also why bdrv_schedule_unref() is marked GRAPH_WRLOCK. |
17 | waited_ = true; \ | ||
18 | } \ | ||
19 | 23 | ||
20 | And that means AIO_WAIT_WHILE_UNLOCKED(NULL, ...) can be substituted. | 24 | The output of iotest 051 is updated because the additional polling |
25 | changes the order of HMP output, resulting in a new "(qemu)" prompt in | ||
26 | the test output that was previously on a separate line and filtered out. | ||
21 | 27 | ||
22 | Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> | 28 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
23 | Tested-by: Philippe Mathieu-Daudé <philmd@linaro.org> | 29 | Message-ID: <20230911094620.45040-6-kwolf@redhat.com> |
24 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | 30 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> |
25 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
26 | Message-Id: <20230309190855.414275-4-stefanha@redhat.com> | ||
27 | Reviewed-by: Wilfred Mallawa <wilfred.mallawa@wdc.com> | ||
28 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 31 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
29 | --- | 32 | --- |
30 | block/graph-lock.c | 2 +- | 33 | include/block/block-global-state.h | 1 + |
31 | 1 file changed, 1 insertion(+), 1 deletion(-) | 34 | block.c | 17 +++++++++++++++++ |
35 | block/graph-lock.c | 26 +++++++++++++++++++------- | ||
36 | tests/qemu-iotests/051.pc.out | 6 +++--- | ||
37 | 4 files changed, 40 insertions(+), 10 deletions(-) | ||
32 | 38 | ||
39 | diff --git a/include/block/block-global-state.h b/include/block/block-global-state.h | ||
40 | index XXXXXXX..XXXXXXX 100644 | ||
41 | --- a/include/block/block-global-state.h | ||
42 | +++ b/include/block/block-global-state.h | ||
43 | @@ -XXX,XX +XXX,XX @@ void bdrv_img_create(const char *filename, const char *fmt, | ||
44 | void bdrv_ref(BlockDriverState *bs); | ||
45 | void no_coroutine_fn bdrv_unref(BlockDriverState *bs); | ||
46 | void coroutine_fn no_co_wrapper bdrv_co_unref(BlockDriverState *bs); | ||
47 | +void GRAPH_WRLOCK bdrv_schedule_unref(BlockDriverState *bs); | ||
48 | void bdrv_unref_child(BlockDriverState *parent, BdrvChild *child); | ||
49 | BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs, | ||
50 | BlockDriverState *child_bs, | ||
51 | diff --git a/block.c b/block.c | ||
52 | index XXXXXXX..XXXXXXX 100644 | ||
53 | --- a/block.c | ||
54 | +++ b/block.c | ||
55 | @@ -XXX,XX +XXX,XX @@ void bdrv_unref(BlockDriverState *bs) | ||
56 | } | ||
57 | } | ||
58 | |||
59 | +/* | ||
60 | + * Release a BlockDriverState reference while holding the graph write lock. | ||
61 | + * | ||
62 | + * Calling bdrv_unref() directly is forbidden while holding the graph lock | ||
63 | + * because bdrv_close() both involves polling and taking the graph lock | ||
64 | + * internally. bdrv_schedule_unref() instead delays decreasing the refcount and | ||
65 | + * possibly closing @bs until the graph lock is released. | ||
66 | + */ | ||
67 | +void bdrv_schedule_unref(BlockDriverState *bs) | ||
68 | +{ | ||
69 | + if (!bs) { | ||
70 | + return; | ||
71 | + } | ||
72 | + aio_bh_schedule_oneshot(qemu_get_aio_context(), | ||
73 | + (QEMUBHFunc *) bdrv_unref, bs); | ||
74 | +} | ||
75 | + | ||
76 | struct BdrvOpBlocker { | ||
77 | Error *reason; | ||
78 | QLIST_ENTRY(BdrvOpBlocker) list; | ||
33 | diff --git a/block/graph-lock.c b/block/graph-lock.c | 79 | diff --git a/block/graph-lock.c b/block/graph-lock.c |
34 | index XXXXXXX..XXXXXXX 100644 | 80 | index XXXXXXX..XXXXXXX 100644 |
35 | --- a/block/graph-lock.c | 81 | --- a/block/graph-lock.c |
36 | +++ b/block/graph-lock.c | 82 | +++ b/block/graph-lock.c |
37 | @@ -XXX,XX +XXX,XX @@ void bdrv_graph_wrlock(void) | 83 | @@ -XXX,XX +XXX,XX @@ void bdrv_graph_wrlock(BlockDriverState *bs) |
38 | * reader lock. | 84 | void bdrv_graph_wrunlock(void) |
39 | */ | 85 | { |
40 | qatomic_set(&has_writer, 0); | 86 | GLOBAL_STATE_CODE(); |
41 | - AIO_WAIT_WHILE(qemu_get_aio_context(), reader_count() >= 1); | 87 | - QEMU_LOCK_GUARD(&aio_context_list_lock); |
42 | + AIO_WAIT_WHILE_UNLOCKED(NULL, reader_count() >= 1); | 88 | assert(qatomic_read(&has_writer)); |
43 | qatomic_set(&has_writer, 1); | 89 | |
44 | 90 | + WITH_QEMU_LOCK_GUARD(&aio_context_list_lock) { | |
45 | /* | 91 | + /* |
92 | + * No need for memory barriers, this works in pair with | ||
93 | + * the slow path of rdlock() and both take the lock. | ||
94 | + */ | ||
95 | + qatomic_store_release(&has_writer, 0); | ||
96 | + | ||
97 | + /* Wake up all coroutines that are waiting to read the graph */ | ||
98 | + qemu_co_enter_all(&reader_queue, &aio_context_list_lock); | ||
99 | + } | ||
100 | + | ||
101 | /* | ||
102 | - * No need for memory barriers, this works in pair with | ||
103 | - * the slow path of rdlock() and both take the lock. | ||
104 | + * Run any BHs that were scheduled during the wrlock section and that | ||
105 | + * callers might expect to have finished (in particular, this is important | ||
106 | + * for bdrv_schedule_unref()). | ||
107 | + * | ||
108 | + * Do this only after restarting coroutines so that nested event loops in | ||
109 | + * BHs don't deadlock if their condition relies on the coroutine making | ||
110 | + * progress. | ||
111 | */ | ||
112 | - qatomic_store_release(&has_writer, 0); | ||
113 | - | ||
114 | - /* Wake up all coroutine that are waiting to read the graph */ | ||
115 | - qemu_co_enter_all(&reader_queue, &aio_context_list_lock); | ||
116 | + aio_bh_poll(qemu_get_aio_context()); | ||
117 | } | ||
118 | |||
119 | void coroutine_fn bdrv_graph_co_rdlock(void) | ||
120 | diff --git a/tests/qemu-iotests/051.pc.out b/tests/qemu-iotests/051.pc.out | ||
121 | index XXXXXXX..XXXXXXX 100644 | ||
122 | --- a/tests/qemu-iotests/051.pc.out | ||
123 | +++ b/tests/qemu-iotests/051.pc.out | ||
124 | @@ -XXX,XX +XXX,XX @@ QEMU_PROG: -device scsi-hd,drive=disk: Device needs media, but drive is empty | ||
125 | |||
126 | Testing: -drive file=TEST_DIR/t.qcow2,if=none,node-name=disk -object iothread,id=thread0 -device virtio-scsi,iothread=thread0,id=virtio-scsi0 -device scsi-hd,bus=virtio-scsi0.0,drive=disk,share-rw=on -device ide-hd,drive=disk,share-rw=on | ||
127 | QEMU X.Y.Z monitor - type 'help' for more information | ||
128 | -QEMU_PROG: -device ide-hd,drive=disk,share-rw=on: Cannot change iothread of active block backend | ||
129 | +(qemu) QEMU_PROG: -device ide-hd,drive=disk,share-rw=on: Cannot change iothread of active block backend | ||
130 | |||
131 | Testing: -drive file=TEST_DIR/t.qcow2,if=none,node-name=disk -object iothread,id=thread0 -device virtio-scsi,iothread=thread0,id=virtio-scsi0 -device scsi-hd,bus=virtio-scsi0.0,drive=disk,share-rw=on -device virtio-blk-pci,drive=disk,share-rw=on | ||
132 | QEMU X.Y.Z monitor - type 'help' for more information | ||
133 | -QEMU_PROG: -device virtio-blk-pci,drive=disk,share-rw=on: Cannot change iothread of active block backend | ||
134 | +(qemu) QEMU_PROG: -device virtio-blk-pci,drive=disk,share-rw=on: Cannot change iothread of active block backend | ||
135 | |||
136 | Testing: -drive file=TEST_DIR/t.qcow2,if=none,node-name=disk -object iothread,id=thread0 -device virtio-scsi,iothread=thread0,id=virtio-scsi0 -device scsi-hd,bus=virtio-scsi0.0,drive=disk,share-rw=on -device lsi53c895a,id=lsi0 -device scsi-hd,bus=lsi0.0,drive=disk,share-rw=on | ||
137 | QEMU X.Y.Z monitor - type 'help' for more information | ||
138 | @@ -XXX,XX +XXX,XX @@ QEMU X.Y.Z monitor - type 'help' for more information | ||
139 | |||
140 | Testing: -drive file=TEST_DIR/t.qcow2,if=none,node-name=disk -object iothread,id=thread0 -device virtio-scsi,iothread=thread0,id=virtio-scsi0 -device scsi-hd,bus=virtio-scsi0.0,drive=disk,share-rw=on -device virtio-blk-pci,drive=disk,iothread=thread0,share-rw=on | ||
141 | QEMU X.Y.Z monitor - type 'help' for more information | ||
142 | -QEMU_PROG: -device virtio-blk-pci,drive=disk,iothread=thread0,share-rw=on: Cannot change iothread of active block backend | ||
143 | +(qemu) QEMU_PROG: -device virtio-blk-pci,drive=disk,iothread=thread0,share-rw=on: Cannot change iothread of active block backend | ||
144 | |||
145 | Testing: -drive file=TEST_DIR/t.qcow2,if=none,node-name=disk -object iothread,id=thread0 -device virtio-scsi,iothread=thread0,id=virtio-scsi0 -device scsi-hd,bus=virtio-scsi0.0,drive=disk,share-rw=on -device virtio-scsi,id=virtio-scsi1,iothread=thread0 -device scsi-hd,bus=virtio-scsi1.0,drive=disk,share-rw=on | ||
146 | QEMU X.Y.Z monitor - type 'help' for more information | ||
46 | -- | 147 | -- |
47 | 2.40.0 | 148 | 2.41.0 |
48 | |||
49 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | Add a new wrapper type for GRAPH_WRLOCK functions that should be called | ||
2 | from coroutine context. | ||
1 | 3 | ||
4 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
5 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
6 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
7 | Message-ID: <20230911094620.45040-7-kwolf@redhat.com> | ||
8 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
9 | --- | ||
10 | include/block/block-common.h | 4 ++++ | ||
11 | scripts/block-coroutine-wrapper.py | 11 +++++++++++ | ||
12 | 2 files changed, 15 insertions(+) | ||
13 | |||
14 | diff --git a/include/block/block-common.h b/include/block/block-common.h | ||
15 | index XXXXXXX..XXXXXXX 100644 | ||
16 | --- a/include/block/block-common.h | ||
17 | +++ b/include/block/block-common.h | ||
18 | @@ -XXX,XX +XXX,XX @@ | ||
19 | * function. The coroutine yields after scheduling the BH and is reentered when | ||
20 | * the wrapped function returns. | ||
21 | * | ||
22 | + * A no_co_wrapper_bdrv_wrlock function is a no_co_wrapper function that | ||
23 | + * automatically takes the graph wrlock when calling the wrapped function. | ||
24 | + * | ||
25 | * If the first parameter of the function is a BlockDriverState, BdrvChild or | ||
26 | * BlockBackend pointer, the AioContext lock for it is taken in the wrapper. | ||
27 | */ | ||
28 | #define no_co_wrapper | ||
29 | +#define no_co_wrapper_bdrv_wrlock | ||
30 | |||
31 | #include "block/blockjob.h" | ||
32 | |||
33 | diff --git a/scripts/block-coroutine-wrapper.py b/scripts/block-coroutine-wrapper.py | ||
34 | index XXXXXXX..XXXXXXX 100644 | ||
35 | --- a/scripts/block-coroutine-wrapper.py | ||
36 | +++ b/scripts/block-coroutine-wrapper.py | ||
37 | @@ -XXX,XX +XXX,XX @@ def __init__(self, wrapper_type: str, return_type: str, name: str, | ||
38 | self.args = [ParamDecl(arg.strip()) for arg in args.split(',')] | ||
39 | self.create_only_co = 'mixed' not in variant | ||
40 | self.graph_rdlock = 'bdrv_rdlock' in variant | ||
41 | + self.graph_wrlock = 'bdrv_wrlock' in variant | ||
42 | |||
43 | self.wrapper_type = wrapper_type | ||
44 | |||
45 | if wrapper_type == 'co': | ||
46 | + if self.graph_wrlock: | ||
47 | + raise ValueError(f"co function can't be wrlock: {self.name}") | ||
48 | subsystem, subname = self.name.split('_', 1) | ||
49 | self.target_name = f'{subsystem}_co_{subname}' | ||
50 | else: | ||
51 | @@ -XXX,XX +XXX,XX @@ def gen_no_co_wrapper(func: FuncDecl) -> str: | ||
52 | name = func.target_name | ||
53 | struct_name = func.struct_name | ||
54 | |||
55 | + graph_lock='' | ||
56 | + graph_unlock='' | ||
57 | + if func.graph_wrlock: | ||
58 | + graph_lock=' bdrv_graph_wrlock(NULL);' | ||
59 | + graph_unlock=' bdrv_graph_wrunlock();' | ||
60 | + | ||
61 | return f"""\ | ||
62 | /* | ||
63 | * Wrappers for {name} | ||
64 | @@ -XXX,XX +XXX,XX @@ def gen_no_co_wrapper(func: FuncDecl) -> str: | ||
65 | {struct_name} *s = opaque; | ||
66 | AioContext *ctx = {func.gen_ctx('s->')}; | ||
67 | |||
68 | +{graph_lock} | ||
69 | aio_context_acquire(ctx); | ||
70 | {func.get_result}{name}({ func.gen_list('s->{name}') }); | ||
71 | aio_context_release(ctx); | ||
72 | +{graph_unlock} | ||
73 | |||
74 | aio_co_wake(s->co); | ||
75 | }} | ||
76 | -- | ||
77 | 2.41.0 | diff view generated by jsdifflib |
1 | From: Stefan Hajnoczi <stefanha@redhat.com> | 1 | Don't assume specific parameter names like 'bs' or 'blk' in the |
---|---|---|---|
2 | generated code, but use the actual name. | ||
2 | 3 | ||
3 | monitor_cleanup() is called from the main loop thread. Calling | 4 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
4 | AIO_WAIT_WHILE(qemu_get_aio_context(), ...) from the main loop thread is | 5 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
5 | equivalent to AIO_WAIT_WHILE_UNLOCKED(NULL, ...) because neither unlocks | 6 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> |
6 | the AioContext and the latter's assertion that we're in the main loop | 7 | Message-ID: <20230911094620.45040-8-kwolf@redhat.com> |
7 | succeeds. | ||
8 | |||
9 | Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> | ||
10 | Tested-by: Philippe Mathieu-Daudé <philmd@linaro.org> | ||
11 | Reviewed-by: Markus Armbruster <armbru@redhat.com> | ||
12 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
13 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
14 | Message-Id: <20230309190855.414275-7-stefanha@redhat.com> | ||
15 | Reviewed-by: Wilfred Mallawa <wilfred.mallawa@wdc.com> | ||
16 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 8 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
17 | --- | 9 | --- |
18 | monitor/monitor.c | 4 ++-- | 10 | scripts/block-coroutine-wrapper.py | 7 ++++--- |
19 | 1 file changed, 2 insertions(+), 2 deletions(-) | 11 | 1 file changed, 4 insertions(+), 3 deletions(-) |
20 | 12 | ||
21 | diff --git a/monitor/monitor.c b/monitor/monitor.c | 13 | diff --git a/scripts/block-coroutine-wrapper.py b/scripts/block-coroutine-wrapper.py |
22 | index XXXXXXX..XXXXXXX 100644 | 14 | index XXXXXXX..XXXXXXX 100644 |
23 | --- a/monitor/monitor.c | 15 | --- a/scripts/block-coroutine-wrapper.py |
24 | +++ b/monitor/monitor.c | 16 | +++ b/scripts/block-coroutine-wrapper.py |
25 | @@ -XXX,XX +XXX,XX @@ void monitor_cleanup(void) | 17 | @@ -XXX,XX +XXX,XX @@ def __init__(self, wrapper_type: str, return_type: str, name: str, |
26 | * We need to poll both qemu_aio_context and iohandler_ctx to make | 18 | |
27 | * sure that the dispatcher coroutine keeps making progress and | 19 | def gen_ctx(self, prefix: str = '') -> str: |
28 | * eventually terminates. qemu_aio_context is automatically | 20 | t = self.args[0].type |
29 | - * polled by calling AIO_WAIT_WHILE on it, but we must poll | 21 | + name = self.args[0].name |
30 | + * polled by calling AIO_WAIT_WHILE_UNLOCKED on it, but we must poll | 22 | if t == 'BlockDriverState *': |
31 | * iohandler_ctx manually. | 23 | - return f'bdrv_get_aio_context({prefix}bs)' |
32 | * | 24 | + return f'bdrv_get_aio_context({prefix}{name})' |
33 | * Letting the iothread continue while shutting down the dispatcher | 25 | elif t == 'BdrvChild *': |
34 | @@ -XXX,XX +XXX,XX @@ void monitor_cleanup(void) | 26 | - return f'bdrv_get_aio_context({prefix}child->bs)' |
35 | aio_co_wake(qmp_dispatcher_co); | 27 | + return f'bdrv_get_aio_context({prefix}{name}->bs)' |
36 | } | 28 | elif t == 'BlockBackend *': |
37 | 29 | - return f'blk_get_aio_context({prefix}blk)' | |
38 | - AIO_WAIT_WHILE(qemu_get_aio_context(), | 30 | + return f'blk_get_aio_context({prefix}{name})' |
39 | + AIO_WAIT_WHILE_UNLOCKED(NULL, | 31 | else: |
40 | (aio_poll(iohandler_get_aio_context(), false), | 32 | return 'qemu_get_aio_context()' |
41 | qatomic_mb_read(&qmp_dispatcher_co_busy))); | ||
42 | 33 | ||
43 | -- | 34 | -- |
44 | 2.40.0 | 35 | 2.41.0 |
45 | |||
46 | diff view generated by jsdifflib |
1 | From: Stefan Hajnoczi <stefanha@redhat.com> | 1 | Instead of taking the writer lock internally, require callers to already |
---|---|---|---|
2 | hold it when calling bdrv_replace_child_noperm(). These callers will | ||
3 | typically already hold the graph lock once the locking work is | ||
4 | completed, which means that they can't call functions that take it | ||
5 | internally. | ||
2 | 6 | ||
3 | The HMP monitor runs in the main loop thread. Calling | 7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
4 | AIO_WAIT_WHILE(qemu_get_aio_context(), ...) from the main loop thread is | 8 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
5 | equivalent to AIO_WAIT_WHILE_UNLOCKED(NULL, ...) because neither unlocks | 9 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> |
6 | the AioContext and the latter's assertion that we're in the main loop | 10 | Message-ID: <20230911094620.45040-9-kwolf@redhat.com> |
7 | succeeds. | ||
8 | |||
9 | Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> | ||
10 | Tested-by: Philippe Mathieu-Daudé <philmd@linaro.org> | ||
11 | Reviewed-by: Markus Armbruster <armbru@redhat.com> | ||
12 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
13 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
14 | Message-Id: <20230309190855.414275-6-stefanha@redhat.com> | ||
15 | Reviewed-by: Wilfred Mallawa <wilfred.mallawa@wdc.com> | ||
16 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
17 | --- | 12 | --- |
18 | monitor/hmp.c | 2 +- | 13 | block.c | 26 +++++++++++++++++++------- |
19 | 1 file changed, 1 insertion(+), 1 deletion(-) | 14 | 1 file changed, 19 insertions(+), 7 deletions(-) |
20 | 15 | ||
21 | diff --git a/monitor/hmp.c b/monitor/hmp.c | 16 | diff --git a/block.c b/block.c |
22 | index XXXXXXX..XXXXXXX 100644 | 17 | index XXXXXXX..XXXXXXX 100644 |
23 | --- a/monitor/hmp.c | 18 | --- a/block.c |
24 | +++ b/monitor/hmp.c | 19 | +++ b/block.c |
25 | @@ -XXX,XX +XXX,XX @@ void handle_hmp_command(MonitorHMP *mon, const char *cmdline) | 20 | @@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_open_inherit(const char *filename, |
26 | Coroutine *co = qemu_coroutine_create(handle_hmp_command_co, &data); | 21 | static bool bdrv_recurse_has_child(BlockDriverState *bs, |
27 | monitor_set_cur(co, &mon->common); | 22 | BlockDriverState *child); |
28 | aio_co_enter(qemu_get_aio_context(), co); | 23 | |
29 | - AIO_WAIT_WHILE(qemu_get_aio_context(), !data.done); | 24 | -static void bdrv_replace_child_noperm(BdrvChild *child, |
30 | + AIO_WAIT_WHILE_UNLOCKED(NULL, !data.done); | 25 | - BlockDriverState *new_bs); |
26 | +static void GRAPH_WRLOCK | ||
27 | +bdrv_replace_child_noperm(BdrvChild *child, BlockDriverState *new_bs); | ||
28 | + | ||
29 | static void bdrv_remove_child(BdrvChild *child, Transaction *tran); | ||
30 | |||
31 | static int bdrv_reopen_prepare(BDRVReopenState *reopen_state, | ||
32 | @@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_abort(void *opaque) | ||
33 | BlockDriverState *new_bs = s->child->bs; | ||
34 | |||
35 | GLOBAL_STATE_CODE(); | ||
36 | + bdrv_graph_wrlock(s->old_bs); | ||
37 | + | ||
38 | /* old_bs reference is transparently moved from @s to @s->child */ | ||
39 | if (!s->child->bs) { | ||
40 | /* | ||
41 | @@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_abort(void *opaque) | ||
31 | } | 42 | } |
32 | 43 | assert(s->child->quiesced_parent); | |
33 | qobject_unref(qdict); | 44 | bdrv_replace_child_noperm(s->child, s->old_bs); |
45 | + | ||
46 | + bdrv_graph_wrunlock(); | ||
47 | bdrv_unref(new_bs); | ||
48 | } | ||
49 | |||
50 | @@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_tran(BdrvChild *child, BlockDriverState *new_bs, | ||
51 | if (new_bs) { | ||
52 | bdrv_ref(new_bs); | ||
53 | } | ||
54 | + | ||
55 | + bdrv_graph_wrlock(new_bs); | ||
56 | bdrv_replace_child_noperm(child, new_bs); | ||
57 | + bdrv_graph_wrunlock(); | ||
58 | /* old_bs reference is transparently moved from @child to @s */ | ||
59 | } | ||
60 | |||
61 | @@ -XXX,XX +XXX,XX @@ uint64_t bdrv_qapi_perm_to_blk_perm(BlockPermission qapi_perm) | ||
62 | * If @new_bs is non-NULL, the parent of @child must already be drained through | ||
63 | * @child and the caller must hold the AioContext lock for @new_bs. | ||
64 | */ | ||
65 | -static void bdrv_replace_child_noperm(BdrvChild *child, | ||
66 | - BlockDriverState *new_bs) | ||
67 | +static void GRAPH_WRLOCK | ||
68 | +bdrv_replace_child_noperm(BdrvChild *child, BlockDriverState *new_bs) | ||
69 | { | ||
70 | BlockDriverState *old_bs = child->bs; | ||
71 | int new_bs_quiesce_counter; | ||
72 | @@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_noperm(BdrvChild *child, | ||
73 | assert(bdrv_get_aio_context(old_bs) == bdrv_get_aio_context(new_bs)); | ||
74 | } | ||
75 | |||
76 | - /* TODO Pull this up into the callers to avoid polling here */ | ||
77 | - bdrv_graph_wrlock(new_bs); | ||
78 | if (old_bs) { | ||
79 | if (child->klass->detach) { | ||
80 | child->klass->detach(child); | ||
81 | @@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_noperm(BdrvChild *child, | ||
82 | child->klass->attach(child); | ||
83 | } | ||
84 | } | ||
85 | - bdrv_graph_wrunlock(); | ||
86 | |||
87 | /* | ||
88 | * If the parent was drained through this BdrvChild previously, but new_bs | ||
89 | @@ -XXX,XX +XXX,XX @@ static void bdrv_attach_child_common_abort(void *opaque) | ||
90 | BlockDriverState *bs = s->child->bs; | ||
91 | |||
92 | GLOBAL_STATE_CODE(); | ||
93 | + | ||
94 | + bdrv_graph_wrlock(NULL); | ||
95 | bdrv_replace_child_noperm(s->child, NULL); | ||
96 | + bdrv_graph_wrunlock(); | ||
97 | |||
98 | if (bdrv_get_aio_context(bs) != s->old_child_ctx) { | ||
99 | bdrv_try_change_aio_context(bs, s->old_child_ctx, NULL, &error_abort); | ||
100 | @@ -XXX,XX +XXX,XX @@ static BdrvChild *bdrv_attach_child_common(BlockDriverState *child_bs, | ||
101 | * a problem, we already did this), but it will still poll until the parent | ||
102 | * is fully quiesced, so it will not be negatively affected either. | ||
103 | */ | ||
104 | + bdrv_graph_wrlock(child_bs); | ||
105 | bdrv_parent_drained_begin_single(new_child); | ||
106 | bdrv_replace_child_noperm(new_child, child_bs); | ||
107 | + bdrv_graph_wrunlock(); | ||
108 | |||
109 | BdrvAttachChildCommonState *s = g_new(BdrvAttachChildCommonState, 1); | ||
110 | *s = (BdrvAttachChildCommonState) { | ||
111 | @@ -XXX,XX +XXX,XX @@ void bdrv_root_unref_child(BdrvChild *child) | ||
112 | BlockDriverState *child_bs = child->bs; | ||
113 | |||
114 | GLOBAL_STATE_CODE(); | ||
115 | + bdrv_graph_wrlock(NULL); | ||
116 | bdrv_replace_child_noperm(child, NULL); | ||
117 | + bdrv_graph_wrunlock(); | ||
118 | bdrv_child_free(child); | ||
119 | |||
120 | if (child_bs) { | ||
34 | -- | 121 | -- |
35 | 2.40.0 | 122 | 2.41.0 |
36 | |||
37 | diff view generated by jsdifflib |
1 | From: Paolo Bonzini <pbonzini@redhat.com> | 1 | Instead of taking the writer lock internally, require callers to already |
---|---|---|---|
2 | 2 | hold it when calling bdrv_replace_child_tran(). These callers will | |
3 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> | 3 | typically already hold the graph lock once the locking work is |
4 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | 4 | completed, which means that they can't call functions that take it |
5 | internally. | ||
6 | |||
7 | While a graph lock is held, polling is not allowed. Therefore draining | ||
8 | the necessary nodes can no longer be done in bdrv_remove_child() and | ||
9 | bdrv_replace_node_noperm(), but the callers must already make sure that | ||
10 | they are drained. | ||
11 | |||
12 | Note that the transaction callbacks still take the lock internally, so | ||
13 | tran_finalize() must be called without the lock held. This is because | ||
14 | bdrv_append() also calls bdrv_attach_child_noperm(), which currently | ||
15 | requires to be called unlocked. Once it changes, the transaction | ||
16 | callbacks can be changed, too. | ||
17 | |||
18 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
19 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
20 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
21 | Message-ID: <20230911094620.45040-10-kwolf@redhat.com> | ||
5 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 22 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
6 | --- | 23 | --- |
7 | nbd/server.c | 48 ++++++++++++++++++++++++------------------------ | 24 | block.c | 78 ++++++++++++++++++++++++++++++++++++--------------------- |
8 | 1 file changed, 24 insertions(+), 24 deletions(-) | 25 | 1 file changed, 50 insertions(+), 28 deletions(-) |
9 | 26 | ||
10 | diff --git a/nbd/server.c b/nbd/server.c | 27 | diff --git a/block.c b/block.c |
11 | index XXXXXXX..XXXXXXX 100644 | 28 | index XXXXXXX..XXXXXXX 100644 |
12 | --- a/nbd/server.c | 29 | --- a/block.c |
13 | +++ b/nbd/server.c | 30 | +++ b/block.c |
14 | @@ -XXX,XX +XXX,XX @@ nbd_read_eof(NBDClient *client, void *buffer, size_t size, Error **errp) | 31 | @@ -XXX,XX +XXX,XX @@ static bool bdrv_recurse_has_child(BlockDriverState *bs, |
15 | return 1; | 32 | static void GRAPH_WRLOCK |
33 | bdrv_replace_child_noperm(BdrvChild *child, BlockDriverState *new_bs); | ||
34 | |||
35 | -static void bdrv_remove_child(BdrvChild *child, Transaction *tran); | ||
36 | +static void GRAPH_WRLOCK | ||
37 | +bdrv_remove_child(BdrvChild *child, Transaction *tran); | ||
38 | |||
39 | static int bdrv_reopen_prepare(BDRVReopenState *reopen_state, | ||
40 | BlockReopenQueue *queue, | ||
41 | @@ -XXX,XX +XXX,XX @@ static TransactionActionDrv bdrv_replace_child_drv = { | ||
42 | * | ||
43 | * The function doesn't update permissions, caller is responsible for this. | ||
44 | */ | ||
45 | -static void bdrv_replace_child_tran(BdrvChild *child, BlockDriverState *new_bs, | ||
46 | - Transaction *tran) | ||
47 | +static void GRAPH_WRLOCK | ||
48 | +bdrv_replace_child_tran(BdrvChild *child, BlockDriverState *new_bs, | ||
49 | + Transaction *tran) | ||
50 | { | ||
51 | BdrvReplaceChildState *s = g_new(BdrvReplaceChildState, 1); | ||
52 | |||
53 | @@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_tran(BdrvChild *child, BlockDriverState *new_bs, | ||
54 | bdrv_ref(new_bs); | ||
55 | } | ||
56 | |||
57 | - bdrv_graph_wrlock(new_bs); | ||
58 | bdrv_replace_child_noperm(child, new_bs); | ||
59 | - bdrv_graph_wrunlock(); | ||
60 | /* old_bs reference is transparently moved from @child to @s */ | ||
16 | } | 61 | } |
17 | 62 | ||
18 | -static int nbd_receive_request(NBDClient *client, NBDRequest *request, | 63 | @@ -XXX,XX +XXX,XX @@ static int bdrv_set_file_or_backing_noperm(BlockDriverState *parent_bs, |
19 | - Error **errp) | 64 | } |
20 | +static int coroutine_fn nbd_receive_request(NBDClient *client, NBDRequest *request, | 65 | |
21 | + Error **errp) | 66 | if (child) { |
22 | { | 67 | + bdrv_drained_begin(child->bs); |
23 | uint8_t buf[NBD_REQUEST_SIZE]; | 68 | + bdrv_graph_wrlock(NULL); |
24 | uint32_t magic; | 69 | + |
25 | @@ -XXX,XX +XXX,XX @@ static inline void set_be_simple_reply(NBDSimpleReply *reply, uint64_t error, | 70 | bdrv_unset_inherits_from(parent_bs, child, tran); |
26 | stq_be_p(&reply->handle, handle); | 71 | bdrv_remove_child(child, tran); |
72 | + | ||
73 | + bdrv_graph_wrunlock(); | ||
74 | + bdrv_drained_end(child->bs); | ||
75 | } | ||
76 | |||
77 | if (!child_bs) { | ||
78 | @@ -XXX,XX +XXX,XX @@ void bdrv_close_all(void) | ||
79 | assert(QTAILQ_EMPTY(&all_bdrv_states)); | ||
27 | } | 80 | } |
28 | 81 | ||
29 | -static int nbd_co_send_simple_reply(NBDClient *client, | 82 | -static bool should_update_child(BdrvChild *c, BlockDriverState *to) |
30 | - uint64_t handle, | 83 | +static bool GRAPH_RDLOCK should_update_child(BdrvChild *c, BlockDriverState *to) |
31 | - uint32_t error, | 84 | { |
32 | - void *data, | 85 | GQueue *queue; |
33 | - size_t len, | 86 | GHashTable *found; |
87 | @@ -XXX,XX +XXX,XX @@ static TransactionActionDrv bdrv_remove_child_drv = { | ||
88 | .commit = bdrv_remove_child_commit, | ||
89 | }; | ||
90 | |||
91 | -/* Function doesn't update permissions, caller is responsible for this. */ | ||
92 | -static void bdrv_remove_child(BdrvChild *child, Transaction *tran) | ||
93 | +/* | ||
94 | + * Function doesn't update permissions, caller is responsible for this. | ||
95 | + * | ||
96 | + * @child->bs (if non-NULL) must be drained. | ||
97 | + */ | ||
98 | +static void GRAPH_WRLOCK bdrv_remove_child(BdrvChild *child, Transaction *tran) | ||
99 | { | ||
100 | if (!child) { | ||
101 | return; | ||
102 | } | ||
103 | |||
104 | if (child->bs) { | ||
105 | - BlockDriverState *bs = child->bs; | ||
106 | - bdrv_drained_begin(bs); | ||
107 | + assert(child->quiesced_parent); | ||
108 | bdrv_replace_child_tran(child, NULL, tran); | ||
109 | - bdrv_drained_end(bs); | ||
110 | } | ||
111 | |||
112 | tran_add(tran, &bdrv_remove_child_drv, child); | ||
113 | } | ||
114 | |||
115 | -static void undrain_on_clean_cb(void *opaque) | ||
116 | -{ | ||
117 | - bdrv_drained_end(opaque); | ||
118 | -} | ||
119 | - | ||
120 | -static TransactionActionDrv undrain_on_clean = { | ||
121 | - .clean = undrain_on_clean_cb, | ||
122 | -}; | ||
123 | - | ||
124 | -static int bdrv_replace_node_noperm(BlockDriverState *from, | ||
125 | - BlockDriverState *to, | ||
126 | - bool auto_skip, Transaction *tran, | ||
34 | - Error **errp) | 127 | - Error **errp) |
35 | +static int coroutine_fn nbd_co_send_simple_reply(NBDClient *client, | 128 | +/* |
36 | + uint64_t handle, | 129 | + * Both @from and @to (if non-NULL) must be drained. @to must be kept drained |
37 | + uint32_t error, | 130 | + * until the transaction is completed. |
38 | + void *data, | 131 | + */ |
39 | + size_t len, | 132 | +static int GRAPH_WRLOCK |
40 | + Error **errp) | 133 | +bdrv_replace_node_noperm(BlockDriverState *from, |
41 | { | 134 | + BlockDriverState *to, |
42 | NBDSimpleReply reply; | 135 | + bool auto_skip, Transaction *tran, |
43 | int nbd_err = system_errno_to_nbd_errno(error); | 136 | + Error **errp) |
44 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn nbd_co_send_sparse_read(NBDClient *client, | 137 | { |
45 | stl_be_p(&chunk.length, pnum); | 138 | BdrvChild *c, *next; |
46 | ret = nbd_co_send_iov(client, iov, 1, errp); | 139 | |
47 | } else { | 140 | GLOBAL_STATE_CODE(); |
48 | - ret = blk_pread(exp->common.blk, offset + progress, pnum, | 141 | |
49 | - data + progress, 0); | 142 | - bdrv_drained_begin(from); |
50 | + ret = blk_co_pread(exp->common.blk, offset + progress, pnum, | 143 | - bdrv_drained_begin(to); |
51 | + data + progress, 0); | 144 | - tran_add(tran, &undrain_on_clean, from); |
52 | if (ret < 0) { | 145 | - tran_add(tran, &undrain_on_clean, to); |
53 | error_setg_errno(errp, -ret, "reading from file failed"); | 146 | + assert(from->quiesce_counter); |
54 | break; | 147 | + assert(to->quiesce_counter); |
55 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn blockalloc_to_extents(BlockBackend *blk, | 148 | |
56 | * @ea is converted to BE by the function | 149 | QLIST_FOREACH_SAFE(c, &from->parents, next_parent, next) { |
57 | * @last controls whether NBD_REPLY_FLAG_DONE is sent. | 150 | assert(c->bs == from); |
58 | */ | 151 | @@ -XXX,XX +XXX,XX @@ static int bdrv_replace_node_common(BlockDriverState *from, |
59 | -static int nbd_co_send_extents(NBDClient *client, uint64_t handle, | 152 | assert(qemu_get_current_aio_context() == qemu_get_aio_context()); |
60 | - NBDExtentArray *ea, | 153 | assert(bdrv_get_aio_context(from) == bdrv_get_aio_context(to)); |
61 | - bool last, uint32_t context_id, Error **errp) | 154 | bdrv_drained_begin(from); |
62 | +static int coroutine_fn | 155 | + bdrv_drained_begin(to); |
63 | +nbd_co_send_extents(NBDClient *client, uint64_t handle, NBDExtentArray *ea, | 156 | + |
64 | + bool last, uint32_t context_id, Error **errp) | 157 | + bdrv_graph_wrlock(to); |
65 | { | 158 | |
66 | NBDStructuredMeta chunk; | 159 | /* |
67 | struct iovec iov[] = { | 160 | * Do the replacement without permission update. |
68 | @@ -XXX,XX +XXX,XX @@ static void bitmap_to_extents(BdrvDirtyBitmap *bitmap, | 161 | @@ -XXX,XX +XXX,XX @@ static int bdrv_replace_node_common(BlockDriverState *from, |
69 | bdrv_dirty_bitmap_unlock(bitmap); | 162 | } |
70 | } | 163 | |
71 | 164 | if (detach_subchain) { | |
72 | -static int nbd_co_send_bitmap(NBDClient *client, uint64_t handle, | 165 | + /* to_cow_parent is already drained because from is drained */ |
73 | - BdrvDirtyBitmap *bitmap, uint64_t offset, | 166 | bdrv_remove_child(bdrv_filter_or_cow_child(to_cow_parent), tran); |
74 | - uint32_t length, bool dont_fragment, bool last, | 167 | } |
75 | - uint32_t context_id, Error **errp) | 168 | |
76 | +static int coroutine_fn nbd_co_send_bitmap(NBDClient *client, uint64_t handle, | 169 | @@ -XXX,XX +XXX,XX @@ static int bdrv_replace_node_common(BlockDriverState *from, |
77 | + BdrvDirtyBitmap *bitmap, uint64_t offset, | 170 | ret = 0; |
78 | + uint32_t length, bool dont_fragment, bool last, | 171 | |
79 | + uint32_t context_id, Error **errp) | 172 | out: |
80 | { | 173 | + bdrv_graph_wrunlock(); |
81 | unsigned int nb_extents = dont_fragment ? 1 : NBD_MAX_BLOCK_STATUS_EXTENTS; | 174 | tran_finalize(tran, ret); |
82 | g_autoptr(NBDExtentArray) ea = nbd_extent_array_new(nb_extents); | 175 | |
83 | @@ -XXX,XX +XXX,XX @@ static int nbd_co_send_bitmap(NBDClient *client, uint64_t handle, | 176 | + bdrv_drained_end(to); |
84 | * to the client (although the caller may still need to disconnect after | 177 | bdrv_drained_end(from); |
85 | * reporting the error). | 178 | bdrv_unref(from); |
86 | */ | 179 | |
87 | -static int nbd_co_receive_request(NBDRequestData *req, NBDRequest *request, | 180 | @@ -XXX,XX +XXX,XX @@ int bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top, |
88 | - Error **errp) | 181 | BdrvChild *child; |
89 | +static int coroutine_fn nbd_co_receive_request(NBDRequestData *req, NBDRequest *request, | 182 | Transaction *tran = tran_new(); |
90 | + Error **errp) | 183 | AioContext *old_context, *new_context = NULL; |
91 | { | 184 | + bool drained = false; |
92 | NBDClient *client = req->client; | 185 | |
93 | int valid_flags; | 186 | GLOBAL_STATE_CODE(); |
94 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int nbd_do_cmd_read(NBDClient *client, NBDRequest *request, | 187 | |
95 | data, request->len, errp); | 188 | @@ -XXX,XX +XXX,XX @@ int bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top, |
96 | } | 189 | aio_context_acquire(new_context); |
97 | 190 | } | |
98 | - ret = blk_pread(exp->common.blk, request->from, request->len, data, 0); | 191 | |
99 | + ret = blk_co_pread(exp->common.blk, request->from, request->len, data, 0); | 192 | + bdrv_drained_begin(bs_new); |
193 | + bdrv_drained_begin(bs_top); | ||
194 | + drained = true; | ||
195 | + | ||
196 | + bdrv_graph_wrlock(bs_new); | ||
197 | ret = bdrv_replace_node_noperm(bs_top, bs_new, true, tran, errp); | ||
198 | + bdrv_graph_wrunlock(); | ||
100 | if (ret < 0) { | 199 | if (ret < 0) { |
101 | return nbd_send_generic_reply(client, request->handle, ret, | 200 | goto out; |
102 | "reading from file failed", errp); | 201 | } |
103 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int nbd_handle_request(NBDClient *client, | 202 | @@ -XXX,XX +XXX,XX @@ out: |
104 | if (request->flags & NBD_CMD_FLAG_FUA) { | 203 | bdrv_refresh_limits(bs_top, NULL, NULL); |
105 | flags |= BDRV_REQ_FUA; | 204 | bdrv_graph_rdunlock_main_loop(); |
106 | } | 205 | |
107 | - ret = blk_pwrite(exp->common.blk, request->from, request->len, data, | 206 | + if (drained) { |
108 | - flags); | 207 | + bdrv_drained_end(bs_top); |
109 | + ret = blk_co_pwrite(exp->common.blk, request->from, request->len, data, | 208 | + bdrv_drained_end(bs_new); |
110 | + flags); | 209 | + } |
111 | return nbd_send_generic_reply(client, request->handle, ret, | 210 | + |
112 | "writing to file failed", errp); | 211 | if (new_context && old_context != new_context) { |
113 | 212 | aio_context_release(new_context); | |
114 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int nbd_handle_request(NBDClient *client, | 213 | aio_context_acquire(old_context); |
115 | if (request->flags & NBD_CMD_FLAG_FAST_ZERO) { | 214 | @@ -XXX,XX +XXX,XX @@ int bdrv_replace_child_bs(BdrvChild *child, BlockDriverState *new_bs, |
116 | flags |= BDRV_REQ_NO_FALLBACK; | 215 | bdrv_ref(old_bs); |
117 | } | 216 | bdrv_drained_begin(old_bs); |
118 | - ret = blk_pwrite_zeroes(exp->common.blk, request->from, request->len, | 217 | bdrv_drained_begin(new_bs); |
119 | - flags); | 218 | + bdrv_graph_wrlock(new_bs); |
120 | + ret = blk_co_pwrite_zeroes(exp->common.blk, request->from, request->len, | 219 | |
121 | + flags); | 220 | bdrv_replace_child_tran(child, new_bs, tran); |
122 | return nbd_send_generic_reply(client, request->handle, ret, | 221 | |
123 | "writing to file failed", errp); | 222 | @@ -XXX,XX +XXX,XX @@ int bdrv_replace_child_bs(BdrvChild *child, BlockDriverState *new_bs, |
223 | refresh_list = g_slist_prepend(refresh_list, new_bs); | ||
224 | |||
225 | ret = bdrv_list_refresh_perms(refresh_list, NULL, tran, errp); | ||
226 | + bdrv_graph_wrunlock(); | ||
227 | |||
228 | tran_finalize(tran, ret); | ||
124 | 229 | ||
125 | -- | 230 | -- |
126 | 2.40.0 | 231 | 2.41.0 | diff view generated by jsdifflib |
1 | From: Stefan Hajnoczi <stefanha@redhat.com> | 1 | Instead of taking the writer lock internally, require callers to already |
---|---|---|---|
2 | hold it when calling bdrv_attach_child_common(). These callers will | ||
3 | typically already hold the graph lock once the locking work is | ||
4 | completed, which means that they can't call functions that take it | ||
5 | internally. | ||
2 | 6 | ||
3 | Not a coroutine_fn, you say? | 7 | Note that the transaction callbacks still take the lock internally, so |
8 | tran_finalize() must be called without the lock held. This is because | ||
9 | bdrv_append() also calls bdrv_replace_node_noperm(), which currently | ||
10 | requires the transaction callbacks to be called unlocked. In the next | ||
11 | step, both of them can be switched to locked tran_finalize() calls | ||
12 | together. | ||
4 | 13 | ||
5 | static int64_t bdrv_sum_allocated_file_size(BlockDriverState *bs) | 14 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
6 | { | 15 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> |
7 | BdrvChild *child; | 16 | Message-ID: <20230911094620.45040-11-kwolf@redhat.com> |
8 | int64_t child_size, sum = 0; | ||
9 | |||
10 | QLIST_FOREACH(child, &bs->children, next) { | ||
11 | if (child->role & (BDRV_CHILD_DATA | BDRV_CHILD_METADATA | | ||
12 | BDRV_CHILD_FILTERED)) | ||
13 | { | ||
14 | child_size = bdrv_co_get_allocated_file_size(child->bs); | ||
15 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
16 | |||
17 | Well what do we have here?! | ||
18 | |||
19 | I rest my case, your honor. | ||
20 | |||
21 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
22 | Message-Id: <20230308211435.346375-1-stefanha@redhat.com> | ||
23 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
24 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 17 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
25 | --- | 18 | --- |
26 | block.c | 2 +- | 19 | block.c | 133 +++++++++++++++++++++++++++++++------------------ |
27 | 1 file changed, 1 insertion(+), 1 deletion(-) | 20 | block/stream.c | 20 ++++++-- |
21 | 2 files changed, 100 insertions(+), 53 deletions(-) | ||
28 | 22 | ||
29 | diff --git a/block.c b/block.c | 23 | diff --git a/block.c b/block.c |
30 | index XXXXXXX..XXXXXXX 100644 | 24 | index XXXXXXX..XXXXXXX 100644 |
31 | --- a/block.c | 25 | --- a/block.c |
32 | +++ b/block.c | 26 | +++ b/block.c |
33 | @@ -XXX,XX +XXX,XX @@ exit: | 27 | @@ -XXX,XX +XXX,XX @@ static TransactionActionDrv bdrv_attach_child_common_drv = { |
34 | * sums the size of all data-bearing children. (This excludes backing | 28 | * @child_bs can move to a different AioContext in this function. Callers must |
35 | * children.) | 29 | * make sure that their AioContext locking is still correct after this. |
36 | */ | 30 | */ |
37 | -static int64_t bdrv_sum_allocated_file_size(BlockDriverState *bs) | 31 | -static BdrvChild *bdrv_attach_child_common(BlockDriverState *child_bs, |
38 | +static int64_t coroutine_fn bdrv_sum_allocated_file_size(BlockDriverState *bs) | 32 | - const char *child_name, |
39 | { | 33 | - const BdrvChildClass *child_class, |
34 | - BdrvChildRole child_role, | ||
35 | - uint64_t perm, uint64_t shared_perm, | ||
36 | - void *opaque, | ||
37 | - Transaction *tran, Error **errp) | ||
38 | +static BdrvChild * GRAPH_WRLOCK | ||
39 | +bdrv_attach_child_common(BlockDriverState *child_bs, | ||
40 | + const char *child_name, | ||
41 | + const BdrvChildClass *child_class, | ||
42 | + BdrvChildRole child_role, | ||
43 | + uint64_t perm, uint64_t shared_perm, | ||
44 | + void *opaque, | ||
45 | + Transaction *tran, Error **errp) | ||
46 | { | ||
47 | BdrvChild *new_child; | ||
48 | AioContext *parent_ctx, *new_child_ctx; | ||
49 | @@ -XXX,XX +XXX,XX @@ static BdrvChild *bdrv_attach_child_common(BlockDriverState *child_bs, | ||
50 | * a problem, we already did this), but it will still poll until the parent | ||
51 | * is fully quiesced, so it will not be negatively affected either. | ||
52 | */ | ||
53 | - bdrv_graph_wrlock(child_bs); | ||
54 | bdrv_parent_drained_begin_single(new_child); | ||
55 | bdrv_replace_child_noperm(new_child, child_bs); | ||
56 | - bdrv_graph_wrunlock(); | ||
57 | |||
58 | BdrvAttachChildCommonState *s = g_new(BdrvAttachChildCommonState, 1); | ||
59 | *s = (BdrvAttachChildCommonState) { | ||
60 | @@ -XXX,XX +XXX,XX @@ static BdrvChild *bdrv_attach_child_common(BlockDriverState *child_bs, | ||
61 | * @child_bs can move to a different AioContext in this function. Callers must | ||
62 | * make sure that their AioContext locking is still correct after this. | ||
63 | */ | ||
64 | -static BdrvChild *bdrv_attach_child_noperm(BlockDriverState *parent_bs, | ||
65 | - BlockDriverState *child_bs, | ||
66 | - const char *child_name, | ||
67 | - const BdrvChildClass *child_class, | ||
68 | - BdrvChildRole child_role, | ||
69 | - Transaction *tran, | ||
70 | - Error **errp) | ||
71 | +static BdrvChild * GRAPH_WRLOCK | ||
72 | +bdrv_attach_child_noperm(BlockDriverState *parent_bs, | ||
73 | + BlockDriverState *child_bs, | ||
74 | + const char *child_name, | ||
75 | + const BdrvChildClass *child_class, | ||
76 | + BdrvChildRole child_role, | ||
77 | + Transaction *tran, | ||
78 | + Error **errp) | ||
79 | { | ||
80 | uint64_t perm, shared_perm; | ||
81 | |||
82 | @@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs, | ||
83 | |||
84 | GLOBAL_STATE_CODE(); | ||
85 | |||
86 | + bdrv_graph_wrlock(child_bs); | ||
87 | + | ||
88 | child = bdrv_attach_child_common(child_bs, child_name, child_class, | ||
89 | child_role, perm, shared_perm, opaque, | ||
90 | tran, errp); | ||
91 | @@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs, | ||
92 | ret = bdrv_refresh_perms(child_bs, tran, errp); | ||
93 | |||
94 | out: | ||
95 | + bdrv_graph_wrunlock(); | ||
96 | tran_finalize(tran, ret); | ||
97 | |||
98 | bdrv_unref(child_bs); | ||
99 | @@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs, | ||
100 | |||
101 | GLOBAL_STATE_CODE(); | ||
102 | |||
103 | + bdrv_graph_wrlock(child_bs); | ||
104 | + | ||
105 | child = bdrv_attach_child_noperm(parent_bs, child_bs, child_name, | ||
106 | child_class, child_role, tran, errp); | ||
107 | if (!child) { | ||
108 | @@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs, | ||
109 | } | ||
110 | |||
111 | out: | ||
112 | + bdrv_graph_wrunlock(); | ||
113 | tran_finalize(tran, ret); | ||
114 | |||
115 | bdrv_unref(child_bs); | ||
116 | @@ -XXX,XX +XXX,XX @@ static BdrvChildRole bdrv_backing_role(BlockDriverState *bs) | ||
117 | * Sets the bs->backing or bs->file link of a BDS. A new reference is created; | ||
118 | * callers which don't need their own reference any more must call bdrv_unref(). | ||
119 | * | ||
120 | + * If the respective child is already present (i.e. we're detaching a node), | ||
121 | + * that child node must be drained. | ||
122 | + * | ||
123 | * Function doesn't update permissions, caller is responsible for this. | ||
124 | * | ||
125 | * The caller must hold the AioContext lock for @child_bs. Both @parent_bs and | ||
126 | * @child_bs can move to a different AioContext in this function. Callers must | ||
127 | * make sure that their AioContext locking is still correct after this. | ||
128 | */ | ||
129 | -static int bdrv_set_file_or_backing_noperm(BlockDriverState *parent_bs, | ||
130 | - BlockDriverState *child_bs, | ||
131 | - bool is_backing, | ||
132 | - Transaction *tran, Error **errp) | ||
133 | +static int GRAPH_WRLOCK | ||
134 | +bdrv_set_file_or_backing_noperm(BlockDriverState *parent_bs, | ||
135 | + BlockDriverState *child_bs, | ||
136 | + bool is_backing, | ||
137 | + Transaction *tran, Error **errp) | ||
138 | { | ||
139 | bool update_inherits_from = | ||
140 | bdrv_inherits_from_recursive(child_bs, parent_bs); | ||
141 | @@ -XXX,XX +XXX,XX @@ static int bdrv_set_file_or_backing_noperm(BlockDriverState *parent_bs, | ||
142 | } | ||
143 | |||
144 | if (child) { | ||
145 | - bdrv_drained_begin(child->bs); | ||
146 | - bdrv_graph_wrlock(NULL); | ||
147 | - | ||
148 | + assert(child->bs->quiesce_counter); | ||
149 | bdrv_unset_inherits_from(parent_bs, child, tran); | ||
150 | bdrv_remove_child(child, tran); | ||
151 | - | ||
152 | - bdrv_graph_wrunlock(); | ||
153 | - bdrv_drained_end(child->bs); | ||
154 | } | ||
155 | |||
156 | if (!child_bs) { | ||
157 | @@ -XXX,XX +XXX,XX @@ static int bdrv_set_file_or_backing_noperm(BlockDriverState *parent_bs, | ||
158 | } | ||
159 | |||
160 | out: | ||
161 | - bdrv_graph_rdlock_main_loop(); | ||
162 | bdrv_refresh_limits(parent_bs, tran, NULL); | ||
163 | - bdrv_graph_rdunlock_main_loop(); | ||
164 | |||
165 | return 0; | ||
166 | } | ||
167 | @@ -XXX,XX +XXX,XX @@ out: | ||
168 | * The caller must hold the AioContext lock for @backing_hd. Both @bs and | ||
169 | * @backing_hd can move to a different AioContext in this function. Callers must | ||
170 | * make sure that their AioContext locking is still correct after this. | ||
171 | + * | ||
172 | + * If a backing child is already present (i.e. we're detaching a node), that | ||
173 | + * child node must be drained. | ||
174 | */ | ||
175 | -static int bdrv_set_backing_noperm(BlockDriverState *bs, | ||
176 | - BlockDriverState *backing_hd, | ||
177 | - Transaction *tran, Error **errp) | ||
178 | +static int GRAPH_WRLOCK | ||
179 | +bdrv_set_backing_noperm(BlockDriverState *bs, | ||
180 | + BlockDriverState *backing_hd, | ||
181 | + Transaction *tran, Error **errp) | ||
182 | { | ||
183 | GLOBAL_STATE_CODE(); | ||
184 | return bdrv_set_file_or_backing_noperm(bs, backing_hd, true, tran, errp); | ||
185 | @@ -XXX,XX +XXX,XX @@ int bdrv_set_backing_hd_drained(BlockDriverState *bs, | ||
186 | |||
187 | GLOBAL_STATE_CODE(); | ||
188 | assert(bs->quiesce_counter > 0); | ||
189 | + if (bs->backing) { | ||
190 | + assert(bs->backing->bs->quiesce_counter > 0); | ||
191 | + } | ||
192 | + bdrv_graph_wrlock(backing_hd); | ||
193 | |||
194 | ret = bdrv_set_backing_noperm(bs, backing_hd, tran, errp); | ||
195 | if (ret < 0) { | ||
196 | @@ -XXX,XX +XXX,XX @@ int bdrv_set_backing_hd_drained(BlockDriverState *bs, | ||
197 | |||
198 | ret = bdrv_refresh_perms(bs, tran, errp); | ||
199 | out: | ||
200 | + bdrv_graph_wrunlock(); | ||
201 | tran_finalize(tran, ret); | ||
202 | return ret; | ||
203 | } | ||
204 | @@ -XXX,XX +XXX,XX @@ out: | ||
205 | int bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd, | ||
206 | Error **errp) | ||
207 | { | ||
208 | + BlockDriverState *drain_bs = bs->backing ? bs->backing->bs : bs; | ||
209 | int ret; | ||
210 | GLOBAL_STATE_CODE(); | ||
211 | |||
212 | - bdrv_drained_begin(bs); | ||
213 | + bdrv_ref(drain_bs); | ||
214 | + bdrv_drained_begin(drain_bs); | ||
215 | ret = bdrv_set_backing_hd_drained(bs, backing_hd, errp); | ||
216 | - bdrv_drained_end(bs); | ||
217 | + bdrv_drained_end(drain_bs); | ||
218 | + bdrv_unref(drain_bs); | ||
219 | |||
220 | return ret; | ||
221 | } | ||
222 | @@ -XXX,XX +XXX,XX @@ int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp) | ||
223 | |||
224 | abort: | ||
225 | tran_abort(tran); | ||
226 | + | ||
227 | QTAILQ_FOREACH_SAFE(bs_entry, bs_queue, entry, next) { | ||
228 | if (bs_entry->prepared) { | ||
229 | ctx = bdrv_get_aio_context(bs_entry->state.bs); | ||
230 | @@ -XXX,XX +XXX,XX @@ static int bdrv_reopen_parse_file_or_backing(BDRVReopenState *reopen_state, | ||
231 | reopen_state->old_file_bs = old_child_bs; | ||
232 | } | ||
233 | |||
234 | + if (old_child_bs) { | ||
235 | + bdrv_ref(old_child_bs); | ||
236 | + bdrv_drained_begin(old_child_bs); | ||
237 | + } | ||
238 | + | ||
239 | old_ctx = bdrv_get_aio_context(bs); | ||
240 | ctx = bdrv_get_aio_context(new_child_bs); | ||
241 | if (old_ctx != ctx) { | ||
242 | @@ -XXX,XX +XXX,XX @@ static int bdrv_reopen_parse_file_or_backing(BDRVReopenState *reopen_state, | ||
243 | aio_context_acquire(ctx); | ||
244 | } | ||
245 | |||
246 | + bdrv_graph_wrlock(new_child_bs); | ||
247 | + | ||
248 | ret = bdrv_set_file_or_backing_noperm(bs, new_child_bs, is_backing, | ||
249 | tran, errp); | ||
250 | |||
251 | + bdrv_graph_wrunlock(); | ||
252 | + | ||
253 | if (old_ctx != ctx) { | ||
254 | aio_context_release(ctx); | ||
255 | aio_context_acquire(old_ctx); | ||
256 | } | ||
257 | |||
258 | + if (old_child_bs) { | ||
259 | + bdrv_drained_end(old_child_bs); | ||
260 | + bdrv_unref(old_child_bs); | ||
261 | + } | ||
262 | + | ||
263 | return ret; | ||
264 | } | ||
265 | |||
266 | @@ -XXX,XX +XXX,XX @@ int bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top, | ||
40 | BdrvChild *child; | 267 | BdrvChild *child; |
41 | int64_t child_size, sum = 0; | 268 | Transaction *tran = tran_new(); |
269 | AioContext *old_context, *new_context = NULL; | ||
270 | - bool drained = false; | ||
271 | |||
272 | GLOBAL_STATE_CODE(); | ||
273 | |||
274 | assert(!bs_new->backing); | ||
275 | |||
276 | old_context = bdrv_get_aio_context(bs_top); | ||
277 | + bdrv_drained_begin(bs_top); | ||
278 | + | ||
279 | + /* | ||
280 | + * bdrv_drained_begin() requires that only the AioContext of the drained | ||
281 | + * node is locked, and at this point it can still differ from the AioContext | ||
282 | + * of bs_top. | ||
283 | + */ | ||
284 | + new_context = bdrv_get_aio_context(bs_new); | ||
285 | + aio_context_release(old_context); | ||
286 | + aio_context_acquire(new_context); | ||
287 | + bdrv_drained_begin(bs_new); | ||
288 | + aio_context_release(new_context); | ||
289 | + aio_context_acquire(old_context); | ||
290 | + new_context = NULL; | ||
291 | + | ||
292 | + bdrv_graph_wrlock(bs_top); | ||
293 | |||
294 | child = bdrv_attach_child_noperm(bs_new, bs_top, "backing", | ||
295 | &child_of_bds, bdrv_backing_role(bs_new), | ||
296 | @@ -XXX,XX +XXX,XX @@ int bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top, | ||
297 | } | ||
298 | |||
299 | /* | ||
300 | - * bdrv_attach_child_noperm could change the AioContext of bs_top. | ||
301 | - * bdrv_replace_node_noperm calls bdrv_drained_begin, so let's temporarily | ||
302 | - * hold the new AioContext, since bdrv_drained_begin calls BDRV_POLL_WHILE | ||
303 | - * that assumes the new lock is taken. | ||
304 | + * bdrv_attach_child_noperm could change the AioContext of bs_top and | ||
305 | + * bs_new, but at least they are in the same AioContext now. This is the | ||
306 | + * AioContext that we need to lock for the rest of the function. | ||
307 | */ | ||
308 | new_context = bdrv_get_aio_context(bs_top); | ||
309 | |||
310 | @@ -XXX,XX +XXX,XX @@ int bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top, | ||
311 | aio_context_acquire(new_context); | ||
312 | } | ||
313 | |||
314 | - bdrv_drained_begin(bs_new); | ||
315 | - bdrv_drained_begin(bs_top); | ||
316 | - drained = true; | ||
317 | - | ||
318 | - bdrv_graph_wrlock(bs_new); | ||
319 | ret = bdrv_replace_node_noperm(bs_top, bs_new, true, tran, errp); | ||
320 | - bdrv_graph_wrunlock(); | ||
321 | if (ret < 0) { | ||
322 | goto out; | ||
323 | } | ||
324 | |||
325 | ret = bdrv_refresh_perms(bs_new, tran, errp); | ||
326 | out: | ||
327 | + bdrv_graph_wrunlock(); | ||
328 | tran_finalize(tran, ret); | ||
329 | |||
330 | bdrv_graph_rdlock_main_loop(); | ||
331 | bdrv_refresh_limits(bs_top, NULL, NULL); | ||
332 | bdrv_graph_rdunlock_main_loop(); | ||
333 | |||
334 | - if (drained) { | ||
335 | - bdrv_drained_end(bs_top); | ||
336 | - bdrv_drained_end(bs_new); | ||
337 | - } | ||
338 | + bdrv_drained_end(bs_top); | ||
339 | + bdrv_drained_end(bs_new); | ||
340 | |||
341 | if (new_context && old_context != new_context) { | ||
342 | aio_context_release(new_context); | ||
343 | diff --git a/block/stream.c b/block/stream.c | ||
344 | index XXXXXXX..XXXXXXX 100644 | ||
345 | --- a/block/stream.c | ||
346 | +++ b/block/stream.c | ||
347 | @@ -XXX,XX +XXX,XX @@ static int stream_prepare(Job *job) | ||
348 | { | ||
349 | StreamBlockJob *s = container_of(job, StreamBlockJob, common.job); | ||
350 | BlockDriverState *unfiltered_bs = bdrv_skip_filters(s->target_bs); | ||
351 | + BlockDriverState *unfiltered_bs_cow = bdrv_cow_bs(unfiltered_bs); | ||
352 | BlockDriverState *base; | ||
353 | BlockDriverState *unfiltered_base; | ||
354 | Error *local_err = NULL; | ||
355 | @@ -XXX,XX +XXX,XX @@ static int stream_prepare(Job *job) | ||
356 | s->cor_filter_bs = NULL; | ||
357 | |||
358 | /* | ||
359 | - * bdrv_set_backing_hd() requires that unfiltered_bs is drained. Drain | ||
360 | - * already here and use bdrv_set_backing_hd_drained() instead because | ||
361 | - * the polling during drained_begin() might change the graph, and if we do | ||
362 | - * this only later, we may end up working with the wrong base node (or it | ||
363 | - * might even have gone away by the time we want to use it). | ||
364 | + * bdrv_set_backing_hd() requires that the unfiltered_bs and the COW child | ||
365 | + * of unfiltered_bs is drained. Drain already here and use | ||
366 | + * bdrv_set_backing_hd_drained() instead because the polling during | ||
367 | + * drained_begin() might change the graph, and if we do this only later, we | ||
368 | + * may end up working with the wrong base node (or it might even have gone | ||
369 | + * away by the time we want to use it). | ||
370 | */ | ||
371 | bdrv_drained_begin(unfiltered_bs); | ||
372 | + if (unfiltered_bs_cow) { | ||
373 | + bdrv_ref(unfiltered_bs_cow); | ||
374 | + bdrv_drained_begin(unfiltered_bs_cow); | ||
375 | + } | ||
376 | |||
377 | base = bdrv_filter_or_cow_bs(s->above_base); | ||
378 | unfiltered_base = bdrv_skip_filters(base); | ||
379 | @@ -XXX,XX +XXX,XX @@ static int stream_prepare(Job *job) | ||
380 | } | ||
381 | |||
382 | out: | ||
383 | + if (unfiltered_bs_cow) { | ||
384 | + bdrv_drained_end(unfiltered_bs_cow); | ||
385 | + bdrv_unref(unfiltered_bs_cow); | ||
386 | + } | ||
387 | bdrv_drained_end(unfiltered_bs); | ||
388 | return ret; | ||
389 | } | ||
42 | -- | 390 | -- |
43 | 2.40.0 | 391 | 2.41.0 | diff view generated by jsdifflib |
1 | From: Paolo Bonzini <pbonzini@redhat.com> | 1 | In previous patches, we changed some transactionable functions to be |
---|---|---|---|
2 | 2 | marked as GRAPH_WRLOCK, but required that tran_finalize() is still | |
3 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> | 3 | called without the lock. This was because all callbacks that can be in |
4 | Message-Id: <20230309084456.304669-3-pbonzini@redhat.com> | 4 | the same transaction need to follow the same convention. |
5 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | 5 | |
6 | Now that we don't have conflicting requirements any more, we can switch | ||
7 | all of the transaction callbacks to be declared GRAPH_WRLOCK, too, and | ||
8 | call tran_finalize() with the lock held. | ||
9 | |||
10 | Document for each of these transactionable functions that the lock needs | ||
11 | to be held when completing the transaction, and make sure that all | ||
12 | callers down to the place where the transaction is finalised actually | ||
13 | have the writer lock. | ||
14 | |||
15 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
16 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
17 | Message-ID: <20230911094620.45040-12-kwolf@redhat.com> | ||
6 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 18 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
7 | --- | 19 | --- |
8 | block/blkdebug.c | 4 ++-- | 20 | block.c | 61 +++++++++++++++++++++++++++++++++++++++++---------------- |
9 | 1 file changed, 2 insertions(+), 2 deletions(-) | 21 | 1 file changed, 44 insertions(+), 17 deletions(-) |
10 | 22 | ||
11 | diff --git a/block/blkdebug.c b/block/blkdebug.c | 23 | diff --git a/block.c b/block.c |
12 | index XXXXXXX..XXXXXXX 100644 | 24 | index XXXXXXX..XXXXXXX 100644 |
13 | --- a/block/blkdebug.c | 25 | --- a/block.c |
14 | +++ b/block/blkdebug.c | 26 | +++ b/block.c |
27 | @@ -XXX,XX +XXX,XX @@ typedef struct BdrvReplaceChildState { | ||
28 | BlockDriverState *old_bs; | ||
29 | } BdrvReplaceChildState; | ||
30 | |||
31 | -static void bdrv_replace_child_commit(void *opaque) | ||
32 | +static void GRAPH_WRLOCK bdrv_replace_child_commit(void *opaque) | ||
33 | { | ||
34 | BdrvReplaceChildState *s = opaque; | ||
35 | GLOBAL_STATE_CODE(); | ||
36 | |||
37 | - bdrv_unref(s->old_bs); | ||
38 | + bdrv_schedule_unref(s->old_bs); | ||
39 | } | ||
40 | |||
41 | -static void bdrv_replace_child_abort(void *opaque) | ||
42 | +static void GRAPH_WRLOCK bdrv_replace_child_abort(void *opaque) | ||
43 | { | ||
44 | BdrvReplaceChildState *s = opaque; | ||
45 | BlockDriverState *new_bs = s->child->bs; | ||
46 | |||
47 | GLOBAL_STATE_CODE(); | ||
48 | - bdrv_graph_wrlock(s->old_bs); | ||
49 | + assert_bdrv_graph_writable(); | ||
50 | |||
51 | /* old_bs reference is transparently moved from @s to @s->child */ | ||
52 | if (!s->child->bs) { | ||
53 | @@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_abort(void *opaque) | ||
54 | assert(s->child->quiesced_parent); | ||
55 | bdrv_replace_child_noperm(s->child, s->old_bs); | ||
56 | |||
57 | - bdrv_graph_wrunlock(); | ||
58 | bdrv_unref(new_bs); | ||
59 | } | ||
60 | |||
61 | @@ -XXX,XX +XXX,XX @@ static TransactionActionDrv bdrv_replace_child_drv = { | ||
62 | * Both @child->bs and @new_bs (if non-NULL) must be drained. @new_bs must be | ||
63 | * kept drained until the transaction is completed. | ||
64 | * | ||
65 | + * After calling this function, the transaction @tran may only be completed | ||
66 | + * while holding a writer lock for the graph. | ||
67 | + * | ||
68 | * The function doesn't update permissions, caller is responsible for this. | ||
69 | */ | ||
70 | static void GRAPH_WRLOCK | ||
71 | @@ -XXX,XX +XXX,XX @@ typedef struct BdrvAttachChildCommonState { | ||
72 | AioContext *old_child_ctx; | ||
73 | } BdrvAttachChildCommonState; | ||
74 | |||
75 | -static void bdrv_attach_child_common_abort(void *opaque) | ||
76 | +static void GRAPH_WRLOCK bdrv_attach_child_common_abort(void *opaque) | ||
77 | { | ||
78 | BdrvAttachChildCommonState *s = opaque; | ||
79 | BlockDriverState *bs = s->child->bs; | ||
80 | |||
81 | GLOBAL_STATE_CODE(); | ||
82 | + assert_bdrv_graph_writable(); | ||
83 | |||
84 | - bdrv_graph_wrlock(NULL); | ||
85 | bdrv_replace_child_noperm(s->child, NULL); | ||
86 | - bdrv_graph_wrunlock(); | ||
87 | |||
88 | if (bdrv_get_aio_context(bs) != s->old_child_ctx) { | ||
89 | bdrv_try_change_aio_context(bs, s->old_child_ctx, NULL, &error_abort); | ||
90 | @@ -XXX,XX +XXX,XX @@ static void bdrv_attach_child_common_abort(void *opaque) | ||
91 | tran_commit(tran); | ||
92 | } | ||
93 | |||
94 | - bdrv_unref(bs); | ||
95 | + bdrv_schedule_unref(bs); | ||
96 | bdrv_child_free(s->child); | ||
97 | } | ||
98 | |||
99 | @@ -XXX,XX +XXX,XX @@ static TransactionActionDrv bdrv_attach_child_common_drv = { | ||
100 | * | ||
101 | * Function doesn't update permissions, caller is responsible for this. | ||
102 | * | ||
103 | + * After calling this function, the transaction @tran may only be completed | ||
104 | + * while holding a writer lock for the graph. | ||
105 | + * | ||
106 | * Returns new created child. | ||
107 | * | ||
108 | * The caller must hold the AioContext lock for @child_bs. Both @parent_bs and | ||
109 | @@ -XXX,XX +XXX,XX @@ bdrv_attach_child_common(BlockDriverState *child_bs, | ||
110 | * The caller must hold the AioContext lock for @child_bs. Both @parent_bs and | ||
111 | * @child_bs can move to a different AioContext in this function. Callers must | ||
112 | * make sure that their AioContext locking is still correct after this. | ||
113 | + * | ||
114 | + * After calling this function, the transaction @tran may only be completed | ||
115 | + * while holding a writer lock for the graph. | ||
116 | */ | ||
117 | static BdrvChild * GRAPH_WRLOCK | ||
118 | bdrv_attach_child_noperm(BlockDriverState *parent_bs, | ||
119 | @@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs, | ||
120 | ret = bdrv_refresh_perms(child_bs, tran, errp); | ||
121 | |||
122 | out: | ||
123 | - bdrv_graph_wrunlock(); | ||
124 | tran_finalize(tran, ret); | ||
125 | + bdrv_graph_wrunlock(); | ||
126 | |||
127 | bdrv_unref(child_bs); | ||
128 | |||
129 | @@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs, | ||
130 | } | ||
131 | |||
132 | out: | ||
133 | - bdrv_graph_wrunlock(); | ||
134 | tran_finalize(tran, ret); | ||
135 | + bdrv_graph_wrunlock(); | ||
136 | |||
137 | bdrv_unref(child_bs); | ||
138 | |||
139 | @@ -XXX,XX +XXX,XX @@ static BdrvChildRole bdrv_backing_role(BlockDriverState *bs) | ||
140 | * The caller must hold the AioContext lock for @child_bs. Both @parent_bs and | ||
141 | * @child_bs can move to a different AioContext in this function. Callers must | ||
142 | * make sure that their AioContext locking is still correct after this. | ||
143 | + * | ||
144 | + * After calling this function, the transaction @tran may only be completed | ||
145 | + * while holding a writer lock for the graph. | ||
146 | */ | ||
147 | static int GRAPH_WRLOCK | ||
148 | bdrv_set_file_or_backing_noperm(BlockDriverState *parent_bs, | ||
15 | @@ -XXX,XX +XXX,XX @@ out: | 149 | @@ -XXX,XX +XXX,XX @@ out: |
150 | * | ||
151 | * If a backing child is already present (i.e. we're detaching a node), that | ||
152 | * child node must be drained. | ||
153 | + * | ||
154 | + * After calling this function, the transaction @tran may only be completed | ||
155 | + * while holding a writer lock for the graph. | ||
156 | */ | ||
157 | static int GRAPH_WRLOCK | ||
158 | bdrv_set_backing_noperm(BlockDriverState *bs, | ||
159 | @@ -XXX,XX +XXX,XX @@ int bdrv_set_backing_hd_drained(BlockDriverState *bs, | ||
160 | |||
161 | ret = bdrv_refresh_perms(bs, tran, errp); | ||
162 | out: | ||
163 | - bdrv_graph_wrunlock(); | ||
164 | tran_finalize(tran, ret); | ||
165 | + bdrv_graph_wrunlock(); | ||
16 | return ret; | 166 | return ret; |
17 | } | 167 | } |
18 | 168 | ||
19 | -static int rule_check(BlockDriverState *bs, uint64_t offset, uint64_t bytes, | 169 | @@ -XXX,XX +XXX,XX @@ int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp) |
20 | - BlkdebugIOType iotype) | 170 | aio_context_release(ctx); |
21 | +static int coroutine_fn rule_check(BlockDriverState *bs, uint64_t offset, | 171 | } |
22 | + uint64_t bytes, BlkdebugIOType iotype) | 172 | |
23 | { | 173 | + bdrv_graph_wrlock(NULL); |
24 | BDRVBlkdebugState *s = bs->opaque; | 174 | tran_commit(tran); |
25 | BlkdebugRule *rule = NULL; | 175 | + bdrv_graph_wrunlock(); |
176 | |||
177 | QTAILQ_FOREACH_REVERSE(bs_entry, bs_queue, entry) { | ||
178 | BlockDriverState *bs = bs_entry->state.bs; | ||
179 | @@ -XXX,XX +XXX,XX @@ int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp) | ||
180 | goto cleanup; | ||
181 | |||
182 | abort: | ||
183 | + bdrv_graph_wrlock(NULL); | ||
184 | tran_abort(tran); | ||
185 | + bdrv_graph_wrunlock(); | ||
186 | |||
187 | QTAILQ_FOREACH_SAFE(bs_entry, bs_queue, entry, next) { | ||
188 | if (bs_entry->prepared) { | ||
189 | @@ -XXX,XX +XXX,XX @@ int bdrv_reopen_set_read_only(BlockDriverState *bs, bool read_only, | ||
190 | * true and reopen_state->new_backing_bs contains a pointer to the new | ||
191 | * backing BlockDriverState (or NULL). | ||
192 | * | ||
193 | + * After calling this function, the transaction @tran may only be completed | ||
194 | + * while holding a writer lock for the graph. | ||
195 | + * | ||
196 | * Return 0 on success, otherwise return < 0 and set @errp. | ||
197 | * | ||
198 | * The caller must hold the AioContext lock of @reopen_state->bs. | ||
199 | @@ -XXX,XX +XXX,XX @@ static int bdrv_reopen_parse_file_or_backing(BDRVReopenState *reopen_state, | ||
200 | * commit() for any other BDS that have been left in a prepare() state | ||
201 | * | ||
202 | * The caller must hold the AioContext lock of @reopen_state->bs. | ||
203 | + * | ||
204 | + * After calling this function, the transaction @change_child_tran may only be | ||
205 | + * completed while holding a writer lock for the graph. | ||
206 | */ | ||
207 | static int bdrv_reopen_prepare(BDRVReopenState *reopen_state, | ||
208 | BlockReopenQueue *queue, | ||
209 | @@ -XXX,XX +XXX,XX @@ static TransactionActionDrv bdrv_remove_child_drv = { | ||
210 | * Function doesn't update permissions, caller is responsible for this. | ||
211 | * | ||
212 | * @child->bs (if non-NULL) must be drained. | ||
213 | + * | ||
214 | + * After calling this function, the transaction @tran may only be completed | ||
215 | + * while holding a writer lock for the graph. | ||
216 | */ | ||
217 | static void GRAPH_WRLOCK bdrv_remove_child(BdrvChild *child, Transaction *tran) | ||
218 | { | ||
219 | @@ -XXX,XX +XXX,XX @@ static void GRAPH_WRLOCK bdrv_remove_child(BdrvChild *child, Transaction *tran) | ||
220 | /* | ||
221 | * Both @from and @to (if non-NULL) must be drained. @to must be kept drained | ||
222 | * until the transaction is completed. | ||
223 | + * | ||
224 | + * After calling this function, the transaction @tran may only be completed | ||
225 | + * while holding a writer lock for the graph. | ||
226 | */ | ||
227 | static int GRAPH_WRLOCK | ||
228 | bdrv_replace_node_noperm(BlockDriverState *from, | ||
229 | @@ -XXX,XX +XXX,XX @@ static int bdrv_replace_node_common(BlockDriverState *from, | ||
230 | ret = 0; | ||
231 | |||
232 | out: | ||
233 | - bdrv_graph_wrunlock(); | ||
234 | tran_finalize(tran, ret); | ||
235 | + bdrv_graph_wrunlock(); | ||
236 | |||
237 | bdrv_drained_end(to); | ||
238 | bdrv_drained_end(from); | ||
239 | @@ -XXX,XX +XXX,XX @@ int bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top, | ||
240 | |||
241 | ret = bdrv_refresh_perms(bs_new, tran, errp); | ||
242 | out: | ||
243 | - bdrv_graph_wrunlock(); | ||
244 | tran_finalize(tran, ret); | ||
245 | |||
246 | - bdrv_graph_rdlock_main_loop(); | ||
247 | bdrv_refresh_limits(bs_top, NULL, NULL); | ||
248 | - bdrv_graph_rdunlock_main_loop(); | ||
249 | + bdrv_graph_wrunlock(); | ||
250 | |||
251 | bdrv_drained_end(bs_top); | ||
252 | bdrv_drained_end(bs_new); | ||
253 | @@ -XXX,XX +XXX,XX @@ int bdrv_replace_child_bs(BdrvChild *child, BlockDriverState *new_bs, | ||
254 | refresh_list = g_slist_prepend(refresh_list, new_bs); | ||
255 | |||
256 | ret = bdrv_list_refresh_perms(refresh_list, NULL, tran, errp); | ||
257 | - bdrv_graph_wrunlock(); | ||
258 | |||
259 | tran_finalize(tran, ret); | ||
260 | |||
261 | + bdrv_graph_wrunlock(); | ||
262 | bdrv_drained_end(old_bs); | ||
263 | bdrv_drained_end(new_bs); | ||
264 | bdrv_unref(old_bs); | ||
26 | -- | 265 | -- |
27 | 2.40.0 | 266 | 2.41.0 | diff view generated by jsdifflib |
1 | From: Wang Liang <wangliangzz@inspur.com> | 1 | Instead of taking the writer lock internally, require callers to already |
---|---|---|---|
2 | hold it when calling bdrv_attach_child_common(). These callers will | ||
3 | typically already hold the graph lock once the locking work is | ||
4 | completed, which means that they can't call functions that take it | ||
5 | internally. | ||
2 | 6 | ||
3 | hmp_commit() calls blk_is_available() from a non-coroutine context (and in | 7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
4 | the main loop). blk_is_available() is a co_wrapper_mixed_bdrv_rdlock | ||
5 | function, and in the non-coroutine context it calls AIO_WAIT_WHILE(), | ||
6 | which crashes if the aio_context lock is not taken before. | ||
7 | |||
8 | Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1615 | ||
9 | Signed-off-by: Wang Liang <wangliangzz@inspur.com> | ||
10 | Message-Id: <20230424103902.45265-1-wangliangzz@126.com> | ||
11 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | 8 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
12 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | 9 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> |
10 | Message-ID: <20230911094620.45040-13-kwolf@redhat.com> | ||
13 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
14 | --- | 12 | --- |
15 | block/monitor/block-hmp-cmds.c | 10 ++++++---- | 13 | include/block/block-global-state.h | 14 ++++++++------ |
16 | 1 file changed, 6 insertions(+), 4 deletions(-) | 14 | block.c | 7 +++---- |
15 | block/quorum.c | 2 ++ | ||
16 | block/replication.c | 6 ++++++ | ||
17 | tests/unit/test-bdrv-drain.c | 14 ++++++++++++++ | ||
18 | tests/unit/test-bdrv-graph-mod.c | 10 ++++++++++ | ||
19 | 6 files changed, 43 insertions(+), 10 deletions(-) | ||
17 | 20 | ||
18 | diff --git a/block/monitor/block-hmp-cmds.c b/block/monitor/block-hmp-cmds.c | 21 | diff --git a/include/block/block-global-state.h b/include/block/block-global-state.h |
19 | index XXXXXXX..XXXXXXX 100644 | 22 | index XXXXXXX..XXXXXXX 100644 |
20 | --- a/block/monitor/block-hmp-cmds.c | 23 | --- a/include/block/block-global-state.h |
21 | +++ b/block/monitor/block-hmp-cmds.c | 24 | +++ b/include/block/block-global-state.h |
22 | @@ -XXX,XX +XXX,XX @@ void hmp_commit(Monitor *mon, const QDict *qdict) | 25 | @@ -XXX,XX +XXX,XX @@ void no_coroutine_fn bdrv_unref(BlockDriverState *bs); |
23 | error_report("Device '%s' not found", device); | 26 | void coroutine_fn no_co_wrapper bdrv_co_unref(BlockDriverState *bs); |
27 | void GRAPH_WRLOCK bdrv_schedule_unref(BlockDriverState *bs); | ||
28 | void bdrv_unref_child(BlockDriverState *parent, BdrvChild *child); | ||
29 | -BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs, | ||
30 | - BlockDriverState *child_bs, | ||
31 | - const char *child_name, | ||
32 | - const BdrvChildClass *child_class, | ||
33 | - BdrvChildRole child_role, | ||
34 | - Error **errp); | ||
35 | + | ||
36 | +BdrvChild * GRAPH_WRLOCK | ||
37 | +bdrv_attach_child(BlockDriverState *parent_bs, | ||
38 | + BlockDriverState *child_bs, | ||
39 | + const char *child_name, | ||
40 | + const BdrvChildClass *child_class, | ||
41 | + BdrvChildRole child_role, | ||
42 | + Error **errp); | ||
43 | |||
44 | bool bdrv_op_is_blocked(BlockDriverState *bs, BlockOpType op, Error **errp); | ||
45 | void bdrv_op_block(BlockDriverState *bs, BlockOpType op, Error *reason); | ||
46 | diff --git a/block.c b/block.c | ||
47 | index XXXXXXX..XXXXXXX 100644 | ||
48 | --- a/block.c | ||
49 | +++ b/block.c | ||
50 | @@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs, | ||
51 | |||
52 | GLOBAL_STATE_CODE(); | ||
53 | |||
54 | - bdrv_graph_wrlock(child_bs); | ||
55 | - | ||
56 | child = bdrv_attach_child_noperm(parent_bs, child_bs, child_name, | ||
57 | child_class, child_role, tran, errp); | ||
58 | if (!child) { | ||
59 | @@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs, | ||
60 | |||
61 | out: | ||
62 | tran_finalize(tran, ret); | ||
63 | - bdrv_graph_wrunlock(); | ||
64 | |||
65 | - bdrv_unref(child_bs); | ||
66 | + bdrv_schedule_unref(child_bs); | ||
67 | |||
68 | return ret < 0 ? NULL : child; | ||
69 | } | ||
70 | @@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_open_child(const char *filename, | ||
71 | return NULL; | ||
72 | } | ||
73 | |||
74 | + bdrv_graph_wrlock(NULL); | ||
75 | ctx = bdrv_get_aio_context(bs); | ||
76 | aio_context_acquire(ctx); | ||
77 | child = bdrv_attach_child(parent, bs, bdref_key, child_class, child_role, | ||
78 | errp); | ||
79 | aio_context_release(ctx); | ||
80 | + bdrv_graph_wrunlock(); | ||
81 | |||
82 | return child; | ||
83 | } | ||
84 | diff --git a/block/quorum.c b/block/quorum.c | ||
85 | index XXXXXXX..XXXXXXX 100644 | ||
86 | --- a/block/quorum.c | ||
87 | +++ b/block/quorum.c | ||
88 | @@ -XXX,XX +XXX,XX @@ static void quorum_add_child(BlockDriverState *bs, BlockDriverState *child_bs, | ||
89 | /* We can safely add the child now */ | ||
90 | bdrv_ref(child_bs); | ||
91 | |||
92 | + bdrv_graph_wrlock(child_bs); | ||
93 | child = bdrv_attach_child(bs, child_bs, indexstr, &child_of_bds, | ||
94 | BDRV_CHILD_DATA, errp); | ||
95 | + bdrv_graph_wrunlock(); | ||
96 | if (child == NULL) { | ||
97 | s->next_child_index--; | ||
98 | goto out; | ||
99 | diff --git a/block/replication.c b/block/replication.c | ||
100 | index XXXXXXX..XXXXXXX 100644 | ||
101 | --- a/block/replication.c | ||
102 | +++ b/block/replication.c | ||
103 | @@ -XXX,XX +XXX,XX @@ static void replication_start(ReplicationState *rs, ReplicationMode mode, | ||
24 | return; | 104 | return; |
25 | } | 105 | } |
26 | - if (!blk_is_available(blk)) { | 106 | |
27 | - error_report("Device '%s' has no medium", device); | 107 | + bdrv_graph_wrlock(bs); |
28 | - return; | ||
29 | - } | ||
30 | |||
31 | bs = bdrv_skip_implicit_filters(blk_bs(blk)); | ||
32 | aio_context = bdrv_get_aio_context(bs); | ||
33 | aio_context_acquire(aio_context); | ||
34 | |||
35 | + if (!blk_is_available(blk)) { | ||
36 | + error_report("Device '%s' has no medium", device); | ||
37 | + aio_context_release(aio_context); | ||
38 | + return; | ||
39 | + } | ||
40 | + | 108 | + |
41 | ret = bdrv_commit(bs); | 109 | bdrv_ref(hidden_disk->bs); |
42 | 110 | s->hidden_disk = bdrv_attach_child(bs, hidden_disk->bs, "hidden disk", | |
43 | aio_context_release(aio_context); | 111 | &child_of_bds, BDRV_CHILD_DATA, |
112 | &local_err); | ||
113 | if (local_err) { | ||
114 | error_propagate(errp, local_err); | ||
115 | + bdrv_graph_wrunlock(); | ||
116 | aio_context_release(aio_context); | ||
117 | return; | ||
118 | } | ||
119 | @@ -XXX,XX +XXX,XX @@ static void replication_start(ReplicationState *rs, ReplicationMode mode, | ||
120 | BDRV_CHILD_DATA, &local_err); | ||
121 | if (local_err) { | ||
122 | error_propagate(errp, local_err); | ||
123 | + bdrv_graph_wrunlock(); | ||
124 | aio_context_release(aio_context); | ||
125 | return; | ||
126 | } | ||
127 | |||
128 | + bdrv_graph_wrunlock(); | ||
129 | + | ||
130 | /* start backup job now */ | ||
131 | error_setg(&s->blocker, | ||
132 | "Block device is in use by internal backup job"); | ||
133 | diff --git a/tests/unit/test-bdrv-drain.c b/tests/unit/test-bdrv-drain.c | ||
134 | index XXXXXXX..XXXXXXX 100644 | ||
135 | --- a/tests/unit/test-bdrv-drain.c | ||
136 | +++ b/tests/unit/test-bdrv-drain.c | ||
137 | @@ -XXX,XX +XXX,XX @@ static void do_test_delete_by_drain(bool detach_instead_of_delete, | ||
138 | |||
139 | null_bs = bdrv_open("null-co://", NULL, NULL, BDRV_O_RDWR | BDRV_O_PROTOCOL, | ||
140 | &error_abort); | ||
141 | + bdrv_graph_wrlock(NULL); | ||
142 | bdrv_attach_child(bs, null_bs, "null-child", &child_of_bds, | ||
143 | BDRV_CHILD_DATA, &error_abort); | ||
144 | + bdrv_graph_wrunlock(); | ||
145 | |||
146 | /* This child will be the one to pass to requests through to, and | ||
147 | * it will stall until a drain occurs */ | ||
148 | @@ -XXX,XX +XXX,XX @@ static void do_test_delete_by_drain(bool detach_instead_of_delete, | ||
149 | &error_abort); | ||
150 | child_bs->total_sectors = 65536 >> BDRV_SECTOR_BITS; | ||
151 | /* Takes our reference to child_bs */ | ||
152 | + bdrv_graph_wrlock(NULL); | ||
153 | tts->wait_child = bdrv_attach_child(bs, child_bs, "wait-child", | ||
154 | &child_of_bds, | ||
155 | BDRV_CHILD_DATA | BDRV_CHILD_PRIMARY, | ||
156 | &error_abort); | ||
157 | + bdrv_graph_wrunlock(); | ||
158 | |||
159 | /* This child is just there to be deleted | ||
160 | * (for detach_instead_of_delete == true) */ | ||
161 | null_bs = bdrv_open("null-co://", NULL, NULL, BDRV_O_RDWR | BDRV_O_PROTOCOL, | ||
162 | &error_abort); | ||
163 | + bdrv_graph_wrlock(NULL); | ||
164 | bdrv_attach_child(bs, null_bs, "null-child", &child_of_bds, BDRV_CHILD_DATA, | ||
165 | &error_abort); | ||
166 | + bdrv_graph_wrunlock(); | ||
167 | |||
168 | blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL); | ||
169 | blk_insert_bs(blk, bs, &error_abort); | ||
170 | @@ -XXX,XX +XXX,XX @@ static void detach_indirect_bh(void *opaque) | ||
171 | bdrv_unref_child(data->parent_b, data->child_b); | ||
172 | |||
173 | bdrv_ref(data->c); | ||
174 | + bdrv_graph_wrlock(NULL); | ||
175 | data->child_c = bdrv_attach_child(data->parent_b, data->c, "PB-C", | ||
176 | &child_of_bds, BDRV_CHILD_DATA, | ||
177 | &error_abort); | ||
178 | + bdrv_graph_wrunlock(); | ||
179 | } | ||
180 | |||
181 | static void detach_by_parent_aio_cb(void *opaque, int ret) | ||
182 | @@ -XXX,XX +XXX,XX @@ static void test_detach_indirect(bool by_parent_cb) | ||
183 | /* Set child relationships */ | ||
184 | bdrv_ref(b); | ||
185 | bdrv_ref(a); | ||
186 | + bdrv_graph_wrlock(NULL); | ||
187 | child_b = bdrv_attach_child(parent_b, b, "PB-B", &child_of_bds, | ||
188 | BDRV_CHILD_DATA, &error_abort); | ||
189 | child_a = bdrv_attach_child(parent_b, a, "PB-A", &child_of_bds, | ||
190 | @@ -XXX,XX +XXX,XX @@ static void test_detach_indirect(bool by_parent_cb) | ||
191 | bdrv_attach_child(parent_a, a, "PA-A", | ||
192 | by_parent_cb ? &child_of_bds : &detach_by_driver_cb_class, | ||
193 | BDRV_CHILD_DATA, &error_abort); | ||
194 | + bdrv_graph_wrunlock(); | ||
195 | |||
196 | g_assert_cmpint(parent_a->refcnt, ==, 1); | ||
197 | g_assert_cmpint(parent_b->refcnt, ==, 1); | ||
198 | @@ -XXX,XX +XXX,XX @@ static void test_drop_intermediate_poll(void) | ||
199 | * Establish the chain last, so the chain links are the first | ||
200 | * elements in the BDS.parents lists | ||
201 | */ | ||
202 | + bdrv_graph_wrlock(NULL); | ||
203 | for (i = 0; i < 3; i++) { | ||
204 | if (i) { | ||
205 | /* Takes the reference to chain[i - 1] */ | ||
206 | @@ -XXX,XX +XXX,XX @@ static void test_drop_intermediate_poll(void) | ||
207 | &chain_child_class, BDRV_CHILD_COW, &error_abort); | ||
208 | } | ||
209 | } | ||
210 | + bdrv_graph_wrunlock(); | ||
211 | |||
212 | job = block_job_create("job", &test_simple_job_driver, NULL, job_node, | ||
213 | 0, BLK_PERM_ALL, 0, 0, NULL, NULL, &error_abort); | ||
214 | @@ -XXX,XX +XXX,XX @@ static void do_test_replace_child_mid_drain(int old_drain_count, | ||
215 | new_child_bs->total_sectors = 1; | ||
216 | |||
217 | bdrv_ref(old_child_bs); | ||
218 | + bdrv_graph_wrlock(NULL); | ||
219 | bdrv_attach_child(parent_bs, old_child_bs, "child", &child_of_bds, | ||
220 | BDRV_CHILD_COW, &error_abort); | ||
221 | + bdrv_graph_wrunlock(); | ||
222 | parent_s->setup_completed = true; | ||
223 | |||
224 | for (i = 0; i < old_drain_count; i++) { | ||
225 | diff --git a/tests/unit/test-bdrv-graph-mod.c b/tests/unit/test-bdrv-graph-mod.c | ||
226 | index XXXXXXX..XXXXXXX 100644 | ||
227 | --- a/tests/unit/test-bdrv-graph-mod.c | ||
228 | +++ b/tests/unit/test-bdrv-graph-mod.c | ||
229 | @@ -XXX,XX +XXX,XX @@ static void test_update_perm_tree(void) | ||
230 | |||
231 | blk_insert_bs(root, bs, &error_abort); | ||
232 | |||
233 | + bdrv_graph_wrlock(NULL); | ||
234 | bdrv_attach_child(filter, bs, "child", &child_of_bds, | ||
235 | BDRV_CHILD_DATA, &error_abort); | ||
236 | + bdrv_graph_wrunlock(); | ||
237 | |||
238 | aio_context_acquire(qemu_get_aio_context()); | ||
239 | ret = bdrv_append(filter, bs, NULL); | ||
240 | @@ -XXX,XX +XXX,XX @@ static void test_should_update_child(void) | ||
241 | bdrv_set_backing_hd(target, bs, &error_abort); | ||
242 | |||
243 | g_assert(target->backing->bs == bs); | ||
244 | + bdrv_graph_wrlock(NULL); | ||
245 | bdrv_attach_child(filter, target, "target", &child_of_bds, | ||
246 | BDRV_CHILD_DATA, &error_abort); | ||
247 | + bdrv_graph_wrunlock(); | ||
248 | aio_context_acquire(qemu_get_aio_context()); | ||
249 | bdrv_append(filter, bs, &error_abort); | ||
250 | aio_context_release(qemu_get_aio_context()); | ||
251 | @@ -XXX,XX +XXX,XX @@ static void test_parallel_exclusive_write(void) | ||
252 | */ | ||
253 | bdrv_ref(base); | ||
254 | |||
255 | + bdrv_graph_wrlock(NULL); | ||
256 | bdrv_attach_child(top, fl1, "backing", &child_of_bds, | ||
257 | BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, | ||
258 | &error_abort); | ||
259 | @@ -XXX,XX +XXX,XX @@ static void test_parallel_exclusive_write(void) | ||
260 | bdrv_attach_child(fl2, base, "backing", &child_of_bds, | ||
261 | BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, | ||
262 | &error_abort); | ||
263 | + bdrv_graph_wrunlock(); | ||
264 | |||
265 | bdrv_replace_node(fl1, fl2, &error_abort); | ||
266 | |||
267 | @@ -XXX,XX +XXX,XX @@ static void test_parallel_perm_update(void) | ||
268 | */ | ||
269 | bdrv_ref(base); | ||
270 | |||
271 | + bdrv_graph_wrlock(NULL); | ||
272 | bdrv_attach_child(top, ws, "file", &child_of_bds, BDRV_CHILD_DATA, | ||
273 | &error_abort); | ||
274 | c_fl1 = bdrv_attach_child(ws, fl1, "first", &child_of_bds, | ||
275 | @@ -XXX,XX +XXX,XX @@ static void test_parallel_perm_update(void) | ||
276 | bdrv_attach_child(fl2, base, "backing", &child_of_bds, | ||
277 | BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, | ||
278 | &error_abort); | ||
279 | + bdrv_graph_wrunlock(); | ||
280 | |||
281 | /* Select fl1 as first child to be active */ | ||
282 | s->selected = c_fl1; | ||
283 | @@ -XXX,XX +XXX,XX @@ static void test_append_greedy_filter(void) | ||
284 | BlockDriverState *base = no_perm_node("base"); | ||
285 | BlockDriverState *fl = exclusive_writer_node("fl1"); | ||
286 | |||
287 | + bdrv_graph_wrlock(NULL); | ||
288 | bdrv_attach_child(top, base, "backing", &child_of_bds, | ||
289 | BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, | ||
290 | &error_abort); | ||
291 | + bdrv_graph_wrunlock(); | ||
292 | |||
293 | aio_context_acquire(qemu_get_aio_context()); | ||
294 | bdrv_append(fl, base, &error_abort); | ||
44 | -- | 295 | -- |
45 | 2.40.0 | 296 | 2.41.0 | diff view generated by jsdifflib |
1 | From: Paolo Bonzini <pbonzini@redhat.com> | 1 | The function reads the parents list, so it needs to hold the graph lock. |
---|---|---|---|
2 | 2 | ||
3 | mirror_flush calls a mixed function blk_flush but it is only called | 3 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
4 | from mirror_run; so call the coroutine version and make mirror_flush | 4 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
5 | a coroutine_fn too. | 5 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> |
6 | 6 | Message-ID: <20230911094620.45040-14-kwolf@redhat.com> | |
7 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> | ||
8 | Message-Id: <20230309084456.304669-4-pbonzini@redhat.com> | ||
9 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
11 | --- | 8 | --- |
12 | block/mirror.c | 4 ++-- | 9 | include/block/block_int-common.h | 6 ++--- |
13 | 1 file changed, 2 insertions(+), 2 deletions(-) | 10 | include/block/block_int-global-state.h | 8 +++--- |
11 | include/sysemu/block-backend-global-state.h | 4 +-- | ||
12 | block.c | 28 +++++++++++++-------- | ||
13 | block/block-backend.c | 26 ++++++++++++++----- | ||
14 | block/crypto.c | 6 +++-- | ||
15 | block/mirror.c | 8 ++++++ | ||
16 | block/vmdk.c | 2 ++ | ||
17 | tests/unit/test-bdrv-graph-mod.c | 4 +++ | ||
18 | 9 files changed, 66 insertions(+), 26 deletions(-) | ||
14 | 19 | ||
20 | diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h | ||
21 | index XXXXXXX..XXXXXXX 100644 | ||
22 | --- a/include/block/block_int-common.h | ||
23 | +++ b/include/block/block_int-common.h | ||
24 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | ||
25 | */ | ||
26 | void (*bdrv_cancel_in_flight)(BlockDriverState *bs); | ||
27 | |||
28 | - int (*bdrv_inactivate)(BlockDriverState *bs); | ||
29 | + int GRAPH_RDLOCK_PTR (*bdrv_inactivate)(BlockDriverState *bs); | ||
30 | |||
31 | int (*bdrv_snapshot_create)(BlockDriverState *bs, | ||
32 | QEMUSnapshotInfo *sn_info); | ||
33 | @@ -XXX,XX +XXX,XX @@ struct BdrvChildClass { | ||
34 | * when migration is completing) and it can start/stop requesting | ||
35 | * permissions and doing I/O on it. | ||
36 | */ | ||
37 | - void (*activate)(BdrvChild *child, Error **errp); | ||
38 | - int (*inactivate)(BdrvChild *child); | ||
39 | + void GRAPH_RDLOCK_PTR (*activate)(BdrvChild *child, Error **errp); | ||
40 | + int GRAPH_RDLOCK_PTR (*inactivate)(BdrvChild *child); | ||
41 | |||
42 | void GRAPH_WRLOCK_PTR (*attach)(BdrvChild *child); | ||
43 | void GRAPH_WRLOCK_PTR (*detach)(BdrvChild *child); | ||
44 | diff --git a/include/block/block_int-global-state.h b/include/block/block_int-global-state.h | ||
45 | index XXXXXXX..XXXXXXX 100644 | ||
46 | --- a/include/block/block_int-global-state.h | ||
47 | +++ b/include/block/block_int-global-state.h | ||
48 | @@ -XXX,XX +XXX,XX @@ void bdrv_get_cumulative_perm(BlockDriverState *bs, uint64_t *perm, | ||
49 | * bdrv_child_refresh_perms() instead and make the parent's | ||
50 | * .bdrv_child_perm() implementation return the correct values. | ||
51 | */ | ||
52 | -int bdrv_child_try_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared, | ||
53 | - Error **errp); | ||
54 | +int GRAPH_RDLOCK | ||
55 | +bdrv_child_try_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared, | ||
56 | + Error **errp); | ||
57 | |||
58 | /** | ||
59 | * Calls bs->drv->bdrv_child_perm() and updates the child's permission | ||
60 | @@ -XXX,XX +XXX,XX @@ int bdrv_child_try_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared, | ||
61 | * values than before, but which will not result in the block layer | ||
62 | * automatically refreshing the permissions. | ||
63 | */ | ||
64 | -int bdrv_child_refresh_perms(BlockDriverState *bs, BdrvChild *c, Error **errp); | ||
65 | +int GRAPH_RDLOCK | ||
66 | +bdrv_child_refresh_perms(BlockDriverState *bs, BdrvChild *c, Error **errp); | ||
67 | |||
68 | bool GRAPH_RDLOCK bdrv_recurse_can_replace(BlockDriverState *bs, | ||
69 | BlockDriverState *to_replace); | ||
70 | diff --git a/include/sysemu/block-backend-global-state.h b/include/sysemu/block-backend-global-state.h | ||
71 | index XXXXXXX..XXXXXXX 100644 | ||
72 | --- a/include/sysemu/block-backend-global-state.h | ||
73 | +++ b/include/sysemu/block-backend-global-state.h | ||
74 | @@ -XXX,XX +XXX,XX @@ int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, Error **errp); | ||
75 | int blk_replace_bs(BlockBackend *blk, BlockDriverState *new_bs, Error **errp); | ||
76 | bool bdrv_has_blk(BlockDriverState *bs); | ||
77 | bool bdrv_is_root_node(BlockDriverState *bs); | ||
78 | -int blk_set_perm(BlockBackend *blk, uint64_t perm, uint64_t shared_perm, | ||
79 | - Error **errp); | ||
80 | +int GRAPH_UNLOCKED blk_set_perm(BlockBackend *blk, uint64_t perm, | ||
81 | + uint64_t shared_perm, Error **errp); | ||
82 | void blk_get_perm(BlockBackend *blk, uint64_t *perm, uint64_t *shared_perm); | ||
83 | |||
84 | void blk_iostatus_enable(BlockBackend *blk); | ||
85 | diff --git a/block.c b/block.c | ||
86 | index XXXXXXX..XXXXXXX 100644 | ||
87 | --- a/block.c | ||
88 | +++ b/block.c | ||
89 | @@ -XXX,XX +XXX,XX @@ static bool bdrv_a_allow_b(BdrvChild *a, BdrvChild *b, Error **errp) | ||
90 | return false; | ||
91 | } | ||
92 | |||
93 | -static bool bdrv_parent_perms_conflict(BlockDriverState *bs, Error **errp) | ||
94 | +static bool GRAPH_RDLOCK | ||
95 | +bdrv_parent_perms_conflict(BlockDriverState *bs, Error **errp) | ||
96 | { | ||
97 | BdrvChild *a, *b; | ||
98 | GLOBAL_STATE_CODE(); | ||
99 | @@ -XXX,XX +XXX,XX @@ static void bdrv_child_perm(BlockDriverState *bs, BlockDriverState *child_bs, | ||
100 | * simplest way to satisfy this criteria: use only result of | ||
101 | * bdrv_topological_dfs() or NULL as @list parameter. | ||
102 | */ | ||
103 | -static GSList *bdrv_topological_dfs(GSList *list, GHashTable *found, | ||
104 | - BlockDriverState *bs) | ||
105 | +static GSList * GRAPH_RDLOCK | ||
106 | +bdrv_topological_dfs(GSList *list, GHashTable *found, BlockDriverState *bs) | ||
107 | { | ||
108 | BdrvChild *child; | ||
109 | g_autoptr(GHashTable) local_found = NULL; | ||
110 | @@ -XXX,XX +XXX,XX @@ static int bdrv_node_refresh_perm(BlockDriverState *bs, BlockReopenQueue *q, | ||
111 | * @list is a product of bdrv_topological_dfs() (may be called several times) - | ||
112 | * a topologically sorted subgraph. | ||
113 | */ | ||
114 | -static int bdrv_do_refresh_perms(GSList *list, BlockReopenQueue *q, | ||
115 | - Transaction *tran, Error **errp) | ||
116 | +static int GRAPH_RDLOCK | ||
117 | +bdrv_do_refresh_perms(GSList *list, BlockReopenQueue *q, Transaction *tran, | ||
118 | + Error **errp) | ||
119 | { | ||
120 | int ret; | ||
121 | BlockDriverState *bs; | ||
122 | @@ -XXX,XX +XXX,XX @@ static int bdrv_do_refresh_perms(GSList *list, BlockReopenQueue *q, | ||
123 | * topologically sorted. It's not a problem if some node occurs in the @list | ||
124 | * several times. | ||
125 | */ | ||
126 | -static int bdrv_list_refresh_perms(GSList *list, BlockReopenQueue *q, | ||
127 | - Transaction *tran, Error **errp) | ||
128 | +static int GRAPH_RDLOCK | ||
129 | +bdrv_list_refresh_perms(GSList *list, BlockReopenQueue *q, Transaction *tran, | ||
130 | + Error **errp) | ||
131 | { | ||
132 | g_autoptr(GHashTable) found = g_hash_table_new(NULL, NULL); | ||
133 | g_autoptr(GSList) refresh_list = NULL; | ||
134 | @@ -XXX,XX +XXX,XX @@ char *bdrv_perm_names(uint64_t perm) | ||
135 | |||
136 | |||
137 | /* @tran is allowed to be NULL. In this case no rollback is possible */ | ||
138 | -static int bdrv_refresh_perms(BlockDriverState *bs, Transaction *tran, | ||
139 | - Error **errp) | ||
140 | +static int GRAPH_RDLOCK | ||
141 | +bdrv_refresh_perms(BlockDriverState *bs, Transaction *tran, Error **errp) | ||
142 | { | ||
143 | int ret; | ||
144 | Transaction *local_tran = NULL; | ||
145 | @@ -XXX,XX +XXX,XX @@ void bdrv_root_unref_child(BdrvChild *child) | ||
146 | GLOBAL_STATE_CODE(); | ||
147 | bdrv_graph_wrlock(NULL); | ||
148 | bdrv_replace_child_noperm(child, NULL); | ||
149 | - bdrv_graph_wrunlock(); | ||
150 | bdrv_child_free(child); | ||
151 | |||
152 | if (child_bs) { | ||
153 | @@ -XXX,XX +XXX,XX @@ void bdrv_root_unref_child(BdrvChild *child) | ||
154 | NULL); | ||
155 | } | ||
156 | |||
157 | + bdrv_graph_wrunlock(); | ||
158 | bdrv_unref(child_bs); | ||
159 | } | ||
160 | |||
161 | @@ -XXX,XX +XXX,XX @@ int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp) | ||
162 | * reconfiguring the fd and that's why it does it in raw_check_perm(), not | ||
163 | * in raw_reopen_prepare() which is called with "old" permissions. | ||
164 | */ | ||
165 | + bdrv_graph_rdlock_main_loop(); | ||
166 | ret = bdrv_list_refresh_perms(refresh_list, bs_queue, tran, errp); | ||
167 | + bdrv_graph_rdunlock_main_loop(); | ||
168 | + | ||
169 | if (ret < 0) { | ||
170 | goto abort; | ||
171 | } | ||
172 | @@ -XXX,XX +XXX,XX @@ int bdrv_activate(BlockDriverState *bs, Error **errp) | ||
173 | BdrvDirtyBitmap *bm; | ||
174 | |||
175 | GLOBAL_STATE_CODE(); | ||
176 | + GRAPH_RDLOCK_GUARD_MAINLOOP(); | ||
177 | |||
178 | if (!bs->drv) { | ||
179 | return -ENOMEDIUM; | ||
180 | @@ -XXX,XX +XXX,XX @@ static int bdrv_inactivate_recurse(BlockDriverState *bs) | ||
181 | uint64_t cumulative_perms, cumulative_shared_perms; | ||
182 | |||
183 | GLOBAL_STATE_CODE(); | ||
184 | + GRAPH_RDLOCK_GUARD_MAINLOOP(); | ||
185 | |||
186 | if (!bs->drv) { | ||
187 | return -ENOMEDIUM; | ||
188 | diff --git a/block/block-backend.c b/block/block-backend.c | ||
189 | index XXXXXXX..XXXXXXX 100644 | ||
190 | --- a/block/block-backend.c | ||
191 | +++ b/block/block-backend.c | ||
192 | @@ -XXX,XX +XXX,XX @@ static QTAILQ_HEAD(, BlockBackend) block_backends = | ||
193 | static QTAILQ_HEAD(, BlockBackend) monitor_block_backends = | ||
194 | QTAILQ_HEAD_INITIALIZER(monitor_block_backends); | ||
195 | |||
196 | +static int coroutine_mixed_fn GRAPH_RDLOCK | ||
197 | +blk_set_perm_locked(BlockBackend *blk, uint64_t perm, uint64_t shared_perm, | ||
198 | + Error **errp); | ||
199 | + | ||
200 | static void blk_root_inherit_options(BdrvChildRole role, bool parent_is_format, | ||
201 | int *child_flags, QDict *child_options, | ||
202 | int parent_flags, QDict *parent_options) | ||
203 | @@ -XXX,XX +XXX,XX @@ static void blk_vm_state_changed(void *opaque, bool running, RunState state) | ||
204 | * | ||
205 | * If an error is returned, the VM cannot be allowed to be resumed. | ||
206 | */ | ||
207 | -static void blk_root_activate(BdrvChild *child, Error **errp) | ||
208 | +static void GRAPH_RDLOCK blk_root_activate(BdrvChild *child, Error **errp) | ||
209 | { | ||
210 | BlockBackend *blk = child->opaque; | ||
211 | Error *local_err = NULL; | ||
212 | @@ -XXX,XX +XXX,XX @@ static void blk_root_activate(BdrvChild *child, Error **errp) | ||
213 | */ | ||
214 | saved_shared_perm = blk->shared_perm; | ||
215 | |||
216 | - blk_set_perm(blk, blk->perm, BLK_PERM_ALL, &local_err); | ||
217 | + blk_set_perm_locked(blk, blk->perm, BLK_PERM_ALL, &local_err); | ||
218 | if (local_err) { | ||
219 | error_propagate(errp, local_err); | ||
220 | blk->disable_perm = true; | ||
221 | @@ -XXX,XX +XXX,XX @@ static void blk_root_activate(BdrvChild *child, Error **errp) | ||
222 | return; | ||
223 | } | ||
224 | |||
225 | - blk_set_perm(blk, blk->perm, blk->shared_perm, &local_err); | ||
226 | + blk_set_perm_locked(blk, blk->perm, blk->shared_perm, &local_err); | ||
227 | if (local_err) { | ||
228 | error_propagate(errp, local_err); | ||
229 | blk->disable_perm = true; | ||
230 | @@ -XXX,XX +XXX,XX @@ static bool blk_can_inactivate(BlockBackend *blk) | ||
231 | return blk->force_allow_inactivate; | ||
232 | } | ||
233 | |||
234 | -static int blk_root_inactivate(BdrvChild *child) | ||
235 | +static int GRAPH_RDLOCK blk_root_inactivate(BdrvChild *child) | ||
236 | { | ||
237 | BlockBackend *blk = child->opaque; | ||
238 | |||
239 | @@ -XXX,XX +XXX,XX @@ int blk_replace_bs(BlockBackend *blk, BlockDriverState *new_bs, Error **errp) | ||
240 | /* | ||
241 | * Sets the permission bitmasks that the user of the BlockBackend needs. | ||
242 | */ | ||
243 | -int blk_set_perm(BlockBackend *blk, uint64_t perm, uint64_t shared_perm, | ||
244 | - Error **errp) | ||
245 | +static int coroutine_mixed_fn GRAPH_RDLOCK | ||
246 | +blk_set_perm_locked(BlockBackend *blk, uint64_t perm, uint64_t shared_perm, | ||
247 | + Error **errp) | ||
248 | { | ||
249 | int ret; | ||
250 | GLOBAL_STATE_CODE(); | ||
251 | @@ -XXX,XX +XXX,XX @@ int blk_set_perm(BlockBackend *blk, uint64_t perm, uint64_t shared_perm, | ||
252 | return 0; | ||
253 | } | ||
254 | |||
255 | +int blk_set_perm(BlockBackend *blk, uint64_t perm, uint64_t shared_perm, | ||
256 | + Error **errp) | ||
257 | +{ | ||
258 | + GLOBAL_STATE_CODE(); | ||
259 | + GRAPH_RDLOCK_GUARD_MAINLOOP(); | ||
260 | + | ||
261 | + return blk_set_perm_locked(blk, perm, shared_perm, errp); | ||
262 | +} | ||
263 | + | ||
264 | void blk_get_perm(BlockBackend *blk, uint64_t *perm, uint64_t *shared_perm) | ||
265 | { | ||
266 | GLOBAL_STATE_CODE(); | ||
267 | diff --git a/block/crypto.c b/block/crypto.c | ||
268 | index XXXXXXX..XXXXXXX 100644 | ||
269 | --- a/block/crypto.c | ||
270 | +++ b/block/crypto.c | ||
271 | @@ -XXX,XX +XXX,XX @@ block_crypto_get_specific_info_luks(BlockDriverState *bs, Error **errp) | ||
272 | return spec_info; | ||
273 | } | ||
274 | |||
275 | -static int | ||
276 | +static int GRAPH_RDLOCK | ||
277 | block_crypto_amend_prepare(BlockDriverState *bs, Error **errp) | ||
278 | { | ||
279 | BlockCrypto *crypto = bs->opaque; | ||
280 | @@ -XXX,XX +XXX,XX @@ block_crypto_amend_prepare(BlockDriverState *bs, Error **errp) | ||
281 | return ret; | ||
282 | } | ||
283 | |||
284 | -static void | ||
285 | +static void GRAPH_RDLOCK | ||
286 | block_crypto_amend_cleanup(BlockDriverState *bs) | ||
287 | { | ||
288 | BlockCrypto *crypto = bs->opaque; | ||
289 | @@ -XXX,XX +XXX,XX @@ block_crypto_amend_options_luks(BlockDriverState *bs, | ||
290 | QCryptoBlockAmendOptions *amend_options = NULL; | ||
291 | int ret = -EINVAL; | ||
292 | |||
293 | + assume_graph_lock(); /* FIXME */ | ||
294 | + | ||
295 | assert(crypto); | ||
296 | assert(crypto->block); | ||
297 | |||
15 | diff --git a/block/mirror.c b/block/mirror.c | 298 | diff --git a/block/mirror.c b/block/mirror.c |
16 | index XXXXXXX..XXXXXXX 100644 | 299 | index XXXXXXX..XXXXXXX 100644 |
17 | --- a/block/mirror.c | 300 | --- a/block/mirror.c |
18 | +++ b/block/mirror.c | 301 | +++ b/block/mirror.c |
19 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn mirror_dirty_init(MirrorBlockJob *s) | 302 | @@ -XXX,XX +XXX,XX @@ static int mirror_exit_common(Job *job) |
20 | /* Called when going out of the streaming phase to flush the bulk of the | 303 | * mirror_top_bs from now on, so keep it drained. */ |
21 | * data to the medium, or just before completing. | 304 | bdrv_drained_begin(mirror_top_bs); |
22 | */ | 305 | bs_opaque->stop = true; |
23 | -static int mirror_flush(MirrorBlockJob *s) | 306 | + |
24 | +static int coroutine_fn mirror_flush(MirrorBlockJob *s) | 307 | + bdrv_graph_rdlock_main_loop(); |
25 | { | 308 | bdrv_child_refresh_perms(mirror_top_bs, mirror_top_bs->backing, |
26 | - int ret = blk_flush(s->target); | 309 | &error_abort); |
27 | + int ret = blk_co_flush(s->target); | 310 | + bdrv_graph_rdunlock_main_loop(); |
311 | + | ||
312 | if (!abort && s->backing_mode == MIRROR_SOURCE_BACKING_CHAIN) { | ||
313 | BlockDriverState *backing = s->is_none_mode ? src : s->base; | ||
314 | BlockDriverState *unfiltered_target = bdrv_skip_filters(target_bs); | ||
315 | @@ -XXX,XX +XXX,XX @@ static BlockJob *mirror_start_job( | ||
316 | uint64_t target_perms, target_shared_perms; | ||
317 | int ret; | ||
318 | |||
319 | + GLOBAL_STATE_CODE(); | ||
320 | + | ||
321 | if (granularity == 0) { | ||
322 | granularity = bdrv_get_default_bitmap_granularity(target); | ||
323 | } | ||
324 | @@ -XXX,XX +XXX,XX @@ fail: | ||
325 | } | ||
326 | |||
327 | bs_opaque->stop = true; | ||
328 | + bdrv_graph_rdlock_main_loop(); | ||
329 | bdrv_child_refresh_perms(mirror_top_bs, mirror_top_bs->backing, | ||
330 | &error_abort); | ||
331 | + bdrv_graph_rdunlock_main_loop(); | ||
332 | bdrv_replace_node(mirror_top_bs, mirror_top_bs->backing->bs, &error_abort); | ||
333 | |||
334 | bdrv_unref(mirror_top_bs); | ||
335 | diff --git a/block/vmdk.c b/block/vmdk.c | ||
336 | index XXXXXXX..XXXXXXX 100644 | ||
337 | --- a/block/vmdk.c | ||
338 | +++ b/block/vmdk.c | ||
339 | @@ -XXX,XX +XXX,XX @@ static int vmdk_open(BlockDriverState *bs, QDict *options, int flags, | ||
340 | BDRVVmdkState *s = bs->opaque; | ||
341 | uint32_t magic; | ||
342 | |||
343 | + GRAPH_RDLOCK_GUARD_MAINLOOP(); | ||
344 | + | ||
345 | ret = bdrv_open_file_child(NULL, options, "file", bs, errp); | ||
28 | if (ret < 0) { | 346 | if (ret < 0) { |
29 | if (mirror_error_action(s, false, -ret) == BLOCK_ERROR_ACTION_REPORT) { | 347 | return ret; |
30 | s->ret = ret; | 348 | diff --git a/tests/unit/test-bdrv-graph-mod.c b/tests/unit/test-bdrv-graph-mod.c |
349 | index XXXXXXX..XXXXXXX 100644 | ||
350 | --- a/tests/unit/test-bdrv-graph-mod.c | ||
351 | +++ b/tests/unit/test-bdrv-graph-mod.c | ||
352 | @@ -XXX,XX +XXX,XX @@ static void test_parallel_perm_update(void) | ||
353 | |||
354 | /* Select fl1 as first child to be active */ | ||
355 | s->selected = c_fl1; | ||
356 | + | ||
357 | + bdrv_graph_rdlock_main_loop(); | ||
358 | + | ||
359 | bdrv_child_refresh_perms(top, top->children.lh_first, &error_abort); | ||
360 | |||
361 | assert(c_fl1->perm & BLK_PERM_WRITE); | ||
362 | @@ -XXX,XX +XXX,XX @@ static void test_parallel_perm_update(void) | ||
363 | assert(c_fl1->perm & BLK_PERM_WRITE); | ||
364 | assert(!(c_fl2->perm & BLK_PERM_WRITE)); | ||
365 | |||
366 | + bdrv_graph_rdunlock_main_loop(); | ||
367 | bdrv_unref(top); | ||
368 | } | ||
369 | |||
31 | -- | 370 | -- |
32 | 2.40.0 | 371 | 2.41.0 | diff view generated by jsdifflib |
1 | From: Paolo Bonzini <pbonzini@redhat.com> | 1 | The function reads the parents list, so it needs to hold the graph lock. |
---|---|---|---|
2 | 2 | ||
3 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> | 3 | This happens to result in BlockDriver.bdrv_set_perm() to be called with |
4 | Message-Id: <20230309084456.304669-6-pbonzini@redhat.com> | 4 | the graph lock held. For consistency, make it the same for all of the |
5 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | 5 | BlockDriver callbacks for updating permissions and annotate the function |
6 | pointers with GRAPH_RDLOCK_PTR. | ||
7 | |||
8 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
9 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
10 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
11 | Message-ID: <20230911094620.45040-15-kwolf@redhat.com> | ||
6 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
7 | --- | 13 | --- |
8 | hw/9pfs/9p.h | 4 ++-- | 14 | include/block/block_int-common.h | 9 ++++--- |
9 | hw/9pfs/codir.c | 6 +++--- | 15 | include/block/block_int-global-state.h | 4 +-- |
10 | 2 files changed, 5 insertions(+), 5 deletions(-) | 16 | block.c | 35 ++++++++++++++++++++------ |
17 | blockdev.c | 6 +++++ | ||
18 | 4 files changed, 40 insertions(+), 14 deletions(-) | ||
11 | 19 | ||
12 | diff --git a/hw/9pfs/9p.h b/hw/9pfs/9p.h | 20 | diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h |
13 | index XXXXXXX..XXXXXXX 100644 | 21 | index XXXXXXX..XXXXXXX 100644 |
14 | --- a/hw/9pfs/9p.h | 22 | --- a/include/block/block_int-common.h |
15 | +++ b/hw/9pfs/9p.h | 23 | +++ b/include/block/block_int-common.h |
16 | @@ -XXX,XX +XXX,XX @@ typedef struct V9fsDir { | 24 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { |
17 | QemuMutex readdir_mutex_L; | 25 | * If both conditions are met, 0 is returned. Otherwise, -errno is returned |
18 | } V9fsDir; | 26 | * and errp is set to an error describing the conflict. |
19 | 27 | */ | |
20 | -static inline void v9fs_readdir_lock(V9fsDir *dir) | 28 | - int (*bdrv_check_perm)(BlockDriverState *bs, uint64_t perm, |
21 | +static inline void coroutine_fn v9fs_readdir_lock(V9fsDir *dir) | 29 | - uint64_t shared, Error **errp); |
30 | + int GRAPH_RDLOCK_PTR (*bdrv_check_perm)(BlockDriverState *bs, uint64_t perm, | ||
31 | + uint64_t shared, Error **errp); | ||
32 | |||
33 | /** | ||
34 | * Called to inform the driver that the set of cumulative set of used | ||
35 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | ||
36 | * This function is only invoked after bdrv_check_perm(), so block drivers | ||
37 | * may rely on preparations made in their .bdrv_check_perm implementation. | ||
38 | */ | ||
39 | - void (*bdrv_set_perm)(BlockDriverState *bs, uint64_t perm, uint64_t shared); | ||
40 | + void GRAPH_RDLOCK_PTR (*bdrv_set_perm)( | ||
41 | + BlockDriverState *bs, uint64_t perm, uint64_t shared); | ||
42 | |||
43 | /* | ||
44 | * Called to inform the driver that after a previous bdrv_check_perm() | ||
45 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | ||
46 | * This function can be called even for nodes that never saw a | ||
47 | * bdrv_check_perm() call. It is a no-op then. | ||
48 | */ | ||
49 | - void (*bdrv_abort_perm_update)(BlockDriverState *bs); | ||
50 | + void GRAPH_RDLOCK_PTR (*bdrv_abort_perm_update)(BlockDriverState *bs); | ||
51 | |||
52 | /** | ||
53 | * Returns in @nperm and @nshared the permissions that the driver for @bs | ||
54 | diff --git a/include/block/block_int-global-state.h b/include/block/block_int-global-state.h | ||
55 | index XXXXXXX..XXXXXXX 100644 | ||
56 | --- a/include/block/block_int-global-state.h | ||
57 | +++ b/include/block/block_int-global-state.h | ||
58 | @@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs, | ||
59 | void *opaque, Error **errp); | ||
60 | void bdrv_root_unref_child(BdrvChild *child); | ||
61 | |||
62 | -void bdrv_get_cumulative_perm(BlockDriverState *bs, uint64_t *perm, | ||
63 | - uint64_t *shared_perm); | ||
64 | +void GRAPH_RDLOCK bdrv_get_cumulative_perm(BlockDriverState *bs, uint64_t *perm, | ||
65 | + uint64_t *shared_perm); | ||
66 | |||
67 | /** | ||
68 | * Sets a BdrvChild's permissions. Avoid if the parent is a BDS; use | ||
69 | diff --git a/block.c b/block.c | ||
70 | index XXXXXXX..XXXXXXX 100644 | ||
71 | --- a/block.c | ||
72 | +++ b/block.c | ||
73 | @@ -XXX,XX +XXX,XX @@ static void bdrv_child_set_perm(BdrvChild *c, uint64_t perm, | ||
74 | tran_add(tran, &bdrv_child_set_pem_drv, s); | ||
75 | } | ||
76 | |||
77 | -static void bdrv_drv_set_perm_commit(void *opaque) | ||
78 | +static void GRAPH_RDLOCK bdrv_drv_set_perm_commit(void *opaque) | ||
22 | { | 79 | { |
23 | if (dir->proto_version == V9FS_PROTO_2000U) { | 80 | BlockDriverState *bs = opaque; |
24 | qemu_co_mutex_lock(&dir->readdir_mutex_u); | 81 | uint64_t cumulative_perms, cumulative_shared_perms; |
25 | @@ -XXX,XX +XXX,XX @@ static inline void v9fs_readdir_lock(V9fsDir *dir) | 82 | @@ -XXX,XX +XXX,XX @@ static void bdrv_drv_set_perm_commit(void *opaque) |
26 | } | 83 | } |
27 | } | 84 | } |
28 | 85 | ||
29 | -static inline void v9fs_readdir_unlock(V9fsDir *dir) | 86 | -static void bdrv_drv_set_perm_abort(void *opaque) |
30 | +static inline void coroutine_fn v9fs_readdir_unlock(V9fsDir *dir) | 87 | +static void GRAPH_RDLOCK bdrv_drv_set_perm_abort(void *opaque) |
31 | { | 88 | { |
32 | if (dir->proto_version == V9FS_PROTO_2000U) { | 89 | BlockDriverState *bs = opaque; |
33 | qemu_co_mutex_unlock(&dir->readdir_mutex_u); | 90 | GLOBAL_STATE_CODE(); |
34 | diff --git a/hw/9pfs/codir.c b/hw/9pfs/codir.c | 91 | @@ -XXX,XX +XXX,XX @@ TransactionActionDrv bdrv_drv_set_perm_drv = { |
92 | .commit = bdrv_drv_set_perm_commit, | ||
93 | }; | ||
94 | |||
95 | -static int bdrv_drv_set_perm(BlockDriverState *bs, uint64_t perm, | ||
96 | - uint64_t shared_perm, Transaction *tran, | ||
97 | - Error **errp) | ||
98 | +/* | ||
99 | + * After calling this function, the transaction @tran may only be completed | ||
100 | + * while holding a reader lock for the graph. | ||
101 | + */ | ||
102 | +static int GRAPH_RDLOCK | ||
103 | +bdrv_drv_set_perm(BlockDriverState *bs, uint64_t perm, uint64_t shared_perm, | ||
104 | + Transaction *tran, Error **errp) | ||
105 | { | ||
106 | GLOBAL_STATE_CODE(); | ||
107 | if (!bs->drv) { | ||
108 | @@ -XXX,XX +XXX,XX @@ bdrv_replace_child_tran(BdrvChild *child, BlockDriverState *new_bs, | ||
109 | /* | ||
110 | * Refresh permissions in @bs subtree. The function is intended to be called | ||
111 | * after some graph modification that was done without permission update. | ||
112 | + * | ||
113 | + * After calling this function, the transaction @tran may only be completed | ||
114 | + * while holding a reader lock for the graph. | ||
115 | */ | ||
116 | -static int bdrv_node_refresh_perm(BlockDriverState *bs, BlockReopenQueue *q, | ||
117 | - Transaction *tran, Error **errp) | ||
118 | +static int GRAPH_RDLOCK | ||
119 | +bdrv_node_refresh_perm(BlockDriverState *bs, BlockReopenQueue *q, | ||
120 | + Transaction *tran, Error **errp) | ||
121 | { | ||
122 | BlockDriver *drv = bs->drv; | ||
123 | BdrvChild *c; | ||
124 | @@ -XXX,XX +XXX,XX @@ static int bdrv_node_refresh_perm(BlockDriverState *bs, BlockReopenQueue *q, | ||
125 | /* | ||
126 | * @list is a product of bdrv_topological_dfs() (may be called several times) - | ||
127 | * a topologically sorted subgraph. | ||
128 | + * | ||
129 | + * After calling this function, the transaction @tran may only be completed | ||
130 | + * while holding a reader lock for the graph. | ||
131 | */ | ||
132 | static int GRAPH_RDLOCK | ||
133 | bdrv_do_refresh_perms(GSList *list, BlockReopenQueue *q, Transaction *tran, | ||
134 | @@ -XXX,XX +XXX,XX @@ bdrv_do_refresh_perms(GSList *list, BlockReopenQueue *q, Transaction *tran, | ||
135 | * @list is any list of nodes. List is completed by all subtrees and | ||
136 | * topologically sorted. It's not a problem if some node occurs in the @list | ||
137 | * several times. | ||
138 | + * | ||
139 | + * After calling this function, the transaction @tran may only be completed | ||
140 | + * while holding a reader lock for the graph. | ||
141 | */ | ||
142 | static int GRAPH_RDLOCK | ||
143 | bdrv_list_refresh_perms(GSList *list, BlockReopenQueue *q, Transaction *tran, | ||
144 | @@ -XXX,XX +XXX,XX @@ char *bdrv_perm_names(uint64_t perm) | ||
145 | } | ||
146 | |||
147 | |||
148 | -/* @tran is allowed to be NULL. In this case no rollback is possible */ | ||
149 | +/* | ||
150 | + * @tran is allowed to be NULL. In this case no rollback is possible. | ||
151 | + * | ||
152 | + * After calling this function, the transaction @tran may only be completed | ||
153 | + * while holding a reader lock for the graph. | ||
154 | + */ | ||
155 | static int GRAPH_RDLOCK | ||
156 | bdrv_refresh_perms(BlockDriverState *bs, Transaction *tran, Error **errp) | ||
157 | { | ||
158 | diff --git a/blockdev.c b/blockdev.c | ||
35 | index XXXXXXX..XXXXXXX 100644 | 159 | index XXXXXXX..XXXXXXX 100644 |
36 | --- a/hw/9pfs/codir.c | 160 | --- a/blockdev.c |
37 | +++ b/hw/9pfs/codir.c | 161 | +++ b/blockdev.c |
38 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn v9fs_co_readdir(V9fsPDU *pdu, V9fsFidState *fidp, | 162 | @@ -XXX,XX +XXX,XX @@ static void external_snapshot_action(TransactionAction *action, |
39 | * | 163 | AioContext *aio_context; |
40 | * See v9fs_co_readdir_many() (as its only user) below for details. | 164 | uint64_t perm, shared; |
41 | */ | 165 | |
42 | -static int do_readdir_many(V9fsPDU *pdu, V9fsFidState *fidp, | 166 | + /* TODO We'll eventually have to take a writer lock in this function */ |
43 | - struct V9fsDirEnt **entries, off_t offset, | 167 | + GRAPH_RDLOCK_GUARD_MAINLOOP(); |
44 | - int32_t maxsize, bool dostat) | 168 | + |
45 | +static int coroutine_fn | 169 | tran_add(tran, &external_snapshot_drv, state); |
46 | +do_readdir_many(V9fsPDU *pdu, V9fsFidState *fidp, struct V9fsDirEnt **entries, | 170 | |
47 | + off_t offset, int32_t maxsize, bool dostat) | 171 | /* 'blockdev-snapshot' and 'blockdev-snapshot-sync' have similar |
48 | { | 172 | @@ -XXX,XX +XXX,XX @@ void qmp_block_commit(const char *job_id, const char *device, |
49 | V9fsState *s = pdu->s; | 173 | int job_flags = JOB_DEFAULT; |
50 | V9fsString name; | 174 | uint64_t top_perm, top_shared; |
175 | |||
176 | + /* TODO We'll eventually have to take a writer lock in this function */ | ||
177 | + GRAPH_RDLOCK_GUARD_MAINLOOP(); | ||
178 | + | ||
179 | if (!has_speed) { | ||
180 | speed = 0; | ||
181 | } | ||
51 | -- | 182 | -- |
52 | 2.40.0 | 183 | 2.41.0 | diff view generated by jsdifflib |
1 | From: Stefan Hajnoczi <stefanha@redhat.com> | 1 | This adds GRAPH_RDLOCK annotations to declare that callers of |
---|---|---|---|
2 | bdrv_child_perm() need to hold a reader lock for the graph because | ||
3 | some implementations access the children list of a node. | ||
2 | 4 | ||
3 | There is no change in behavior. Switch to AIO_WAIT_WHILE_UNLOCKED() | 5 | The callers of bdrv_child_perm() conveniently already hold the lock. |
4 | instead of AIO_WAIT_WHILE() to document that this code has already been | ||
5 | audited and converted. The AioContext argument is already NULL so | ||
6 | aio_context_release() is never called anyway. | ||
7 | 6 | ||
8 | Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> | 7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
9 | Tested-by: Philippe Mathieu-Daudé <philmd@linaro.org> | 8 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
10 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | 9 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> |
11 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> | 10 | Message-ID: <20230911094620.45040-16-kwolf@redhat.com> |
12 | Message-Id: <20230309190855.414275-3-stefanha@redhat.com> | ||
13 | Reviewed-by: Wilfred Mallawa <wilfred.mallawa@wdc.com> | ||
14 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
15 | --- | 12 | --- |
16 | block/export/export.c | 2 +- | 13 | include/block/block_int-common.h | 10 +++++----- |
17 | 1 file changed, 1 insertion(+), 1 deletion(-) | 14 | block.c | 11 ++++++----- |
15 | block/copy-before-write.c | 10 +++++----- | ||
16 | 3 files changed, 16 insertions(+), 15 deletions(-) | ||
18 | 17 | ||
19 | diff --git a/block/export/export.c b/block/export/export.c | 18 | diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h |
20 | index XXXXXXX..XXXXXXX 100644 | 19 | index XXXXXXX..XXXXXXX 100644 |
21 | --- a/block/export/export.c | 20 | --- a/include/block/block_int-common.h |
22 | +++ b/block/export/export.c | 21 | +++ b/include/block/block_int-common.h |
23 | @@ -XXX,XX +XXX,XX @@ void blk_exp_close_all_type(BlockExportType type) | 22 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { |
24 | blk_exp_request_shutdown(exp); | 23 | * permissions, but those that will be needed after applying the |
25 | } | 24 | * @reopen_queue. |
26 | 25 | */ | |
27 | - AIO_WAIT_WHILE(NULL, blk_exp_has_type(type)); | 26 | - void (*bdrv_child_perm)(BlockDriverState *bs, BdrvChild *c, |
28 | + AIO_WAIT_WHILE_UNLOCKED(NULL, blk_exp_has_type(type)); | 27 | - BdrvChildRole role, |
28 | - BlockReopenQueue *reopen_queue, | ||
29 | - uint64_t parent_perm, uint64_t parent_shared, | ||
30 | - uint64_t *nperm, uint64_t *nshared); | ||
31 | + void GRAPH_RDLOCK_PTR (*bdrv_child_perm)( | ||
32 | + BlockDriverState *bs, BdrvChild *c, BdrvChildRole role, | ||
33 | + BlockReopenQueue *reopen_queue, | ||
34 | + uint64_t parent_perm, uint64_t parent_shared, | ||
35 | + uint64_t *nperm, uint64_t *nshared); | ||
36 | |||
37 | /** | ||
38 | * Register/unregister a buffer for I/O. For example, when the driver is | ||
39 | diff --git a/block.c b/block.c | ||
40 | index XXXXXXX..XXXXXXX 100644 | ||
41 | --- a/block.c | ||
42 | +++ b/block.c | ||
43 | @@ -XXX,XX +XXX,XX @@ bdrv_parent_perms_conflict(BlockDriverState *bs, Error **errp) | ||
44 | return false; | ||
29 | } | 45 | } |
30 | 46 | ||
31 | void blk_exp_close_all(void) | 47 | -static void bdrv_child_perm(BlockDriverState *bs, BlockDriverState *child_bs, |
48 | - BdrvChild *c, BdrvChildRole role, | ||
49 | - BlockReopenQueue *reopen_queue, | ||
50 | - uint64_t parent_perm, uint64_t parent_shared, | ||
51 | - uint64_t *nperm, uint64_t *nshared) | ||
52 | +static void GRAPH_RDLOCK | ||
53 | +bdrv_child_perm(BlockDriverState *bs, BlockDriverState *child_bs, | ||
54 | + BdrvChild *c, BdrvChildRole role, | ||
55 | + BlockReopenQueue *reopen_queue, | ||
56 | + uint64_t parent_perm, uint64_t parent_shared, | ||
57 | + uint64_t *nperm, uint64_t *nshared) | ||
58 | { | ||
59 | assert(bs->drv && bs->drv->bdrv_child_perm); | ||
60 | GLOBAL_STATE_CODE(); | ||
61 | diff --git a/block/copy-before-write.c b/block/copy-before-write.c | ||
62 | index XXXXXXX..XXXXXXX 100644 | ||
63 | --- a/block/copy-before-write.c | ||
64 | +++ b/block/copy-before-write.c | ||
65 | @@ -XXX,XX +XXX,XX @@ static void cbw_refresh_filename(BlockDriverState *bs) | ||
66 | bs->file->bs->filename); | ||
67 | } | ||
68 | |||
69 | -static void cbw_child_perm(BlockDriverState *bs, BdrvChild *c, | ||
70 | - BdrvChildRole role, | ||
71 | - BlockReopenQueue *reopen_queue, | ||
72 | - uint64_t perm, uint64_t shared, | ||
73 | - uint64_t *nperm, uint64_t *nshared) | ||
74 | +static void GRAPH_RDLOCK | ||
75 | +cbw_child_perm(BlockDriverState *bs, BdrvChild *c, BdrvChildRole role, | ||
76 | + BlockReopenQueue *reopen_queue, | ||
77 | + uint64_t perm, uint64_t shared, | ||
78 | + uint64_t *nperm, uint64_t *nshared) | ||
79 | { | ||
80 | if (!(role & BDRV_CHILD_FILTERED)) { | ||
81 | /* | ||
32 | -- | 82 | -- |
33 | 2.40.0 | 83 | 2.41.0 |
34 | |||
35 | diff view generated by jsdifflib |
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | 1 | The function reads the parents list, so it needs to hold the graph lock. |
---|---|---|---|
2 | 2 | ||
3 | Remove usage of aio_context_acquire by always submitting asynchronous | 3 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
4 | AIO to the current thread's LinuxAioState. | 4 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
5 | 5 | Message-ID: <20230911094620.45040-18-kwolf@redhat.com> | |
6 | In order to prevent mistakes from the caller side, avoid passing LinuxAioState | ||
7 | in laio_io_{plug/unplug} and laio_co_submit, and document the functions | ||
8 | to make clear that they work in the current thread's AioContext. | ||
9 | |||
10 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
11 | Message-Id: <20230203131731.851116-2-eesposit@redhat.com> | ||
12 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
13 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | 6 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> |
14 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
15 | --- | 8 | --- |
16 | include/block/aio.h | 4 ---- | 9 | block.c | 2 ++ |
17 | include/block/raw-aio.h | 18 ++++++++++++------ | 10 | 1 file changed, 2 insertions(+) |
18 | include/sysemu/block-backend-io.h | 5 +++++ | ||
19 | block/file-posix.c | 10 +++------- | ||
20 | block/linux-aio.c | 29 +++++++++++++++++------------ | ||
21 | 5 files changed, 37 insertions(+), 29 deletions(-) | ||
22 | 11 | ||
23 | diff --git a/include/block/aio.h b/include/block/aio.h | 12 | diff --git a/block.c b/block.c |
24 | index XXXXXXX..XXXXXXX 100644 | 13 | index XXXXXXX..XXXXXXX 100644 |
25 | --- a/include/block/aio.h | 14 | --- a/block.c |
26 | +++ b/include/block/aio.h | 15 | +++ b/block.c |
27 | @@ -XXX,XX +XXX,XX @@ struct AioContext { | 16 | @@ -XXX,XX +XXX,XX @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base, |
28 | struct ThreadPool *thread_pool; | 17 | backing_file_str = base->filename; |
29 | |||
30 | #ifdef CONFIG_LINUX_AIO | ||
31 | - /* | ||
32 | - * State for native Linux AIO. Uses aio_context_acquire/release for | ||
33 | - * locking. | ||
34 | - */ | ||
35 | struct LinuxAioState *linux_aio; | ||
36 | #endif | ||
37 | #ifdef CONFIG_LINUX_IO_URING | ||
38 | diff --git a/include/block/raw-aio.h b/include/block/raw-aio.h | ||
39 | index XXXXXXX..XXXXXXX 100644 | ||
40 | --- a/include/block/raw-aio.h | ||
41 | +++ b/include/block/raw-aio.h | ||
42 | @@ -XXX,XX +XXX,XX @@ | ||
43 | typedef struct LinuxAioState LinuxAioState; | ||
44 | LinuxAioState *laio_init(Error **errp); | ||
45 | void laio_cleanup(LinuxAioState *s); | ||
46 | -int coroutine_fn laio_co_submit(BlockDriverState *bs, LinuxAioState *s, int fd, | ||
47 | - uint64_t offset, QEMUIOVector *qiov, int type, | ||
48 | - uint64_t dev_max_batch); | ||
49 | + | ||
50 | +/* laio_co_submit: submit I/O requests in the thread's current AioContext. */ | ||
51 | +int coroutine_fn laio_co_submit(int fd, uint64_t offset, QEMUIOVector *qiov, | ||
52 | + int type, uint64_t dev_max_batch); | ||
53 | + | ||
54 | void laio_detach_aio_context(LinuxAioState *s, AioContext *old_context); | ||
55 | void laio_attach_aio_context(LinuxAioState *s, AioContext *new_context); | ||
56 | -void laio_io_plug(BlockDriverState *bs, LinuxAioState *s); | ||
57 | -void laio_io_unplug(BlockDriverState *bs, LinuxAioState *s, | ||
58 | - uint64_t dev_max_batch); | ||
59 | + | ||
60 | +/* | ||
61 | + * laio_io_plug/unplug work in the thread's current AioContext, therefore the | ||
62 | + * caller must ensure that they are paired in the same IOThread. | ||
63 | + */ | ||
64 | +void laio_io_plug(void); | ||
65 | +void laio_io_unplug(uint64_t dev_max_batch); | ||
66 | #endif | ||
67 | /* io_uring.c - Linux io_uring implementation */ | ||
68 | #ifdef CONFIG_LINUX_IO_URING | ||
69 | diff --git a/include/sysemu/block-backend-io.h b/include/sysemu/block-backend-io.h | ||
70 | index XXXXXXX..XXXXXXX 100644 | ||
71 | --- a/include/sysemu/block-backend-io.h | ||
72 | +++ b/include/sysemu/block-backend-io.h | ||
73 | @@ -XXX,XX +XXX,XX @@ void blk_iostatus_set_err(BlockBackend *blk, int error); | ||
74 | int blk_get_max_iov(BlockBackend *blk); | ||
75 | int blk_get_max_hw_iov(BlockBackend *blk); | ||
76 | |||
77 | +/* | ||
78 | + * blk_io_plug/unplug are thread-local operations. This means that multiple | ||
79 | + * IOThreads can simultaneously call plug/unplug, but the caller must ensure | ||
80 | + * that each unplug() is called in the same IOThread of the matching plug(). | ||
81 | + */ | ||
82 | void coroutine_fn blk_co_io_plug(BlockBackend *blk); | ||
83 | void co_wrapper blk_io_plug(BlockBackend *blk); | ||
84 | |||
85 | diff --git a/block/file-posix.c b/block/file-posix.c | ||
86 | index XXXXXXX..XXXXXXX 100644 | ||
87 | --- a/block/file-posix.c | ||
88 | +++ b/block/file-posix.c | ||
89 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_prw(BlockDriverState *bs, uint64_t offset, | ||
90 | #endif | ||
91 | #ifdef CONFIG_LINUX_AIO | ||
92 | } else if (s->use_linux_aio) { | ||
93 | - LinuxAioState *aio = aio_get_linux_aio(bdrv_get_aio_context(bs)); | ||
94 | assert(qiov->size == bytes); | ||
95 | - return laio_co_submit(bs, aio, s->fd, offset, qiov, type, | ||
96 | - s->aio_max_batch); | ||
97 | + return laio_co_submit(s->fd, offset, qiov, type, s->aio_max_batch); | ||
98 | #endif | ||
99 | } | 18 | } |
100 | 19 | ||
101 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn raw_co_io_plug(BlockDriverState *bs) | 20 | + bdrv_graph_rdlock_main_loop(); |
102 | BDRVRawState __attribute__((unused)) *s = bs->opaque; | 21 | QLIST_FOREACH(c, &top->parents, next_parent) { |
103 | #ifdef CONFIG_LINUX_AIO | 22 | updated_children = g_slist_prepend(updated_children, c); |
104 | if (s->use_linux_aio) { | ||
105 | - LinuxAioState *aio = aio_get_linux_aio(bdrv_get_aio_context(bs)); | ||
106 | - laio_io_plug(bs, aio); | ||
107 | + laio_io_plug(); | ||
108 | } | 23 | } |
109 | #endif | 24 | + bdrv_graph_rdunlock_main_loop(); |
110 | #ifdef CONFIG_LINUX_IO_URING | 25 | |
111 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn raw_co_io_unplug(BlockDriverState *bs) | 26 | /* |
112 | BDRVRawState __attribute__((unused)) *s = bs->opaque; | 27 | * It seems correct to pass detach_subchain=true here, but it triggers |
113 | #ifdef CONFIG_LINUX_AIO | ||
114 | if (s->use_linux_aio) { | ||
115 | - LinuxAioState *aio = aio_get_linux_aio(bdrv_get_aio_context(bs)); | ||
116 | - laio_io_unplug(bs, aio, s->aio_max_batch); | ||
117 | + laio_io_unplug(s->aio_max_batch); | ||
118 | } | ||
119 | #endif | ||
120 | #ifdef CONFIG_LINUX_IO_URING | ||
121 | diff --git a/block/linux-aio.c b/block/linux-aio.c | ||
122 | index XXXXXXX..XXXXXXX 100644 | ||
123 | --- a/block/linux-aio.c | ||
124 | +++ b/block/linux-aio.c | ||
125 | @@ -XXX,XX +XXX,XX @@ | ||
126 | #include "qemu/coroutine.h" | ||
127 | #include "qapi/error.h" | ||
128 | |||
129 | +/* Only used for assertions. */ | ||
130 | +#include "qemu/coroutine_int.h" | ||
131 | + | ||
132 | #include <libaio.h> | ||
133 | |||
134 | /* | ||
135 | @@ -XXX,XX +XXX,XX @@ struct LinuxAioState { | ||
136 | io_context_t ctx; | ||
137 | EventNotifier e; | ||
138 | |||
139 | - /* io queue for submit at batch. Protected by AioContext lock. */ | ||
140 | + /* No locking required, only accessed from AioContext home thread */ | ||
141 | LaioQueue io_q; | ||
142 | - | ||
143 | - /* I/O completion processing. Only runs in I/O thread. */ | ||
144 | QEMUBH *completion_bh; | ||
145 | int event_idx; | ||
146 | int event_max; | ||
147 | @@ -XXX,XX +XXX,XX @@ static void qemu_laio_process_completion(struct qemu_laiocb *laiocb) | ||
148 | * later. Coroutines cannot be entered recursively so avoid doing | ||
149 | * that! | ||
150 | */ | ||
151 | + assert(laiocb->co->ctx == laiocb->ctx->aio_context); | ||
152 | if (!qemu_coroutine_entered(laiocb->co)) { | ||
153 | aio_co_wake(laiocb->co); | ||
154 | } | ||
155 | @@ -XXX,XX +XXX,XX @@ static void qemu_laio_process_completions(LinuxAioState *s) | ||
156 | |||
157 | static void qemu_laio_process_completions_and_submit(LinuxAioState *s) | ||
158 | { | ||
159 | - aio_context_acquire(s->aio_context); | ||
160 | qemu_laio_process_completions(s); | ||
161 | |||
162 | if (!s->io_q.plugged && !QSIMPLEQ_EMPTY(&s->io_q.pending)) { | ||
163 | ioq_submit(s); | ||
164 | } | ||
165 | - aio_context_release(s->aio_context); | ||
166 | } | ||
167 | |||
168 | static void qemu_laio_completion_bh(void *opaque) | ||
169 | @@ -XXX,XX +XXX,XX @@ static uint64_t laio_max_batch(LinuxAioState *s, uint64_t dev_max_batch) | ||
170 | return max_batch; | ||
171 | } | ||
172 | |||
173 | -void laio_io_plug(BlockDriverState *bs, LinuxAioState *s) | ||
174 | +void laio_io_plug(void) | ||
175 | { | ||
176 | + AioContext *ctx = qemu_get_current_aio_context(); | ||
177 | + LinuxAioState *s = aio_get_linux_aio(ctx); | ||
178 | + | ||
179 | s->io_q.plugged++; | ||
180 | } | ||
181 | |||
182 | -void laio_io_unplug(BlockDriverState *bs, LinuxAioState *s, | ||
183 | - uint64_t dev_max_batch) | ||
184 | +void laio_io_unplug(uint64_t dev_max_batch) | ||
185 | { | ||
186 | + AioContext *ctx = qemu_get_current_aio_context(); | ||
187 | + LinuxAioState *s = aio_get_linux_aio(ctx); | ||
188 | + | ||
189 | assert(s->io_q.plugged); | ||
190 | s->io_q.plugged--; | ||
191 | |||
192 | @@ -XXX,XX +XXX,XX @@ static int laio_do_submit(int fd, struct qemu_laiocb *laiocb, off_t offset, | ||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | -int coroutine_fn laio_co_submit(BlockDriverState *bs, LinuxAioState *s, int fd, | ||
197 | - uint64_t offset, QEMUIOVector *qiov, int type, | ||
198 | - uint64_t dev_max_batch) | ||
199 | +int coroutine_fn laio_co_submit(int fd, uint64_t offset, QEMUIOVector *qiov, | ||
200 | + int type, uint64_t dev_max_batch) | ||
201 | { | ||
202 | int ret; | ||
203 | + AioContext *ctx = qemu_get_current_aio_context(); | ||
204 | struct qemu_laiocb laiocb = { | ||
205 | .co = qemu_coroutine_self(), | ||
206 | .nbytes = qiov->size, | ||
207 | - .ctx = s, | ||
208 | + .ctx = aio_get_linux_aio(ctx), | ||
209 | .ret = -EINPROGRESS, | ||
210 | .is_read = (type == QEMU_AIO_READ), | ||
211 | .qiov = qiov, | ||
212 | -- | 28 | -- |
213 | 2.40.0 | 29 | 2.41.0 | diff view generated by jsdifflib |
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | 1 | The function reads the parents list, so it needs to hold the graph lock. |
---|---|---|---|
2 | 2 | ||
3 | Use qemu_get_current_aio_context() where possible, since we always | 3 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
4 | submit work to the current thread anyways. | 4 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
5 | 5 | Message-ID: <20230911094620.45040-19-kwolf@redhat.com> | |
6 | We want to also be sure that the thread submitting the work is | ||
7 | the same as the one processing the pool, to avoid adding | ||
8 | synchronization to the pool list. | ||
9 | |||
10 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
11 | Message-Id: <20230203131731.851116-4-eesposit@redhat.com> | ||
12 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
13 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | 6 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> |
14 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
15 | --- | 8 | --- |
16 | include/block/thread-pool.h | 5 +++++ | 9 | block.c | 4 ++++ |
17 | block/file-posix.c | 21 ++++++++++----------- | 10 | 1 file changed, 4 insertions(+) |
18 | block/file-win32.c | 2 +- | ||
19 | block/qcow2-threads.c | 2 +- | ||
20 | util/thread-pool.c | 9 ++++----- | ||
21 | 5 files changed, 21 insertions(+), 18 deletions(-) | ||
22 | 11 | ||
23 | diff --git a/include/block/thread-pool.h b/include/block/thread-pool.h | 12 | diff --git a/block.c b/block.c |
24 | index XXXXXXX..XXXXXXX 100644 | 13 | index XXXXXXX..XXXXXXX 100644 |
25 | --- a/include/block/thread-pool.h | 14 | --- a/block.c |
26 | +++ b/include/block/thread-pool.h | 15 | +++ b/block.c |
27 | @@ -XXX,XX +XXX,XX @@ typedef struct ThreadPool ThreadPool; | 16 | @@ -XXX,XX +XXX,XX @@ static bool bdrv_change_aio_context(BlockDriverState *bs, AioContext *ctx, |
28 | ThreadPool *thread_pool_new(struct AioContext *ctx); | 17 | return true; |
29 | void thread_pool_free(ThreadPool *pool); | ||
30 | |||
31 | +/* | ||
32 | + * thread_pool_submit* API: submit I/O requests in the thread's | ||
33 | + * current AioContext. | ||
34 | + */ | ||
35 | BlockAIOCB *thread_pool_submit_aio(ThreadPool *pool, | ||
36 | ThreadPoolFunc *func, void *arg, | ||
37 | BlockCompletionFunc *cb, void *opaque); | ||
38 | int coroutine_fn thread_pool_submit_co(ThreadPool *pool, | ||
39 | ThreadPoolFunc *func, void *arg); | ||
40 | void thread_pool_submit(ThreadPool *pool, ThreadPoolFunc *func, void *arg); | ||
41 | + | ||
42 | void thread_pool_update_params(ThreadPool *pool, struct AioContext *ctx); | ||
43 | |||
44 | #endif | ||
45 | diff --git a/block/file-posix.c b/block/file-posix.c | ||
46 | index XXXXXXX..XXXXXXX 100644 | ||
47 | --- a/block/file-posix.c | ||
48 | +++ b/block/file-posix.c | ||
49 | @@ -XXX,XX +XXX,XX @@ out: | ||
50 | return result; | ||
51 | } | ||
52 | |||
53 | -static int coroutine_fn raw_thread_pool_submit(BlockDriverState *bs, | ||
54 | - ThreadPoolFunc func, void *arg) | ||
55 | +static int coroutine_fn raw_thread_pool_submit(ThreadPoolFunc func, void *arg) | ||
56 | { | ||
57 | /* @bs can be NULL, bdrv_get_aio_context() returns the main context then */ | ||
58 | - ThreadPool *pool = aio_get_thread_pool(bdrv_get_aio_context(bs)); | ||
59 | + ThreadPool *pool = aio_get_thread_pool(qemu_get_current_aio_context()); | ||
60 | return thread_pool_submit_co(pool, func, arg); | ||
61 | } | ||
62 | |||
63 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_prw(BlockDriverState *bs, uint64_t offset, | ||
64 | }; | ||
65 | |||
66 | assert(qiov->size == bytes); | ||
67 | - return raw_thread_pool_submit(bs, handle_aiocb_rw, &acb); | ||
68 | + return raw_thread_pool_submit(handle_aiocb_rw, &acb); | ||
69 | } | ||
70 | |||
71 | static int coroutine_fn raw_co_preadv(BlockDriverState *bs, int64_t offset, | ||
72 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_flush_to_disk(BlockDriverState *bs) | ||
73 | return luring_co_submit(bs, s->fd, 0, NULL, QEMU_AIO_FLUSH); | ||
74 | } | 18 | } |
75 | #endif | 19 | |
76 | - return raw_thread_pool_submit(bs, handle_aiocb_flush, &acb); | 20 | + bdrv_graph_rdlock_main_loop(); |
77 | + return raw_thread_pool_submit(handle_aiocb_flush, &acb); | 21 | QLIST_FOREACH(c, &bs->parents, next_parent) { |
78 | } | 22 | if (!bdrv_parent_change_aio_context(c, ctx, visited, tran, errp)) { |
79 | 23 | + bdrv_graph_rdunlock_main_loop(); | |
80 | static void raw_aio_attach_aio_context(BlockDriverState *bs, | 24 | return false; |
81 | @@ -XXX,XX +XXX,XX @@ raw_regular_truncate(BlockDriverState *bs, int fd, int64_t offset, | ||
82 | }, | ||
83 | }; | ||
84 | |||
85 | - return raw_thread_pool_submit(bs, handle_aiocb_truncate, &acb); | ||
86 | + return raw_thread_pool_submit(handle_aiocb_truncate, &acb); | ||
87 | } | ||
88 | |||
89 | static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset, | ||
90 | @@ -XXX,XX +XXX,XX @@ raw_do_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
91 | acb.aio_type |= QEMU_AIO_BLKDEV; | ||
92 | } | ||
93 | |||
94 | - ret = raw_thread_pool_submit(bs, handle_aiocb_discard, &acb); | ||
95 | + ret = raw_thread_pool_submit(handle_aiocb_discard, &acb); | ||
96 | raw_account_discard(s, bytes, ret); | ||
97 | return ret; | ||
98 | } | ||
99 | @@ -XXX,XX +XXX,XX @@ raw_do_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
100 | handler = handle_aiocb_write_zeroes; | ||
101 | } | ||
102 | |||
103 | - return raw_thread_pool_submit(bs, handler, &acb); | ||
104 | + return raw_thread_pool_submit(handler, &acb); | ||
105 | } | ||
106 | |||
107 | static int coroutine_fn raw_co_pwrite_zeroes( | ||
108 | @@ -XXX,XX +XXX,XX @@ raw_co_copy_range_to(BlockDriverState *bs, | ||
109 | }, | ||
110 | }; | ||
111 | |||
112 | - return raw_thread_pool_submit(bs, handle_aiocb_copy_range, &acb); | ||
113 | + return raw_thread_pool_submit(handle_aiocb_copy_range, &acb); | ||
114 | } | ||
115 | |||
116 | BlockDriver bdrv_file = { | ||
117 | @@ -XXX,XX +XXX,XX @@ hdev_co_ioctl(BlockDriverState *bs, unsigned long int req, void *buf) | ||
118 | struct sg_io_hdr *io_hdr = buf; | ||
119 | if (io_hdr->cmdp[0] == PERSISTENT_RESERVE_OUT || | ||
120 | io_hdr->cmdp[0] == PERSISTENT_RESERVE_IN) { | ||
121 | - return pr_manager_execute(s->pr_mgr, bdrv_get_aio_context(bs), | ||
122 | + return pr_manager_execute(s->pr_mgr, qemu_get_current_aio_context(), | ||
123 | s->fd, io_hdr); | ||
124 | } | 25 | } |
125 | } | 26 | } |
126 | @@ -XXX,XX +XXX,XX @@ hdev_co_ioctl(BlockDriverState *bs, unsigned long int req, void *buf) | 27 | |
127 | }, | 28 | QLIST_FOREACH(c, &bs->children, next) { |
128 | }; | 29 | if (!bdrv_child_change_aio_context(c, ctx, visited, tran, errp)) { |
129 | 30 | + bdrv_graph_rdunlock_main_loop(); | |
130 | - return raw_thread_pool_submit(bs, handle_aiocb_ioctl, &acb); | 31 | return false; |
131 | + return raw_thread_pool_submit(handle_aiocb_ioctl, &acb); | ||
132 | } | ||
133 | #endif /* linux */ | ||
134 | |||
135 | diff --git a/block/file-win32.c b/block/file-win32.c | ||
136 | index XXXXXXX..XXXXXXX 100644 | ||
137 | --- a/block/file-win32.c | ||
138 | +++ b/block/file-win32.c | ||
139 | @@ -XXX,XX +XXX,XX @@ static BlockAIOCB *paio_submit(BlockDriverState *bs, HANDLE hfile, | ||
140 | acb->aio_offset = offset; | ||
141 | |||
142 | trace_file_paio_submit(acb, opaque, offset, count, type); | ||
143 | - pool = aio_get_thread_pool(bdrv_get_aio_context(bs)); | ||
144 | + pool = aio_get_thread_pool(qemu_get_current_aio_context()); | ||
145 | return thread_pool_submit_aio(pool, aio_worker, acb, cb, opaque); | ||
146 | } | ||
147 | |||
148 | diff --git a/block/qcow2-threads.c b/block/qcow2-threads.c | ||
149 | index XXXXXXX..XXXXXXX 100644 | ||
150 | --- a/block/qcow2-threads.c | ||
151 | +++ b/block/qcow2-threads.c | ||
152 | @@ -XXX,XX +XXX,XX @@ qcow2_co_process(BlockDriverState *bs, ThreadPoolFunc *func, void *arg) | ||
153 | { | ||
154 | int ret; | ||
155 | BDRVQcow2State *s = bs->opaque; | ||
156 | - ThreadPool *pool = aio_get_thread_pool(bdrv_get_aio_context(bs)); | ||
157 | + ThreadPool *pool = aio_get_thread_pool(qemu_get_current_aio_context()); | ||
158 | |||
159 | qemu_co_mutex_lock(&s->lock); | ||
160 | while (s->nb_threads >= QCOW2_MAX_THREADS) { | ||
161 | diff --git a/util/thread-pool.c b/util/thread-pool.c | ||
162 | index XXXXXXX..XXXXXXX 100644 | ||
163 | --- a/util/thread-pool.c | ||
164 | +++ b/util/thread-pool.c | ||
165 | @@ -XXX,XX +XXX,XX @@ struct ThreadPoolElement { | ||
166 | /* Access to this list is protected by lock. */ | ||
167 | QTAILQ_ENTRY(ThreadPoolElement) reqs; | ||
168 | |||
169 | - /* Access to this list is protected by the global mutex. */ | ||
170 | + /* This list is only written by the thread pool's mother thread. */ | ||
171 | QLIST_ENTRY(ThreadPoolElement) all; | ||
172 | }; | ||
173 | |||
174 | @@ -XXX,XX +XXX,XX @@ static void thread_pool_completion_bh(void *opaque) | ||
175 | ThreadPool *pool = opaque; | ||
176 | ThreadPoolElement *elem, *next; | ||
177 | |||
178 | - aio_context_acquire(pool->ctx); | ||
179 | restart: | ||
180 | QLIST_FOREACH_SAFE(elem, &pool->head, all, next) { | ||
181 | if (elem->state != THREAD_DONE) { | ||
182 | @@ -XXX,XX +XXX,XX @@ restart: | ||
183 | */ | ||
184 | qemu_bh_schedule(pool->completion_bh); | ||
185 | |||
186 | - aio_context_release(pool->ctx); | ||
187 | elem->common.cb(elem->common.opaque, elem->ret); | ||
188 | - aio_context_acquire(pool->ctx); | ||
189 | |||
190 | /* We can safely cancel the completion_bh here regardless of someone | ||
191 | * else having scheduled it meanwhile because we reenter the | ||
192 | @@ -XXX,XX +XXX,XX @@ restart: | ||
193 | qemu_aio_unref(elem); | ||
194 | } | 32 | } |
195 | } | 33 | } |
196 | - aio_context_release(pool->ctx); | 34 | + bdrv_graph_rdunlock_main_loop(); |
197 | } | 35 | |
198 | 36 | state = g_new(BdrvStateSetAioContext, 1); | |
199 | static void thread_pool_cancel(BlockAIOCB *acb) | 37 | *state = (BdrvStateSetAioContext) { |
200 | @@ -XXX,XX +XXX,XX @@ BlockAIOCB *thread_pool_submit_aio(ThreadPool *pool, | ||
201 | { | ||
202 | ThreadPoolElement *req; | ||
203 | |||
204 | + /* Assert that the thread submitting work is the same running the pool */ | ||
205 | + assert(pool->ctx == qemu_get_current_aio_context()); | ||
206 | + | ||
207 | req = qemu_aio_get(&thread_pool_aiocb_info, NULL, cb, opaque); | ||
208 | req->func = func; | ||
209 | req->arg = arg; | ||
210 | -- | 38 | -- |
211 | 2.40.0 | 39 | 2.41.0 | diff view generated by jsdifflib |
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | 1 | Instead of taking the writer lock internally, require callers to already |
---|---|---|---|
2 | hold it when calling bdrv_root_unref_child(). These callers will | ||
3 | typically already hold the graph lock once the locking work is | ||
4 | completed, which means that they can't call functions that take it | ||
5 | internally. | ||
2 | 6 | ||
3 | thread_pool_submit_aio() is always called on a pool taken from | 7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
4 | qemu_get_current_aio_context(), and that is the only intended | 8 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
5 | use: each pool runs only in the same thread that is submitting | ||
6 | work to it, it can't run anywhere else. | ||
7 | |||
8 | Therefore simplify the thread_pool_submit* API and remove the | ||
9 | ThreadPool function parameter. | ||
10 | |||
11 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
12 | Message-Id: <20230203131731.851116-5-eesposit@redhat.com> | ||
13 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
14 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | 9 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> |
10 | Message-ID: <20230911094620.45040-20-kwolf@redhat.com> | ||
15 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
16 | --- | 12 | --- |
17 | include/block/thread-pool.h | 10 ++++------ | 13 | include/block/block_int-global-state.h | 2 +- |
18 | backends/tpm/tpm_backend.c | 4 +--- | 14 | block.c | 6 +++--- |
19 | block/file-posix.c | 4 +--- | 15 | block/block-backend.c | 3 +++ |
20 | block/file-win32.c | 4 +--- | 16 | blockjob.c | 2 ++ |
21 | block/qcow2-threads.c | 3 +-- | 17 | 4 files changed, 9 insertions(+), 4 deletions(-) |
22 | hw/9pfs/coth.c | 3 +-- | ||
23 | hw/ppc/spapr_nvdimm.c | 6 ++---- | ||
24 | hw/virtio/virtio-pmem.c | 3 +-- | ||
25 | scsi/pr-manager.c | 3 +-- | ||
26 | scsi/qemu-pr-helper.c | 3 +-- | ||
27 | tests/unit/test-thread-pool.c | 12 +++++------- | ||
28 | util/thread-pool.c | 16 ++++++++-------- | ||
29 | 12 files changed, 27 insertions(+), 44 deletions(-) | ||
30 | 18 | ||
31 | diff --git a/include/block/thread-pool.h b/include/block/thread-pool.h | 19 | diff --git a/include/block/block_int-global-state.h b/include/block/block_int-global-state.h |
32 | index XXXXXXX..XXXXXXX 100644 | 20 | index XXXXXXX..XXXXXXX 100644 |
33 | --- a/include/block/thread-pool.h | 21 | --- a/include/block/block_int-global-state.h |
34 | +++ b/include/block/thread-pool.h | 22 | +++ b/include/block/block_int-global-state.h |
35 | @@ -XXX,XX +XXX,XX @@ void thread_pool_free(ThreadPool *pool); | 23 | @@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs, |
36 | * thread_pool_submit* API: submit I/O requests in the thread's | 24 | BdrvChildRole child_role, |
37 | * current AioContext. | 25 | uint64_t perm, uint64_t shared_perm, |
38 | */ | 26 | void *opaque, Error **errp); |
39 | -BlockAIOCB *thread_pool_submit_aio(ThreadPool *pool, | 27 | -void bdrv_root_unref_child(BdrvChild *child); |
40 | - ThreadPoolFunc *func, void *arg, | 28 | +void GRAPH_WRLOCK bdrv_root_unref_child(BdrvChild *child); |
41 | - BlockCompletionFunc *cb, void *opaque); | 29 | |
42 | -int coroutine_fn thread_pool_submit_co(ThreadPool *pool, | 30 | void GRAPH_RDLOCK bdrv_get_cumulative_perm(BlockDriverState *bs, uint64_t *perm, |
43 | - ThreadPoolFunc *func, void *arg); | 31 | uint64_t *shared_perm); |
44 | -void thread_pool_submit(ThreadPool *pool, ThreadPoolFunc *func, void *arg); | 32 | diff --git a/block.c b/block.c |
45 | +BlockAIOCB *thread_pool_submit_aio(ThreadPoolFunc *func, void *arg, | ||
46 | + BlockCompletionFunc *cb, void *opaque); | ||
47 | +int coroutine_fn thread_pool_submit_co(ThreadPoolFunc *func, void *arg); | ||
48 | +void thread_pool_submit(ThreadPoolFunc *func, void *arg); | ||
49 | |||
50 | void thread_pool_update_params(ThreadPool *pool, struct AioContext *ctx); | ||
51 | |||
52 | diff --git a/backends/tpm/tpm_backend.c b/backends/tpm/tpm_backend.c | ||
53 | index XXXXXXX..XXXXXXX 100644 | 33 | index XXXXXXX..XXXXXXX 100644 |
54 | --- a/backends/tpm/tpm_backend.c | 34 | --- a/block.c |
55 | +++ b/backends/tpm/tpm_backend.c | 35 | +++ b/block.c |
56 | @@ -XXX,XX +XXX,XX @@ bool tpm_backend_had_startup_error(TPMBackend *s) | 36 | @@ -XXX,XX +XXX,XX @@ void bdrv_root_unref_child(BdrvChild *child) |
57 | 37 | BlockDriverState *child_bs = child->bs; | |
58 | void tpm_backend_deliver_request(TPMBackend *s, TPMBackendCmd *cmd) | 38 | |
59 | { | 39 | GLOBAL_STATE_CODE(); |
60 | - ThreadPool *pool = aio_get_thread_pool(qemu_get_aio_context()); | 40 | - bdrv_graph_wrlock(NULL); |
61 | - | 41 | bdrv_replace_child_noperm(child, NULL); |
62 | if (s->cmd != NULL) { | 42 | bdrv_child_free(child); |
63 | error_report("There is a TPM request pending"); | 43 | |
44 | @@ -XXX,XX +XXX,XX @@ void bdrv_root_unref_child(BdrvChild *child) | ||
45 | NULL); | ||
46 | } | ||
47 | |||
48 | - bdrv_graph_wrunlock(); | ||
49 | - bdrv_unref(child_bs); | ||
50 | + bdrv_schedule_unref(child_bs); | ||
51 | } | ||
52 | |||
53 | typedef struct BdrvSetInheritsFrom { | ||
54 | @@ -XXX,XX +XXX,XX @@ void bdrv_unref_child(BlockDriverState *parent, BdrvChild *child) | ||
64 | return; | 55 | return; |
65 | @@ -XXX,XX +XXX,XX @@ void tpm_backend_deliver_request(TPMBackend *s, TPMBackendCmd *cmd) | 56 | } |
66 | 57 | ||
67 | s->cmd = cmd; | 58 | + bdrv_graph_wrlock(NULL); |
68 | object_ref(OBJECT(s)); | 59 | bdrv_unset_inherits_from(parent, child, NULL); |
69 | - thread_pool_submit_aio(pool, tpm_backend_worker_thread, s, | 60 | bdrv_root_unref_child(child); |
70 | + thread_pool_submit_aio(tpm_backend_worker_thread, s, | 61 | + bdrv_graph_wrunlock(); |
71 | tpm_backend_request_completed, s); | ||
72 | } | 62 | } |
73 | 63 | ||
74 | diff --git a/block/file-posix.c b/block/file-posix.c | 64 | |
65 | diff --git a/block/block-backend.c b/block/block-backend.c | ||
75 | index XXXXXXX..XXXXXXX 100644 | 66 | index XXXXXXX..XXXXXXX 100644 |
76 | --- a/block/file-posix.c | 67 | --- a/block/block-backend.c |
77 | +++ b/block/file-posix.c | 68 | +++ b/block/block-backend.c |
78 | @@ -XXX,XX +XXX,XX @@ out: | 69 | @@ -XXX,XX +XXX,XX @@ void blk_remove_bs(BlockBackend *blk) |
79 | 70 | blk_drain(blk); | |
80 | static int coroutine_fn raw_thread_pool_submit(ThreadPoolFunc func, void *arg) | 71 | root = blk->root; |
81 | { | 72 | blk->root = NULL; |
82 | - /* @bs can be NULL, bdrv_get_aio_context() returns the main context then */ | 73 | + |
83 | - ThreadPool *pool = aio_get_thread_pool(qemu_get_current_aio_context()); | 74 | + bdrv_graph_wrlock(NULL); |
84 | - return thread_pool_submit_co(pool, func, arg); | 75 | bdrv_root_unref_child(root); |
85 | + return thread_pool_submit_co(func, arg); | 76 | + bdrv_graph_wrunlock(); |
86 | } | 77 | } |
87 | 78 | ||
88 | /* | 79 | /* |
89 | diff --git a/block/file-win32.c b/block/file-win32.c | 80 | diff --git a/blockjob.c b/blockjob.c |
90 | index XXXXXXX..XXXXXXX 100644 | 81 | index XXXXXXX..XXXXXXX 100644 |
91 | --- a/block/file-win32.c | 82 | --- a/blockjob.c |
92 | +++ b/block/file-win32.c | 83 | +++ b/blockjob.c |
93 | @@ -XXX,XX +XXX,XX @@ static BlockAIOCB *paio_submit(BlockDriverState *bs, HANDLE hfile, | 84 | @@ -XXX,XX +XXX,XX @@ void block_job_remove_all_bdrv(BlockJob *job) |
94 | BlockCompletionFunc *cb, void *opaque, int type) | 85 | * one to make sure that such a concurrent access does not attempt |
95 | { | 86 | * to process an already freed BdrvChild. |
96 | RawWin32AIOData *acb = g_new(RawWin32AIOData, 1); | 87 | */ |
97 | - ThreadPool *pool; | 88 | + bdrv_graph_wrlock(NULL); |
98 | 89 | while (job->nodes) { | |
99 | acb->bs = bs; | 90 | GSList *l = job->nodes; |
100 | acb->hfile = hfile; | 91 | BdrvChild *c = l->data; |
101 | @@ -XXX,XX +XXX,XX @@ static BlockAIOCB *paio_submit(BlockDriverState *bs, HANDLE hfile, | 92 | @@ -XXX,XX +XXX,XX @@ void block_job_remove_all_bdrv(BlockJob *job) |
102 | acb->aio_offset = offset; | 93 | |
103 | 94 | g_slist_free_1(l); | |
104 | trace_file_paio_submit(acb, opaque, offset, count, type); | 95 | } |
105 | - pool = aio_get_thread_pool(qemu_get_current_aio_context()); | 96 | + bdrv_graph_wrunlock(); |
106 | - return thread_pool_submit_aio(pool, aio_worker, acb, cb, opaque); | ||
107 | + return thread_pool_submit_aio(aio_worker, acb, cb, opaque); | ||
108 | } | 97 | } |
109 | 98 | ||
110 | int qemu_ftruncate64(int fd, int64_t length) | 99 | bool block_job_has_bdrv(BlockJob *job, BlockDriverState *bs) |
111 | diff --git a/block/qcow2-threads.c b/block/qcow2-threads.c | ||
112 | index XXXXXXX..XXXXXXX 100644 | ||
113 | --- a/block/qcow2-threads.c | ||
114 | +++ b/block/qcow2-threads.c | ||
115 | @@ -XXX,XX +XXX,XX @@ qcow2_co_process(BlockDriverState *bs, ThreadPoolFunc *func, void *arg) | ||
116 | { | ||
117 | int ret; | ||
118 | BDRVQcow2State *s = bs->opaque; | ||
119 | - ThreadPool *pool = aio_get_thread_pool(qemu_get_current_aio_context()); | ||
120 | |||
121 | qemu_co_mutex_lock(&s->lock); | ||
122 | while (s->nb_threads >= QCOW2_MAX_THREADS) { | ||
123 | @@ -XXX,XX +XXX,XX @@ qcow2_co_process(BlockDriverState *bs, ThreadPoolFunc *func, void *arg) | ||
124 | s->nb_threads++; | ||
125 | qemu_co_mutex_unlock(&s->lock); | ||
126 | |||
127 | - ret = thread_pool_submit_co(pool, func, arg); | ||
128 | + ret = thread_pool_submit_co(func, arg); | ||
129 | |||
130 | qemu_co_mutex_lock(&s->lock); | ||
131 | s->nb_threads--; | ||
132 | diff --git a/hw/9pfs/coth.c b/hw/9pfs/coth.c | ||
133 | index XXXXXXX..XXXXXXX 100644 | ||
134 | --- a/hw/9pfs/coth.c | ||
135 | +++ b/hw/9pfs/coth.c | ||
136 | @@ -XXX,XX +XXX,XX @@ static int coroutine_enter_func(void *arg) | ||
137 | void co_run_in_worker_bh(void *opaque) | ||
138 | { | ||
139 | Coroutine *co = opaque; | ||
140 | - thread_pool_submit_aio(aio_get_thread_pool(qemu_get_aio_context()), | ||
141 | - coroutine_enter_func, co, coroutine_enter_cb, co); | ||
142 | + thread_pool_submit_aio(coroutine_enter_func, co, coroutine_enter_cb, co); | ||
143 | } | ||
144 | diff --git a/hw/ppc/spapr_nvdimm.c b/hw/ppc/spapr_nvdimm.c | ||
145 | index XXXXXXX..XXXXXXX 100644 | ||
146 | --- a/hw/ppc/spapr_nvdimm.c | ||
147 | +++ b/hw/ppc/spapr_nvdimm.c | ||
148 | @@ -XXX,XX +XXX,XX @@ static int spapr_nvdimm_flush_post_load(void *opaque, int version_id) | ||
149 | { | ||
150 | SpaprNVDIMMDevice *s_nvdimm = (SpaprNVDIMMDevice *)opaque; | ||
151 | SpaprNVDIMMDeviceFlushState *state; | ||
152 | - ThreadPool *pool = aio_get_thread_pool(qemu_get_aio_context()); | ||
153 | HostMemoryBackend *backend = MEMORY_BACKEND(PC_DIMM(s_nvdimm)->hostmem); | ||
154 | bool is_pmem = object_property_get_bool(OBJECT(backend), "pmem", NULL); | ||
155 | bool pmem_override = object_property_get_bool(OBJECT(s_nvdimm), | ||
156 | @@ -XXX,XX +XXX,XX @@ static int spapr_nvdimm_flush_post_load(void *opaque, int version_id) | ||
157 | } | ||
158 | |||
159 | QLIST_FOREACH(state, &s_nvdimm->pending_nvdimm_flush_states, node) { | ||
160 | - thread_pool_submit_aio(pool, flush_worker_cb, state, | ||
161 | + thread_pool_submit_aio(flush_worker_cb, state, | ||
162 | spapr_nvdimm_flush_completion_cb, state); | ||
163 | } | ||
164 | |||
165 | @@ -XXX,XX +XXX,XX @@ static target_ulong h_scm_flush(PowerPCCPU *cpu, SpaprMachineState *spapr, | ||
166 | PCDIMMDevice *dimm; | ||
167 | HostMemoryBackend *backend = NULL; | ||
168 | SpaprNVDIMMDeviceFlushState *state; | ||
169 | - ThreadPool *pool = aio_get_thread_pool(qemu_get_aio_context()); | ||
170 | int fd; | ||
171 | |||
172 | if (!drc || !drc->dev || | ||
173 | @@ -XXX,XX +XXX,XX @@ static target_ulong h_scm_flush(PowerPCCPU *cpu, SpaprMachineState *spapr, | ||
174 | |||
175 | state->drcidx = drc_index; | ||
176 | |||
177 | - thread_pool_submit_aio(pool, flush_worker_cb, state, | ||
178 | + thread_pool_submit_aio(flush_worker_cb, state, | ||
179 | spapr_nvdimm_flush_completion_cb, state); | ||
180 | |||
181 | continue_token = state->continue_token; | ||
182 | diff --git a/hw/virtio/virtio-pmem.c b/hw/virtio/virtio-pmem.c | ||
183 | index XXXXXXX..XXXXXXX 100644 | ||
184 | --- a/hw/virtio/virtio-pmem.c | ||
185 | +++ b/hw/virtio/virtio-pmem.c | ||
186 | @@ -XXX,XX +XXX,XX @@ static void virtio_pmem_flush(VirtIODevice *vdev, VirtQueue *vq) | ||
187 | VirtIODeviceRequest *req_data; | ||
188 | VirtIOPMEM *pmem = VIRTIO_PMEM(vdev); | ||
189 | HostMemoryBackend *backend = MEMORY_BACKEND(pmem->memdev); | ||
190 | - ThreadPool *pool = aio_get_thread_pool(qemu_get_aio_context()); | ||
191 | |||
192 | trace_virtio_pmem_flush_request(); | ||
193 | req_data = virtqueue_pop(vq, sizeof(VirtIODeviceRequest)); | ||
194 | @@ -XXX,XX +XXX,XX @@ static void virtio_pmem_flush(VirtIODevice *vdev, VirtQueue *vq) | ||
195 | req_data->fd = memory_region_get_fd(&backend->mr); | ||
196 | req_data->pmem = pmem; | ||
197 | req_data->vdev = vdev; | ||
198 | - thread_pool_submit_aio(pool, worker_cb, req_data, done_cb, req_data); | ||
199 | + thread_pool_submit_aio(worker_cb, req_data, done_cb, req_data); | ||
200 | } | ||
201 | |||
202 | static void virtio_pmem_get_config(VirtIODevice *vdev, uint8_t *config) | ||
203 | diff --git a/scsi/pr-manager.c b/scsi/pr-manager.c | ||
204 | index XXXXXXX..XXXXXXX 100644 | ||
205 | --- a/scsi/pr-manager.c | ||
206 | +++ b/scsi/pr-manager.c | ||
207 | @@ -XXX,XX +XXX,XX @@ static int pr_manager_worker(void *opaque) | ||
208 | int coroutine_fn pr_manager_execute(PRManager *pr_mgr, AioContext *ctx, int fd, | ||
209 | struct sg_io_hdr *hdr) | ||
210 | { | ||
211 | - ThreadPool *pool = aio_get_thread_pool(ctx); | ||
212 | PRManagerData data = { | ||
213 | .pr_mgr = pr_mgr, | ||
214 | .fd = fd, | ||
215 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn pr_manager_execute(PRManager *pr_mgr, AioContext *ctx, int fd, | ||
216 | |||
217 | /* The matching object_unref is in pr_manager_worker. */ | ||
218 | object_ref(OBJECT(pr_mgr)); | ||
219 | - return thread_pool_submit_co(pool, pr_manager_worker, &data); | ||
220 | + return thread_pool_submit_co(pr_manager_worker, &data); | ||
221 | } | ||
222 | |||
223 | bool pr_manager_is_connected(PRManager *pr_mgr) | ||
224 | diff --git a/scsi/qemu-pr-helper.c b/scsi/qemu-pr-helper.c | ||
225 | index XXXXXXX..XXXXXXX 100644 | ||
226 | --- a/scsi/qemu-pr-helper.c | ||
227 | +++ b/scsi/qemu-pr-helper.c | ||
228 | @@ -XXX,XX +XXX,XX @@ static int do_sgio_worker(void *opaque) | ||
229 | static int do_sgio(int fd, const uint8_t *cdb, uint8_t *sense, | ||
230 | uint8_t *buf, int *sz, int dir) | ||
231 | { | ||
232 | - ThreadPool *pool = aio_get_thread_pool(qemu_get_aio_context()); | ||
233 | int r; | ||
234 | |||
235 | PRHelperSGIOData data = { | ||
236 | @@ -XXX,XX +XXX,XX @@ static int do_sgio(int fd, const uint8_t *cdb, uint8_t *sense, | ||
237 | .dir = dir, | ||
238 | }; | ||
239 | |||
240 | - r = thread_pool_submit_co(pool, do_sgio_worker, &data); | ||
241 | + r = thread_pool_submit_co(do_sgio_worker, &data); | ||
242 | *sz = data.sz; | ||
243 | return r; | ||
244 | } | ||
245 | diff --git a/tests/unit/test-thread-pool.c b/tests/unit/test-thread-pool.c | ||
246 | index XXXXXXX..XXXXXXX 100644 | ||
247 | --- a/tests/unit/test-thread-pool.c | ||
248 | +++ b/tests/unit/test-thread-pool.c | ||
249 | @@ -XXX,XX +XXX,XX @@ | ||
250 | #include "qemu/main-loop.h" | ||
251 | |||
252 | static AioContext *ctx; | ||
253 | -static ThreadPool *pool; | ||
254 | static int active; | ||
255 | |||
256 | typedef struct { | ||
257 | @@ -XXX,XX +XXX,XX @@ static void done_cb(void *opaque, int ret) | ||
258 | static void test_submit(void) | ||
259 | { | ||
260 | WorkerTestData data = { .n = 0 }; | ||
261 | - thread_pool_submit(pool, worker_cb, &data); | ||
262 | + thread_pool_submit(worker_cb, &data); | ||
263 | while (data.n == 0) { | ||
264 | aio_poll(ctx, true); | ||
265 | } | ||
266 | @@ -XXX,XX +XXX,XX @@ static void test_submit(void) | ||
267 | static void test_submit_aio(void) | ||
268 | { | ||
269 | WorkerTestData data = { .n = 0, .ret = -EINPROGRESS }; | ||
270 | - data.aiocb = thread_pool_submit_aio(pool, worker_cb, &data, | ||
271 | + data.aiocb = thread_pool_submit_aio(worker_cb, &data, | ||
272 | done_cb, &data); | ||
273 | |||
274 | /* The callbacks are not called until after the first wait. */ | ||
275 | @@ -XXX,XX +XXX,XX @@ static void co_test_cb(void *opaque) | ||
276 | active = 1; | ||
277 | data->n = 0; | ||
278 | data->ret = -EINPROGRESS; | ||
279 | - thread_pool_submit_co(pool, worker_cb, data); | ||
280 | + thread_pool_submit_co(worker_cb, data); | ||
281 | |||
282 | /* The test continues in test_submit_co, after qemu_coroutine_enter... */ | ||
283 | |||
284 | @@ -XXX,XX +XXX,XX @@ static void test_submit_many(void) | ||
285 | for (i = 0; i < 100; i++) { | ||
286 | data[i].n = 0; | ||
287 | data[i].ret = -EINPROGRESS; | ||
288 | - thread_pool_submit_aio(pool, worker_cb, &data[i], done_cb, &data[i]); | ||
289 | + thread_pool_submit_aio(worker_cb, &data[i], done_cb, &data[i]); | ||
290 | } | ||
291 | |||
292 | active = 100; | ||
293 | @@ -XXX,XX +XXX,XX @@ static void do_test_cancel(bool sync) | ||
294 | for (i = 0; i < 100; i++) { | ||
295 | data[i].n = 0; | ||
296 | data[i].ret = -EINPROGRESS; | ||
297 | - data[i].aiocb = thread_pool_submit_aio(pool, long_cb, &data[i], | ||
298 | + data[i].aiocb = thread_pool_submit_aio(long_cb, &data[i], | ||
299 | done_cb, &data[i]); | ||
300 | } | ||
301 | |||
302 | @@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv) | ||
303 | { | ||
304 | qemu_init_main_loop(&error_abort); | ||
305 | ctx = qemu_get_current_aio_context(); | ||
306 | - pool = aio_get_thread_pool(ctx); | ||
307 | |||
308 | g_test_init(&argc, &argv, NULL); | ||
309 | g_test_add_func("/thread-pool/submit", test_submit); | ||
310 | diff --git a/util/thread-pool.c b/util/thread-pool.c | ||
311 | index XXXXXXX..XXXXXXX 100644 | ||
312 | --- a/util/thread-pool.c | ||
313 | +++ b/util/thread-pool.c | ||
314 | @@ -XXX,XX +XXX,XX @@ static const AIOCBInfo thread_pool_aiocb_info = { | ||
315 | .get_aio_context = thread_pool_get_aio_context, | ||
316 | }; | ||
317 | |||
318 | -BlockAIOCB *thread_pool_submit_aio(ThreadPool *pool, | ||
319 | - ThreadPoolFunc *func, void *arg, | ||
320 | - BlockCompletionFunc *cb, void *opaque) | ||
321 | +BlockAIOCB *thread_pool_submit_aio(ThreadPoolFunc *func, void *arg, | ||
322 | + BlockCompletionFunc *cb, void *opaque) | ||
323 | { | ||
324 | ThreadPoolElement *req; | ||
325 | + AioContext *ctx = qemu_get_current_aio_context(); | ||
326 | + ThreadPool *pool = aio_get_thread_pool(ctx); | ||
327 | |||
328 | /* Assert that the thread submitting work is the same running the pool */ | ||
329 | assert(pool->ctx == qemu_get_current_aio_context()); | ||
330 | @@ -XXX,XX +XXX,XX @@ static void thread_pool_co_cb(void *opaque, int ret) | ||
331 | aio_co_wake(co->co); | ||
332 | } | ||
333 | |||
334 | -int coroutine_fn thread_pool_submit_co(ThreadPool *pool, ThreadPoolFunc *func, | ||
335 | - void *arg) | ||
336 | +int coroutine_fn thread_pool_submit_co(ThreadPoolFunc *func, void *arg) | ||
337 | { | ||
338 | ThreadPoolCo tpc = { .co = qemu_coroutine_self(), .ret = -EINPROGRESS }; | ||
339 | assert(qemu_in_coroutine()); | ||
340 | - thread_pool_submit_aio(pool, func, arg, thread_pool_co_cb, &tpc); | ||
341 | + thread_pool_submit_aio(func, arg, thread_pool_co_cb, &tpc); | ||
342 | qemu_coroutine_yield(); | ||
343 | return tpc.ret; | ||
344 | } | ||
345 | |||
346 | -void thread_pool_submit(ThreadPool *pool, ThreadPoolFunc *func, void *arg) | ||
347 | +void thread_pool_submit(ThreadPoolFunc *func, void *arg) | ||
348 | { | ||
349 | - thread_pool_submit_aio(pool, func, arg, NULL, NULL); | ||
350 | + thread_pool_submit_aio(func, arg, NULL, NULL); | ||
351 | } | ||
352 | |||
353 | void thread_pool_update_params(ThreadPool *pool, AioContext *ctx) | ||
354 | -- | 100 | -- |
355 | 2.40.0 | 101 | 2.41.0 | diff view generated by jsdifflib |
1 | From: Paolo Bonzini <pbonzini@redhat.com> | 1 | Instead of taking the writer lock internally, require callers to already |
---|---|---|---|
2 | hold it when calling bdrv_unref_child(). These callers will typically | ||
3 | already hold the graph lock once the locking work is completed, which | ||
4 | means that they can't call functions that take it internally. | ||
2 | 5 | ||
3 | Functions that can do I/O (including calling bdrv_is_allocated | 6 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
4 | and bdrv_block_status functions) are prime candidates for being | 7 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
5 | coroutine_fns. Make the change for those that are themselves called | 8 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> |
6 | only from coroutine_fns. Also annotate that they are called with the | 9 | Message-ID: <20230911094620.45040-21-kwolf@redhat.com> |
7 | graph rdlock taken, thus allowing them to call bdrv_co_*() functions | ||
8 | for I/O. | ||
9 | |||
10 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> | ||
11 | Message-Id: <20230309084456.304669-9-pbonzini@redhat.com> | ||
12 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
13 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
14 | --- | 11 | --- |
15 | block/qcow2.h | 15 ++++++++------- | 12 | include/block/block-global-state.h | 7 ++++++- |
16 | block/qcow2-bitmap.c | 2 +- | 13 | block.c | 11 +++++++---- |
17 | block/qcow2-cluster.c | 21 +++++++++++++-------- | 14 | block/blklogwrites.c | 4 ++++ |
18 | block/qcow2-refcount.c | 8 ++++---- | 15 | block/blkverify.c | 2 ++ |
19 | block/qcow2-snapshot.c | 25 +++++++++++++------------ | 16 | block/qcow2.c | 4 +++- |
20 | block/qcow2.c | 27 ++++++++++++++------------- | 17 | block/quorum.c | 6 ++++++ |
21 | 6 files changed, 53 insertions(+), 45 deletions(-) | 18 | block/replication.c | 3 +++ |
19 | block/snapshot.c | 2 ++ | ||
20 | block/vmdk.c | 11 +++++++++++ | ||
21 | tests/unit/test-bdrv-drain.c | 8 ++++++-- | ||
22 | 10 files changed, 50 insertions(+), 8 deletions(-) | ||
22 | 23 | ||
23 | diff --git a/block/qcow2.h b/block/qcow2.h | 24 | diff --git a/include/block/block-global-state.h b/include/block/block-global-state.h |
24 | index XXXXXXX..XXXXXXX 100644 | 25 | index XXXXXXX..XXXXXXX 100644 |
25 | --- a/block/qcow2.h | 26 | --- a/include/block/block-global-state.h |
26 | +++ b/block/qcow2.h | 27 | +++ b/include/block/block-global-state.h |
27 | @@ -XXX,XX +XXX,XX @@ int64_t qcow2_refcount_area(BlockDriverState *bs, uint64_t offset, | 28 | @@ -XXX,XX +XXX,XX @@ void bdrv_ref(BlockDriverState *bs); |
28 | uint64_t new_refblock_offset); | 29 | void no_coroutine_fn bdrv_unref(BlockDriverState *bs); |
29 | 30 | void coroutine_fn no_co_wrapper bdrv_co_unref(BlockDriverState *bs); | |
30 | int64_t qcow2_alloc_clusters(BlockDriverState *bs, uint64_t size); | 31 | void GRAPH_WRLOCK bdrv_schedule_unref(BlockDriverState *bs); |
31 | -int64_t qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset, | 32 | -void bdrv_unref_child(BlockDriverState *parent, BdrvChild *child); |
32 | - int64_t nb_clusters); | 33 | + |
33 | -int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size); | 34 | +void GRAPH_WRLOCK |
34 | +int64_t coroutine_fn qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset, | 35 | +bdrv_unref_child(BlockDriverState *parent, BdrvChild *child); |
35 | + int64_t nb_clusters); | 36 | + |
36 | +int64_t coroutine_fn qcow2_alloc_bytes(BlockDriverState *bs, int size); | 37 | +void coroutine_fn no_co_wrapper_bdrv_wrlock |
37 | void qcow2_free_clusters(BlockDriverState *bs, | 38 | +bdrv_co_unref_child(BlockDriverState *parent, BdrvChild *child); |
38 | int64_t offset, int64_t size, | 39 | |
39 | enum qcow2_discard_type type); | 40 | BdrvChild * GRAPH_WRLOCK |
40 | @@ -XXX,XX +XXX,XX @@ int qcow2_change_refcount_order(BlockDriverState *bs, int refcount_order, | 41 | bdrv_attach_child(BlockDriverState *parent_bs, |
41 | BlockDriverAmendStatusCB *status_cb, | 42 | diff --git a/block.c b/block.c |
42 | void *cb_opaque, Error **errp); | 43 | index XXXXXXX..XXXXXXX 100644 |
43 | int coroutine_fn GRAPH_RDLOCK qcow2_shrink_reftable(BlockDriverState *bs); | 44 | --- a/block.c |
44 | -int64_t qcow2_get_last_cluster(BlockDriverState *bs, int64_t size); | 45 | +++ b/block.c |
45 | +int64_t coroutine_fn qcow2_get_last_cluster(BlockDriverState *bs, int64_t size); | 46 | @@ -XXX,XX +XXX,XX @@ bdrv_open_driver(BlockDriverState *bs, BlockDriver *drv, const char *node_name, |
46 | int coroutine_fn qcow2_detect_metadata_preallocation(BlockDriverState *bs); | 47 | open_failed: |
47 | 48 | bs->drv = NULL; | |
48 | /* qcow2-cluster.c functions */ | 49 | if (bs->file != NULL) { |
49 | @@ -XXX,XX +XXX,XX @@ void qcow2_parse_compressed_l2_entry(BlockDriverState *bs, uint64_t l2_entry, | 50 | + bdrv_graph_wrlock(NULL); |
50 | int coroutine_fn GRAPH_RDLOCK | 51 | bdrv_unref_child(bs, bs->file); |
51 | qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m); | 52 | + bdrv_graph_wrunlock(); |
52 | 53 | assert(!bs->file); | |
53 | -void qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m); | 54 | } |
54 | +void coroutine_fn qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m); | 55 | g_free(bs->opaque); |
55 | int qcow2_cluster_discard(BlockDriverState *bs, uint64_t offset, | 56 | @@ -XXX,XX +XXX,XX @@ static void bdrv_set_inherits_from(BlockDriverState *bs, |
56 | uint64_t bytes, enum qcow2_discard_type type, | 57 | * @root that point to @root, where necessary. |
57 | bool full_discard); | 58 | * @tran is allowed to be NULL. In this case no rollback is possible |
58 | @@ -XXX,XX +XXX,XX @@ int qcow2_snapshot_load_tmp(BlockDriverState *bs, | 59 | */ |
59 | Error **errp); | 60 | -static void bdrv_unset_inherits_from(BlockDriverState *root, BdrvChild *child, |
60 | 61 | - Transaction *tran) | |
61 | void qcow2_free_snapshots(BlockDriverState *bs); | 62 | +static void GRAPH_WRLOCK |
62 | -int qcow2_read_snapshots(BlockDriverState *bs, Error **errp); | 63 | +bdrv_unset_inherits_from(BlockDriverState *root, BdrvChild *child, |
63 | +int coroutine_fn GRAPH_RDLOCK | 64 | + Transaction *tran) |
64 | +qcow2_read_snapshots(BlockDriverState *bs, Error **errp); | ||
65 | int qcow2_write_snapshots(BlockDriverState *bs); | ||
66 | |||
67 | int coroutine_fn GRAPH_RDLOCK | ||
68 | @@ -XXX,XX +XXX,XX @@ bool coroutine_fn qcow2_load_dirty_bitmaps(BlockDriverState *bs, | ||
69 | bool qcow2_get_bitmap_info_list(BlockDriverState *bs, | ||
70 | Qcow2BitmapInfoList **info_list, Error **errp); | ||
71 | int qcow2_reopen_bitmaps_rw(BlockDriverState *bs, Error **errp); | ||
72 | -int qcow2_truncate_bitmaps_check(BlockDriverState *bs, Error **errp); | ||
73 | +int coroutine_fn qcow2_truncate_bitmaps_check(BlockDriverState *bs, Error **errp); | ||
74 | bool qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs, | ||
75 | bool release_stored, Error **errp); | ||
76 | int qcow2_reopen_bitmaps_ro(BlockDriverState *bs, Error **errp); | ||
77 | diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c | ||
78 | index XXXXXXX..XXXXXXX 100644 | ||
79 | --- a/block/qcow2-bitmap.c | ||
80 | +++ b/block/qcow2-bitmap.c | ||
81 | @@ -XXX,XX +XXX,XX @@ out: | ||
82 | } | ||
83 | |||
84 | /* Checks to see if it's safe to resize bitmaps */ | ||
85 | -int qcow2_truncate_bitmaps_check(BlockDriverState *bs, Error **errp) | ||
86 | +int coroutine_fn qcow2_truncate_bitmaps_check(BlockDriverState *bs, Error **errp) | ||
87 | { | 65 | { |
88 | BDRVQcow2State *s = bs->opaque; | 66 | BdrvChild *c; |
89 | Qcow2BitmapList *bm_list; | 67 | |
90 | diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c | 68 | @@ -XXX,XX +XXX,XX @@ void bdrv_unref_child(BlockDriverState *parent, BdrvChild *child) |
91 | index XXXXXXX..XXXXXXX 100644 | 69 | return; |
92 | --- a/block/qcow2-cluster.c | 70 | } |
93 | +++ b/block/qcow2-cluster.c | 71 | |
94 | @@ -XXX,XX +XXX,XX @@ err: | 72 | - bdrv_graph_wrlock(NULL); |
95 | * Frees the allocated clusters because the request failed and they won't | 73 | bdrv_unset_inherits_from(parent, child, NULL); |
96 | * actually be linked. | 74 | bdrv_root_unref_child(child); |
97 | */ | 75 | - bdrv_graph_wrunlock(); |
98 | -void qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m) | 76 | } |
99 | +void coroutine_fn qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m) | 77 | |
78 | |||
79 | @@ -XXX,XX +XXX,XX @@ static void bdrv_close(BlockDriverState *bs) | ||
80 | bs->drv = NULL; | ||
81 | } | ||
82 | |||
83 | + bdrv_graph_wrlock(NULL); | ||
84 | QLIST_FOREACH_SAFE(child, &bs->children, next, next) { | ||
85 | bdrv_unref_child(bs, child); | ||
86 | } | ||
87 | + bdrv_graph_wrunlock(); | ||
88 | |||
89 | assert(!bs->backing); | ||
90 | assert(!bs->file); | ||
91 | diff --git a/block/blklogwrites.c b/block/blklogwrites.c | ||
92 | index XXXXXXX..XXXXXXX 100644 | ||
93 | --- a/block/blklogwrites.c | ||
94 | +++ b/block/blklogwrites.c | ||
95 | @@ -XXX,XX +XXX,XX @@ static int blk_log_writes_open(BlockDriverState *bs, QDict *options, int flags, | ||
96 | ret = 0; | ||
97 | fail_log: | ||
98 | if (ret < 0) { | ||
99 | + bdrv_graph_wrlock(NULL); | ||
100 | bdrv_unref_child(bs, s->log_file); | ||
101 | + bdrv_graph_wrunlock(); | ||
102 | s->log_file = NULL; | ||
103 | } | ||
104 | fail: | ||
105 | @@ -XXX,XX +XXX,XX @@ static void blk_log_writes_close(BlockDriverState *bs) | ||
100 | { | 106 | { |
101 | BDRVQcow2State *s = bs->opaque; | 107 | BDRVBlkLogWritesState *s = bs->opaque; |
102 | if (!has_data_file(bs) && !m->keep_old_clusters) { | 108 | |
103 | @@ -XXX,XX +XXX,XX @@ void qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m) | 109 | + bdrv_graph_wrlock(NULL); |
104 | * | 110 | bdrv_unref_child(bs, s->log_file); |
105 | * Returns 0 on success, -errno on failure. | 111 | s->log_file = NULL; |
106 | */ | 112 | + bdrv_graph_wrunlock(); |
107 | -static int calculate_l2_meta(BlockDriverState *bs, uint64_t host_cluster_offset, | 113 | } |
108 | - uint64_t guest_offset, unsigned bytes, | 114 | |
109 | - uint64_t *l2_slice, QCowL2Meta **m, bool keep_old) | 115 | static int64_t coroutine_fn GRAPH_RDLOCK |
110 | +static int coroutine_fn calculate_l2_meta(BlockDriverState *bs, | 116 | diff --git a/block/blkverify.c b/block/blkverify.c |
111 | + uint64_t host_cluster_offset, | 117 | index XXXXXXX..XXXXXXX 100644 |
112 | + uint64_t guest_offset, unsigned bytes, | 118 | --- a/block/blkverify.c |
113 | + uint64_t *l2_slice, QCowL2Meta **m, | 119 | +++ b/block/blkverify.c |
114 | + bool keep_old) | 120 | @@ -XXX,XX +XXX,XX @@ static void blkverify_close(BlockDriverState *bs) |
115 | { | 121 | { |
116 | BDRVQcow2State *s = bs->opaque; | 122 | BDRVBlkverifyState *s = bs->opaque; |
117 | int sc_index, l2_index = offset_to_l2_slice_index(s, guest_offset); | 123 | |
118 | @@ -XXX,XX +XXX,XX @@ out: | 124 | + bdrv_graph_wrlock(NULL); |
119 | * function has been waiting for another request and the allocation must be | 125 | bdrv_unref_child(bs, s->test_file); |
120 | * restarted, but the whole request should not be failed. | 126 | s->test_file = NULL; |
121 | */ | 127 | + bdrv_graph_wrunlock(); |
122 | -static int do_alloc_cluster_offset(BlockDriverState *bs, uint64_t guest_offset, | 128 | } |
123 | - uint64_t *host_offset, uint64_t *nb_clusters) | 129 | |
124 | +static int coroutine_fn do_alloc_cluster_offset(BlockDriverState *bs, | 130 | static int64_t coroutine_fn GRAPH_RDLOCK |
125 | + uint64_t guest_offset, | ||
126 | + uint64_t *host_offset, | ||
127 | + uint64_t *nb_clusters) | ||
128 | { | ||
129 | BDRVQcow2State *s = bs->opaque; | ||
130 | |||
131 | @@ -XXX,XX +XXX,XX @@ static int zero_in_l2_slice(BlockDriverState *bs, uint64_t offset, | ||
132 | return nb_clusters; | ||
133 | } | ||
134 | |||
135 | -static int zero_l2_subclusters(BlockDriverState *bs, uint64_t offset, | ||
136 | - unsigned nb_subclusters) | ||
137 | +static int coroutine_fn | ||
138 | +zero_l2_subclusters(BlockDriverState *bs, uint64_t offset, | ||
139 | + unsigned nb_subclusters) | ||
140 | { | ||
141 | BDRVQcow2State *s = bs->opaque; | ||
142 | uint64_t *l2_slice; | ||
143 | diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c | ||
144 | index XXXXXXX..XXXXXXX 100644 | ||
145 | --- a/block/qcow2-refcount.c | ||
146 | +++ b/block/qcow2-refcount.c | ||
147 | @@ -XXX,XX +XXX,XX @@ int64_t qcow2_alloc_clusters(BlockDriverState *bs, uint64_t size) | ||
148 | return offset; | ||
149 | } | ||
150 | |||
151 | -int64_t qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset, | ||
152 | - int64_t nb_clusters) | ||
153 | +int64_t coroutine_fn qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset, | ||
154 | + int64_t nb_clusters) | ||
155 | { | ||
156 | BDRVQcow2State *s = bs->opaque; | ||
157 | uint64_t cluster_index, refcount; | ||
158 | @@ -XXX,XX +XXX,XX @@ int64_t qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset, | ||
159 | |||
160 | /* only used to allocate compressed sectors. We try to allocate | ||
161 | contiguous sectors. size must be <= cluster_size */ | ||
162 | -int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size) | ||
163 | +int64_t coroutine_fn qcow2_alloc_bytes(BlockDriverState *bs, int size) | ||
164 | { | ||
165 | BDRVQcow2State *s = bs->opaque; | ||
166 | int64_t offset; | ||
167 | @@ -XXX,XX +XXX,XX @@ out: | ||
168 | return ret; | ||
169 | } | ||
170 | |||
171 | -int64_t qcow2_get_last_cluster(BlockDriverState *bs, int64_t size) | ||
172 | +int64_t coroutine_fn qcow2_get_last_cluster(BlockDriverState *bs, int64_t size) | ||
173 | { | ||
174 | BDRVQcow2State *s = bs->opaque; | ||
175 | int64_t i; | ||
176 | diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c | ||
177 | index XXXXXXX..XXXXXXX 100644 | ||
178 | --- a/block/qcow2-snapshot.c | ||
179 | +++ b/block/qcow2-snapshot.c | ||
180 | @@ -XXX,XX +XXX,XX @@ void qcow2_free_snapshots(BlockDriverState *bs) | ||
181 | * qcow2_check_refcounts() does not do anything with snapshots' | ||
182 | * extra data.) | ||
183 | */ | ||
184 | -static int qcow2_do_read_snapshots(BlockDriverState *bs, bool repair, | ||
185 | - int *nb_clusters_reduced, | ||
186 | - int *extra_data_dropped, | ||
187 | - Error **errp) | ||
188 | +static coroutine_fn GRAPH_RDLOCK | ||
189 | +int qcow2_do_read_snapshots(BlockDriverState *bs, bool repair, | ||
190 | + int *nb_clusters_reduced, | ||
191 | + int *extra_data_dropped, | ||
192 | + Error **errp) | ||
193 | { | ||
194 | BDRVQcow2State *s = bs->opaque; | ||
195 | QCowSnapshotHeader h; | ||
196 | @@ -XXX,XX +XXX,XX @@ static int qcow2_do_read_snapshots(BlockDriverState *bs, bool repair, | ||
197 | |||
198 | /* Read statically sized part of the snapshot header */ | ||
199 | offset = ROUND_UP(offset, 8); | ||
200 | - ret = bdrv_pread(bs->file, offset, sizeof(h), &h, 0); | ||
201 | + ret = bdrv_co_pread(bs->file, offset, sizeof(h), &h, 0); | ||
202 | if (ret < 0) { | ||
203 | error_setg_errno(errp, -ret, "Failed to read snapshot table"); | ||
204 | goto fail; | ||
205 | @@ -XXX,XX +XXX,XX @@ static int qcow2_do_read_snapshots(BlockDriverState *bs, bool repair, | ||
206 | } | ||
207 | |||
208 | /* Read known extra data */ | ||
209 | - ret = bdrv_pread(bs->file, offset, | ||
210 | - MIN(sizeof(extra), sn->extra_data_size), &extra, 0); | ||
211 | + ret = bdrv_co_pread(bs->file, offset, | ||
212 | + MIN(sizeof(extra), sn->extra_data_size), &extra, 0); | ||
213 | if (ret < 0) { | ||
214 | error_setg_errno(errp, -ret, "Failed to read snapshot table"); | ||
215 | goto fail; | ||
216 | @@ -XXX,XX +XXX,XX @@ static int qcow2_do_read_snapshots(BlockDriverState *bs, bool repair, | ||
217 | /* Store unknown extra data */ | ||
218 | unknown_extra_data_size = sn->extra_data_size - sizeof(extra); | ||
219 | sn->unknown_extra_data = g_malloc(unknown_extra_data_size); | ||
220 | - ret = bdrv_pread(bs->file, offset, unknown_extra_data_size, | ||
221 | - sn->unknown_extra_data, 0); | ||
222 | + ret = bdrv_co_pread(bs->file, offset, unknown_extra_data_size, | ||
223 | + sn->unknown_extra_data, 0); | ||
224 | if (ret < 0) { | ||
225 | error_setg_errno(errp, -ret, | ||
226 | "Failed to read snapshot table"); | ||
227 | @@ -XXX,XX +XXX,XX @@ static int qcow2_do_read_snapshots(BlockDriverState *bs, bool repair, | ||
228 | |||
229 | /* Read snapshot ID */ | ||
230 | sn->id_str = g_malloc(id_str_size + 1); | ||
231 | - ret = bdrv_pread(bs->file, offset, id_str_size, sn->id_str, 0); | ||
232 | + ret = bdrv_co_pread(bs->file, offset, id_str_size, sn->id_str, 0); | ||
233 | if (ret < 0) { | ||
234 | error_setg_errno(errp, -ret, "Failed to read snapshot table"); | ||
235 | goto fail; | ||
236 | @@ -XXX,XX +XXX,XX @@ static int qcow2_do_read_snapshots(BlockDriverState *bs, bool repair, | ||
237 | |||
238 | /* Read snapshot name */ | ||
239 | sn->name = g_malloc(name_size + 1); | ||
240 | - ret = bdrv_pread(bs->file, offset, name_size, sn->name, 0); | ||
241 | + ret = bdrv_co_pread(bs->file, offset, name_size, sn->name, 0); | ||
242 | if (ret < 0) { | ||
243 | error_setg_errno(errp, -ret, "Failed to read snapshot table"); | ||
244 | goto fail; | ||
245 | @@ -XXX,XX +XXX,XX @@ fail: | ||
246 | return ret; | ||
247 | } | ||
248 | |||
249 | -int qcow2_read_snapshots(BlockDriverState *bs, Error **errp) | ||
250 | +int coroutine_fn qcow2_read_snapshots(BlockDriverState *bs, Error **errp) | ||
251 | { | ||
252 | return qcow2_do_read_snapshots(bs, false, NULL, NULL, errp); | ||
253 | } | ||
254 | diff --git a/block/qcow2.c b/block/qcow2.c | 131 | diff --git a/block/qcow2.c b/block/qcow2.c |
255 | index XXXXXXX..XXXXXXX 100644 | 132 | index XXXXXXX..XXXXXXX 100644 |
256 | --- a/block/qcow2.c | 133 | --- a/block/qcow2.c |
257 | +++ b/block/qcow2.c | 134 | +++ b/block/qcow2.c |
258 | @@ -XXX,XX +XXX,XX @@ qcow2_extract_crypto_opts(QemuOpts *opts, const char *fmt, Error **errp) | 135 | @@ -XXX,XX +XXX,XX @@ qcow2_do_open(BlockDriverState *bs, QDict *options, int flags, |
259 | * unknown magic is skipped (future extension this version knows nothing about) | 136 | g_free(s->image_data_file); |
260 | * return 0 upon success, non-0 otherwise | 137 | if (open_data_file && has_data_file(bs)) { |
261 | */ | 138 | bdrv_graph_co_rdunlock(); |
262 | -static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset, | 139 | - bdrv_unref_child(bs, s->data_file); |
263 | - uint64_t end_offset, void **p_feature_table, | 140 | + bdrv_co_unref_child(bs, s->data_file); |
264 | - int flags, bool *need_update_header, | 141 | bdrv_graph_co_rdlock(); |
265 | - Error **errp) | 142 | s->data_file = NULL; |
266 | +static int coroutine_fn GRAPH_RDLOCK | 143 | } |
267 | +qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset, | 144 | @@ -XXX,XX +XXX,XX @@ static void qcow2_do_close(BlockDriverState *bs, bool close_data_file) |
268 | + uint64_t end_offset, void **p_feature_table, | 145 | g_free(s->image_backing_format); |
269 | + int flags, bool *need_update_header, Error **errp) | 146 | |
147 | if (close_data_file && has_data_file(bs)) { | ||
148 | + bdrv_graph_wrlock(NULL); | ||
149 | bdrv_unref_child(bs, s->data_file); | ||
150 | + bdrv_graph_wrunlock(); | ||
151 | s->data_file = NULL; | ||
152 | } | ||
153 | |||
154 | diff --git a/block/quorum.c b/block/quorum.c | ||
155 | index XXXXXXX..XXXXXXX 100644 | ||
156 | --- a/block/quorum.c | ||
157 | +++ b/block/quorum.c | ||
158 | @@ -XXX,XX +XXX,XX @@ static int quorum_open(BlockDriverState *bs, QDict *options, int flags, | ||
159 | |||
160 | close_exit: | ||
161 | /* cleanup on error */ | ||
162 | + bdrv_graph_wrlock(NULL); | ||
163 | for (i = 0; i < s->num_children; i++) { | ||
164 | if (!opened[i]) { | ||
165 | continue; | ||
166 | } | ||
167 | bdrv_unref_child(bs, s->children[i]); | ||
168 | } | ||
169 | + bdrv_graph_wrunlock(); | ||
170 | g_free(s->children); | ||
171 | g_free(opened); | ||
172 | exit: | ||
173 | @@ -XXX,XX +XXX,XX @@ static void quorum_close(BlockDriverState *bs) | ||
174 | BDRVQuorumState *s = bs->opaque; | ||
175 | int i; | ||
176 | |||
177 | + bdrv_graph_wrlock(NULL); | ||
178 | for (i = 0; i < s->num_children; i++) { | ||
179 | bdrv_unref_child(bs, s->children[i]); | ||
180 | } | ||
181 | + bdrv_graph_wrunlock(); | ||
182 | |||
183 | g_free(s->children); | ||
184 | } | ||
185 | @@ -XXX,XX +XXX,XX @@ static void quorum_del_child(BlockDriverState *bs, BdrvChild *child, | ||
186 | memmove(&s->children[i], &s->children[i + 1], | ||
187 | (s->num_children - i - 1) * sizeof(BdrvChild *)); | ||
188 | s->children = g_renew(BdrvChild *, s->children, --s->num_children); | ||
189 | + bdrv_graph_wrlock(NULL); | ||
190 | bdrv_unref_child(bs, child); | ||
191 | + bdrv_graph_wrunlock(); | ||
192 | |||
193 | quorum_refresh_flags(bs); | ||
194 | bdrv_drained_end(bs); | ||
195 | diff --git a/block/replication.c b/block/replication.c | ||
196 | index XXXXXXX..XXXXXXX 100644 | ||
197 | --- a/block/replication.c | ||
198 | +++ b/block/replication.c | ||
199 | @@ -XXX,XX +XXX,XX @@ static void replication_done(void *opaque, int ret) | ||
200 | if (ret == 0) { | ||
201 | s->stage = BLOCK_REPLICATION_DONE; | ||
202 | |||
203 | + bdrv_graph_wrlock(NULL); | ||
204 | bdrv_unref_child(bs, s->secondary_disk); | ||
205 | s->secondary_disk = NULL; | ||
206 | bdrv_unref_child(bs, s->hidden_disk); | ||
207 | s->hidden_disk = NULL; | ||
208 | + bdrv_graph_wrunlock(); | ||
209 | + | ||
210 | s->error = 0; | ||
211 | } else { | ||
212 | s->stage = BLOCK_REPLICATION_FAILOVER_FAILED; | ||
213 | diff --git a/block/snapshot.c b/block/snapshot.c | ||
214 | index XXXXXXX..XXXXXXX 100644 | ||
215 | --- a/block/snapshot.c | ||
216 | +++ b/block/snapshot.c | ||
217 | @@ -XXX,XX +XXX,XX @@ int bdrv_snapshot_goto(BlockDriverState *bs, | ||
218 | } | ||
219 | |||
220 | /* .bdrv_open() will re-attach it */ | ||
221 | + bdrv_graph_wrlock(NULL); | ||
222 | bdrv_unref_child(bs, fallback); | ||
223 | + bdrv_graph_wrunlock(); | ||
224 | |||
225 | ret = bdrv_snapshot_goto(fallback_bs, snapshot_id, errp); | ||
226 | open_ret = drv->bdrv_open(bs, options, bs->open_flags, &local_err); | ||
227 | diff --git a/block/vmdk.c b/block/vmdk.c | ||
228 | index XXXXXXX..XXXXXXX 100644 | ||
229 | --- a/block/vmdk.c | ||
230 | +++ b/block/vmdk.c | ||
231 | @@ -XXX,XX +XXX,XX @@ static void vmdk_free_extents(BlockDriverState *bs) | ||
232 | BDRVVmdkState *s = bs->opaque; | ||
233 | VmdkExtent *e; | ||
234 | |||
235 | + bdrv_graph_wrlock(NULL); | ||
236 | for (i = 0; i < s->num_extents; i++) { | ||
237 | e = &s->extents[i]; | ||
238 | g_free(e->l1_table); | ||
239 | @@ -XXX,XX +XXX,XX @@ static void vmdk_free_extents(BlockDriverState *bs) | ||
240 | bdrv_unref_child(bs, e->file); | ||
241 | } | ||
242 | } | ||
243 | + bdrv_graph_wrunlock(); | ||
244 | + | ||
245 | g_free(s->extents); | ||
246 | } | ||
247 | |||
248 | @@ -XXX,XX +XXX,XX @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, | ||
249 | ret = vmdk_add_extent(bs, extent_file, true, sectors, | ||
250 | 0, 0, 0, 0, 0, &extent, errp); | ||
251 | if (ret < 0) { | ||
252 | + bdrv_graph_wrlock(NULL); | ||
253 | bdrv_unref_child(bs, extent_file); | ||
254 | + bdrv_graph_wrunlock(); | ||
255 | goto out; | ||
256 | } | ||
257 | extent->flat_start_offset = flat_offset << 9; | ||
258 | @@ -XXX,XX +XXX,XX @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, | ||
259 | } | ||
260 | g_free(buf); | ||
261 | if (ret) { | ||
262 | + bdrv_graph_wrlock(NULL); | ||
263 | bdrv_unref_child(bs, extent_file); | ||
264 | + bdrv_graph_wrunlock(); | ||
265 | goto out; | ||
266 | } | ||
267 | extent = &s->extents[s->num_extents - 1]; | ||
268 | } else if (!strcmp(type, "SESPARSE")) { | ||
269 | ret = vmdk_open_se_sparse(bs, extent_file, bs->open_flags, errp); | ||
270 | if (ret) { | ||
271 | + bdrv_graph_wrlock(NULL); | ||
272 | bdrv_unref_child(bs, extent_file); | ||
273 | + bdrv_graph_wrunlock(); | ||
274 | goto out; | ||
275 | } | ||
276 | extent = &s->extents[s->num_extents - 1]; | ||
277 | } else { | ||
278 | error_setg(errp, "Unsupported extent type '%s'", type); | ||
279 | + bdrv_graph_wrlock(NULL); | ||
280 | bdrv_unref_child(bs, extent_file); | ||
281 | + bdrv_graph_wrunlock(); | ||
282 | ret = -ENOTSUP; | ||
283 | goto out; | ||
284 | } | ||
285 | diff --git a/tests/unit/test-bdrv-drain.c b/tests/unit/test-bdrv-drain.c | ||
286 | index XXXXXXX..XXXXXXX 100644 | ||
287 | --- a/tests/unit/test-bdrv-drain.c | ||
288 | +++ b/tests/unit/test-bdrv-drain.c | ||
289 | @@ -XXX,XX +XXX,XX @@ typedef struct BDRVTestTopState { | ||
290 | static void bdrv_test_top_close(BlockDriverState *bs) | ||
270 | { | 291 | { |
271 | BDRVQcow2State *s = bs->opaque; | 292 | BdrvChild *c, *next_c; |
272 | QCowExtension ext; | 293 | + |
273 | @@ -XXX,XX +XXX,XX @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset, | 294 | + bdrv_graph_wrlock(NULL); |
274 | printf("attempting to read extended header in offset %lu\n", offset); | 295 | QLIST_FOREACH_SAFE(c, &bs->children, next, next_c) { |
275 | #endif | 296 | bdrv_unref_child(bs, c); |
276 | 297 | } | |
277 | - ret = bdrv_pread(bs->file, offset, sizeof(ext), &ext, 0); | 298 | + bdrv_graph_wrunlock(); |
278 | + ret = bdrv_co_pread(bs->file, offset, sizeof(ext), &ext, 0); | 299 | } |
279 | if (ret < 0) { | 300 | |
280 | error_setg_errno(errp, -ret, "qcow2_read_extension: ERROR: " | 301 | static int coroutine_fn GRAPH_RDLOCK |
281 | "pread fail from offset %" PRIu64, offset); | 302 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn test_co_delete_by_drain(void *opaque) |
282 | @@ -XXX,XX +XXX,XX @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset, | 303 | } else { |
283 | sizeof(bs->backing_format)); | 304 | BdrvChild *c, *next_c; |
284 | return 2; | 305 | QLIST_FOREACH_SAFE(c, &bs->children, next, next_c) { |
285 | } | 306 | - bdrv_unref_child(bs, c); |
286 | - ret = bdrv_pread(bs->file, offset, ext.len, bs->backing_format, 0); | 307 | + bdrv_co_unref_child(bs, c); |
287 | + ret = bdrv_co_pread(bs->file, offset, ext.len, bs->backing_format, 0); | 308 | } |
288 | if (ret < 0) { | 309 | } |
289 | error_setg_errno(errp, -ret, "ERROR: ext_backing_format: " | 310 | |
290 | "Could not read format name"); | 311 | @@ -XXX,XX +XXX,XX @@ static void detach_indirect_bh(void *opaque) |
291 | @@ -XXX,XX +XXX,XX @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset, | 312 | struct detach_by_parent_data *data = opaque; |
292 | case QCOW2_EXT_MAGIC_FEATURE_TABLE: | 313 | |
293 | if (p_feature_table != NULL) { | 314 | bdrv_dec_in_flight(data->child_b->bs); |
294 | void *feature_table = g_malloc0(ext.len + 2 * sizeof(Qcow2Feature)); | 315 | + |
295 | - ret = bdrv_pread(bs->file, offset, ext.len, feature_table, 0); | 316 | + bdrv_graph_wrlock(NULL); |
296 | + ret = bdrv_co_pread(bs->file, offset, ext.len, feature_table, 0); | 317 | bdrv_unref_child(data->parent_b, data->child_b); |
297 | if (ret < 0) { | 318 | |
298 | error_setg_errno(errp, -ret, "ERROR: ext_feature_table: " | 319 | bdrv_ref(data->c); |
299 | "Could not read table"); | 320 | - bdrv_graph_wrlock(NULL); |
300 | @@ -XXX,XX +XXX,XX @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset, | 321 | data->child_c = bdrv_attach_child(data->parent_b, data->c, "PB-C", |
301 | return -EINVAL; | 322 | &child_of_bds, BDRV_CHILD_DATA, |
302 | } | 323 | &error_abort); |
303 | |||
304 | - ret = bdrv_pread(bs->file, offset, ext.len, &s->crypto_header, 0); | ||
305 | + ret = bdrv_co_pread(bs->file, offset, ext.len, &s->crypto_header, 0); | ||
306 | if (ret < 0) { | ||
307 | error_setg_errno(errp, -ret, | ||
308 | "Unable to read CRYPTO header extension"); | ||
309 | @@ -XXX,XX +XXX,XX @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset, | ||
310 | break; | ||
311 | } | ||
312 | |||
313 | - ret = bdrv_pread(bs->file, offset, ext.len, &bitmaps_ext, 0); | ||
314 | + ret = bdrv_co_pread(bs->file, offset, ext.len, &bitmaps_ext, 0); | ||
315 | if (ret < 0) { | ||
316 | error_setg_errno(errp, -ret, "bitmaps_ext: " | ||
317 | "Could not read ext header"); | ||
318 | @@ -XXX,XX +XXX,XX @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset, | ||
319 | case QCOW2_EXT_MAGIC_DATA_FILE: | ||
320 | { | ||
321 | s->image_data_file = g_malloc0(ext.len + 1); | ||
322 | - ret = bdrv_pread(bs->file, offset, ext.len, s->image_data_file, 0); | ||
323 | + ret = bdrv_co_pread(bs->file, offset, ext.len, s->image_data_file, 0); | ||
324 | if (ret < 0) { | ||
325 | error_setg_errno(errp, -ret, | ||
326 | "ERROR: Could not read data file name"); | ||
327 | @@ -XXX,XX +XXX,XX @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset, | ||
328 | uext->len = ext.len; | ||
329 | QLIST_INSERT_HEAD(&s->unknown_header_ext, uext, next); | ||
330 | |||
331 | - ret = bdrv_pread(bs->file, offset, uext->len, uext->data, 0); | ||
332 | + ret = bdrv_co_pread(bs->file, offset, uext->len, uext->data, 0); | ||
333 | if (ret < 0) { | ||
334 | error_setg_errno(errp, -ret, "ERROR: unknown extension: " | ||
335 | "Could not read data"); | ||
336 | @@ -XXX,XX +XXX,XX @@ static void qcow2_update_options_abort(BlockDriverState *bs, | ||
337 | qapi_free_QCryptoBlockOpenOptions(r->crypto_opts); | ||
338 | } | ||
339 | |||
340 | -static int qcow2_update_options(BlockDriverState *bs, QDict *options, | ||
341 | - int flags, Error **errp) | ||
342 | +static int coroutine_fn | ||
343 | +qcow2_update_options(BlockDriverState *bs, QDict *options, int flags, | ||
344 | + Error **errp) | ||
345 | { | ||
346 | Qcow2ReopenState r = {}; | ||
347 | int ret; | ||
348 | -- | 324 | -- |
349 | 2.40.0 | 325 | 2.41.0 | diff view generated by jsdifflib |
1 | From: Wilfred Mallawa <wilfred.mallawa@wdc.com> | 1 | The functions read the parents list in the generic block layer, so we |
---|---|---|---|
2 | need to hold the graph lock already there. The BlockDriver | ||
3 | implementations actually modify the graph, so it has to be a writer | ||
4 | lock. | ||
2 | 5 | ||
3 | Fixup a few minor typos | 6 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
4 | 7 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | |
5 | Signed-off-by: Wilfred Mallawa <wilfred.mallawa@wdc.com> | 8 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> |
6 | Message-Id: <20230313003744.55476-1-wilfred.mallawa@opensource.wdc.com> | 9 | Message-ID: <20230911094620.45040-22-kwolf@redhat.com> |
7 | Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> | ||
8 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
9 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
10 | --- | 11 | --- |
11 | include/block/aio-wait.h | 2 +- | 12 | include/block/block-global-state.h | 8 +++++--- |
12 | include/block/block_int-common.h | 2 +- | 13 | include/block/block_int-common.h | 9 +++++---- |
13 | 2 files changed, 2 insertions(+), 2 deletions(-) | 14 | block/quorum.c | 23 ++++++----------------- |
15 | blockdev.c | 17 +++++++++++------ | ||
16 | 4 files changed, 27 insertions(+), 30 deletions(-) | ||
14 | 17 | ||
15 | diff --git a/include/block/aio-wait.h b/include/block/aio-wait.h | 18 | diff --git a/include/block/block-global-state.h b/include/block/block-global-state.h |
16 | index XXXXXXX..XXXXXXX 100644 | 19 | index XXXXXXX..XXXXXXX 100644 |
17 | --- a/include/block/aio-wait.h | 20 | --- a/include/block/block-global-state.h |
18 | +++ b/include/block/aio-wait.h | 21 | +++ b/include/block/block-global-state.h |
19 | @@ -XXX,XX +XXX,XX @@ extern AioWait global_aio_wait; | 22 | @@ -XXX,XX +XXX,XX @@ int bdrv_try_change_aio_context(BlockDriverState *bs, AioContext *ctx, |
20 | * @ctx: the aio context, or NULL if multiple aio contexts (for which the | 23 | int bdrv_probe_blocksizes(BlockDriverState *bs, BlockSizes *bsz); |
21 | * caller does not hold a lock) are involved in the polling condition. | 24 | int bdrv_probe_geometry(BlockDriverState *bs, HDGeometry *geo); |
22 | * @cond: wait while this conditional expression is true | 25 | |
23 | - * @unlock: whether to unlock and then lock again @ctx. This apples | 26 | -void bdrv_add_child(BlockDriverState *parent, BlockDriverState *child, |
24 | + * @unlock: whether to unlock and then lock again @ctx. This applies | 27 | - Error **errp); |
25 | * only when waiting for another AioContext from the main loop. | 28 | -void bdrv_del_child(BlockDriverState *parent, BdrvChild *child, Error **errp); |
26 | * Otherwise it's ignored. | 29 | +void GRAPH_WRLOCK |
30 | +bdrv_add_child(BlockDriverState *parent, BlockDriverState *child, Error **errp); | ||
31 | + | ||
32 | +void GRAPH_WRLOCK | ||
33 | +bdrv_del_child(BlockDriverState *parent, BdrvChild *child, Error **errp); | ||
34 | |||
35 | /** | ||
27 | * | 36 | * |
28 | diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h | 37 | diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h |
29 | index XXXXXXX..XXXXXXX 100644 | 38 | index XXXXXXX..XXXXXXX 100644 |
30 | --- a/include/block/block_int-common.h | 39 | --- a/include/block/block_int-common.h |
31 | +++ b/include/block/block_int-common.h | 40 | +++ b/include/block/block_int-common.h |
32 | @@ -XXX,XX +XXX,XX @@ extern QemuOptsList bdrv_create_opts_simple; | 41 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { |
33 | /* | 42 | */ |
34 | * Common functions that are neither I/O nor Global State. | 43 | int (*bdrv_probe_geometry)(BlockDriverState *bs, HDGeometry *geo); |
35 | * | 44 | |
36 | - * See include/block/block-commmon.h for more information about | 45 | - void (*bdrv_add_child)(BlockDriverState *parent, BlockDriverState *child, |
37 | + * See include/block/block-common.h for more information about | 46 | - Error **errp); |
38 | * the Common API. | 47 | - void (*bdrv_del_child)(BlockDriverState *parent, BdrvChild *child, |
39 | */ | 48 | - Error **errp); |
40 | 49 | + void GRAPH_WRLOCK_PTR (*bdrv_add_child)( | |
50 | + BlockDriverState *parent, BlockDriverState *child, Error **errp); | ||
51 | + | ||
52 | + void GRAPH_WRLOCK_PTR (*bdrv_del_child)( | ||
53 | + BlockDriverState *parent, BdrvChild *child, Error **errp); | ||
54 | |||
55 | /** | ||
56 | * Informs the block driver that a permission change is intended. The | ||
57 | diff --git a/block/quorum.c b/block/quorum.c | ||
58 | index XXXXXXX..XXXXXXX 100644 | ||
59 | --- a/block/quorum.c | ||
60 | +++ b/block/quorum.c | ||
61 | @@ -XXX,XX +XXX,XX @@ static void quorum_close(BlockDriverState *bs) | ||
62 | g_free(s->children); | ||
63 | } | ||
64 | |||
65 | -static void quorum_add_child(BlockDriverState *bs, BlockDriverState *child_bs, | ||
66 | - Error **errp) | ||
67 | +static void GRAPH_WRLOCK | ||
68 | +quorum_add_child(BlockDriverState *bs, BlockDriverState *child_bs, Error **errp) | ||
69 | { | ||
70 | BDRVQuorumState *s = bs->opaque; | ||
71 | BdrvChild *child; | ||
72 | @@ -XXX,XX +XXX,XX @@ static void quorum_add_child(BlockDriverState *bs, BlockDriverState *child_bs, | ||
73 | } | ||
74 | s->next_child_index++; | ||
75 | |||
76 | - bdrv_drained_begin(bs); | ||
77 | - | ||
78 | /* We can safely add the child now */ | ||
79 | bdrv_ref(child_bs); | ||
80 | |||
81 | - bdrv_graph_wrlock(child_bs); | ||
82 | child = bdrv_attach_child(bs, child_bs, indexstr, &child_of_bds, | ||
83 | BDRV_CHILD_DATA, errp); | ||
84 | - bdrv_graph_wrunlock(); | ||
85 | if (child == NULL) { | ||
86 | s->next_child_index--; | ||
87 | - goto out; | ||
88 | + return; | ||
89 | } | ||
90 | s->children = g_renew(BdrvChild *, s->children, s->num_children + 1); | ||
91 | s->children[s->num_children++] = child; | ||
92 | quorum_refresh_flags(bs); | ||
93 | - | ||
94 | -out: | ||
95 | - bdrv_drained_end(bs); | ||
96 | } | ||
97 | |||
98 | -static void quorum_del_child(BlockDriverState *bs, BdrvChild *child, | ||
99 | - Error **errp) | ||
100 | +static void GRAPH_WRLOCK | ||
101 | +quorum_del_child(BlockDriverState *bs, BdrvChild *child, Error **errp) | ||
102 | { | ||
103 | BDRVQuorumState *s = bs->opaque; | ||
104 | char indexstr[INDEXSTR_LEN]; | ||
105 | @@ -XXX,XX +XXX,XX @@ static void quorum_del_child(BlockDriverState *bs, BdrvChild *child, | ||
106 | s->next_child_index--; | ||
107 | } | ||
108 | |||
109 | - bdrv_drained_begin(bs); | ||
110 | - | ||
111 | /* We can safely remove this child now */ | ||
112 | memmove(&s->children[i], &s->children[i + 1], | ||
113 | (s->num_children - i - 1) * sizeof(BdrvChild *)); | ||
114 | s->children = g_renew(BdrvChild *, s->children, --s->num_children); | ||
115 | - bdrv_graph_wrlock(NULL); | ||
116 | + | ||
117 | bdrv_unref_child(bs, child); | ||
118 | - bdrv_graph_wrunlock(); | ||
119 | |||
120 | quorum_refresh_flags(bs); | ||
121 | - bdrv_drained_end(bs); | ||
122 | } | ||
123 | |||
124 | static void quorum_gather_child_options(BlockDriverState *bs, QDict *target, | ||
125 | diff --git a/blockdev.c b/blockdev.c | ||
126 | index XXXXXXX..XXXXXXX 100644 | ||
127 | --- a/blockdev.c | ||
128 | +++ b/blockdev.c | ||
129 | @@ -XXX,XX +XXX,XX @@ out: | ||
130 | aio_context_release(aio_context); | ||
131 | } | ||
132 | |||
133 | -static BdrvChild *bdrv_find_child(BlockDriverState *parent_bs, | ||
134 | - const char *child_name) | ||
135 | +static BdrvChild * GRAPH_RDLOCK | ||
136 | +bdrv_find_child(BlockDriverState *parent_bs, const char *child_name) | ||
137 | { | ||
138 | BdrvChild *child; | ||
139 | |||
140 | @@ -XXX,XX +XXX,XX @@ void qmp_x_blockdev_change(const char *parent, const char *child, | ||
141 | BlockDriverState *parent_bs, *new_bs = NULL; | ||
142 | BdrvChild *p_child; | ||
143 | |||
144 | + bdrv_graph_wrlock(NULL); | ||
145 | + | ||
146 | parent_bs = bdrv_lookup_bs(parent, parent, errp); | ||
147 | if (!parent_bs) { | ||
148 | - return; | ||
149 | + goto out; | ||
150 | } | ||
151 | |||
152 | if (!child == !node) { | ||
153 | @@ -XXX,XX +XXX,XX @@ void qmp_x_blockdev_change(const char *parent, const char *child, | ||
154 | } else { | ||
155 | error_setg(errp, "Either child or node must be specified"); | ||
156 | } | ||
157 | - return; | ||
158 | + goto out; | ||
159 | } | ||
160 | |||
161 | if (child) { | ||
162 | @@ -XXX,XX +XXX,XX @@ void qmp_x_blockdev_change(const char *parent, const char *child, | ||
163 | if (!p_child) { | ||
164 | error_setg(errp, "Node '%s' does not have child '%s'", | ||
165 | parent, child); | ||
166 | - return; | ||
167 | + goto out; | ||
168 | } | ||
169 | bdrv_del_child(parent_bs, p_child, errp); | ||
170 | } | ||
171 | @@ -XXX,XX +XXX,XX @@ void qmp_x_blockdev_change(const char *parent, const char *child, | ||
172 | new_bs = bdrv_find_node(node); | ||
173 | if (!new_bs) { | ||
174 | error_setg(errp, "Node '%s' not found", node); | ||
175 | - return; | ||
176 | + goto out; | ||
177 | } | ||
178 | bdrv_add_child(parent_bs, new_bs, errp); | ||
179 | } | ||
180 | + | ||
181 | +out: | ||
182 | + bdrv_graph_wrunlock(); | ||
183 | } | ||
184 | |||
185 | BlockJobInfoList *qmp_query_block_jobs(Error **errp) | ||
41 | -- | 186 | -- |
42 | 2.40.0 | 187 | 2.41.0 |
43 | |||
44 | diff view generated by jsdifflib |
1 | From: Paolo Bonzini <pbonzini@redhat.com> | 1 | From: Andrey Drobyshev via <qemu-block@nongnu.org> |
---|---|---|---|
2 | 2 | ||
3 | Functions that can do I/O are prime candidates for being coroutine_fns. Make the | 3 | Functions qcow2_get_host_offset(), get_cluster_offset(), |
4 | change for the one that is itself called only from coroutine_fns. Unfortunately | 4 | vmdk_co_block_status() explicitly report compressed cluster types when data |
5 | vmdk does not use a coroutine_fn for the bulk of the open (like qcow2 does) so | 5 | is compressed. However, this information is never passed further. Let's |
6 | vmdk_read_cid cannot have the same treatment. | 6 | make use of it by adding new BDRV_BLOCK_COMPRESSED flag for |
7 | bdrv_block_status(), so that caller may know that the data range is | ||
8 | compressed. In particular, we're going to use this flag to tweak | ||
9 | "qemu-img map" output. | ||
7 | 10 | ||
8 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> | 11 | This new flag is only being utilized by qcow, qcow2 and vmdk formats, as only |
9 | Message-Id: <20230309084456.304669-10-pbonzini@redhat.com> | 12 | those support compression. |
13 | |||
14 | Reviewed-by: Denis V. Lunev <den@openvz.org> | ||
15 | Reviewed-by: Hanna Czenczek <hreitz@redhat.com> | ||
16 | Signed-off-by: Andrey Drobyshev <andrey.drobyshev@virtuozzo.com> | ||
17 | Message-ID: <20230907210226.953821-2-andrey.drobyshev@virtuozzo.com> | ||
10 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | 18 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> |
11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 19 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
12 | --- | 20 | --- |
13 | block/vmdk.c | 2 +- | 21 | include/block/block-common.h | 3 +++ |
14 | 1 file changed, 1 insertion(+), 1 deletion(-) | 22 | block/qcow.c | 5 ++++- |
23 | block/qcow2.c | 3 +++ | ||
24 | block/vmdk.c | 2 ++ | ||
25 | 4 files changed, 12 insertions(+), 1 deletion(-) | ||
15 | 26 | ||
27 | diff --git a/include/block/block-common.h b/include/block/block-common.h | ||
28 | index XXXXXXX..XXXXXXX 100644 | ||
29 | --- a/include/block/block-common.h | ||
30 | +++ b/include/block/block-common.h | ||
31 | @@ -XXX,XX +XXX,XX @@ typedef enum { | ||
32 | * layer rather than any backing, set by block layer | ||
33 | * BDRV_BLOCK_EOF: the returned pnum covers through end of file for this | ||
34 | * layer, set by block layer | ||
35 | + * BDRV_BLOCK_COMPRESSED: the underlying data is compressed; only valid for | ||
36 | + * the formats supporting compression: qcow, qcow2 | ||
37 | * | ||
38 | * Internal flags: | ||
39 | * BDRV_BLOCK_RAW: for use by passthrough drivers, such as raw, to request | ||
40 | @@ -XXX,XX +XXX,XX @@ typedef enum { | ||
41 | #define BDRV_BLOCK_ALLOCATED 0x10 | ||
42 | #define BDRV_BLOCK_EOF 0x20 | ||
43 | #define BDRV_BLOCK_RECURSE 0x40 | ||
44 | +#define BDRV_BLOCK_COMPRESSED 0x80 | ||
45 | |||
46 | typedef QTAILQ_HEAD(BlockReopenQueue, BlockReopenQueueEntry) BlockReopenQueue; | ||
47 | |||
48 | diff --git a/block/qcow.c b/block/qcow.c | ||
49 | index XXXXXXX..XXXXXXX 100644 | ||
50 | --- a/block/qcow.c | ||
51 | +++ b/block/qcow.c | ||
52 | @@ -XXX,XX +XXX,XX @@ qcow_co_block_status(BlockDriverState *bs, bool want_zero, | ||
53 | if (!cluster_offset) { | ||
54 | return 0; | ||
55 | } | ||
56 | - if ((cluster_offset & QCOW_OFLAG_COMPRESSED) || s->crypto) { | ||
57 | + if (cluster_offset & QCOW_OFLAG_COMPRESSED) { | ||
58 | + return BDRV_BLOCK_DATA | BDRV_BLOCK_COMPRESSED; | ||
59 | + } | ||
60 | + if (s->crypto) { | ||
61 | return BDRV_BLOCK_DATA; | ||
62 | } | ||
63 | *map = cluster_offset | index_in_cluster; | ||
64 | diff --git a/block/qcow2.c b/block/qcow2.c | ||
65 | index XXXXXXX..XXXXXXX 100644 | ||
66 | --- a/block/qcow2.c | ||
67 | +++ b/block/qcow2.c | ||
68 | @@ -XXX,XX +XXX,XX @@ qcow2_co_block_status(BlockDriverState *bs, bool want_zero, int64_t offset, | ||
69 | { | ||
70 | status |= BDRV_BLOCK_RECURSE; | ||
71 | } | ||
72 | + if (type == QCOW2_SUBCLUSTER_COMPRESSED) { | ||
73 | + status |= BDRV_BLOCK_COMPRESSED; | ||
74 | + } | ||
75 | return status; | ||
76 | } | ||
77 | |||
16 | diff --git a/block/vmdk.c b/block/vmdk.c | 78 | diff --git a/block/vmdk.c b/block/vmdk.c |
17 | index XXXXXXX..XXXXXXX 100644 | 79 | index XXXXXXX..XXXXXXX 100644 |
18 | --- a/block/vmdk.c | 80 | --- a/block/vmdk.c |
19 | +++ b/block/vmdk.c | 81 | +++ b/block/vmdk.c |
20 | @@ -XXX,XX +XXX,XX @@ out: | 82 | @@ -XXX,XX +XXX,XX @@ vmdk_co_block_status(BlockDriverState *bs, bool want_zero, |
21 | return ret; | 83 | if (extent->flat) { |
22 | } | 84 | ret |= BDRV_BLOCK_RECURSE; |
23 | 85 | } | |
24 | -static int vmdk_is_cid_valid(BlockDriverState *bs) | 86 | + } else { |
25 | +static int coroutine_fn vmdk_is_cid_valid(BlockDriverState *bs) | 87 | + ret |= BDRV_BLOCK_COMPRESSED; |
26 | { | 88 | } |
27 | BDRVVmdkState *s = bs->opaque; | 89 | *file = extent->file->bs; |
28 | uint32_t cur_pcid; | 90 | break; |
29 | -- | 91 | -- |
30 | 2.40.0 | 92 | 2.41.0 | diff view generated by jsdifflib |
1 | From: Paolo Bonzini <pbonzini@redhat.com> | 1 | From: Andrey Drobyshev via <qemu-block@nongnu.org> |
---|---|---|---|
2 | 2 | ||
3 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> | 3 | Right now "qemu-img map" reports compressed blocks as containing data |
4 | Message-Id: <20230309084456.304669-8-pbonzini@redhat.com> | 4 | but having no host offset. This is not very informative. Instead, |
5 | let's add another boolean field named "compressed" in case JSON output | ||
6 | mode is specified. This is achieved by utilizing new allocation status | ||
7 | flag BDRV_BLOCK_COMPRESSED for bdrv_block_status(). | ||
8 | |||
9 | Also update the expected qemu-iotests outputs to contain the new field. | ||
10 | |||
11 | Signed-off-by: Andrey Drobyshev <andrey.drobyshev@virtuozzo.com> | ||
12 | Message-ID: <20230907210226.953821-3-andrey.drobyshev@virtuozzo.com> | ||
5 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | 13 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> |
6 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 14 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
7 | --- | 15 | --- |
8 | tests/unit/test-thread-pool.c | 2 +- | 16 | qapi/block-core.json | 6 +- |
9 | 1 file changed, 1 insertion(+), 1 deletion(-) | 17 | qemu-img.c | 8 +- |
18 | tests/qemu-iotests/122.out | 84 +- | ||
19 | tests/qemu-iotests/146.out | 780 +++++++++--------- | ||
20 | tests/qemu-iotests/154.out | 194 ++--- | ||
21 | tests/qemu-iotests/179.out | 178 ++-- | ||
22 | tests/qemu-iotests/209.out | 4 +- | ||
23 | tests/qemu-iotests/221.out | 16 +- | ||
24 | tests/qemu-iotests/223.out | 60 +- | ||
25 | tests/qemu-iotests/241.out | 10 +- | ||
26 | tests/qemu-iotests/244.out | 24 +- | ||
27 | tests/qemu-iotests/252.out | 10 +- | ||
28 | tests/qemu-iotests/253.out | 20 +- | ||
29 | tests/qemu-iotests/274.out | 48 +- | ||
30 | .../tests/nbd-qemu-allocation.out | 16 +- | ||
31 | tests/qemu-iotests/tests/qemu-img-bitmaps.out | 24 +- | ||
32 | 16 files changed, 744 insertions(+), 738 deletions(-) | ||
10 | 33 | ||
11 | diff --git a/tests/unit/test-thread-pool.c b/tests/unit/test-thread-pool.c | 34 | diff --git a/qapi/block-core.json b/qapi/block-core.json |
12 | index XXXXXXX..XXXXXXX 100644 | 35 | index XXXXXXX..XXXXXXX 100644 |
13 | --- a/tests/unit/test-thread-pool.c | 36 | --- a/qapi/block-core.json |
14 | +++ b/tests/unit/test-thread-pool.c | 37 | +++ b/qapi/block-core.json |
15 | @@ -XXX,XX +XXX,XX @@ static void test_submit_aio(void) | 38 | @@ -XXX,XX +XXX,XX @@ |
16 | g_assert_cmpint(data.ret, ==, 0); | 39 | # |
17 | } | 40 | # @zero: whether the virtual blocks read as zeroes |
18 | 41 | # | |
19 | -static void co_test_cb(void *opaque) | 42 | +# @compressed: true if the data is stored compressed (since 8.2) |
20 | +static void coroutine_fn co_test_cb(void *opaque) | 43 | +# |
21 | { | 44 | # @depth: number of layers (0 = top image, 1 = top image's backing |
22 | WorkerTestData *data = opaque; | 45 | # file, ..., n - 1 = bottom image (where n is the number of images |
46 | # in the chain)) before reaching one for which the range is | ||
47 | @@ -XXX,XX +XXX,XX @@ | ||
48 | ## | ||
49 | { 'struct': 'MapEntry', | ||
50 | 'data': {'start': 'int', 'length': 'int', 'data': 'bool', | ||
51 | - 'zero': 'bool', 'depth': 'int', 'present': 'bool', | ||
52 | - '*offset': 'int', '*filename': 'str' } } | ||
53 | + 'zero': 'bool', 'compressed': 'bool', 'depth': 'int', | ||
54 | + 'present': 'bool', '*offset': 'int', '*filename': 'str' } } | ||
55 | |||
56 | ## | ||
57 | # @BlockdevCacheInfo: | ||
58 | diff --git a/qemu-img.c b/qemu-img.c | ||
59 | index XXXXXXX..XXXXXXX 100644 | ||
60 | --- a/qemu-img.c | ||
61 | +++ b/qemu-img.c | ||
62 | @@ -XXX,XX +XXX,XX @@ static int dump_map_entry(OutputFormat output_format, MapEntry *e, | ||
63 | case OFORMAT_JSON: | ||
64 | printf("{ \"start\": %"PRId64", \"length\": %"PRId64"," | ||
65 | " \"depth\": %"PRId64", \"present\": %s, \"zero\": %s," | ||
66 | - " \"data\": %s", e->start, e->length, e->depth, | ||
67 | + " \"data\": %s, \"compressed\": %s", | ||
68 | + e->start, e->length, e->depth, | ||
69 | e->present ? "true" : "false", | ||
70 | e->zero ? "true" : "false", | ||
71 | - e->data ? "true" : "false"); | ||
72 | + e->data ? "true" : "false", | ||
73 | + e->compressed ? "true" : "false"); | ||
74 | if (e->has_offset) { | ||
75 | printf(", \"offset\": %"PRId64"", e->offset); | ||
76 | } | ||
77 | @@ -XXX,XX +XXX,XX @@ static int get_block_status(BlockDriverState *bs, int64_t offset, | ||
78 | .length = bytes, | ||
79 | .data = !!(ret & BDRV_BLOCK_DATA), | ||
80 | .zero = !!(ret & BDRV_BLOCK_ZERO), | ||
81 | + .compressed = !!(ret & BDRV_BLOCK_COMPRESSED), | ||
82 | .offset = map, | ||
83 | .has_offset = has_offset, | ||
84 | .depth = depth, | ||
85 | @@ -XXX,XX +XXX,XX @@ static inline bool entry_mergeable(const MapEntry *curr, const MapEntry *next) | ||
86 | } | ||
87 | if (curr->zero != next->zero || | ||
88 | curr->data != next->data || | ||
89 | + curr->compressed != next->compressed || | ||
90 | curr->depth != next->depth || | ||
91 | curr->present != next->present || | ||
92 | !curr->filename != !next->filename || | ||
93 | diff --git a/tests/qemu-iotests/122.out b/tests/qemu-iotests/122.out | ||
94 | index XXXXXXX..XXXXXXX 100644 | ||
95 | --- a/tests/qemu-iotests/122.out | ||
96 | +++ b/tests/qemu-iotests/122.out | ||
97 | @@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 4194304 | ||
98 | 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
99 | read 65536/65536 bytes at offset 8388608 | ||
100 | 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
101 | -[{ "start": 0, "length": 65536, "depth": 0, "present": true, "zero": false, "data": true}, | ||
102 | -{ "start": 65536, "length": 4128768, "depth": 0, "present": false, "zero": true, "data": false}, | ||
103 | -{ "start": 4194304, "length": 65536, "depth": 0, "present": true, "zero": false, "data": true}, | ||
104 | -{ "start": 4259840, "length": 4128768, "depth": 0, "present": false, "zero": true, "data": false}, | ||
105 | -{ "start": 8388608, "length": 65536, "depth": 0, "present": true, "zero": false, "data": true}, | ||
106 | -{ "start": 8454144, "length": 4128768, "depth": 0, "present": false, "zero": true, "data": false}] | ||
107 | +[{ "start": 0, "length": 65536, "depth": 0, "present": true, "zero": false, "data": true, "compressed": true}, | ||
108 | +{ "start": 65536, "length": 4128768, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}, | ||
109 | +{ "start": 4194304, "length": 65536, "depth": 0, "present": true, "zero": false, "data": true, "compressed": true}, | ||
110 | +{ "start": 4259840, "length": 4128768, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}, | ||
111 | +{ "start": 8388608, "length": 65536, "depth": 0, "present": true, "zero": false, "data": true, "compressed": true}, | ||
112 | +{ "start": 8454144, "length": 4128768, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}] | ||
113 | read 65536/65536 bytes at offset 0 | ||
114 | 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
115 | read 65536/65536 bytes at offset 4194304 | ||
116 | @@ -XXX,XX +XXX,XX @@ wrote 1024/1024 bytes at offset 1046528 | ||
117 | 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
118 | wrote 1024/1024 bytes at offset 0 | ||
119 | 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
120 | -[{ "start": 0, "length": 65536, "depth": 0, "present": true, "zero": false, "data": true}, | ||
121 | -{ "start": 65536, "length": 65536, "depth": 0, "present": false, "zero": true, "data": false}, | ||
122 | -{ "start": 131072, "length": 196608, "depth": 0, "present": true, "zero": false, "data": true}, | ||
123 | -{ "start": 327680, "length": 655360, "depth": 0, "present": false, "zero": true, "data": false}, | ||
124 | -{ "start": 983040, "length": 65536, "depth": 0, "present": true, "zero": false, "data": true}, | ||
125 | -{ "start": 1048576, "length": 1046528, "depth": 0, "present": false, "zero": true, "data": false}] | ||
126 | +[{ "start": 0, "length": 65536, "depth": 0, "present": true, "zero": false, "data": true, "compressed": true}, | ||
127 | +{ "start": 65536, "length": 65536, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}, | ||
128 | +{ "start": 131072, "length": 196608, "depth": 0, "present": true, "zero": false, "data": true, "compressed": true}, | ||
129 | +{ "start": 327680, "length": 655360, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}, | ||
130 | +{ "start": 983040, "length": 65536, "depth": 0, "present": true, "zero": false, "data": true, "compressed": true}, | ||
131 | +{ "start": 1048576, "length": 1046528, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}] | ||
132 | read 16384/16384 bytes at offset 0 | ||
133 | 16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
134 | read 16384/16384 bytes at offset 16384 | ||
135 | @@ -XXX,XX +XXX,XX @@ read 3145728/3145728 bytes at offset 0 | ||
136 | 3 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
137 | read 63963136/63963136 bytes at offset 3145728 | ||
138 | 61 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
139 | -[{ "start": 0, "length": 67108864, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}] | ||
140 | +[{ "start": 0, "length": 67108864, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}] | ||
141 | |||
142 | convert -c -S 0: | ||
143 | read 3145728/3145728 bytes at offset 0 | ||
144 | 3 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
145 | read 63963136/63963136 bytes at offset 3145728 | ||
146 | 61 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
147 | -[{ "start": 0, "length": 67108864, "depth": 0, "present": true, "zero": false, "data": true}] | ||
148 | +[{ "start": 0, "length": 67108864, "depth": 0, "present": true, "zero": false, "data": true, "compressed": true}] | ||
149 | Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864 | ||
150 | wrote 33554432/33554432 bytes at offset 0 | ||
151 | 32 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
152 | @@ -XXX,XX +XXX,XX @@ read 30408704/30408704 bytes at offset 3145728 | ||
153 | 29 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
154 | read 33554432/33554432 bytes at offset 33554432 | ||
155 | 32 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
156 | -[{ "start": 0, "length": 67108864, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}] | ||
157 | +[{ "start": 0, "length": 67108864, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}] | ||
158 | |||
159 | convert -c -S 0 with source backing file: | ||
160 | read 3145728/3145728 bytes at offset 0 | ||
161 | @@ -XXX,XX +XXX,XX @@ read 30408704/30408704 bytes at offset 3145728 | ||
162 | 29 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
163 | read 33554432/33554432 bytes at offset 33554432 | ||
164 | 32 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
165 | -[{ "start": 0, "length": 67108864, "depth": 0, "present": true, "zero": false, "data": true}] | ||
166 | +[{ "start": 0, "length": 67108864, "depth": 0, "present": true, "zero": false, "data": true, "compressed": true}] | ||
167 | |||
168 | convert -S 0 -B ... | ||
169 | read 3145728/3145728 bytes at offset 0 | ||
170 | @@ -XXX,XX +XXX,XX @@ read 30408704/30408704 bytes at offset 3145728 | ||
171 | 29 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
172 | read 33554432/33554432 bytes at offset 33554432 | ||
173 | 32 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
174 | -[{ "start": 0, "length": 67108864, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}] | ||
175 | +[{ "start": 0, "length": 67108864, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}] | ||
176 | |||
177 | convert -c -S 0 -B ... | ||
178 | read 3145728/3145728 bytes at offset 0 | ||
179 | @@ -XXX,XX +XXX,XX @@ read 30408704/30408704 bytes at offset 3145728 | ||
180 | 29 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
181 | read 33554432/33554432 bytes at offset 33554432 | ||
182 | 32 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
183 | -[{ "start": 0, "length": 67108864, "depth": 0, "present": true, "zero": false, "data": true}] | ||
184 | +[{ "start": 0, "length": 67108864, "depth": 0, "present": true, "zero": false, "data": true, "compressed": true}] | ||
185 | |||
186 | === Non-zero -S === | ||
187 | |||
188 | @@ -XXX,XX +XXX,XX @@ wrote 1024/1024 bytes at offset 66560 | ||
189 | 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
190 | |||
191 | convert -S 4k | ||
192 | -[{ "start": 0, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
193 | -{ "start": 4096, "length": 4096, "depth": 0, "present": false, "zero": true, "data": false}, | ||
194 | -{ "start": 8192, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
195 | -{ "start": 12288, "length": 4096, "depth": 0, "present": false, "zero": true, "data": false}, | ||
196 | -{ "start": 16384, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
197 | -{ "start": 20480, "length": 67088384, "depth": 0, "present": false, "zero": true, "data": false}] | ||
198 | +[{ "start": 0, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
199 | +{ "start": 4096, "length": 4096, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}, | ||
200 | +{ "start": 8192, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
201 | +{ "start": 12288, "length": 4096, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}, | ||
202 | +{ "start": 16384, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
203 | +{ "start": 20480, "length": 67088384, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}] | ||
204 | |||
205 | convert -c -S 4k | ||
206 | -[{ "start": 0, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true}, | ||
207 | -{ "start": 1024, "length": 7168, "depth": 0, "present": false, "zero": true, "data": false}, | ||
208 | -{ "start": 8192, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true}, | ||
209 | -{ "start": 9216, "length": 8192, "depth": 0, "present": false, "zero": true, "data": false}, | ||
210 | -{ "start": 17408, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true}, | ||
211 | -{ "start": 18432, "length": 67090432, "depth": 0, "present": false, "zero": true, "data": false}] | ||
212 | +[{ "start": 0, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true, "compressed": true}, | ||
213 | +{ "start": 1024, "length": 7168, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}, | ||
214 | +{ "start": 8192, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true, "compressed": true}, | ||
215 | +{ "start": 9216, "length": 8192, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}, | ||
216 | +{ "start": 17408, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true, "compressed": true}, | ||
217 | +{ "start": 18432, "length": 67090432, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}] | ||
218 | |||
219 | convert -S 8k | ||
220 | -[{ "start": 0, "length": 24576, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
221 | -{ "start": 24576, "length": 67084288, "depth": 0, "present": false, "zero": true, "data": false}] | ||
222 | +[{ "start": 0, "length": 24576, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
223 | +{ "start": 24576, "length": 67084288, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}] | ||
224 | |||
225 | convert -c -S 8k | ||
226 | -[{ "start": 0, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true}, | ||
227 | -{ "start": 1024, "length": 7168, "depth": 0, "present": false, "zero": true, "data": false}, | ||
228 | -{ "start": 8192, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true}, | ||
229 | -{ "start": 9216, "length": 8192, "depth": 0, "present": false, "zero": true, "data": false}, | ||
230 | -{ "start": 17408, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true}, | ||
231 | -{ "start": 18432, "length": 67090432, "depth": 0, "present": false, "zero": true, "data": false}] | ||
232 | +[{ "start": 0, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true, "compressed": true}, | ||
233 | +{ "start": 1024, "length": 7168, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}, | ||
234 | +{ "start": 8192, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true, "compressed": true}, | ||
235 | +{ "start": 9216, "length": 8192, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}, | ||
236 | +{ "start": 17408, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true, "compressed": true}, | ||
237 | +{ "start": 18432, "length": 67090432, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}] | ||
238 | |||
239 | === -n to a non-zero image === | ||
240 | |||
241 | @@ -XXX,XX +XXX,XX @@ Images are identical. | ||
242 | |||
243 | Formatting 'TEST_DIR/t.IMGFMT.orig', fmt=IMGFMT size=67108864 | ||
244 | Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 | ||
245 | -[{ "start": 0, "length": 67108864, "depth": 0, "present": true, "zero": true, "data": false}] | ||
246 | +[{ "start": 0, "length": 67108864, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}] | ||
247 | Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 | ||
248 | -[{ "start": 0, "length": 67108864, "depth": 0, "present": false, "zero": true, "data": false}] | ||
249 | +[{ "start": 0, "length": 67108864, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}] | ||
250 | |||
251 | === -n to an empty image with a backing file === | ||
252 | |||
253 | Formatting 'TEST_DIR/t.IMGFMT.orig', fmt=IMGFMT size=67108864 | ||
254 | Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864 | ||
255 | Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT | ||
256 | -[{ "start": 0, "length": 67108864, "depth": 0, "present": true, "zero": true, "data": false}] | ||
257 | +[{ "start": 0, "length": 67108864, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}] | ||
258 | Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT | ||
259 | -[{ "start": 0, "length": 67108864, "depth": 0, "present": true, "zero": false, "data": true, "offset": 327680}] | ||
260 | +[{ "start": 0, "length": 67108864, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": 327680}] | ||
261 | |||
262 | === -n -B to an image without a backing file === | ||
263 | |||
264 | diff --git a/tests/qemu-iotests/146.out b/tests/qemu-iotests/146.out | ||
265 | index XXXXXXX..XXXXXXX 100644 | ||
266 | --- a/tests/qemu-iotests/146.out | ||
267 | +++ b/tests/qemu-iotests/146.out | ||
268 | @@ -XXX,XX +XXX,XX @@ QA output created by 146 | ||
269 | |||
270 | === Testing VPC Autodetect === | ||
271 | |||
272 | -[{ "start": 0, "length": 136363130880, "depth": 0, "present": true, "zero": true, "data": false}] | ||
273 | +[{ "start": 0, "length": 136363130880, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}] | ||
274 | |||
275 | === Testing VPC with current_size force === | ||
276 | |||
277 | -[{ "start": 0, "length": 136365211648, "depth": 0, "present": true, "zero": true, "data": false}] | ||
278 | +[{ "start": 0, "length": 136365211648, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}] | ||
279 | |||
280 | === Testing VPC with chs force === | ||
281 | |||
282 | -[{ "start": 0, "length": 136363130880, "depth": 0, "present": true, "zero": true, "data": false}] | ||
283 | +[{ "start": 0, "length": 136363130880, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}] | ||
284 | |||
285 | === Testing Hyper-V Autodetect === | ||
286 | |||
287 | -[{ "start": 0, "length": 136365211648, "depth": 0, "present": true, "zero": true, "data": false}] | ||
288 | +[{ "start": 0, "length": 136365211648, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}] | ||
289 | |||
290 | === Testing Hyper-V with current_size force === | ||
291 | |||
292 | -[{ "start": 0, "length": 136365211648, "depth": 0, "present": true, "zero": true, "data": false}] | ||
293 | +[{ "start": 0, "length": 136365211648, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}] | ||
294 | |||
295 | === Testing Hyper-V with chs force === | ||
296 | |||
297 | -[{ "start": 0, "length": 136363130880, "depth": 0, "present": true, "zero": true, "data": false}] | ||
298 | +[{ "start": 0, "length": 136363130880, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}] | ||
299 | |||
300 | === Testing d2v Autodetect === | ||
301 | |||
302 | -[{ "start": 0, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
303 | -{ "start": 2097152, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
304 | -{ "start": 4194304, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
305 | -{ "start": 6291456, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
306 | -{ "start": 8388608, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
307 | -{ "start": 10485760, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
308 | -{ "start": 12582912, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
309 | -{ "start": 14680064, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
310 | -{ "start": 16777216, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
311 | -{ "start": 18874368, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
312 | -{ "start": 20971520, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
313 | -{ "start": 23068672, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
314 | -{ "start": 25165824, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
315 | -{ "start": 27262976, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
316 | -{ "start": 29360128, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
317 | -{ "start": 31457280, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
318 | -{ "start": 33554432, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
319 | -{ "start": 35651584, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
320 | -{ "start": 37748736, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
321 | -{ "start": 39845888, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
322 | -{ "start": 41943040, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
323 | -{ "start": 44040192, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
324 | -{ "start": 46137344, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
325 | -{ "start": 48234496, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
326 | -{ "start": 50331648, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
327 | -{ "start": 52428800, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
328 | -{ "start": 54525952, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
329 | -{ "start": 56623104, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
330 | -{ "start": 58720256, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
331 | -{ "start": 60817408, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
332 | -{ "start": 62914560, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
333 | -{ "start": 65011712, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
334 | -{ "start": 67108864, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
335 | -{ "start": 69206016, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
336 | -{ "start": 71303168, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
337 | -{ "start": 73400320, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
338 | -{ "start": 75497472, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
339 | -{ "start": 77594624, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
340 | -{ "start": 79691776, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
341 | -{ "start": 81788928, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
342 | -{ "start": 83886080, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
343 | -{ "start": 85983232, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
344 | -{ "start": 88080384, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
345 | -{ "start": 90177536, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
346 | -{ "start": 92274688, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
347 | -{ "start": 94371840, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
348 | -{ "start": 96468992, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
349 | -{ "start": 98566144, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
350 | -{ "start": 100663296, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
351 | -{ "start": 102760448, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
352 | -{ "start": 104857600, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
353 | -{ "start": 106954752, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
354 | -{ "start": 109051904, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
355 | -{ "start": 111149056, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
356 | -{ "start": 113246208, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
357 | -{ "start": 115343360, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
358 | -{ "start": 117440512, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
359 | -{ "start": 119537664, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
360 | -{ "start": 121634816, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
361 | -{ "start": 123731968, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
362 | -{ "start": 125829120, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
363 | -{ "start": 127926272, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
364 | -{ "start": 130023424, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
365 | -{ "start": 132120576, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
366 | -{ "start": 134217728, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
367 | -{ "start": 136314880, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
368 | -{ "start": 138412032, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
369 | -{ "start": 140509184, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
370 | -{ "start": 142606336, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
371 | -{ "start": 144703488, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
372 | -{ "start": 146800640, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
373 | -{ "start": 148897792, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
374 | -{ "start": 150994944, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
375 | -{ "start": 153092096, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
376 | -{ "start": 155189248, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
377 | -{ "start": 157286400, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
378 | -{ "start": 159383552, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
379 | -{ "start": 161480704, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
380 | -{ "start": 163577856, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
381 | -{ "start": 165675008, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
382 | -{ "start": 167772160, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
383 | -{ "start": 169869312, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
384 | -{ "start": 171966464, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
385 | -{ "start": 174063616, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
386 | -{ "start": 176160768, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
387 | -{ "start": 178257920, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
388 | -{ "start": 180355072, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
389 | -{ "start": 182452224, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
390 | -{ "start": 184549376, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
391 | -{ "start": 186646528, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
392 | -{ "start": 188743680, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
393 | -{ "start": 190840832, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
394 | -{ "start": 192937984, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
395 | -{ "start": 195035136, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
396 | -{ "start": 197132288, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
397 | -{ "start": 199229440, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
398 | -{ "start": 201326592, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
399 | -{ "start": 203423744, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
400 | -{ "start": 205520896, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
401 | -{ "start": 207618048, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
402 | -{ "start": 209715200, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
403 | -{ "start": 211812352, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
404 | -{ "start": 213909504, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
405 | -{ "start": 216006656, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
406 | -{ "start": 218103808, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
407 | -{ "start": 220200960, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
408 | -{ "start": 222298112, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
409 | -{ "start": 224395264, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
410 | -{ "start": 226492416, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
411 | -{ "start": 228589568, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
412 | -{ "start": 230686720, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
413 | -{ "start": 232783872, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
414 | -{ "start": 234881024, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
415 | -{ "start": 236978176, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
416 | -{ "start": 239075328, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
417 | -{ "start": 241172480, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
418 | -{ "start": 243269632, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
419 | -{ "start": 245366784, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
420 | -{ "start": 247463936, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
421 | -{ "start": 249561088, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
422 | -{ "start": 251658240, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
423 | -{ "start": 253755392, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
424 | -{ "start": 255852544, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
425 | -{ "start": 257949696, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
426 | -{ "start": 260046848, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
427 | -{ "start": 262144000, "length": 1310720, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}] | ||
428 | +[{ "start": 0, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
429 | +{ "start": 2097152, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
430 | +{ "start": 4194304, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
431 | +{ "start": 6291456, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
432 | +{ "start": 8388608, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
433 | +{ "start": 10485760, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
434 | +{ "start": 12582912, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
435 | +{ "start": 14680064, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
436 | +{ "start": 16777216, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
437 | +{ "start": 18874368, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
438 | +{ "start": 20971520, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
439 | +{ "start": 23068672, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
440 | +{ "start": 25165824, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
441 | +{ "start": 27262976, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
442 | +{ "start": 29360128, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
443 | +{ "start": 31457280, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
444 | +{ "start": 33554432, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
445 | +{ "start": 35651584, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
446 | +{ "start": 37748736, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
447 | +{ "start": 39845888, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
448 | +{ "start": 41943040, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
449 | +{ "start": 44040192, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
450 | +{ "start": 46137344, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
451 | +{ "start": 48234496, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
452 | +{ "start": 50331648, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
453 | +{ "start": 52428800, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
454 | +{ "start": 54525952, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
455 | +{ "start": 56623104, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
456 | +{ "start": 58720256, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
457 | +{ "start": 60817408, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
458 | +{ "start": 62914560, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
459 | +{ "start": 65011712, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
460 | +{ "start": 67108864, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
461 | +{ "start": 69206016, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
462 | +{ "start": 71303168, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
463 | +{ "start": 73400320, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
464 | +{ "start": 75497472, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
465 | +{ "start": 77594624, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
466 | +{ "start": 79691776, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
467 | +{ "start": 81788928, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
468 | +{ "start": 83886080, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
469 | +{ "start": 85983232, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
470 | +{ "start": 88080384, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
471 | +{ "start": 90177536, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
472 | +{ "start": 92274688, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
473 | +{ "start": 94371840, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
474 | +{ "start": 96468992, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
475 | +{ "start": 98566144, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
476 | +{ "start": 100663296, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
477 | +{ "start": 102760448, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
478 | +{ "start": 104857600, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
479 | +{ "start": 106954752, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
480 | +{ "start": 109051904, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
481 | +{ "start": 111149056, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
482 | +{ "start": 113246208, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
483 | +{ "start": 115343360, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
484 | +{ "start": 117440512, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
485 | +{ "start": 119537664, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
486 | +{ "start": 121634816, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
487 | +{ "start": 123731968, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
488 | +{ "start": 125829120, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
489 | +{ "start": 127926272, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
490 | +{ "start": 130023424, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
491 | +{ "start": 132120576, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
492 | +{ "start": 134217728, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
493 | +{ "start": 136314880, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
494 | +{ "start": 138412032, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
495 | +{ "start": 140509184, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
496 | +{ "start": 142606336, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
497 | +{ "start": 144703488, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
498 | +{ "start": 146800640, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
499 | +{ "start": 148897792, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
500 | +{ "start": 150994944, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
501 | +{ "start": 153092096, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
502 | +{ "start": 155189248, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
503 | +{ "start": 157286400, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
504 | +{ "start": 159383552, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
505 | +{ "start": 161480704, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
506 | +{ "start": 163577856, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
507 | +{ "start": 165675008, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
508 | +{ "start": 167772160, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
509 | +{ "start": 169869312, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
510 | +{ "start": 171966464, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
511 | +{ "start": 174063616, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
512 | +{ "start": 176160768, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
513 | +{ "start": 178257920, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
514 | +{ "start": 180355072, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
515 | +{ "start": 182452224, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
516 | +{ "start": 184549376, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
517 | +{ "start": 186646528, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
518 | +{ "start": 188743680, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
519 | +{ "start": 190840832, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
520 | +{ "start": 192937984, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
521 | +{ "start": 195035136, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
522 | +{ "start": 197132288, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
523 | +{ "start": 199229440, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
524 | +{ "start": 201326592, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
525 | +{ "start": 203423744, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
526 | +{ "start": 205520896, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
527 | +{ "start": 207618048, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
528 | +{ "start": 209715200, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
529 | +{ "start": 211812352, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
530 | +{ "start": 213909504, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
531 | +{ "start": 216006656, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
532 | +{ "start": 218103808, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
533 | +{ "start": 220200960, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
534 | +{ "start": 222298112, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
535 | +{ "start": 224395264, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
536 | +{ "start": 226492416, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
537 | +{ "start": 228589568, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
538 | +{ "start": 230686720, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
539 | +{ "start": 232783872, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
540 | +{ "start": 234881024, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
541 | +{ "start": 236978176, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
542 | +{ "start": 239075328, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
543 | +{ "start": 241172480, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
544 | +{ "start": 243269632, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
545 | +{ "start": 245366784, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
546 | +{ "start": 247463936, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
547 | +{ "start": 249561088, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
548 | +{ "start": 251658240, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
549 | +{ "start": 253755392, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
550 | +{ "start": 255852544, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
551 | +{ "start": 257949696, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
552 | +{ "start": 260046848, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
553 | +{ "start": 262144000, "length": 1310720, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}] | ||
554 | |||
555 | === Testing d2v with current_size force === | ||
556 | |||
557 | -[{ "start": 0, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
558 | -{ "start": 2097152, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
559 | -{ "start": 4194304, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
560 | -{ "start": 6291456, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
561 | -{ "start": 8388608, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
562 | -{ "start": 10485760, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
563 | -{ "start": 12582912, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
564 | -{ "start": 14680064, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
565 | -{ "start": 16777216, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
566 | -{ "start": 18874368, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
567 | -{ "start": 20971520, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
568 | -{ "start": 23068672, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
569 | -{ "start": 25165824, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
570 | -{ "start": 27262976, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
571 | -{ "start": 29360128, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
572 | -{ "start": 31457280, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
573 | -{ "start": 33554432, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
574 | -{ "start": 35651584, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
575 | -{ "start": 37748736, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
576 | -{ "start": 39845888, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
577 | -{ "start": 41943040, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
578 | -{ "start": 44040192, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
579 | -{ "start": 46137344, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
580 | -{ "start": 48234496, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
581 | -{ "start": 50331648, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
582 | -{ "start": 52428800, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
583 | -{ "start": 54525952, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
584 | -{ "start": 56623104, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
585 | -{ "start": 58720256, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
586 | -{ "start": 60817408, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
587 | -{ "start": 62914560, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
588 | -{ "start": 65011712, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
589 | -{ "start": 67108864, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
590 | -{ "start": 69206016, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
591 | -{ "start": 71303168, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
592 | -{ "start": 73400320, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
593 | -{ "start": 75497472, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
594 | -{ "start": 77594624, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
595 | -{ "start": 79691776, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
596 | -{ "start": 81788928, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
597 | -{ "start": 83886080, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
598 | -{ "start": 85983232, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
599 | -{ "start": 88080384, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
600 | -{ "start": 90177536, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
601 | -{ "start": 92274688, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
602 | -{ "start": 94371840, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
603 | -{ "start": 96468992, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
604 | -{ "start": 98566144, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
605 | -{ "start": 100663296, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
606 | -{ "start": 102760448, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
607 | -{ "start": 104857600, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
608 | -{ "start": 106954752, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
609 | -{ "start": 109051904, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
610 | -{ "start": 111149056, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
611 | -{ "start": 113246208, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
612 | -{ "start": 115343360, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
613 | -{ "start": 117440512, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
614 | -{ "start": 119537664, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
615 | -{ "start": 121634816, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
616 | -{ "start": 123731968, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
617 | -{ "start": 125829120, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
618 | -{ "start": 127926272, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
619 | -{ "start": 130023424, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
620 | -{ "start": 132120576, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
621 | -{ "start": 134217728, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
622 | -{ "start": 136314880, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
623 | -{ "start": 138412032, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
624 | -{ "start": 140509184, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
625 | -{ "start": 142606336, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
626 | -{ "start": 144703488, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
627 | -{ "start": 146800640, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
628 | -{ "start": 148897792, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
629 | -{ "start": 150994944, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
630 | -{ "start": 153092096, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
631 | -{ "start": 155189248, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
632 | -{ "start": 157286400, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
633 | -{ "start": 159383552, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
634 | -{ "start": 161480704, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
635 | -{ "start": 163577856, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
636 | -{ "start": 165675008, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
637 | -{ "start": 167772160, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
638 | -{ "start": 169869312, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
639 | -{ "start": 171966464, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
640 | -{ "start": 174063616, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
641 | -{ "start": 176160768, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
642 | -{ "start": 178257920, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
643 | -{ "start": 180355072, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
644 | -{ "start": 182452224, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
645 | -{ "start": 184549376, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
646 | -{ "start": 186646528, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
647 | -{ "start": 188743680, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
648 | -{ "start": 190840832, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
649 | -{ "start": 192937984, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
650 | -{ "start": 195035136, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
651 | -{ "start": 197132288, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
652 | -{ "start": 199229440, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
653 | -{ "start": 201326592, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
654 | -{ "start": 203423744, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
655 | -{ "start": 205520896, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
656 | -{ "start": 207618048, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
657 | -{ "start": 209715200, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
658 | -{ "start": 211812352, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
659 | -{ "start": 213909504, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
660 | -{ "start": 216006656, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
661 | -{ "start": 218103808, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
662 | -{ "start": 220200960, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
663 | -{ "start": 222298112, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
664 | -{ "start": 224395264, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
665 | -{ "start": 226492416, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
666 | -{ "start": 228589568, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
667 | -{ "start": 230686720, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
668 | -{ "start": 232783872, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
669 | -{ "start": 234881024, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
670 | -{ "start": 236978176, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
671 | -{ "start": 239075328, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
672 | -{ "start": 241172480, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
673 | -{ "start": 243269632, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
674 | -{ "start": 245366784, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
675 | -{ "start": 247463936, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
676 | -{ "start": 249561088, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
677 | -{ "start": 251658240, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
678 | -{ "start": 253755392, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
679 | -{ "start": 255852544, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
680 | -{ "start": 257949696, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
681 | -{ "start": 260046848, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
682 | -{ "start": 262144000, "length": 1310720, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}] | ||
683 | +[{ "start": 0, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
684 | +{ "start": 2097152, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
685 | +{ "start": 4194304, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
686 | +{ "start": 6291456, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
687 | +{ "start": 8388608, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
688 | +{ "start": 10485760, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
689 | +{ "start": 12582912, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
690 | +{ "start": 14680064, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
691 | +{ "start": 16777216, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
692 | +{ "start": 18874368, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
693 | +{ "start": 20971520, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
694 | +{ "start": 23068672, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
695 | +{ "start": 25165824, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
696 | +{ "start": 27262976, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
697 | +{ "start": 29360128, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
698 | +{ "start": 31457280, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
699 | +{ "start": 33554432, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
700 | +{ "start": 35651584, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
701 | +{ "start": 37748736, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
702 | +{ "start": 39845888, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
703 | +{ "start": 41943040, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
704 | +{ "start": 44040192, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
705 | +{ "start": 46137344, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
706 | +{ "start": 48234496, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
707 | +{ "start": 50331648, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
708 | +{ "start": 52428800, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
709 | +{ "start": 54525952, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
710 | +{ "start": 56623104, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
711 | +{ "start": 58720256, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
712 | +{ "start": 60817408, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
713 | +{ "start": 62914560, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
714 | +{ "start": 65011712, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
715 | +{ "start": 67108864, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
716 | +{ "start": 69206016, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
717 | +{ "start": 71303168, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
718 | +{ "start": 73400320, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
719 | +{ "start": 75497472, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
720 | +{ "start": 77594624, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
721 | +{ "start": 79691776, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
722 | +{ "start": 81788928, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
723 | +{ "start": 83886080, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
724 | +{ "start": 85983232, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
725 | +{ "start": 88080384, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
726 | +{ "start": 90177536, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
727 | +{ "start": 92274688, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
728 | +{ "start": 94371840, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
729 | +{ "start": 96468992, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
730 | +{ "start": 98566144, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
731 | +{ "start": 100663296, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
732 | +{ "start": 102760448, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
733 | +{ "start": 104857600, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
734 | +{ "start": 106954752, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
735 | +{ "start": 109051904, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
736 | +{ "start": 111149056, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
737 | +{ "start": 113246208, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
738 | +{ "start": 115343360, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
739 | +{ "start": 117440512, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
740 | +{ "start": 119537664, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
741 | +{ "start": 121634816, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
742 | +{ "start": 123731968, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
743 | +{ "start": 125829120, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
744 | +{ "start": 127926272, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
745 | +{ "start": 130023424, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
746 | +{ "start": 132120576, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
747 | +{ "start": 134217728, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
748 | +{ "start": 136314880, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
749 | +{ "start": 138412032, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
750 | +{ "start": 140509184, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
751 | +{ "start": 142606336, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
752 | +{ "start": 144703488, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
753 | +{ "start": 146800640, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
754 | +{ "start": 148897792, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
755 | +{ "start": 150994944, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
756 | +{ "start": 153092096, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
757 | +{ "start": 155189248, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
758 | +{ "start": 157286400, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
759 | +{ "start": 159383552, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
760 | +{ "start": 161480704, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
761 | +{ "start": 163577856, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
762 | +{ "start": 165675008, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
763 | +{ "start": 167772160, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
764 | +{ "start": 169869312, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
765 | +{ "start": 171966464, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
766 | +{ "start": 174063616, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
767 | +{ "start": 176160768, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
768 | +{ "start": 178257920, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
769 | +{ "start": 180355072, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
770 | +{ "start": 182452224, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
771 | +{ "start": 184549376, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
772 | +{ "start": 186646528, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
773 | +{ "start": 188743680, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
774 | +{ "start": 190840832, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
775 | +{ "start": 192937984, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
776 | +{ "start": 195035136, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
777 | +{ "start": 197132288, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
778 | +{ "start": 199229440, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
779 | +{ "start": 201326592, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
780 | +{ "start": 203423744, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
781 | +{ "start": 205520896, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
782 | +{ "start": 207618048, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
783 | +{ "start": 209715200, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
784 | +{ "start": 211812352, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
785 | +{ "start": 213909504, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
786 | +{ "start": 216006656, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
787 | +{ "start": 218103808, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
788 | +{ "start": 220200960, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
789 | +{ "start": 222298112, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
790 | +{ "start": 224395264, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
791 | +{ "start": 226492416, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
792 | +{ "start": 228589568, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
793 | +{ "start": 230686720, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
794 | +{ "start": 232783872, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
795 | +{ "start": 234881024, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
796 | +{ "start": 236978176, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
797 | +{ "start": 239075328, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
798 | +{ "start": 241172480, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
799 | +{ "start": 243269632, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
800 | +{ "start": 245366784, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
801 | +{ "start": 247463936, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
802 | +{ "start": 249561088, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
803 | +{ "start": 251658240, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
804 | +{ "start": 253755392, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
805 | +{ "start": 255852544, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
806 | +{ "start": 257949696, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
807 | +{ "start": 260046848, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
808 | +{ "start": 262144000, "length": 1310720, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}] | ||
809 | |||
810 | === Testing d2v with chs force === | ||
811 | |||
812 | -[{ "start": 0, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
813 | -{ "start": 2097152, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
814 | -{ "start": 4194304, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
815 | -{ "start": 6291456, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
816 | -{ "start": 8388608, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
817 | -{ "start": 10485760, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
818 | -{ "start": 12582912, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
819 | -{ "start": 14680064, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
820 | -{ "start": 16777216, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
821 | -{ "start": 18874368, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
822 | -{ "start": 20971520, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
823 | -{ "start": 23068672, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
824 | -{ "start": 25165824, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
825 | -{ "start": 27262976, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
826 | -{ "start": 29360128, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
827 | -{ "start": 31457280, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
828 | -{ "start": 33554432, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
829 | -{ "start": 35651584, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
830 | -{ "start": 37748736, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
831 | -{ "start": 39845888, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
832 | -{ "start": 41943040, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
833 | -{ "start": 44040192, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
834 | -{ "start": 46137344, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
835 | -{ "start": 48234496, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
836 | -{ "start": 50331648, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
837 | -{ "start": 52428800, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
838 | -{ "start": 54525952, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
839 | -{ "start": 56623104, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
840 | -{ "start": 58720256, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
841 | -{ "start": 60817408, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
842 | -{ "start": 62914560, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
843 | -{ "start": 65011712, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
844 | -{ "start": 67108864, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
845 | -{ "start": 69206016, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
846 | -{ "start": 71303168, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
847 | -{ "start": 73400320, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
848 | -{ "start": 75497472, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
849 | -{ "start": 77594624, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
850 | -{ "start": 79691776, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
851 | -{ "start": 81788928, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
852 | -{ "start": 83886080, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
853 | -{ "start": 85983232, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
854 | -{ "start": 88080384, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
855 | -{ "start": 90177536, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
856 | -{ "start": 92274688, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
857 | -{ "start": 94371840, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
858 | -{ "start": 96468992, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
859 | -{ "start": 98566144, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
860 | -{ "start": 100663296, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
861 | -{ "start": 102760448, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
862 | -{ "start": 104857600, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
863 | -{ "start": 106954752, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
864 | -{ "start": 109051904, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
865 | -{ "start": 111149056, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
866 | -{ "start": 113246208, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
867 | -{ "start": 115343360, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
868 | -{ "start": 117440512, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
869 | -{ "start": 119537664, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
870 | -{ "start": 121634816, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
871 | -{ "start": 123731968, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
872 | -{ "start": 125829120, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
873 | -{ "start": 127926272, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
874 | -{ "start": 130023424, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
875 | -{ "start": 132120576, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
876 | -{ "start": 134217728, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
877 | -{ "start": 136314880, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
878 | -{ "start": 138412032, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
879 | -{ "start": 140509184, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
880 | -{ "start": 142606336, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
881 | -{ "start": 144703488, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
882 | -{ "start": 146800640, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
883 | -{ "start": 148897792, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
884 | -{ "start": 150994944, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
885 | -{ "start": 153092096, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
886 | -{ "start": 155189248, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
887 | -{ "start": 157286400, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
888 | -{ "start": 159383552, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
889 | -{ "start": 161480704, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
890 | -{ "start": 163577856, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
891 | -{ "start": 165675008, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
892 | -{ "start": 167772160, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
893 | -{ "start": 169869312, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
894 | -{ "start": 171966464, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
895 | -{ "start": 174063616, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
896 | -{ "start": 176160768, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
897 | -{ "start": 178257920, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
898 | -{ "start": 180355072, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
899 | -{ "start": 182452224, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
900 | -{ "start": 184549376, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
901 | -{ "start": 186646528, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
902 | -{ "start": 188743680, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
903 | -{ "start": 190840832, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
904 | -{ "start": 192937984, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
905 | -{ "start": 195035136, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
906 | -{ "start": 197132288, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
907 | -{ "start": 199229440, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
908 | -{ "start": 201326592, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
909 | -{ "start": 203423744, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
910 | -{ "start": 205520896, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
911 | -{ "start": 207618048, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
912 | -{ "start": 209715200, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
913 | -{ "start": 211812352, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
914 | -{ "start": 213909504, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
915 | -{ "start": 216006656, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
916 | -{ "start": 218103808, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
917 | -{ "start": 220200960, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
918 | -{ "start": 222298112, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
919 | -{ "start": 224395264, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
920 | -{ "start": 226492416, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
921 | -{ "start": 228589568, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
922 | -{ "start": 230686720, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
923 | -{ "start": 232783872, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
924 | -{ "start": 234881024, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
925 | -{ "start": 236978176, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
926 | -{ "start": 239075328, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
927 | -{ "start": 241172480, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
928 | -{ "start": 243269632, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
929 | -{ "start": 245366784, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
930 | -{ "start": 247463936, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
931 | -{ "start": 249561088, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
932 | -{ "start": 251658240, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
933 | -{ "start": 253755392, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
934 | -{ "start": 255852544, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
935 | -{ "start": 257949696, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
936 | -{ "start": 260046848, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
937 | -{ "start": 262144000, "length": 1310720, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}] | ||
938 | +[{ "start": 0, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
939 | +{ "start": 2097152, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
940 | +{ "start": 4194304, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
941 | +{ "start": 6291456, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
942 | +{ "start": 8388608, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
943 | +{ "start": 10485760, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
944 | +{ "start": 12582912, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
945 | +{ "start": 14680064, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
946 | +{ "start": 16777216, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
947 | +{ "start": 18874368, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
948 | +{ "start": 20971520, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
949 | +{ "start": 23068672, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
950 | +{ "start": 25165824, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
951 | +{ "start": 27262976, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
952 | +{ "start": 29360128, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
953 | +{ "start": 31457280, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
954 | +{ "start": 33554432, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
955 | +{ "start": 35651584, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
956 | +{ "start": 37748736, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
957 | +{ "start": 39845888, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
958 | +{ "start": 41943040, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
959 | +{ "start": 44040192, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
960 | +{ "start": 46137344, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
961 | +{ "start": 48234496, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
962 | +{ "start": 50331648, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
963 | +{ "start": 52428800, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
964 | +{ "start": 54525952, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
965 | +{ "start": 56623104, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
966 | +{ "start": 58720256, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
967 | +{ "start": 60817408, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
968 | +{ "start": 62914560, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
969 | +{ "start": 65011712, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
970 | +{ "start": 67108864, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
971 | +{ "start": 69206016, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
972 | +{ "start": 71303168, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
973 | +{ "start": 73400320, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
974 | +{ "start": 75497472, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
975 | +{ "start": 77594624, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
976 | +{ "start": 79691776, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
977 | +{ "start": 81788928, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
978 | +{ "start": 83886080, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
979 | +{ "start": 85983232, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
980 | +{ "start": 88080384, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
981 | +{ "start": 90177536, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
982 | +{ "start": 92274688, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
983 | +{ "start": 94371840, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
984 | +{ "start": 96468992, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
985 | +{ "start": 98566144, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
986 | +{ "start": 100663296, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
987 | +{ "start": 102760448, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
988 | +{ "start": 104857600, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
989 | +{ "start": 106954752, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
990 | +{ "start": 109051904, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
991 | +{ "start": 111149056, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
992 | +{ "start": 113246208, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
993 | +{ "start": 115343360, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
994 | +{ "start": 117440512, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
995 | +{ "start": 119537664, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
996 | +{ "start": 121634816, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
997 | +{ "start": 123731968, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
998 | +{ "start": 125829120, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
999 | +{ "start": 127926272, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1000 | +{ "start": 130023424, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1001 | +{ "start": 132120576, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1002 | +{ "start": 134217728, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1003 | +{ "start": 136314880, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1004 | +{ "start": 138412032, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1005 | +{ "start": 140509184, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1006 | +{ "start": 142606336, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1007 | +{ "start": 144703488, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1008 | +{ "start": 146800640, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1009 | +{ "start": 148897792, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1010 | +{ "start": 150994944, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1011 | +{ "start": 153092096, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1012 | +{ "start": 155189248, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1013 | +{ "start": 157286400, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1014 | +{ "start": 159383552, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1015 | +{ "start": 161480704, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1016 | +{ "start": 163577856, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1017 | +{ "start": 165675008, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1018 | +{ "start": 167772160, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1019 | +{ "start": 169869312, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1020 | +{ "start": 171966464, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1021 | +{ "start": 174063616, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1022 | +{ "start": 176160768, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1023 | +{ "start": 178257920, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1024 | +{ "start": 180355072, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1025 | +{ "start": 182452224, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1026 | +{ "start": 184549376, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1027 | +{ "start": 186646528, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1028 | +{ "start": 188743680, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1029 | +{ "start": 190840832, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1030 | +{ "start": 192937984, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1031 | +{ "start": 195035136, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1032 | +{ "start": 197132288, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1033 | +{ "start": 199229440, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1034 | +{ "start": 201326592, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1035 | +{ "start": 203423744, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1036 | +{ "start": 205520896, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1037 | +{ "start": 207618048, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1038 | +{ "start": 209715200, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1039 | +{ "start": 211812352, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1040 | +{ "start": 213909504, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1041 | +{ "start": 216006656, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1042 | +{ "start": 218103808, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1043 | +{ "start": 220200960, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1044 | +{ "start": 222298112, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1045 | +{ "start": 224395264, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1046 | +{ "start": 226492416, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1047 | +{ "start": 228589568, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1048 | +{ "start": 230686720, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1049 | +{ "start": 232783872, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1050 | +{ "start": 234881024, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1051 | +{ "start": 236978176, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1052 | +{ "start": 239075328, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1053 | +{ "start": 241172480, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1054 | +{ "start": 243269632, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1055 | +{ "start": 245366784, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1056 | +{ "start": 247463936, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1057 | +{ "start": 249561088, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1058 | +{ "start": 251658240, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1059 | +{ "start": 253755392, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1060 | +{ "start": 255852544, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1061 | +{ "start": 257949696, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1062 | +{ "start": 260046848, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1063 | +{ "start": 262144000, "length": 1310720, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}] | ||
1064 | |||
1065 | === Testing Image create, default === | ||
1066 | |||
1067 | @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/IMGFMT-create-test.IMGFMT', fmt=IMGFMT size=4294967296 | ||
1068 | |||
1069 | === Read created image, default opts ==== | ||
1070 | |||
1071 | -[{ "start": 0, "length": 4295467008, "depth": 0, "present": true, "zero": true, "data": false}] | ||
1072 | +[{ "start": 0, "length": 4295467008, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}] | ||
1073 | |||
1074 | === Read created image, force_size_calc=chs ==== | ||
1075 | |||
1076 | -[{ "start": 0, "length": 4295467008, "depth": 0, "present": true, "zero": true, "data": false}] | ||
1077 | +[{ "start": 0, "length": 4295467008, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}] | ||
1078 | |||
1079 | === Read created image, force_size_calc=current_size ==== | ||
1080 | |||
1081 | -[{ "start": 0, "length": 4295467008, "depth": 0, "present": true, "zero": true, "data": false}] | ||
1082 | +[{ "start": 0, "length": 4295467008, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}] | ||
1083 | |||
1084 | === Testing Image create, force_size === | ||
1085 | |||
1086 | @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/IMGFMT-create-test.IMGFMT', fmt=IMGFMT size=4294967296 | ||
1087 | |||
1088 | === Read created image, default opts ==== | ||
1089 | |||
1090 | -[{ "start": 0, "length": 4294967296, "depth": 0, "present": true, "zero": true, "data": false}] | ||
1091 | +[{ "start": 0, "length": 4294967296, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}] | ||
1092 | |||
1093 | === Read created image, force_size_calc=chs ==== | ||
1094 | |||
1095 | -[{ "start": 0, "length": 4294967296, "depth": 0, "present": true, "zero": true, "data": false}] | ||
1096 | +[{ "start": 0, "length": 4294967296, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}] | ||
1097 | |||
1098 | === Read created image, force_size_calc=current_size ==== | ||
1099 | |||
1100 | -[{ "start": 0, "length": 4294967296, "depth": 0, "present": true, "zero": true, "data": false}] | ||
1101 | +[{ "start": 0, "length": 4294967296, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}] | ||
1102 | *** done | ||
1103 | diff --git a/tests/qemu-iotests/154.out b/tests/qemu-iotests/154.out | ||
1104 | index XXXXXXX..XXXXXXX 100644 | ||
1105 | --- a/tests/qemu-iotests/154.out | ||
1106 | +++ b/tests/qemu-iotests/154.out | ||
1107 | @@ -XXX,XX +XXX,XX @@ wrote 2048/2048 bytes at offset 17408 | ||
1108 | 2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1109 | wrote 2048/2048 bytes at offset 27648 | ||
1110 | 2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1111 | -[{ "start": 0, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false}, | ||
1112 | -{ "start": 4096, "length": 4096, "depth": 1, "present": false, "zero": true, "data": false}, | ||
1113 | -{ "start": 8192, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false}, | ||
1114 | -{ "start": 12288, "length": 4096, "depth": 1, "present": false, "zero": true, "data": false}, | ||
1115 | -{ "start": 16384, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false}, | ||
1116 | -{ "start": 20480, "length": 4096, "depth": 1, "present": false, "zero": true, "data": false}, | ||
1117 | -{ "start": 24576, "length": 8192, "depth": 0, "present": true, "zero": true, "data": false}, | ||
1118 | -{ "start": 32768, "length": 134184960, "depth": 1, "present": false, "zero": true, "data": false}] | ||
1119 | +[{ "start": 0, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}, | ||
1120 | +{ "start": 4096, "length": 4096, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1121 | +{ "start": 8192, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}, | ||
1122 | +{ "start": 12288, "length": 4096, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1123 | +{ "start": 16384, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}, | ||
1124 | +{ "start": 20480, "length": 4096, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1125 | +{ "start": 24576, "length": 8192, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}, | ||
1126 | +{ "start": 32768, "length": 134184960, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}] | ||
1127 | |||
1128 | == backing file contains non-zero data before write_zeroes == | ||
1129 | Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728 | ||
1130 | @@ -XXX,XX +XXX,XX @@ read 1024/1024 bytes at offset 65536 | ||
1131 | 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1132 | read 2048/2048 bytes at offset 67584 | ||
1133 | 2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1134 | -[{ "start": 0, "length": 32768, "depth": 1, "present": false, "zero": true, "data": false}, | ||
1135 | -{ "start": 32768, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
1136 | -{ "start": 36864, "length": 28672, "depth": 1, "present": false, "zero": true, "data": false}, | ||
1137 | -{ "start": 65536, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
1138 | -{ "start": 69632, "length": 134148096, "depth": 1, "present": false, "zero": true, "data": false}] | ||
1139 | +[{ "start": 0, "length": 32768, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1140 | +{ "start": 32768, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1141 | +{ "start": 36864, "length": 28672, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1142 | +{ "start": 65536, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1143 | +{ "start": 69632, "length": 134148096, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}] | ||
1144 | |||
1145 | == backing file contains non-zero data after write_zeroes == | ||
1146 | Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728 | ||
1147 | @@ -XXX,XX +XXX,XX @@ read 1024/1024 bytes at offset 44032 | ||
1148 | 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1149 | read 3072/3072 bytes at offset 40960 | ||
1150 | 3 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1151 | -[{ "start": 0, "length": 32768, "depth": 1, "present": false, "zero": true, "data": false}, | ||
1152 | -{ "start": 32768, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
1153 | -{ "start": 36864, "length": 4096, "depth": 1, "present": false, "zero": true, "data": false}, | ||
1154 | -{ "start": 40960, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
1155 | -{ "start": 45056, "length": 134172672, "depth": 1, "present": false, "zero": true, "data": false}] | ||
1156 | +[{ "start": 0, "length": 32768, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1157 | +{ "start": 32768, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1158 | +{ "start": 36864, "length": 4096, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1159 | +{ "start": 40960, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1160 | +{ "start": 45056, "length": 134172672, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}] | ||
1161 | |||
1162 | == write_zeroes covers non-zero data == | ||
1163 | Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728 | ||
1164 | @@ -XXX,XX +XXX,XX @@ wrote 2048/2048 bytes at offset 29696 | ||
1165 | 2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1166 | read 4096/4096 bytes at offset 28672 | ||
1167 | 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1168 | -[{ "start": 0, "length": 4096, "depth": 1, "present": false, "zero": true, "data": false}, | ||
1169 | -{ "start": 4096, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false}, | ||
1170 | -{ "start": 8192, "length": 4096, "depth": 1, "present": false, "zero": true, "data": false}, | ||
1171 | -{ "start": 12288, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false}, | ||
1172 | -{ "start": 16384, "length": 4096, "depth": 1, "present": false, "zero": true, "data": false}, | ||
1173 | -{ "start": 20480, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false}, | ||
1174 | -{ "start": 24576, "length": 4096, "depth": 1, "present": false, "zero": true, "data": false}, | ||
1175 | -{ "start": 28672, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false}, | ||
1176 | -{ "start": 32768, "length": 134184960, "depth": 1, "present": false, "zero": true, "data": false}] | ||
1177 | +[{ "start": 0, "length": 4096, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1178 | +{ "start": 4096, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}, | ||
1179 | +{ "start": 8192, "length": 4096, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1180 | +{ "start": 12288, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}, | ||
1181 | +{ "start": 16384, "length": 4096, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1182 | +{ "start": 20480, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}, | ||
1183 | +{ "start": 24576, "length": 4096, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1184 | +{ "start": 28672, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}, | ||
1185 | +{ "start": 32768, "length": 134184960, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}] | ||
1186 | |||
1187 | == spanning two clusters, non-zero before request == | ||
1188 | Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728 | ||
1189 | @@ -XXX,XX +XXX,XX @@ read 1024/1024 bytes at offset 67584 | ||
1190 | 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1191 | read 5120/5120 bytes at offset 68608 | ||
1192 | 5 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1193 | -[{ "start": 0, "length": 32768, "depth": 1, "present": false, "zero": true, "data": false}, | ||
1194 | -{ "start": 32768, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
1195 | -{ "start": 36864, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false}, | ||
1196 | -{ "start": 40960, "length": 8192, "depth": 1, "present": false, "zero": true, "data": false}, | ||
1197 | -{ "start": 49152, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
1198 | -{ "start": 53248, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false}, | ||
1199 | -{ "start": 57344, "length": 8192, "depth": 1, "present": false, "zero": true, "data": false}, | ||
1200 | -{ "start": 65536, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
1201 | -{ "start": 69632, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false}, | ||
1202 | -{ "start": 73728, "length": 134144000, "depth": 1, "present": false, "zero": true, "data": false}] | ||
1203 | +[{ "start": 0, "length": 32768, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1204 | +{ "start": 32768, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1205 | +{ "start": 36864, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}, | ||
1206 | +{ "start": 40960, "length": 8192, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1207 | +{ "start": 49152, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1208 | +{ "start": 53248, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}, | ||
1209 | +{ "start": 57344, "length": 8192, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1210 | +{ "start": 65536, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1211 | +{ "start": 69632, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}, | ||
1212 | +{ "start": 73728, "length": 134144000, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}] | ||
1213 | |||
1214 | == spanning two clusters, non-zero after request == | ||
1215 | Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728 | ||
1216 | @@ -XXX,XX +XXX,XX @@ read 7168/7168 bytes at offset 65536 | ||
1217 | 7 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1218 | read 1024/1024 bytes at offset 72704 | ||
1219 | 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1220 | -[{ "start": 0, "length": 32768, "depth": 1, "present": false, "zero": true, "data": false}, | ||
1221 | -{ "start": 32768, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false}, | ||
1222 | -{ "start": 36864, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
1223 | -{ "start": 40960, "length": 8192, "depth": 1, "present": false, "zero": true, "data": false}, | ||
1224 | -{ "start": 49152, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false}, | ||
1225 | -{ "start": 53248, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
1226 | -{ "start": 57344, "length": 8192, "depth": 1, "present": false, "zero": true, "data": false}, | ||
1227 | -{ "start": 65536, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false}, | ||
1228 | -{ "start": 69632, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
1229 | -{ "start": 73728, "length": 134144000, "depth": 1, "present": false, "zero": true, "data": false}] | ||
1230 | +[{ "start": 0, "length": 32768, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1231 | +{ "start": 32768, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}, | ||
1232 | +{ "start": 36864, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1233 | +{ "start": 40960, "length": 8192, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1234 | +{ "start": 49152, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}, | ||
1235 | +{ "start": 53248, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1236 | +{ "start": 57344, "length": 8192, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1237 | +{ "start": 65536, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}, | ||
1238 | +{ "start": 69632, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1239 | +{ "start": 73728, "length": 134144000, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}] | ||
1240 | |||
1241 | == spanning two clusters, partially overwriting backing file == | ||
1242 | Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728 | ||
1243 | @@ -XXX,XX +XXX,XX @@ read 1024/1024 bytes at offset 5120 | ||
1244 | 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1245 | read 2048/2048 bytes at offset 6144 | ||
1246 | 2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1247 | -[{ "start": 0, "length": 8192, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
1248 | -{ "start": 8192, "length": 134209536, "depth": 1, "present": false, "zero": true, "data": false}] | ||
1249 | +[{ "start": 0, "length": 8192, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1250 | +{ "start": 8192, "length": 134209536, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}] | ||
1251 | |||
1252 | == spanning multiple clusters, non-zero in first cluster == | ||
1253 | Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728 | ||
1254 | @@ -XXX,XX +XXX,XX @@ read 2048/2048 bytes at offset 65536 | ||
1255 | 2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1256 | read 10240/10240 bytes at offset 67584 | ||
1257 | 10 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1258 | -[{ "start": 0, "length": 65536, "depth": 1, "present": false, "zero": true, "data": false}, | ||
1259 | -{ "start": 65536, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
1260 | -{ "start": 69632, "length": 8192, "depth": 0, "present": true, "zero": true, "data": false}, | ||
1261 | -{ "start": 77824, "length": 134139904, "depth": 1, "present": false, "zero": true, "data": false}] | ||
1262 | +[{ "start": 0, "length": 65536, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1263 | +{ "start": 65536, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1264 | +{ "start": 69632, "length": 8192, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}, | ||
1265 | +{ "start": 77824, "length": 134139904, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}] | ||
1266 | |||
1267 | == spanning multiple clusters, non-zero in intermediate cluster == | ||
1268 | Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728 | ||
1269 | @@ -XXX,XX +XXX,XX @@ wrote 7168/7168 bytes at offset 67584 | ||
1270 | 7 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1271 | read 12288/12288 bytes at offset 65536 | ||
1272 | 12 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1273 | -[{ "start": 0, "length": 65536, "depth": 1, "present": false, "zero": true, "data": false}, | ||
1274 | -{ "start": 65536, "length": 12288, "depth": 0, "present": true, "zero": true, "data": false}, | ||
1275 | -{ "start": 77824, "length": 134139904, "depth": 1, "present": false, "zero": true, "data": false}] | ||
1276 | +[{ "start": 0, "length": 65536, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1277 | +{ "start": 65536, "length": 12288, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}, | ||
1278 | +{ "start": 77824, "length": 134139904, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}] | ||
1279 | |||
1280 | == spanning multiple clusters, non-zero in final cluster == | ||
1281 | Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728 | ||
1282 | @@ -XXX,XX +XXX,XX @@ read 10240/10240 bytes at offset 65536 | ||
1283 | 10 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1284 | read 2048/2048 bytes at offset 75776 | ||
1285 | 2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1286 | -[{ "start": 0, "length": 65536, "depth": 1, "present": false, "zero": true, "data": false}, | ||
1287 | -{ "start": 65536, "length": 8192, "depth": 0, "present": true, "zero": true, "data": false}, | ||
1288 | -{ "start": 73728, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
1289 | -{ "start": 77824, "length": 134139904, "depth": 1, "present": false, "zero": true, "data": false}] | ||
1290 | +[{ "start": 0, "length": 65536, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1291 | +{ "start": 65536, "length": 8192, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}, | ||
1292 | +{ "start": 73728, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1293 | +{ "start": 77824, "length": 134139904, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}] | ||
1294 | |||
1295 | == spanning multiple clusters, partially overwriting backing file == | ||
1296 | Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728 | ||
1297 | @@ -XXX,XX +XXX,XX @@ read 2048/2048 bytes at offset 74752 | ||
1298 | 2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1299 | read 1024/1024 bytes at offset 76800 | ||
1300 | 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1301 | -[{ "start": 0, "length": 65536, "depth": 1, "present": false, "zero": true, "data": false}, | ||
1302 | -{ "start": 65536, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
1303 | -{ "start": 69632, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false}, | ||
1304 | -{ "start": 73728, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
1305 | -{ "start": 77824, "length": 134139904, "depth": 1, "present": false, "zero": true, "data": false}] | ||
1306 | +[{ "start": 0, "length": 65536, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1307 | +{ "start": 65536, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1308 | +{ "start": 69632, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}, | ||
1309 | +{ "start": 73728, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1310 | +{ "start": 77824, "length": 134139904, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}] | ||
1311 | |||
1312 | == unaligned image tail cluster, no allocation needed == | ||
1313 | Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776 | ||
1314 | wrote 512/512 bytes at offset 134217728 | ||
1315 | 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1316 | 2048/2048 bytes allocated at offset 128 MiB | ||
1317 | -[{ "start": 0, "length": 134217728, "depth": 0, "present": false, "zero": true, "data": false}, | ||
1318 | -{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false}] | ||
1319 | +[{ "start": 0, "length": 134217728, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1320 | +{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}] | ||
1321 | Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776 | ||
1322 | wrote 512/512 bytes at offset 134219264 | ||
1323 | 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1324 | 2048/2048 bytes allocated at offset 128 MiB | ||
1325 | -[{ "start": 0, "length": 134217728, "depth": 0, "present": false, "zero": true, "data": false}, | ||
1326 | -{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false}] | ||
1327 | +[{ "start": 0, "length": 134217728, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1328 | +{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}] | ||
1329 | Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776 | ||
1330 | wrote 1024/1024 bytes at offset 134218240 | ||
1331 | 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1332 | 2048/2048 bytes allocated at offset 128 MiB | ||
1333 | -[{ "start": 0, "length": 134217728, "depth": 0, "present": false, "zero": true, "data": false}, | ||
1334 | -{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false}] | ||
1335 | +[{ "start": 0, "length": 134217728, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1336 | +{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}] | ||
1337 | Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776 | ||
1338 | wrote 2048/2048 bytes at offset 134217728 | ||
1339 | 2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1340 | 2048/2048 bytes allocated at offset 128 MiB | ||
1341 | -[{ "start": 0, "length": 134217728, "depth": 0, "present": false, "zero": true, "data": false}, | ||
1342 | -{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false}] | ||
1343 | +[{ "start": 0, "length": 134217728, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1344 | +{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}] | ||
1345 | Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134218752 | ||
1346 | Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT | ||
1347 | wrote 512/512 bytes at offset 134217728 | ||
1348 | 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1349 | 2048/2048 bytes allocated at offset 128 MiB | ||
1350 | -[{ "start": 0, "length": 134217728, "depth": 1, "present": false, "zero": true, "data": false}, | ||
1351 | -{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false}] | ||
1352 | +[{ "start": 0, "length": 134217728, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1353 | +{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}] | ||
1354 | Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT | ||
1355 | wrote 512/512 bytes at offset 134219264 | ||
1356 | 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1357 | 2048/2048 bytes allocated at offset 128 MiB | ||
1358 | -[{ "start": 0, "length": 134217728, "depth": 1, "present": false, "zero": true, "data": false}, | ||
1359 | -{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false}] | ||
1360 | +[{ "start": 0, "length": 134217728, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1361 | +{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}] | ||
1362 | Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT | ||
1363 | wrote 1024/1024 bytes at offset 134218240 | ||
1364 | 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1365 | 2048/2048 bytes allocated at offset 128 MiB | ||
1366 | -[{ "start": 0, "length": 134217728, "depth": 1, "present": false, "zero": true, "data": false}, | ||
1367 | -{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false}] | ||
1368 | +[{ "start": 0, "length": 134217728, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1369 | +{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}] | ||
1370 | Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT | ||
1371 | wrote 2048/2048 bytes at offset 134217728 | ||
1372 | 2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1373 | 2048/2048 bytes allocated at offset 128 MiB | ||
1374 | -[{ "start": 0, "length": 134217728, "depth": 1, "present": false, "zero": true, "data": false}, | ||
1375 | -{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false}] | ||
1376 | +[{ "start": 0, "length": 134217728, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1377 | +{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}] | ||
1378 | wrote 512/512 bytes at offset 134217728 | ||
1379 | 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1380 | Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT | ||
1381 | wrote 512/512 bytes at offset 134217728 | ||
1382 | 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1383 | 2048/2048 bytes allocated at offset 128 MiB | ||
1384 | -[{ "start": 0, "length": 134217728, "depth": 1, "present": false, "zero": true, "data": false}, | ||
1385 | -{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false}] | ||
1386 | +[{ "start": 0, "length": 134217728, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1387 | +{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}] | ||
1388 | Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT | ||
1389 | wrote 512/512 bytes at offset 134219264 | ||
1390 | 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1391 | 2048/2048 bytes allocated at offset 128 MiB | ||
1392 | -[{ "start": 0, "length": 134217728, "depth": 1, "present": false, "zero": true, "data": false}, | ||
1393 | -{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false}] | ||
1394 | +[{ "start": 0, "length": 134217728, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1395 | +{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}] | ||
1396 | Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT | ||
1397 | wrote 1024/1024 bytes at offset 134218240 | ||
1398 | 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1399 | 2048/2048 bytes allocated at offset 128 MiB | ||
1400 | -[{ "start": 0, "length": 134217728, "depth": 1, "present": false, "zero": true, "data": false}, | ||
1401 | -{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false}] | ||
1402 | +[{ "start": 0, "length": 134217728, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1403 | +{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}] | ||
1404 | Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT | ||
1405 | wrote 2048/2048 bytes at offset 134217728 | ||
1406 | 2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1407 | 2048/2048 bytes allocated at offset 128 MiB | ||
1408 | -[{ "start": 0, "length": 134217728, "depth": 1, "present": false, "zero": true, "data": false}, | ||
1409 | -{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false}] | ||
1410 | +[{ "start": 0, "length": 134217728, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1411 | +{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}] | ||
1412 | Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134218752 | ||
1413 | wrote 1024/1024 bytes at offset 134217728 | ||
1414 | 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1415 | @@ -XXX,XX +XXX,XX @@ read 512/512 bytes at offset 134217728 | ||
1416 | read 512/512 bytes at offset 134218240 | ||
1417 | 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1418 | 1024/1024 bytes allocated at offset 128 MiB | ||
1419 | -[{ "start": 0, "length": 134217728, "depth": 0, "present": false, "zero": true, "data": false}, | ||
1420 | -{ "start": 134217728, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}] | ||
1421 | +[{ "start": 0, "length": 134217728, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1422 | +{ "start": 134217728, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}] | ||
1423 | wrote 1024/1024 bytes at offset 134217728 | ||
1424 | 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1425 | 1024/1024 bytes allocated at offset 128 MiB | ||
1426 | read 1024/1024 bytes at offset 134217728 | ||
1427 | 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1428 | -[{ "start": 0, "length": 134217728, "depth": 0, "present": false, "zero": true, "data": false}, | ||
1429 | -{ "start": 134217728, "length": 1024, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET}] | ||
1430 | +[{ "start": 0, "length": 134217728, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1431 | +{ "start": 134217728, "length": 1024, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": OFFSET}] | ||
1432 | |||
1433 | == unaligned image tail cluster, allocation required == | ||
1434 | Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134218752 | ||
1435 | @@ -XXX,XX +XXX,XX @@ read 512/512 bytes at offset 134217728 | ||
1436 | 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1437 | read 1536/1536 bytes at offset 134218240 | ||
1438 | 1.500 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1439 | -[{ "start": 0, "length": 134217728, "depth": 1, "present": false, "zero": true, "data": false}, | ||
1440 | -{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}] | ||
1441 | +[{ "start": 0, "length": 134217728, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1442 | +{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}] | ||
1443 | Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134218752 | ||
1444 | Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT | ||
1445 | wrote 512/512 bytes at offset 134218240 | ||
1446 | @@ -XXX,XX +XXX,XX @@ read 512/512 bytes at offset 134218240 | ||
1447 | 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1448 | read 1024/1024 bytes at offset 134218752 | ||
1449 | 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1450 | -[{ "start": 0, "length": 134217728, "depth": 1, "present": false, "zero": true, "data": false}, | ||
1451 | -{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}] | ||
1452 | +[{ "start": 0, "length": 134217728, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1453 | +{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}] | ||
1454 | *** done | ||
1455 | diff --git a/tests/qemu-iotests/179.out b/tests/qemu-iotests/179.out | ||
1456 | index XXXXXXX..XXXXXXX 100644 | ||
1457 | --- a/tests/qemu-iotests/179.out | ||
1458 | +++ b/tests/qemu-iotests/179.out | ||
1459 | @@ -XXX,XX +XXX,XX @@ wrote 2097152/2097152 bytes at offset 6291456 | ||
1460 | 2 MiB (0x200000) bytes not allocated at offset 4 MiB (0x400000) | ||
1461 | 2 MiB (0x200000) bytes allocated at offset 6 MiB (0x600000) | ||
1462 | 56 MiB (0x3800000) bytes not allocated at offset 8 MiB (0x800000) | ||
1463 | -[{ "start": 0, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false}, | ||
1464 | -{ "start": 2097152, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false}, | ||
1465 | -{ "start": 4194304, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false}, | ||
1466 | -{ "start": 6291456, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false}, | ||
1467 | -{ "start": 8388608, "length": 58720256, "depth": 0, "present": false, "zero": true, "data": false}] | ||
1468 | +[{ "start": 0, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1469 | +{ "start": 2097152, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}, | ||
1470 | +{ "start": 4194304, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1471 | +{ "start": 6291456, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}, | ||
1472 | +{ "start": 8388608, "length": 58720256, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}] | ||
1473 | wrote 2097150/2097150 bytes at offset 10485761 | ||
1474 | 2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1475 | wrote 2097150/2097150 bytes at offset 14680065 | ||
1476 | @@ -XXX,XX +XXX,XX @@ wrote 2097150/2097150 bytes at offset 14680065 | ||
1477 | 2 MiB (0x200000) bytes not allocated at offset 12 MiB (0xc00000) | ||
1478 | 2 MiB (0x200000) bytes allocated at offset 14 MiB (0xe00000) | ||
1479 | 48 MiB (0x3000000) bytes not allocated at offset 16 MiB (0x1000000) | ||
1480 | -[{ "start": 0, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false}, | ||
1481 | -{ "start": 2097152, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false}, | ||
1482 | -{ "start": 4194304, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false}, | ||
1483 | -{ "start": 6291456, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false}, | ||
1484 | -{ "start": 8388608, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false}, | ||
1485 | -{ "start": 10485760, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false}, | ||
1486 | -{ "start": 12582912, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false}, | ||
1487 | -{ "start": 14680064, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false}, | ||
1488 | -{ "start": 16777216, "length": 50331648, "depth": 0, "present": false, "zero": true, "data": false}] | ||
1489 | +[{ "start": 0, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1490 | +{ "start": 2097152, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}, | ||
1491 | +{ "start": 4194304, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1492 | +{ "start": 6291456, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}, | ||
1493 | +{ "start": 8388608, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1494 | +{ "start": 10485760, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}, | ||
1495 | +{ "start": 12582912, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1496 | +{ "start": 14680064, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}, | ||
1497 | +{ "start": 16777216, "length": 50331648, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}] | ||
1498 | wrote 14680064/14680064 bytes at offset 18874368 | ||
1499 | 14 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1500 | wrote 2097152/2097152 bytes at offset 20971520 | ||
1501 | @@ -XXX,XX +XXX,XX @@ wrote 6291456/6291456 bytes at offset 25165824 | ||
1502 | 2 MiB (0x200000) bytes not allocated at offset 16 MiB (0x1000000) | ||
1503 | 14 MiB (0xe00000) bytes allocated at offset 18 MiB (0x1200000) | ||
1504 | 32 MiB (0x2000000) bytes not allocated at offset 32 MiB (0x2000000) | ||
1505 | -[{ "start": 0, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false}, | ||
1506 | -{ "start": 2097152, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false}, | ||
1507 | -{ "start": 4194304, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false}, | ||
1508 | -{ "start": 6291456, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false}, | ||
1509 | -{ "start": 8388608, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false}, | ||
1510 | -{ "start": 10485760, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false}, | ||
1511 | -{ "start": 12582912, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false}, | ||
1512 | -{ "start": 14680064, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false}, | ||
1513 | -{ "start": 16777216, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false}, | ||
1514 | -{ "start": 18874368, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
1515 | -{ "start": 20971520, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false}, | ||
1516 | -{ "start": 23068672, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
1517 | -{ "start": 25165824, "length": 6291456, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET}, | ||
1518 | -{ "start": 31457280, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
1519 | -{ "start": 33554432, "length": 33554432, "depth": 0, "present": false, "zero": true, "data": false}] | ||
1520 | +[{ "start": 0, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1521 | +{ "start": 2097152, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}, | ||
1522 | +{ "start": 4194304, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1523 | +{ "start": 6291456, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}, | ||
1524 | +{ "start": 8388608, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1525 | +{ "start": 10485760, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}, | ||
1526 | +{ "start": 12582912, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1527 | +{ "start": 14680064, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}, | ||
1528 | +{ "start": 16777216, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1529 | +{ "start": 18874368, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1530 | +{ "start": 20971520, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}, | ||
1531 | +{ "start": 23068672, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1532 | +{ "start": 25165824, "length": 6291456, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": OFFSET}, | ||
1533 | +{ "start": 31457280, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1534 | +{ "start": 33554432, "length": 33554432, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}] | ||
1535 | wrote 2097152/2097152 bytes at offset 27262976 | ||
1536 | 2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1537 | wrote 2097152/2097152 bytes at offset 29360128 | ||
1538 | @@ -XXX,XX +XXX,XX @@ wrote 2097152/2097152 bytes at offset 29360128 | ||
1539 | 2 MiB (0x200000) bytes not allocated at offset 16 MiB (0x1000000) | ||
1540 | 14 MiB (0xe00000) bytes allocated at offset 18 MiB (0x1200000) | ||
1541 | 32 MiB (0x2000000) bytes not allocated at offset 32 MiB (0x2000000) | ||
1542 | -[{ "start": 0, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false}, | ||
1543 | -{ "start": 2097152, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false}, | ||
1544 | -{ "start": 4194304, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false}, | ||
1545 | -{ "start": 6291456, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false}, | ||
1546 | -{ "start": 8388608, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false}, | ||
1547 | -{ "start": 10485760, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false}, | ||
1548 | -{ "start": 12582912, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false}, | ||
1549 | -{ "start": 14680064, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false}, | ||
1550 | -{ "start": 16777216, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false}, | ||
1551 | -{ "start": 18874368, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
1552 | -{ "start": 20971520, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false}, | ||
1553 | -{ "start": 23068672, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
1554 | -{ "start": 25165824, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET}, | ||
1555 | -{ "start": 27262976, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false}, | ||
1556 | -{ "start": 29360128, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET}, | ||
1557 | -{ "start": 31457280, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
1558 | -{ "start": 33554432, "length": 33554432, "depth": 0, "present": false, "zero": true, "data": false}] | ||
1559 | +[{ "start": 0, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1560 | +{ "start": 2097152, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}, | ||
1561 | +{ "start": 4194304, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1562 | +{ "start": 6291456, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}, | ||
1563 | +{ "start": 8388608, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1564 | +{ "start": 10485760, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}, | ||
1565 | +{ "start": 12582912, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1566 | +{ "start": 14680064, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}, | ||
1567 | +{ "start": 16777216, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1568 | +{ "start": 18874368, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1569 | +{ "start": 20971520, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}, | ||
1570 | +{ "start": 23068672, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1571 | +{ "start": 25165824, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": OFFSET}, | ||
1572 | +{ "start": 27262976, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}, | ||
1573 | +{ "start": 29360128, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": OFFSET}, | ||
1574 | +{ "start": 31457280, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1575 | +{ "start": 33554432, "length": 33554432, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}] | ||
1576 | wrote 8388608/8388608 bytes at offset 33554432 | ||
1577 | 8 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1578 | wrote 2097152/2097152 bytes at offset 35651584 | ||
1579 | @@ -XXX,XX +XXX,XX @@ wrote 2097152/2097152 bytes at offset 37748736 | ||
1580 | 2 MiB (0x200000) bytes not allocated at offset 16 MiB (0x1000000) | ||
1581 | 22 MiB (0x1600000) bytes allocated at offset 18 MiB (0x1200000) | ||
1582 | 24 MiB (0x1800000) bytes not allocated at offset 40 MiB (0x2800000) | ||
1583 | -[{ "start": 0, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false}, | ||
1584 | -{ "start": 2097152, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false}, | ||
1585 | -{ "start": 4194304, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false}, | ||
1586 | -{ "start": 6291456, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false}, | ||
1587 | -{ "start": 8388608, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false}, | ||
1588 | -{ "start": 10485760, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false}, | ||
1589 | -{ "start": 12582912, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false}, | ||
1590 | -{ "start": 14680064, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false}, | ||
1591 | -{ "start": 16777216, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false}, | ||
1592 | -{ "start": 18874368, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
1593 | -{ "start": 20971520, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false}, | ||
1594 | -{ "start": 23068672, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
1595 | -{ "start": 25165824, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET}, | ||
1596 | -{ "start": 27262976, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false}, | ||
1597 | -{ "start": 29360128, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET}, | ||
1598 | -{ "start": 31457280, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
1599 | -{ "start": 33554432, "length": 8388608, "depth": 0, "present": true, "zero": true, "data": false}, | ||
1600 | -{ "start": 41943040, "length": 25165824, "depth": 0, "present": false, "zero": true, "data": false}] | ||
1601 | +[{ "start": 0, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1602 | +{ "start": 2097152, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}, | ||
1603 | +{ "start": 4194304, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1604 | +{ "start": 6291456, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}, | ||
1605 | +{ "start": 8388608, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1606 | +{ "start": 10485760, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}, | ||
1607 | +{ "start": 12582912, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1608 | +{ "start": 14680064, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}, | ||
1609 | +{ "start": 16777216, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1610 | +{ "start": 18874368, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1611 | +{ "start": 20971520, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}, | ||
1612 | +{ "start": 23068672, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1613 | +{ "start": 25165824, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": OFFSET}, | ||
1614 | +{ "start": 27262976, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}, | ||
1615 | +{ "start": 29360128, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": OFFSET}, | ||
1616 | +{ "start": 31457280, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1617 | +{ "start": 33554432, "length": 8388608, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}, | ||
1618 | +{ "start": 41943040, "length": 25165824, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}] | ||
1619 | wrote 8388608/8388608 bytes at offset 41943040 | ||
1620 | 8 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1621 | wrote 8388608/8388608 bytes at offset 50331648 | ||
1622 | @@ -XXX,XX +XXX,XX @@ wrote 2097152/2097152 bytes at offset 62914560 | ||
1623 | 4 MiB (0x400000) bytes not allocated at offset 54 MiB (0x3600000) | ||
1624 | 4 MiB (0x400000) bytes allocated at offset 58 MiB (0x3a00000) | ||
1625 | 2 MiB (0x200000) bytes not allocated at offset 62 MiB (0x3e00000) | ||
1626 | -[{ "start": 0, "length": 2097152, "depth": 1, "present": false, "zero": true, "data": false}, | ||
1627 | -{ "start": 2097152, "length": 2097152, "depth": 1, "present": true, "zero": true, "data": false}, | ||
1628 | -{ "start": 4194304, "length": 2097152, "depth": 1, "present": false, "zero": true, "data": false}, | ||
1629 | -{ "start": 6291456, "length": 2097152, "depth": 1, "present": true, "zero": true, "data": false}, | ||
1630 | -{ "start": 8388608, "length": 2097152, "depth": 1, "present": false, "zero": true, "data": false}, | ||
1631 | -{ "start": 10485760, "length": 2097152, "depth": 1, "present": true, "zero": true, "data": false}, | ||
1632 | -{ "start": 12582912, "length": 2097152, "depth": 1, "present": false, "zero": true, "data": false}, | ||
1633 | -{ "start": 14680064, "length": 2097152, "depth": 1, "present": true, "zero": true, "data": false}, | ||
1634 | -{ "start": 16777216, "length": 2097152, "depth": 1, "present": false, "zero": true, "data": false}, | ||
1635 | -{ "start": 18874368, "length": 2097152, "depth": 1, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
1636 | -{ "start": 20971520, "length": 2097152, "depth": 1, "present": true, "zero": true, "data": false}, | ||
1637 | -{ "start": 23068672, "length": 2097152, "depth": 1, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
1638 | -{ "start": 25165824, "length": 2097152, "depth": 1, "present": true, "zero": true, "data": false, "offset": OFFSET}, | ||
1639 | -{ "start": 27262976, "length": 2097152, "depth": 1, "present": true, "zero": true, "data": false}, | ||
1640 | -{ "start": 29360128, "length": 2097152, "depth": 1, "present": true, "zero": true, "data": false, "offset": OFFSET}, | ||
1641 | -{ "start": 31457280, "length": 2097152, "depth": 1, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
1642 | -{ "start": 33554432, "length": 10485760, "depth": 1, "present": true, "zero": true, "data": false}, | ||
1643 | -{ "start": 44040192, "length": 4194304, "depth": 0, "present": true, "zero": true, "data": false}, | ||
1644 | -{ "start": 48234496, "length": 2097152, "depth": 1, "present": true, "zero": true, "data": false}, | ||
1645 | -{ "start": 50331648, "length": 2097152, "depth": 1, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
1646 | -{ "start": 52428800, "length": 4194304, "depth": 0, "present": true, "zero": true, "data": false}, | ||
1647 | -{ "start": 56623104, "length": 2097152, "depth": 1, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
1648 | -{ "start": 58720256, "length": 2097152, "depth": 1, "present": false, "zero": true, "data": false}, | ||
1649 | -{ "start": 60817408, "length": 4194304, "depth": 0, "present": true, "zero": true, "data": false}, | ||
1650 | -{ "start": 65011712, "length": 2097152, "depth": 1, "present": false, "zero": true, "data": false}] | ||
1651 | +[{ "start": 0, "length": 2097152, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1652 | +{ "start": 2097152, "length": 2097152, "depth": 1, "present": true, "zero": true, "data": false, "compressed": false}, | ||
1653 | +{ "start": 4194304, "length": 2097152, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1654 | +{ "start": 6291456, "length": 2097152, "depth": 1, "present": true, "zero": true, "data": false, "compressed": false}, | ||
1655 | +{ "start": 8388608, "length": 2097152, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1656 | +{ "start": 10485760, "length": 2097152, "depth": 1, "present": true, "zero": true, "data": false, "compressed": false}, | ||
1657 | +{ "start": 12582912, "length": 2097152, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1658 | +{ "start": 14680064, "length": 2097152, "depth": 1, "present": true, "zero": true, "data": false, "compressed": false}, | ||
1659 | +{ "start": 16777216, "length": 2097152, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1660 | +{ "start": 18874368, "length": 2097152, "depth": 1, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1661 | +{ "start": 20971520, "length": 2097152, "depth": 1, "present": true, "zero": true, "data": false, "compressed": false}, | ||
1662 | +{ "start": 23068672, "length": 2097152, "depth": 1, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1663 | +{ "start": 25165824, "length": 2097152, "depth": 1, "present": true, "zero": true, "data": false, "compressed": false, "offset": OFFSET}, | ||
1664 | +{ "start": 27262976, "length": 2097152, "depth": 1, "present": true, "zero": true, "data": false, "compressed": false}, | ||
1665 | +{ "start": 29360128, "length": 2097152, "depth": 1, "present": true, "zero": true, "data": false, "compressed": false, "offset": OFFSET}, | ||
1666 | +{ "start": 31457280, "length": 2097152, "depth": 1, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1667 | +{ "start": 33554432, "length": 10485760, "depth": 1, "present": true, "zero": true, "data": false, "compressed": false}, | ||
1668 | +{ "start": 44040192, "length": 4194304, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}, | ||
1669 | +{ "start": 48234496, "length": 2097152, "depth": 1, "present": true, "zero": true, "data": false, "compressed": false}, | ||
1670 | +{ "start": 50331648, "length": 2097152, "depth": 1, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1671 | +{ "start": 52428800, "length": 4194304, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}, | ||
1672 | +{ "start": 56623104, "length": 2097152, "depth": 1, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1673 | +{ "start": 58720256, "length": 2097152, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1674 | +{ "start": 60817408, "length": 4194304, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}, | ||
1675 | +{ "start": 65011712, "length": 2097152, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}] | ||
1676 | No errors were found on the image. | ||
1677 | No errors were found on the image. | ||
1678 | |||
1679 | diff --git a/tests/qemu-iotests/209.out b/tests/qemu-iotests/209.out | ||
1680 | index XXXXXXX..XXXXXXX 100644 | ||
1681 | --- a/tests/qemu-iotests/209.out | ||
1682 | +++ b/tests/qemu-iotests/209.out | ||
1683 | @@ -XXX,XX +XXX,XX @@ | ||
1684 | -[{ "start": 0, "length": 524288, "depth": 0, "present": true, "zero": false, "data": true, "offset": 0}, | ||
1685 | -{ "start": 524288, "length": 524288, "depth": 0, "present": true, "zero": true, "data": false, "offset": 524288}] | ||
1686 | +[{ "start": 0, "length": 524288, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": 0}, | ||
1687 | +{ "start": 524288, "length": 524288, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": 524288}] | ||
1688 | |||
1689 | done. | ||
1690 | diff --git a/tests/qemu-iotests/221.out b/tests/qemu-iotests/221.out | ||
1691 | index XXXXXXX..XXXXXXX 100644 | ||
1692 | --- a/tests/qemu-iotests/221.out | ||
1693 | +++ b/tests/qemu-iotests/221.out | ||
1694 | @@ -XXX,XX +XXX,XX @@ QA output created by 221 | ||
1695 | Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=65537 | ||
1696 | discard 65537/65537 bytes at offset 0 | ||
1697 | 64.001 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1698 | -[{ "start": 0, "length": 66048, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET}] | ||
1699 | -[{ "start": 0, "length": 66048, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET}] | ||
1700 | +[{ "start": 0, "length": 66048, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": OFFSET}] | ||
1701 | +[{ "start": 0, "length": 66048, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": OFFSET}] | ||
1702 | wrote 1/1 bytes at offset 65536 | ||
1703 | 1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1704 | -[{ "start": 0, "length": 65536, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET}, | ||
1705 | -{ "start": 65536, "length": 1, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
1706 | -{ "start": 65537, "length": 511, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET}] | ||
1707 | -[{ "start": 0, "length": 65536, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET}, | ||
1708 | -{ "start": 65536, "length": 1, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
1709 | -{ "start": 65537, "length": 511, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET}] | ||
1710 | +[{ "start": 0, "length": 65536, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": OFFSET}, | ||
1711 | +{ "start": 65536, "length": 1, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1712 | +{ "start": 65537, "length": 511, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": OFFSET}] | ||
1713 | +[{ "start": 0, "length": 65536, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": OFFSET}, | ||
1714 | +{ "start": 65536, "length": 1, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1715 | +{ "start": 65537, "length": 511, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": OFFSET}] | ||
1716 | *** done | ||
1717 | diff --git a/tests/qemu-iotests/223.out b/tests/qemu-iotests/223.out | ||
1718 | index XXXXXXX..XXXXXXX 100644 | ||
1719 | --- a/tests/qemu-iotests/223.out | ||
1720 | +++ b/tests/qemu-iotests/223.out | ||
1721 | @@ -XXX,XX +XXX,XX @@ read 1048576/1048576 bytes at offset 1048576 | ||
1722 | 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1723 | read 2097152/2097152 bytes at offset 2097152 | ||
1724 | 2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1725 | -[{ "start": 0, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
1726 | -{ "start": 4096, "length": 1044480, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET}, | ||
1727 | -{ "start": 1048576, "length": 3145728, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}] | ||
1728 | -[{ "start": 0, "length": 65536, "depth": 0, "present": false, "zero": false, "data": false}, | ||
1729 | -{ "start": 65536, "length": 2031616, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
1730 | -{ "start": 2097152, "length": 2097152, "depth": 0, "present": false, "zero": false, "data": false}] | ||
1731 | +[{ "start": 0, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1732 | +{ "start": 4096, "length": 1044480, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": OFFSET}, | ||
1733 | +{ "start": 1048576, "length": 3145728, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}] | ||
1734 | +[{ "start": 0, "length": 65536, "depth": 0, "present": false, "zero": false, "data": false, "compressed": false}, | ||
1735 | +{ "start": 65536, "length": 2031616, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1736 | +{ "start": 2097152, "length": 2097152, "depth": 0, "present": false, "zero": false, "data": false, "compressed": false}] | ||
1737 | |||
1738 | === Contrast to small granularity dirty-bitmap === | ||
1739 | |||
1740 | -[{ "start": 0, "length": 512, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
1741 | -{ "start": 512, "length": 512, "depth": 0, "present": false, "zero": false, "data": false}, | ||
1742 | -{ "start": 1024, "length": 2096128, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
1743 | -{ "start": 2097152, "length": 2097152, "depth": 0, "present": false, "zero": false, "data": false}] | ||
1744 | +[{ "start": 0, "length": 512, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1745 | +{ "start": 512, "length": 512, "depth": 0, "present": false, "zero": false, "data": false, "compressed": false}, | ||
1746 | +{ "start": 1024, "length": 2096128, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1747 | +{ "start": 2097152, "length": 2097152, "depth": 0, "present": false, "zero": false, "data": false, "compressed": false}] | ||
1748 | |||
1749 | === Check bitmap taken from another node === | ||
1750 | |||
1751 | -[{ "start": 0, "length": 4194304, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}] | ||
1752 | +[{ "start": 0, "length": 4194304, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}] | ||
1753 | |||
1754 | === End qemu NBD server === | ||
1755 | |||
1756 | @@ -XXX,XX +XXX,XX @@ read 1048576/1048576 bytes at offset 1048576 | ||
1757 | 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1758 | read 2097152/2097152 bytes at offset 2097152 | ||
1759 | 2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1760 | -[{ "start": 0, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
1761 | -{ "start": 4096, "length": 1044480, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET}, | ||
1762 | -{ "start": 1048576, "length": 3145728, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}] | ||
1763 | -[{ "start": 0, "length": 65536, "depth": 0, "present": false, "zero": false, "data": false}, | ||
1764 | -{ "start": 65536, "length": 2031616, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
1765 | -{ "start": 2097152, "length": 2097152, "depth": 0, "present": false, "zero": false, "data": false}] | ||
1766 | +[{ "start": 0, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1767 | +{ "start": 4096, "length": 1044480, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": OFFSET}, | ||
1768 | +{ "start": 1048576, "length": 3145728, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}] | ||
1769 | +[{ "start": 0, "length": 65536, "depth": 0, "present": false, "zero": false, "data": false, "compressed": false}, | ||
1770 | +{ "start": 65536, "length": 2031616, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1771 | +{ "start": 2097152, "length": 2097152, "depth": 0, "present": false, "zero": false, "data": false, "compressed": false}] | ||
1772 | |||
1773 | === Contrast to small granularity dirty-bitmap === | ||
1774 | |||
1775 | -[{ "start": 0, "length": 512, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
1776 | -{ "start": 512, "length": 512, "depth": 0, "present": false, "zero": false, "data": false}, | ||
1777 | -{ "start": 1024, "length": 2096128, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
1778 | -{ "start": 2097152, "length": 2097152, "depth": 0, "present": false, "zero": false, "data": false}] | ||
1779 | +[{ "start": 0, "length": 512, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1780 | +{ "start": 512, "length": 512, "depth": 0, "present": false, "zero": false, "data": false, "compressed": false}, | ||
1781 | +{ "start": 1024, "length": 2096128, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1782 | +{ "start": 2097152, "length": 2097152, "depth": 0, "present": false, "zero": false, "data": false, "compressed": false}] | ||
1783 | |||
1784 | === Check bitmap taken from another node === | ||
1785 | |||
1786 | -[{ "start": 0, "length": 4194304, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}] | ||
1787 | +[{ "start": 0, "length": 4194304, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}] | ||
1788 | |||
1789 | === End qemu NBD server === | ||
1790 | |||
1791 | @@ -XXX,XX +XXX,XX @@ read 2097152/2097152 bytes at offset 2097152 | ||
1792 | |||
1793 | === Use qemu-nbd as server === | ||
1794 | |||
1795 | -[{ "start": 0, "length": 65536, "depth": 0, "present": false, "zero": false, "data": false}, | ||
1796 | -{ "start": 65536, "length": 2031616, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
1797 | -{ "start": 2097152, "length": 2097152, "depth": 0, "present": false, "zero": false, "data": false}] | ||
1798 | -[{ "start": 0, "length": 512, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
1799 | -{ "start": 512, "length": 512, "depth": 0, "present": false, "zero": false, "data": false}, | ||
1800 | -{ "start": 1024, "length": 11321, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}] | ||
1801 | -[{ "start": 12345, "length": 2084807, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
1802 | -{ "start": 2097152, "length": 2097152, "depth": 0, "present": false, "zero": false, "data": false}] | ||
1803 | +[{ "start": 0, "length": 65536, "depth": 0, "present": false, "zero": false, "data": false, "compressed": false}, | ||
1804 | +{ "start": 65536, "length": 2031616, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1805 | +{ "start": 2097152, "length": 2097152, "depth": 0, "present": false, "zero": false, "data": false, "compressed": false}] | ||
1806 | +[{ "start": 0, "length": 512, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1807 | +{ "start": 512, "length": 512, "depth": 0, "present": false, "zero": false, "data": false, "compressed": false}, | ||
1808 | +{ "start": 1024, "length": 11321, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}] | ||
1809 | +[{ "start": 12345, "length": 2084807, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1810 | +{ "start": 2097152, "length": 2097152, "depth": 0, "present": false, "zero": false, "data": false, "compressed": false}] | ||
1811 | *** done | ||
1812 | diff --git a/tests/qemu-iotests/241.out b/tests/qemu-iotests/241.out | ||
1813 | index XXXXXXX..XXXXXXX 100644 | ||
1814 | --- a/tests/qemu-iotests/241.out | ||
1815 | +++ b/tests/qemu-iotests/241.out | ||
1816 | @@ -XXX,XX +XXX,XX @@ exports available: 1 | ||
1817 | export: '' | ||
1818 | size: 1024 | ||
1819 | min block: 1 | ||
1820 | -[{ "start": 0, "length": 1000, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
1821 | -{ "start": 1000, "length": 24, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET}] | ||
1822 | +[{ "start": 0, "length": 1000, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1823 | +{ "start": 1000, "length": 24, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": OFFSET}] | ||
1824 | 1 KiB (0x400) bytes allocated at offset 0 bytes (0x0) | ||
1825 | |||
1826 | === Exporting unaligned raw image, forced server sector alignment === | ||
1827 | @@ -XXX,XX +XXX,XX @@ exports available: 1 | ||
1828 | export: '' | ||
1829 | size: 1024 | ||
1830 | min block: 512 | ||
1831 | -[{ "start": 0, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}] | ||
1832 | +[{ "start": 0, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}] | ||
1833 | 1 KiB (0x400) bytes allocated at offset 0 bytes (0x0) | ||
1834 | WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw. | ||
1835 | Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. | ||
1836 | @@ -XXX,XX +XXX,XX @@ exports available: 1 | ||
1837 | export: '' | ||
1838 | size: 1024 | ||
1839 | min block: 1 | ||
1840 | -[{ "start": 0, "length": 1000, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
1841 | -{ "start": 1000, "length": 24, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET}] | ||
1842 | +[{ "start": 0, "length": 1000, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1843 | +{ "start": 1000, "length": 24, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": OFFSET}] | ||
1844 | 1 KiB (0x400) bytes allocated at offset 0 bytes (0x0) | ||
1845 | *** done | ||
1846 | diff --git a/tests/qemu-iotests/244.out b/tests/qemu-iotests/244.out | ||
1847 | index XXXXXXX..XXXXXXX 100644 | ||
1848 | --- a/tests/qemu-iotests/244.out | ||
1849 | +++ b/tests/qemu-iotests/244.out | ||
1850 | @@ -XXX,XX +XXX,XX @@ wrote 3145728/3145728 bytes at offset 3145728 | ||
1851 | 3 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1852 | No errors were found on the image. | ||
1853 | |||
1854 | -[{ "start": 0, "length": 1048576, "depth": 0, "present": false, "zero": true, "data": false}, | ||
1855 | -{ "start": 1048576, "length": 1048576, "depth": 0, "present": true, "zero": false, "data": true, "offset": 1048576}, | ||
1856 | -{ "start": 2097152, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false}, | ||
1857 | -{ "start": 4194304, "length": 1048576, "depth": 0, "present": true, "zero": true, "data": false, "offset": 4194304}, | ||
1858 | -{ "start": 5242880, "length": 1048576, "depth": 0, "present": true, "zero": true, "data": false}, | ||
1859 | -{ "start": 6291456, "length": 60817408, "depth": 0, "present": false, "zero": true, "data": false}] | ||
1860 | +[{ "start": 0, "length": 1048576, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1861 | +{ "start": 1048576, "length": 1048576, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": 1048576}, | ||
1862 | +{ "start": 2097152, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}, | ||
1863 | +{ "start": 4194304, "length": 1048576, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": 4194304}, | ||
1864 | +{ "start": 5242880, "length": 1048576, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}, | ||
1865 | +{ "start": 6291456, "length": 60817408, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}] | ||
1866 | |||
1867 | read 1048576/1048576 bytes at offset 0 | ||
1868 | 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1869 | @@ -XXX,XX +XXX,XX @@ wrote 3145728/3145728 bytes at offset 3145728 | ||
1870 | 3 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1871 | No errors were found on the image. | ||
1872 | |||
1873 | -[{ "start": 0, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": 0}, | ||
1874 | -{ "start": 2097152, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false}, | ||
1875 | -{ "start": 4194304, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "offset": 4194304}, | ||
1876 | -{ "start": 6291456, "length": 60817408, "depth": 0, "present": true, "zero": false, "data": true, "offset": 6291456}] | ||
1877 | +[{ "start": 0, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": 0}, | ||
1878 | +{ "start": 2097152, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}, | ||
1879 | +{ "start": 4194304, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": 4194304}, | ||
1880 | +{ "start": 6291456, "length": 60817408, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": 6291456}] | ||
1881 | |||
1882 | read 1048576/1048576 bytes at offset 0 | ||
1883 | 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1884 | @@ -XXX,XX +XXX,XX @@ read 1048576/1048576 bytes at offset 0 | ||
1885 | 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1886 | Offset Length Mapped to File | ||
1887 | 0 0x100000 0 TEST_DIR/t.qcow2.data | ||
1888 | -[{ "start": 0, "length": 1048576, "depth": 0, "present": true, "zero": false, "data": true, "offset": 0}, | ||
1889 | -{ "start": 1048576, "length": 66060288, "depth": 0, "present": false, "zero": true, "data": false}] | ||
1890 | +[{ "start": 0, "length": 1048576, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": 0}, | ||
1891 | +{ "start": 1048576, "length": 66060288, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}] | ||
1892 | |||
1893 | === Copy offloading === | ||
1894 | |||
1895 | diff --git a/tests/qemu-iotests/252.out b/tests/qemu-iotests/252.out | ||
1896 | index XXXXXXX..XXXXXXX 100644 | ||
1897 | --- a/tests/qemu-iotests/252.out | ||
1898 | +++ b/tests/qemu-iotests/252.out | ||
1899 | @@ -XXX,XX +XXX,XX @@ read 131072/131072 bytes at offset 131072 | ||
1900 | read 131072/131072 bytes at offset 262144 | ||
1901 | 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1902 | |||
1903 | -[{ "start": 0, "length": 262144, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
1904 | -{ "start": 262144, "length": 131072, "depth": 0, "present": false, "zero": true, "data": false}] | ||
1905 | +[{ "start": 0, "length": 262144, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1906 | +{ "start": 262144, "length": 131072, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}] | ||
1907 | |||
1908 | read 131072/131072 bytes at offset 0 | ||
1909 | 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1910 | @@ -XXX,XX +XXX,XX @@ read 131072/131072 bytes at offset 131072 | ||
1911 | read 131072/131072 bytes at offset 262144 | ||
1912 | 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1913 | |||
1914 | -[{ "start": 0, "length": 262144, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
1915 | -{ "start": 262144, "length": 65536, "depth": 0, "present": true, "zero": true, "data": false}, | ||
1916 | -{ "start": 327680, "length": 65536, "depth": 1, "present": false, "zero": true, "data": false}] | ||
1917 | +[{ "start": 0, "length": 262144, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1918 | +{ "start": 262144, "length": 65536, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}, | ||
1919 | +{ "start": 327680, "length": 65536, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}] | ||
1920 | *** done | ||
1921 | diff --git a/tests/qemu-iotests/253.out b/tests/qemu-iotests/253.out | ||
1922 | index XXXXXXX..XXXXXXX 100644 | ||
1923 | --- a/tests/qemu-iotests/253.out | ||
1924 | +++ b/tests/qemu-iotests/253.out | ||
1925 | @@ -XXX,XX +XXX,XX @@ QA output created by 253 | ||
1926 | === Check mapping of unaligned raw image === | ||
1927 | |||
1928 | Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048575 | ||
1929 | -[{ "start": 0, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
1930 | -{ "start": 4096, "length": 1044480, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET}] | ||
1931 | -[{ "start": 0, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
1932 | -{ "start": 4096, "length": 1044480, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET}] | ||
1933 | +[{ "start": 0, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1934 | +{ "start": 4096, "length": 1044480, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": OFFSET}] | ||
1935 | +[{ "start": 0, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1936 | +{ "start": 4096, "length": 1044480, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": OFFSET}] | ||
1937 | wrote 65535/65535 bytes at offset 983040 | ||
1938 | 63.999 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
1939 | -[{ "start": 0, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
1940 | -{ "start": 4096, "length": 978944, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET}, | ||
1941 | -{ "start": 983040, "length": 65536, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}] | ||
1942 | -[{ "start": 0, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
1943 | -{ "start": 4096, "length": 978944, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET}, | ||
1944 | -{ "start": 983040, "length": 65536, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}] | ||
1945 | +[{ "start": 0, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1946 | +{ "start": 4096, "length": 978944, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": OFFSET}, | ||
1947 | +{ "start": 983040, "length": 65536, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}] | ||
1948 | +[{ "start": 0, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
1949 | +{ "start": 4096, "length": 978944, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": OFFSET}, | ||
1950 | +{ "start": 983040, "length": 65536, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}] | ||
1951 | *** done | ||
1952 | diff --git a/tests/qemu-iotests/274.out b/tests/qemu-iotests/274.out | ||
1953 | index XXXXXXX..XXXXXXX 100644 | ||
1954 | --- a/tests/qemu-iotests/274.out | ||
1955 | +++ b/tests/qemu-iotests/274.out | ||
1956 | @@ -XXX,XX +XXX,XX @@ read 1048576/1048576 bytes at offset 1048576 | ||
1957 | 0/1048576 bytes allocated at offset 1 MiB | ||
1958 | |||
1959 | === Checking map === | ||
1960 | -[{ "start": 0, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": 327680}] | ||
1961 | +[{ "start": 0, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": 327680}] | ||
1962 | |||
1963 | Offset Length Mapped to File | ||
1964 | 0 0x200000 0x50000 TEST_DIR/PID-base | ||
1965 | |||
1966 | -[{ "start": 0, "length": 1048576, "depth": 1, "present": true, "zero": false, "data": true, "offset": 327680}] | ||
1967 | +[{ "start": 0, "length": 1048576, "depth": 1, "present": true, "zero": false, "data": true, "compressed": false, "offset": 327680}] | ||
1968 | |||
1969 | Offset Length Mapped to File | ||
1970 | 0 0x100000 0x50000 TEST_DIR/PID-base | ||
1971 | |||
1972 | -[{ "start": 0, "length": 1048576, "depth": 2, "present": true, "zero": false, "data": true, "offset": 327680}, | ||
1973 | -{ "start": 1048576, "length": 1048576, "depth": 0, "present": false, "zero": true, "data": false}] | ||
1974 | +[{ "start": 0, "length": 1048576, "depth": 2, "present": true, "zero": false, "data": true, "compressed": false, "offset": 327680}, | ||
1975 | +{ "start": 1048576, "length": 1048576, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}] | ||
1976 | |||
1977 | Offset Length Mapped to File | ||
1978 | 0 0x100000 0x50000 TEST_DIR/PID-base | ||
1979 | @@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 5368709120 | ||
1980 | 1 GiB (0x40000000) bytes not allocated at offset 0 bytes (0x0) | ||
1981 | 7 GiB (0x1c0000000) bytes allocated at offset 1 GiB (0x40000000) | ||
1982 | |||
1983 | -[{ "start": 0, "length": 1073741824, "depth": 1, "present": false, "zero": true, "data": false}, | ||
1984 | -{ "start": 1073741824, "length": 7516192768, "depth": 0, "present": true, "zero": true, "data": false}] | ||
1985 | +[{ "start": 0, "length": 1073741824, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}, | ||
1986 | +{ "start": 1073741824, "length": 7516192768, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}] | ||
1987 | |||
1988 | === preallocation=metadata === | ||
1989 | wrote 65536/65536 bytes at offset 33285996544 | ||
1990 | @@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 33285996544 | ||
1991 | 30 GiB (0x780000000) bytes not allocated at offset 0 bytes (0x0) | ||
1992 | 3 GiB (0xc0000000) bytes allocated at offset 30 GiB (0x780000000) | ||
1993 | |||
1994 | -[{ "start": 0, "length": 32212254720, "depth": 1, "present": false, "zero": true, "data": false}, | ||
1995 | -{ "start": 32212254720, "length": 536870912, "depth": 0, "present": true, "zero": true, "data": false, "offset": 327680}, | ||
1996 | -{ "start": 32749125632, "length": 536870912, "depth": 0, "present": true, "zero": true, "data": false, "offset": 537264128}, | ||
1997 | -{ "start": 33285996544, "length": 536870912, "depth": 0, "present": true, "zero": true, "data": false, "offset": 1074200576}, | ||
1998 | -{ "start": 33822867456, "length": 536870912, "depth": 0, "present": true, "zero": true, "data": false, "offset": 1611137024}, | ||
1999 | -{ "start": 34359738368, "length": 536870912, "depth": 0, "present": true, "zero": true, "data": false, "offset": 2148139008}, | ||
2000 | -{ "start": 34896609280, "length": 536870912, "depth": 0, "present": true, "zero": true, "data": false, "offset": 2685075456}] | ||
2001 | +[{ "start": 0, "length": 32212254720, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}, | ||
2002 | +{ "start": 32212254720, "length": 536870912, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": 327680}, | ||
2003 | +{ "start": 32749125632, "length": 536870912, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": 537264128}, | ||
2004 | +{ "start": 33285996544, "length": 536870912, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": 1074200576}, | ||
2005 | +{ "start": 33822867456, "length": 536870912, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": 1611137024}, | ||
2006 | +{ "start": 34359738368, "length": 536870912, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": 2148139008}, | ||
2007 | +{ "start": 34896609280, "length": 536870912, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": 2685075456}] | ||
2008 | |||
2009 | === preallocation=falloc === | ||
2010 | wrote 65536/65536 bytes at offset 9437184 | ||
2011 | @@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 9437184 | ||
2012 | 5 MiB (0x500000) bytes not allocated at offset 0 bytes (0x0) | ||
2013 | 10 MiB (0xa00000) bytes allocated at offset 5 MiB (0x500000) | ||
2014 | |||
2015 | -[{ "start": 0, "length": 5242880, "depth": 1, "present": false, "zero": true, "data": false}, | ||
2016 | -{ "start": 5242880, "length": 10485760, "depth": 0, "present": true, "zero": false, "data": true, "offset": 327680}] | ||
2017 | +[{ "start": 0, "length": 5242880, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}, | ||
2018 | +{ "start": 5242880, "length": 10485760, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": 327680}] | ||
2019 | |||
2020 | === preallocation=full === | ||
2021 | wrote 65536/65536 bytes at offset 11534336 | ||
2022 | @@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 11534336 | ||
2023 | 8 MiB (0x800000) bytes not allocated at offset 0 bytes (0x0) | ||
2024 | 4 MiB (0x400000) bytes allocated at offset 8 MiB (0x800000) | ||
2025 | |||
2026 | -[{ "start": 0, "length": 8388608, "depth": 1, "present": false, "zero": true, "data": false}, | ||
2027 | -{ "start": 8388608, "length": 4194304, "depth": 0, "present": true, "zero": false, "data": true, "offset": 327680}] | ||
2028 | +[{ "start": 0, "length": 8388608, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}, | ||
2029 | +{ "start": 8388608, "length": 4194304, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": 327680}] | ||
2030 | |||
2031 | === preallocation=off === | ||
2032 | wrote 65536/65536 bytes at offset 259072 | ||
2033 | @@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 259072 | ||
2034 | 192 KiB (0x30000) bytes not allocated at offset 0 bytes (0x0) | ||
2035 | 320 KiB (0x50000) bytes allocated at offset 192 KiB (0x30000) | ||
2036 | |||
2037 | -[{ "start": 0, "length": 196608, "depth": 1, "present": false, "zero": true, "data": false}, | ||
2038 | -{ "start": 196608, "length": 65536, "depth": 0, "present": true, "zero": false, "data": true, "offset": 327680}, | ||
2039 | -{ "start": 262144, "length": 262144, "depth": 0, "present": true, "zero": true, "data": false}] | ||
2040 | +[{ "start": 0, "length": 196608, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}, | ||
2041 | +{ "start": 196608, "length": 65536, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": 327680}, | ||
2042 | +{ "start": 262144, "length": 262144, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}] | ||
2043 | |||
2044 | === preallocation=off === | ||
2045 | wrote 65536/65536 bytes at offset 344064 | ||
2046 | @@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 344064 | ||
2047 | 256 KiB (0x40000) bytes not allocated at offset 0 bytes (0x0) | ||
2048 | 256 KiB (0x40000) bytes allocated at offset 256 KiB (0x40000) | ||
2049 | |||
2050 | -[{ "start": 0, "length": 262144, "depth": 1, "present": false, "zero": true, "data": false}, | ||
2051 | -{ "start": 262144, "length": 262144, "depth": 0, "present": true, "zero": true, "data": false}] | ||
2052 | +[{ "start": 0, "length": 262144, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}, | ||
2053 | +{ "start": 262144, "length": 262144, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}] | ||
2054 | |||
2055 | === preallocation=off === | ||
2056 | wrote 65536/65536 bytes at offset 446464 | ||
2057 | @@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 446464 | ||
2058 | 256 KiB (0x40000) bytes not allocated at offset 0 bytes (0x0) | ||
2059 | 244 KiB (0x3d000) bytes allocated at offset 256 KiB (0x40000) | ||
2060 | |||
2061 | -[{ "start": 0, "length": 262144, "depth": 1, "present": false, "zero": true, "data": false}, | ||
2062 | -{ "start": 262144, "length": 249856, "depth": 0, "present": true, "zero": true, "data": false}] | ||
2063 | +[{ "start": 0, "length": 262144, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}, | ||
2064 | +{ "start": 262144, "length": 249856, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}] | ||
2065 | |||
2066 | diff --git a/tests/qemu-iotests/tests/nbd-qemu-allocation.out b/tests/qemu-iotests/tests/nbd-qemu-allocation.out | ||
2067 | index XXXXXXX..XXXXXXX 100644 | ||
2068 | --- a/tests/qemu-iotests/tests/nbd-qemu-allocation.out | ||
2069 | +++ b/tests/qemu-iotests/tests/nbd-qemu-allocation.out | ||
2070 | @@ -XXX,XX +XXX,XX @@ wrote 2097152/2097152 bytes at offset 1048576 | ||
2071 | |||
2072 | === Check allocation over NBD === | ||
2073 | |||
2074 | -[{ "start": 0, "length": 1048576, "depth": 1, "present": true, "zero": false, "data": true, "offset": 327680}, | ||
2075 | -{ "start": 1048576, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": 327680}, | ||
2076 | -{ "start": 3145728, "length": 1048576, "depth": 1, "present": false, "zero": true, "data": false}] | ||
2077 | +[{ "start": 0, "length": 1048576, "depth": 1, "present": true, "zero": false, "data": true, "compressed": false, "offset": 327680}, | ||
2078 | +{ "start": 1048576, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": 327680}, | ||
2079 | +{ "start": 3145728, "length": 1048576, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}] | ||
2080 | exports available: 1 | ||
2081 | export: '' | ||
2082 | size: 4194304 | ||
2083 | @@ -XXX,XX +XXX,XX @@ exports available: 1 | ||
2084 | available meta contexts: 2 | ||
2085 | base:allocation | ||
2086 | qemu:allocation-depth | ||
2087 | -[{ "start": 0, "length": 3145728, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
2088 | -{ "start": 3145728, "length": 1048576, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET}] | ||
2089 | -[{ "start": 0, "length": 1048576, "depth": 0, "present": true, "zero": true, "data": true, "offset": OFFSET}, | ||
2090 | -{ "start": 1048576, "length": 2097152, "depth": 0, "present": false, "zero": false, "data": false}, | ||
2091 | -{ "start": 3145728, "length": 1048576, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}] | ||
2092 | +[{ "start": 0, "length": 3145728, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
2093 | +{ "start": 3145728, "length": 1048576, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": OFFSET}] | ||
2094 | +[{ "start": 0, "length": 1048576, "depth": 0, "present": true, "zero": true, "data": true, "compressed": false, "offset": OFFSET}, | ||
2095 | +{ "start": 1048576, "length": 2097152, "depth": 0, "present": false, "zero": false, "data": false, "compressed": false}, | ||
2096 | +{ "start": 3145728, "length": 1048576, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}] | ||
2097 | *** done | ||
2098 | diff --git a/tests/qemu-iotests/tests/qemu-img-bitmaps.out b/tests/qemu-iotests/tests/qemu-img-bitmaps.out | ||
2099 | index XXXXXXX..XXXXXXX 100644 | ||
2100 | --- a/tests/qemu-iotests/tests/qemu-img-bitmaps.out | ||
2101 | +++ b/tests/qemu-iotests/tests/qemu-img-bitmaps.out | ||
2102 | @@ -XXX,XX +XXX,XX @@ Format specific information: | ||
2103 | |||
2104 | === Check bitmap contents === | ||
2105 | |||
2106 | -[{ "start": 0, "length": 3145728, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
2107 | -{ "start": 3145728, "length": 1048576, "depth": 0, "present": false, "zero": false, "data": false}, | ||
2108 | -{ "start": 4194304, "length": 6291456, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}] | ||
2109 | -[{ "start": 0, "length": 1048576, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
2110 | -{ "start": 1048576, "length": 1048576, "depth": 0, "present": false, "zero": false, "data": false}, | ||
2111 | -{ "start": 2097152, "length": 8388608, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}] | ||
2112 | -[{ "start": 0, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
2113 | -{ "start": 2097152, "length": 1048576, "depth": 0, "present": false, "zero": false, "data": false}, | ||
2114 | -{ "start": 3145728, "length": 7340032, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}] | ||
2115 | -[{ "start": 0, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}, | ||
2116 | -{ "start": 2097152, "length": 1048576, "depth": 0, "present": false, "zero": false, "data": false}, | ||
2117 | -{ "start": 3145728, "length": 7340032, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}] | ||
2118 | +[{ "start": 0, "length": 3145728, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
2119 | +{ "start": 3145728, "length": 1048576, "depth": 0, "present": false, "zero": false, "data": false, "compressed": false}, | ||
2120 | +{ "start": 4194304, "length": 6291456, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}] | ||
2121 | +[{ "start": 0, "length": 1048576, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
2122 | +{ "start": 1048576, "length": 1048576, "depth": 0, "present": false, "zero": false, "data": false, "compressed": false}, | ||
2123 | +{ "start": 2097152, "length": 8388608, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}] | ||
2124 | +[{ "start": 0, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
2125 | +{ "start": 2097152, "length": 1048576, "depth": 0, "present": false, "zero": false, "data": false, "compressed": false}, | ||
2126 | +{ "start": 3145728, "length": 7340032, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}] | ||
2127 | +[{ "start": 0, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, | ||
2128 | +{ "start": 2097152, "length": 1048576, "depth": 0, "present": false, "zero": false, "data": false, "compressed": false}, | ||
2129 | +{ "start": 3145728, "length": 7340032, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}] | ||
2130 | |||
2131 | === Check handling of inconsistent bitmap === | ||
23 | 2132 | ||
24 | -- | 2133 | -- |
25 | 2.40.0 | 2134 | 2.41.0 | diff view generated by jsdifflib |
1 | From: Stefan Hajnoczi <stefanha@redhat.com> | 1 | From: Stefan Hajnoczi <stefanha@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | The main loop thread increments/decrements BlockBackend->quiesce_counter | 3 | The synchronous bdrv_aio_cancel() function needs the acb's AioContext so |
4 | when drained sections begin/end. The counter is read in the I/O code | 4 | it can call aio_poll() to wait for cancellation. |
5 | path. Therefore this field is used to communicate between threads | 5 | |
6 | without a lock. | 6 | It turns out that all users run under the BQL in the main AioContext, so |
7 | 7 | this callback is not needed. | |
8 | Acquire/release are not necessary because the BlockBackend->in_flight | 8 | |
9 | counter already uses sequentially consistent accesses and running I/O | 9 | Remove the callback, mark bdrv_aio_cancel() GLOBAL_STATE_CODE just like |
10 | requests hold that counter when blk_wait_while_drained() is called. | 10 | its blk_aio_cancel() caller, and poll the main loop AioContext. |
11 | qatomic_read() can be used. | 11 | |
12 | 12 | The purpose of this cleanup is to identify bdrv_aio_cancel() as an API | |
13 | Use qatomic_fetch_inc()/qatomic_fetch_dec() for modifications even | 13 | that does not work with the multi-queue block layer. |
14 | though sequentially consistent atomic accesses are not strictly required | ||
15 | here. They are, however, nicer to read than multiple calls to | ||
16 | qatomic_read() and qatomic_set(). Since beginning and ending drain is | ||
17 | not a hot path the extra cost doesn't matter. | ||
18 | 14 | ||
19 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> | 15 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> |
20 | Message-Id: <20230307210427.269214-2-stefanha@redhat.com> | 16 | Message-ID: <20230912231037.826804-2-stefanha@redhat.com> |
21 | Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> | ||
22 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | 17 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> |
18 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
19 | Reviewed-by: Klaus Jensen <k.jensen@samsung.com> | ||
23 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 20 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
24 | --- | 21 | --- |
25 | block/block-backend.c | 14 +++++++------- | 22 | include/block/aio.h | 1 - |
26 | 1 file changed, 7 insertions(+), 7 deletions(-) | 23 | include/block/block-global-state.h | 2 ++ |
27 | 24 | include/block/block-io.h | 1 - | |
25 | block/block-backend.c | 17 ----------------- | ||
26 | block/io.c | 23 ++++++++--------------- | ||
27 | hw/nvme/ctrl.c | 7 ------- | ||
28 | softmmu/dma-helpers.c | 8 -------- | ||
29 | util/thread-pool.c | 8 -------- | ||
30 | 8 files changed, 10 insertions(+), 57 deletions(-) | ||
31 | |||
32 | diff --git a/include/block/aio.h b/include/block/aio.h | ||
33 | index XXXXXXX..XXXXXXX 100644 | ||
34 | --- a/include/block/aio.h | ||
35 | +++ b/include/block/aio.h | ||
36 | @@ -XXX,XX +XXX,XX @@ typedef void BlockCompletionFunc(void *opaque, int ret); | ||
37 | |||
38 | typedef struct AIOCBInfo { | ||
39 | void (*cancel_async)(BlockAIOCB *acb); | ||
40 | - AioContext *(*get_aio_context)(BlockAIOCB *acb); | ||
41 | size_t aiocb_size; | ||
42 | } AIOCBInfo; | ||
43 | |||
44 | diff --git a/include/block/block-global-state.h b/include/block/block-global-state.h | ||
45 | index XXXXXXX..XXXXXXX 100644 | ||
46 | --- a/include/block/block-global-state.h | ||
47 | +++ b/include/block/block-global-state.h | ||
48 | @@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin_nopoll(void); | ||
49 | void bdrv_drain_all_end(void); | ||
50 | void bdrv_drain_all(void); | ||
51 | |||
52 | +void bdrv_aio_cancel(BlockAIOCB *acb); | ||
53 | + | ||
54 | int bdrv_has_zero_init_1(BlockDriverState *bs); | ||
55 | int bdrv_has_zero_init(BlockDriverState *bs); | ||
56 | BlockDriverState *bdrv_find_node(const char *node_name); | ||
57 | diff --git a/include/block/block-io.h b/include/block/block-io.h | ||
58 | index XXXXXXX..XXXXXXX 100644 | ||
59 | --- a/include/block/block-io.h | ||
60 | +++ b/include/block/block-io.h | ||
61 | @@ -XXX,XX +XXX,XX @@ bdrv_co_delete_file_noerr(BlockDriverState *bs); | ||
62 | |||
63 | |||
64 | /* async block I/O */ | ||
65 | -void bdrv_aio_cancel(BlockAIOCB *acb); | ||
66 | void bdrv_aio_cancel_async(BlockAIOCB *acb); | ||
67 | |||
68 | /* sg packet commands */ | ||
28 | diff --git a/block/block-backend.c b/block/block-backend.c | 69 | diff --git a/block/block-backend.c b/block/block-backend.c |
29 | index XXXXXXX..XXXXXXX 100644 | 70 | index XXXXXXX..XXXXXXX 100644 |
30 | --- a/block/block-backend.c | 71 | --- a/block/block-backend.c |
31 | +++ b/block/block-backend.c | 72 | +++ b/block/block-backend.c |
32 | @@ -XXX,XX +XXX,XX @@ struct BlockBackend { | 73 | @@ -XXX,XX +XXX,XX @@ |
33 | NotifierList remove_bs_notifiers, insert_bs_notifiers; | 74 | |
34 | QLIST_HEAD(, BlockBackendAioNotifier) aio_notifiers; | 75 | #define NOT_DONE 0x7fffffff /* used while emulated sync operation in progress */ |
35 | 76 | ||
36 | - int quiesce_counter; | 77 | -static AioContext *blk_aiocb_get_aio_context(BlockAIOCB *acb); |
37 | + int quiesce_counter; /* atomic: written under BQL, read by other threads */ | 78 | - |
38 | CoQueue queued_requests; | 79 | typedef struct BlockBackendAioNotifier { |
39 | bool disable_request_queuing; | 80 | void (*attached_aio_context)(AioContext *new_context, void *opaque); |
40 | 81 | void (*detach_aio_context)(void *opaque); | |
41 | @@ -XXX,XX +XXX,XX @@ void blk_set_dev_ops(BlockBackend *blk, const BlockDevOps *ops, | 82 | @@ -XXX,XX +XXX,XX @@ typedef struct BlockBackendAIOCB { |
42 | blk->dev_opaque = opaque; | 83 | } BlockBackendAIOCB; |
43 | 84 | ||
44 | /* Are we currently quiesced? Should we enforce this right now? */ | 85 | static const AIOCBInfo block_backend_aiocb_info = { |
45 | - if (blk->quiesce_counter && ops && ops->drained_begin) { | 86 | - .get_aio_context = blk_aiocb_get_aio_context, |
46 | + if (qatomic_read(&blk->quiesce_counter) && ops && ops->drained_begin) { | 87 | .aiocb_size = sizeof(BlockBackendAIOCB), |
47 | ops->drained_begin(opaque); | 88 | }; |
89 | |||
90 | @@ -XXX,XX +XXX,XX @@ typedef struct BlkAioEmAIOCB { | ||
91 | bool has_returned; | ||
92 | } BlkAioEmAIOCB; | ||
93 | |||
94 | -static AioContext *blk_aio_em_aiocb_get_aio_context(BlockAIOCB *acb_) | ||
95 | -{ | ||
96 | - BlkAioEmAIOCB *acb = container_of(acb_, BlkAioEmAIOCB, common); | ||
97 | - | ||
98 | - return blk_get_aio_context(acb->rwco.blk); | ||
99 | -} | ||
100 | - | ||
101 | static const AIOCBInfo blk_aio_em_aiocb_info = { | ||
102 | .aiocb_size = sizeof(BlkAioEmAIOCB), | ||
103 | - .get_aio_context = blk_aio_em_aiocb_get_aio_context, | ||
104 | }; | ||
105 | |||
106 | static void blk_aio_complete(BlkAioEmAIOCB *acb) | ||
107 | @@ -XXX,XX +XXX,XX @@ AioContext *blk_get_aio_context(BlockBackend *blk) | ||
108 | return blk->ctx; | ||
109 | } | ||
110 | |||
111 | -static AioContext *blk_aiocb_get_aio_context(BlockAIOCB *acb) | ||
112 | -{ | ||
113 | - BlockBackendAIOCB *blk_acb = DO_UPCAST(BlockBackendAIOCB, common, acb); | ||
114 | - return blk_get_aio_context(blk_acb->blk); | ||
115 | -} | ||
116 | - | ||
117 | int blk_set_aio_context(BlockBackend *blk, AioContext *new_context, | ||
118 | Error **errp) | ||
119 | { | ||
120 | diff --git a/block/io.c b/block/io.c | ||
121 | index XXXXXXX..XXXXXXX 100644 | ||
122 | --- a/block/io.c | ||
123 | +++ b/block/io.c | ||
124 | @@ -XXX,XX +XXX,XX @@ int bdrv_load_vmstate(BlockDriverState *bs, uint8_t *buf, | ||
125 | /**************************************************************/ | ||
126 | /* async I/Os */ | ||
127 | |||
128 | +/** | ||
129 | + * Synchronously cancels an acb. Must be called with the BQL held and the acb | ||
130 | + * must be processed with the BQL held too (IOThreads are not allowed). | ||
131 | + * | ||
132 | + * Use bdrv_aio_cancel_async() instead when possible. | ||
133 | + */ | ||
134 | void bdrv_aio_cancel(BlockAIOCB *acb) | ||
135 | { | ||
136 | - IO_CODE(); | ||
137 | + GLOBAL_STATE_CODE(); | ||
138 | qemu_aio_ref(acb); | ||
139 | bdrv_aio_cancel_async(acb); | ||
140 | - while (acb->refcnt > 1) { | ||
141 | - if (acb->aiocb_info->get_aio_context) { | ||
142 | - aio_poll(acb->aiocb_info->get_aio_context(acb), true); | ||
143 | - } else if (acb->bs) { | ||
144 | - /* qemu_aio_ref and qemu_aio_unref are not thread-safe, so | ||
145 | - * assert that we're not using an I/O thread. Thread-safe | ||
146 | - * code should use bdrv_aio_cancel_async exclusively. | ||
147 | - */ | ||
148 | - assert(bdrv_get_aio_context(acb->bs) == qemu_get_aio_context()); | ||
149 | - aio_poll(bdrv_get_aio_context(acb->bs), true); | ||
150 | - } else { | ||
151 | - abort(); | ||
152 | - } | ||
153 | - } | ||
154 | + AIO_WAIT_WHILE_UNLOCKED(NULL, acb->refcnt > 1); | ||
155 | qemu_aio_unref(acb); | ||
156 | } | ||
157 | |||
158 | diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c | ||
159 | index XXXXXXX..XXXXXXX 100644 | ||
160 | --- a/hw/nvme/ctrl.c | ||
161 | +++ b/hw/nvme/ctrl.c | ||
162 | @@ -XXX,XX +XXX,XX @@ static inline bool nvme_is_write(NvmeRequest *req) | ||
163 | rw->opcode == NVME_CMD_WRITE_ZEROES; | ||
164 | } | ||
165 | |||
166 | -static AioContext *nvme_get_aio_context(BlockAIOCB *acb) | ||
167 | -{ | ||
168 | - return qemu_get_aio_context(); | ||
169 | -} | ||
170 | - | ||
171 | static void nvme_misc_cb(void *opaque, int ret) | ||
172 | { | ||
173 | NvmeRequest *req = opaque; | ||
174 | @@ -XXX,XX +XXX,XX @@ static void nvme_flush_cancel(BlockAIOCB *acb) | ||
175 | static const AIOCBInfo nvme_flush_aiocb_info = { | ||
176 | .aiocb_size = sizeof(NvmeFlushAIOCB), | ||
177 | .cancel_async = nvme_flush_cancel, | ||
178 | - .get_aio_context = nvme_get_aio_context, | ||
179 | }; | ||
180 | |||
181 | static void nvme_do_flush(NvmeFlushAIOCB *iocb); | ||
182 | @@ -XXX,XX +XXX,XX @@ static void nvme_format_cancel(BlockAIOCB *aiocb) | ||
183 | static const AIOCBInfo nvme_format_aiocb_info = { | ||
184 | .aiocb_size = sizeof(NvmeFormatAIOCB), | ||
185 | .cancel_async = nvme_format_cancel, | ||
186 | - .get_aio_context = nvme_get_aio_context, | ||
187 | }; | ||
188 | |||
189 | static void nvme_format_set(NvmeNamespace *ns, uint8_t lbaf, uint8_t mset, | ||
190 | diff --git a/softmmu/dma-helpers.c b/softmmu/dma-helpers.c | ||
191 | index XXXXXXX..XXXXXXX 100644 | ||
192 | --- a/softmmu/dma-helpers.c | ||
193 | +++ b/softmmu/dma-helpers.c | ||
194 | @@ -XXX,XX +XXX,XX @@ static void dma_aio_cancel(BlockAIOCB *acb) | ||
48 | } | 195 | } |
49 | } | 196 | } |
50 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn blk_wait_while_drained(BlockBackend *blk) | 197 | |
51 | { | 198 | -static AioContext *dma_get_aio_context(BlockAIOCB *acb) |
52 | assert(blk->in_flight > 0); | 199 | -{ |
53 | 200 | - DMAAIOCB *dbs = container_of(acb, DMAAIOCB, common); | |
54 | - if (blk->quiesce_counter && !blk->disable_request_queuing) { | 201 | - |
55 | + if (qatomic_read(&blk->quiesce_counter) && !blk->disable_request_queuing) { | 202 | - return dbs->ctx; |
56 | blk_dec_in_flight(blk); | 203 | -} |
57 | qemu_co_queue_wait(&blk->queued_requests, NULL); | 204 | - |
58 | blk_inc_in_flight(blk); | 205 | static const AIOCBInfo dma_aiocb_info = { |
59 | @@ -XXX,XX +XXX,XX @@ static void blk_root_drained_begin(BdrvChild *child) | 206 | .aiocb_size = sizeof(DMAAIOCB), |
60 | BlockBackend *blk = child->opaque; | 207 | .cancel_async = dma_aio_cancel, |
61 | ThrottleGroupMember *tgm = &blk->public.throttle_group_member; | 208 | - .get_aio_context = dma_get_aio_context, |
62 | 209 | }; | |
63 | - if (++blk->quiesce_counter == 1) { | 210 | |
64 | + if (qatomic_fetch_inc(&blk->quiesce_counter) == 0) { | 211 | BlockAIOCB *dma_blk_io(AioContext *ctx, |
65 | if (blk->dev_ops && blk->dev_ops->drained_begin) { | 212 | diff --git a/util/thread-pool.c b/util/thread-pool.c |
66 | blk->dev_ops->drained_begin(blk->dev_opaque); | 213 | index XXXXXXX..XXXXXXX 100644 |
67 | } | 214 | --- a/util/thread-pool.c |
68 | @@ -XXX,XX +XXX,XX @@ static bool blk_root_drained_poll(BdrvChild *child) | 215 | +++ b/util/thread-pool.c |
69 | { | 216 | @@ -XXX,XX +XXX,XX @@ static void thread_pool_cancel(BlockAIOCB *acb) |
70 | BlockBackend *blk = child->opaque; | 217 | |
71 | bool busy = false; | 218 | } |
72 | - assert(blk->quiesce_counter); | 219 | |
73 | + assert(qatomic_read(&blk->quiesce_counter)); | 220 | -static AioContext *thread_pool_get_aio_context(BlockAIOCB *acb) |
74 | 221 | -{ | |
75 | if (blk->dev_ops && blk->dev_ops->drained_poll) { | 222 | - ThreadPoolElement *elem = (ThreadPoolElement *)acb; |
76 | busy = blk->dev_ops->drained_poll(blk->dev_opaque); | 223 | - ThreadPool *pool = elem->pool; |
77 | @@ -XXX,XX +XXX,XX @@ static bool blk_root_drained_poll(BdrvChild *child) | 224 | - return pool->ctx; |
78 | static void blk_root_drained_end(BdrvChild *child) | 225 | -} |
79 | { | 226 | - |
80 | BlockBackend *blk = child->opaque; | 227 | static const AIOCBInfo thread_pool_aiocb_info = { |
81 | - assert(blk->quiesce_counter); | 228 | .aiocb_size = sizeof(ThreadPoolElement), |
82 | + assert(qatomic_read(&blk->quiesce_counter)); | 229 | .cancel_async = thread_pool_cancel, |
83 | 230 | - .get_aio_context = thread_pool_get_aio_context, | |
84 | assert(blk->public.throttle_group_member.io_limits_disabled); | 231 | }; |
85 | qatomic_dec(&blk->public.throttle_group_member.io_limits_disabled); | 232 | |
86 | 233 | BlockAIOCB *thread_pool_submit_aio(ThreadPoolFunc *func, void *arg, | |
87 | - if (--blk->quiesce_counter == 0) { | ||
88 | + if (qatomic_fetch_dec(&blk->quiesce_counter) == 1) { | ||
89 | if (blk->dev_ops && blk->dev_ops->drained_end) { | ||
90 | blk->dev_ops->drained_end(blk->dev_opaque); | ||
91 | } | ||
92 | -- | 234 | -- |
93 | 2.40.0 | 235 | 2.41.0 |
94 | |||
95 | diff view generated by jsdifflib |
1 | From: Stefan Hajnoczi <stefanha@redhat.com> | 1 | From: Stefan Hajnoczi <stefanha@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | This field is accessed by multiple threads without a lock. Use explicit | 3 | This patch fixes a race condition in test-bdrv-drain that is difficult |
4 | qatomic_read()/qatomic_set() calls. There is no need for acquire/release | 4 | to reproduce. test-bdrv-drain sometimes fails without an error message |
5 | because blk_set_disable_request_queuing() doesn't provide any | 5 | on the block pull request sent by Kevin Wolf on Sep 4, 2023. I was able |
6 | guarantees (it helps that it's used at BlockBackend creation time and | 6 | to reproduce it locally and found that "block-backend: process I/O in |
7 | not when there is I/O in flight). | 7 | the current AioContext" (in this patch series) is the first commit where |
8 | it reproduces. | ||
9 | |||
10 | I do not know why "block-backend: process I/O in the current AioContext" | ||
11 | exposes this bug. It might be related to the fact that the test's preadv | ||
12 | request runs in the main thread instead of IOThread a after my commit. | ||
13 | That might simply change the timing of the test. | ||
14 | |||
15 | Now on to the race condition in test-bdrv-drain. The main thread | ||
16 | schedules a BH in IOThread a and then drains the BDS: | ||
17 | |||
18 | aio_bh_schedule_oneshot(ctx_a, test_iothread_main_thread_bh, &data); | ||
19 | |||
20 | /* The request is running on the IOThread a. Draining its block device | ||
21 | * will make sure that it has completed as far as the BDS is concerned, | ||
22 | * but the drain in this thread can continue immediately after | ||
23 | * bdrv_dec_in_flight() and aio_ret might be assigned only slightly | ||
24 | * later. */ | ||
25 | do_drain_begin(drain_type, bs); | ||
26 | |||
27 | If the BH completes before do_drain_begin() then there is nothing to | ||
28 | worry about. | ||
29 | |||
30 | If the BH invokes bdrv_flush() before do_drain_begin(), then | ||
31 | do_drain_begin() waits for it to complete. | ||
32 | |||
33 | The problematic case is when do_drain_begin() runs before the BH enters | ||
34 | bdrv_flush(). Then do_drain_begin() misses the BH and the drain | ||
35 | mechanism has failed in quiescing I/O. | ||
36 | |||
37 | Fix this by incrementing the in_flight counter so that do_drain_begin() | ||
38 | waits for test_iothread_main_thread_bh(). | ||
8 | 39 | ||
9 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> | 40 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> |
10 | Reviewed-by: Hanna Czenczek <hreitz@redhat.com> | 41 | Message-ID: <20230912231037.826804-3-stefanha@redhat.com> |
11 | Message-Id: <20230307210427.269214-3-stefanha@redhat.com> | 42 | Reviewed-by: Eric Blake <eblake@redhat.com> |
12 | Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> | ||
13 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | 43 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> |
14 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 44 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
15 | --- | 45 | --- |
16 | block/block-backend.c | 7 ++++--- | 46 | tests/unit/test-bdrv-drain.c | 8 ++++++++ |
17 | 1 file changed, 4 insertions(+), 3 deletions(-) | 47 | 1 file changed, 8 insertions(+) |
18 | 48 | ||
19 | diff --git a/block/block-backend.c b/block/block-backend.c | 49 | diff --git a/tests/unit/test-bdrv-drain.c b/tests/unit/test-bdrv-drain.c |
20 | index XXXXXXX..XXXXXXX 100644 | 50 | index XXXXXXX..XXXXXXX 100644 |
21 | --- a/block/block-backend.c | 51 | --- a/tests/unit/test-bdrv-drain.c |
22 | +++ b/block/block-backend.c | 52 | +++ b/tests/unit/test-bdrv-drain.c |
23 | @@ -XXX,XX +XXX,XX @@ struct BlockBackend { | 53 | @@ -XXX,XX +XXX,XX @@ static void test_iothread_main_thread_bh(void *opaque) |
24 | 54 | * executed during drain, otherwise this would deadlock. */ | |
25 | int quiesce_counter; /* atomic: written under BQL, read by other threads */ | 55 | aio_context_acquire(bdrv_get_aio_context(data->bs)); |
26 | CoQueue queued_requests; | 56 | bdrv_flush(data->bs); |
27 | - bool disable_request_queuing; | 57 | + bdrv_dec_in_flight(data->bs); /* incremented by test_iothread_common() */ |
28 | + bool disable_request_queuing; /* atomic */ | 58 | aio_context_release(bdrv_get_aio_context(data->bs)); |
29 | |||
30 | VMChangeStateEntry *vmsh; | ||
31 | bool force_allow_inactivate; | ||
32 | @@ -XXX,XX +XXX,XX @@ void blk_set_allow_aio_context_change(BlockBackend *blk, bool allow) | ||
33 | void blk_set_disable_request_queuing(BlockBackend *blk, bool disable) | ||
34 | { | ||
35 | IO_CODE(); | ||
36 | - blk->disable_request_queuing = disable; | ||
37 | + qatomic_set(&blk->disable_request_queuing, disable); | ||
38 | } | 59 | } |
39 | 60 | ||
40 | static int coroutine_fn GRAPH_RDLOCK | 61 | @@ -XXX,XX +XXX,XX @@ static void test_iothread_common(enum drain_type drain_type, int drain_thread) |
41 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn blk_wait_while_drained(BlockBackend *blk) | 62 | aio_context_acquire(ctx_a); |
42 | { | 63 | } |
43 | assert(blk->in_flight > 0); | 64 | |
44 | 65 | + /* | |
45 | - if (qatomic_read(&blk->quiesce_counter) && !blk->disable_request_queuing) { | 66 | + * Increment in_flight so that do_drain_begin() waits for |
46 | + if (qatomic_read(&blk->quiesce_counter) && | 67 | + * test_iothread_main_thread_bh(). This prevents the race between |
47 | + !qatomic_read(&blk->disable_request_queuing)) { | 68 | + * test_iothread_main_thread_bh() in IOThread a and do_drain_begin() in |
48 | blk_dec_in_flight(blk); | 69 | + * this thread. test_iothread_main_thread_bh() decrements in_flight. |
49 | qemu_co_queue_wait(&blk->queued_requests, NULL); | 70 | + */ |
50 | blk_inc_in_flight(blk); | 71 | + bdrv_inc_in_flight(bs); |
72 | aio_bh_schedule_oneshot(ctx_a, test_iothread_main_thread_bh, &data); | ||
73 | |||
74 | /* The request is running on the IOThread a. Draining its block device | ||
51 | -- | 75 | -- |
52 | 2.40.0 | 76 | 2.41.0 |
53 | |||
54 | diff view generated by jsdifflib |
1 | From: Stefan Hajnoczi <stefanha@redhat.com> | 1 | From: Stefan Hajnoczi <stefanha@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | There is no need for the AioContext lock in bdrv_drain_all() because | 3 | Switch blk_aio_*() APIs over to multi-queue by using |
4 | nothing in AIO_WAIT_WHILE() needs the lock and the condition is atomic. | 4 | qemu_get_current_aio_context() instead of blk_get_aio_context(). This |
5 | change will allow devices to process I/O in multiple IOThreads in the | ||
6 | future. | ||
5 | 7 | ||
6 | AIO_WAIT_WHILE_UNLOCKED() has no use for the AioContext parameter other | 8 | I audited existing blk_aio_*() callers: |
7 | than performing a check that is nowadays already done by the | 9 | - migration/block.c: blk_mig_lock() protects the data accessed by the |
8 | GLOBAL_STATE_CODE()/IO_CODE() macros. Set the ctx argument to NULL here | 10 | completion callback. |
9 | to help us keep track of all converted callers. Eventually all callers | 11 | - The remaining emulated devices and exports run with |
10 | will have been converted and then the argument can be dropped entirely. | 12 | qemu_get_aio_context() == blk_get_aio_context(). |
11 | 13 | ||
14 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
15 | Message-ID: <20230912231037.826804-4-stefanha@redhat.com> | ||
12 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | 16 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> |
13 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> | 17 | Reviewed-by: Eric Blake <eblake@redhat.com> |
14 | Message-Id: <20230309190855.414275-2-stefanha@redhat.com> | ||
15 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
16 | Reviewed-by: Wilfred Mallawa <wilfred.mallawa@wdc.com> | ||
17 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 18 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
18 | --- | 19 | --- |
19 | block/block-backend.c | 8 +------- | 20 | block/block-backend.c | 6 +++--- |
20 | 1 file changed, 1 insertion(+), 7 deletions(-) | 21 | 1 file changed, 3 insertions(+), 3 deletions(-) |
21 | 22 | ||
22 | diff --git a/block/block-backend.c b/block/block-backend.c | 23 | diff --git a/block/block-backend.c b/block/block-backend.c |
23 | index XXXXXXX..XXXXXXX 100644 | 24 | index XXXXXXX..XXXXXXX 100644 |
24 | --- a/block/block-backend.c | 25 | --- a/block/block-backend.c |
25 | +++ b/block/block-backend.c | 26 | +++ b/block/block-backend.c |
26 | @@ -XXX,XX +XXX,XX @@ void blk_drain_all(void) | 27 | @@ -XXX,XX +XXX,XX @@ BlockAIOCB *blk_abort_aio_request(BlockBackend *blk, |
27 | bdrv_drain_all_begin(); | 28 | acb->blk = blk; |
28 | 29 | acb->ret = ret; | |
29 | while ((blk = blk_all_next(blk)) != NULL) { | 30 | |
30 | - AioContext *ctx = blk_get_aio_context(blk); | 31 | - replay_bh_schedule_oneshot_event(blk_get_aio_context(blk), |
31 | - | 32 | + replay_bh_schedule_oneshot_event(qemu_get_current_aio_context(), |
32 | - aio_context_acquire(ctx); | 33 | error_callback_bh, acb); |
33 | - | 34 | return &acb->common; |
34 | /* We may have -ENOMEDIUM completions in flight */ | 35 | } |
35 | - AIO_WAIT_WHILE(ctx, qatomic_read(&blk->in_flight) > 0); | 36 | @@ -XXX,XX +XXX,XX @@ static BlockAIOCB *blk_aio_prwv(BlockBackend *blk, int64_t offset, |
36 | - | 37 | acb->has_returned = false; |
37 | - aio_context_release(ctx); | 38 | |
38 | + AIO_WAIT_WHILE_UNLOCKED(NULL, qatomic_read(&blk->in_flight) > 0); | 39 | co = qemu_coroutine_create(co_entry, acb); |
40 | - aio_co_enter(blk_get_aio_context(blk), co); | ||
41 | + aio_co_enter(qemu_get_current_aio_context(), co); | ||
42 | |||
43 | acb->has_returned = true; | ||
44 | if (acb->rwco.ret != NOT_DONE) { | ||
45 | - replay_bh_schedule_oneshot_event(blk_get_aio_context(blk), | ||
46 | + replay_bh_schedule_oneshot_event(qemu_get_current_aio_context(), | ||
47 | blk_aio_complete_bh, acb); | ||
39 | } | 48 | } |
40 | 49 | ||
41 | bdrv_drain_all_end(); | ||
42 | -- | 50 | -- |
43 | 2.40.0 | 51 | 2.41.0 | diff view generated by jsdifflib |
1 | From: Stefan Hajnoczi <stefanha@redhat.com> | 1 | From: Stefan Hajnoczi <stefanha@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | The CoQueue API offers thread-safety via the lock argument that | 3 | Process zoned requests in the current thread's AioContext instead of in |
4 | qemu_co_queue_wait() and qemu_co_enter_next() take. BlockBackend | 4 | the BlockBackend's AioContext. |
5 | currently does not make use of the lock argument. This means that | ||
6 | multiple threads submitting I/O requests can corrupt the CoQueue's | ||
7 | QSIMPLEQ. | ||
8 | 5 | ||
9 | Add a QemuMutex and pass it to CoQueue APIs so that the queue is | 6 | There is no need to use the BlockBackend's AioContext thanks to CoMutex |
10 | protected. While we're at it, also assert that the queue is empty when | 7 | bs->wps->colock, which protects zone metadata. |
11 | the BlockBackend is deleted. | ||
12 | 8 | ||
13 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> | 9 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> |
14 | Reviewed-by: Hanna Czenczek <hreitz@redhat.com> | 10 | Message-ID: <20230912231037.826804-5-stefanha@redhat.com> |
15 | Message-Id: <20230307210427.269214-4-stefanha@redhat.com> | ||
16 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | 11 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> |
12 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
17 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 13 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
18 | --- | 14 | --- |
19 | block/block-backend.c | 18 ++++++++++++++++-- | 15 | block/block-backend.c | 12 ++++++------ |
20 | 1 file changed, 16 insertions(+), 2 deletions(-) | 16 | 1 file changed, 6 insertions(+), 6 deletions(-) |
21 | 17 | ||
22 | diff --git a/block/block-backend.c b/block/block-backend.c | 18 | diff --git a/block/block-backend.c b/block/block-backend.c |
23 | index XXXXXXX..XXXXXXX 100644 | 19 | index XXXXXXX..XXXXXXX 100644 |
24 | --- a/block/block-backend.c | 20 | --- a/block/block-backend.c |
25 | +++ b/block/block-backend.c | 21 | +++ b/block/block-backend.c |
26 | @@ -XXX,XX +XXX,XX @@ struct BlockBackend { | 22 | @@ -XXX,XX +XXX,XX @@ BlockAIOCB *blk_aio_zone_report(BlockBackend *blk, int64_t offset, |
27 | QLIST_HEAD(, BlockBackendAioNotifier) aio_notifiers; | 23 | acb->has_returned = false; |
28 | 24 | ||
29 | int quiesce_counter; /* atomic: written under BQL, read by other threads */ | 25 | co = qemu_coroutine_create(blk_aio_zone_report_entry, acb); |
30 | + QemuMutex queued_requests_lock; /* protects queued_requests */ | 26 | - aio_co_enter(blk_get_aio_context(blk), co); |
31 | CoQueue queued_requests; | 27 | + aio_co_enter(qemu_get_current_aio_context(), co); |
32 | bool disable_request_queuing; /* atomic */ | 28 | |
33 | 29 | acb->has_returned = true; | |
34 | @@ -XXX,XX +XXX,XX @@ BlockBackend *blk_new(AioContext *ctx, uint64_t perm, uint64_t shared_perm) | 30 | if (acb->rwco.ret != NOT_DONE) { |
35 | 31 | - replay_bh_schedule_oneshot_event(blk_get_aio_context(blk), | |
36 | block_acct_init(&blk->stats); | 32 | + replay_bh_schedule_oneshot_event(qemu_get_current_aio_context(), |
37 | 33 | blk_aio_complete_bh, acb); | |
38 | + qemu_mutex_init(&blk->queued_requests_lock); | ||
39 | qemu_co_queue_init(&blk->queued_requests); | ||
40 | notifier_list_init(&blk->remove_bs_notifiers); | ||
41 | notifier_list_init(&blk->insert_bs_notifiers); | ||
42 | @@ -XXX,XX +XXX,XX @@ static void blk_delete(BlockBackend *blk) | ||
43 | assert(QLIST_EMPTY(&blk->remove_bs_notifiers.notifiers)); | ||
44 | assert(QLIST_EMPTY(&blk->insert_bs_notifiers.notifiers)); | ||
45 | assert(QLIST_EMPTY(&blk->aio_notifiers)); | ||
46 | + assert(qemu_co_queue_empty(&blk->queued_requests)); | ||
47 | + qemu_mutex_destroy(&blk->queued_requests_lock); | ||
48 | QTAILQ_REMOVE(&block_backends, blk, link); | ||
49 | drive_info_del(blk->legacy_dinfo); | ||
50 | block_acct_cleanup(&blk->stats); | ||
51 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn blk_wait_while_drained(BlockBackend *blk) | ||
52 | |||
53 | if (qatomic_read(&blk->quiesce_counter) && | ||
54 | !qatomic_read(&blk->disable_request_queuing)) { | ||
55 | + /* | ||
56 | + * Take lock before decrementing in flight counter so main loop thread | ||
57 | + * waits for us to enqueue ourselves before it can leave the drained | ||
58 | + * section. | ||
59 | + */ | ||
60 | + qemu_mutex_lock(&blk->queued_requests_lock); | ||
61 | blk_dec_in_flight(blk); | ||
62 | - qemu_co_queue_wait(&blk->queued_requests, NULL); | ||
63 | + qemu_co_queue_wait(&blk->queued_requests, &blk->queued_requests_lock); | ||
64 | blk_inc_in_flight(blk); | ||
65 | + qemu_mutex_unlock(&blk->queued_requests_lock); | ||
66 | } | 34 | } |
67 | } | 35 | |
68 | 36 | @@ -XXX,XX +XXX,XX @@ BlockAIOCB *blk_aio_zone_mgmt(BlockBackend *blk, BlockZoneOp op, | |
69 | @@ -XXX,XX +XXX,XX @@ static void blk_root_drained_end(BdrvChild *child) | 37 | acb->has_returned = false; |
70 | if (blk->dev_ops && blk->dev_ops->drained_end) { | 38 | |
71 | blk->dev_ops->drained_end(blk->dev_opaque); | 39 | co = qemu_coroutine_create(blk_aio_zone_mgmt_entry, acb); |
72 | } | 40 | - aio_co_enter(blk_get_aio_context(blk), co); |
73 | - while (qemu_co_enter_next(&blk->queued_requests, NULL)) { | 41 | + aio_co_enter(qemu_get_current_aio_context(), co); |
74 | + qemu_mutex_lock(&blk->queued_requests_lock); | 42 | |
75 | + while (qemu_co_enter_next(&blk->queued_requests, | 43 | acb->has_returned = true; |
76 | + &blk->queued_requests_lock)) { | 44 | if (acb->rwco.ret != NOT_DONE) { |
77 | /* Resume all queued requests */ | 45 | - replay_bh_schedule_oneshot_event(blk_get_aio_context(blk), |
78 | } | 46 | + replay_bh_schedule_oneshot_event(qemu_get_current_aio_context(), |
79 | + qemu_mutex_unlock(&blk->queued_requests_lock); | 47 | blk_aio_complete_bh, acb); |
80 | } | 48 | } |
81 | } | 49 | |
50 | @@ -XXX,XX +XXX,XX @@ BlockAIOCB *blk_aio_zone_append(BlockBackend *blk, int64_t *offset, | ||
51 | acb->has_returned = false; | ||
52 | |||
53 | co = qemu_coroutine_create(blk_aio_zone_append_entry, acb); | ||
54 | - aio_co_enter(blk_get_aio_context(blk), co); | ||
55 | + aio_co_enter(qemu_get_current_aio_context(), co); | ||
56 | acb->has_returned = true; | ||
57 | if (acb->rwco.ret != NOT_DONE) { | ||
58 | - replay_bh_schedule_oneshot_event(blk_get_aio_context(blk), | ||
59 | + replay_bh_schedule_oneshot_event(qemu_get_current_aio_context(), | ||
60 | blk_aio_complete_bh, acb); | ||
61 | } | ||
82 | 62 | ||
83 | -- | 63 | -- |
84 | 2.40.0 | 64 | 2.41.0 | diff view generated by jsdifflib |
1 | From: Stefan Hajnoczi <stefanha@redhat.com> | 1 | From: Stefan Hajnoczi <stefanha@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Since the AioContext argument was already NULL, AIO_WAIT_WHILE() was | 3 | Use qemu_get_current_aio_context() in mixed wrappers and coroutine |
4 | never going to unlock the AioContext. Therefore it is possible to | 4 | wrappers so that code runs in the caller's AioContext instead of moving |
5 | replace AIO_WAIT_WHILE() with AIO_WAIT_WHILE_UNLOCKED(). | 5 | to the BlockDriverState's AioContext. This change is necessary for the |
6 | multi-queue block layer where any thread can call into the block layer. | ||
6 | 7 | ||
7 | Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> | 8 | Most wrappers are IO_CODE where it's safe to use the current AioContext |
8 | Tested-by: Philippe Mathieu-Daudé <philmd@linaro.org> | 9 | nowadays. BlockDrivers and the core block layer use their own locks and |
10 | no longer depend on the AioContext lock for thread-safety. | ||
11 | |||
12 | The bdrv_create() wrapper invokes GLOBAL_STATE code. Using the current | ||
13 | AioContext is safe because this code is only called with the BQL held | ||
14 | from the main loop thread. | ||
15 | |||
16 | The output of qemu-iotests 051 is sensitive to event loop activity. | ||
17 | Update the output because the monitor BH runs at a different time, | ||
18 | causing prompts to be printed differently in the output. | ||
19 | |||
20 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
21 | Message-ID: <20230912231037.826804-6-stefanha@redhat.com> | ||
9 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | 22 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> |
10 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> | 23 | Reviewed-by: Eric Blake <eblake@redhat.com> |
11 | Message-Id: <20230309190855.414275-5-stefanha@redhat.com> | ||
12 | Reviewed-by: Wilfred Mallawa <wilfred.mallawa@wdc.com> | ||
13 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 24 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
14 | --- | 25 | --- |
15 | block/io.c | 2 +- | 26 | scripts/block-coroutine-wrapper.py | 6 ++---- |
16 | 1 file changed, 1 insertion(+), 1 deletion(-) | 27 | 1 file changed, 2 insertions(+), 4 deletions(-) |
17 | 28 | ||
18 | diff --git a/block/io.c b/block/io.c | 29 | diff --git a/scripts/block-coroutine-wrapper.py b/scripts/block-coroutine-wrapper.py |
19 | index XXXXXXX..XXXXXXX 100644 | 30 | index XXXXXXX..XXXXXXX 100644 |
20 | --- a/block/io.c | 31 | --- a/scripts/block-coroutine-wrapper.py |
21 | +++ b/block/io.c | 32 | +++ b/scripts/block-coroutine-wrapper.py |
22 | @@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void) | 33 | @@ -XXX,XX +XXX,XX @@ def __init__(self, wrapper_type: str, return_type: str, name: str, |
23 | bdrv_drain_all_begin_nopoll(); | 34 | raise ValueError(f"no_co function can't be rdlock: {self.name}") |
24 | 35 | self.target_name = f'{subsystem}_{subname}' | |
25 | /* Now poll the in-flight requests */ | 36 | |
26 | - AIO_WAIT_WHILE(NULL, bdrv_drain_all_poll()); | 37 | - self.ctx = self.gen_ctx() |
27 | + AIO_WAIT_WHILE_UNLOCKED(NULL, bdrv_drain_all_poll()); | 38 | - |
28 | 39 | self.get_result = 's->ret = ' | |
29 | while ((bs = bdrv_next_all_states(bs))) { | 40 | self.ret = 'return s.ret;' |
30 | bdrv_drain_assert_idle(bs); | 41 | self.co_ret = 'return ' |
42 | @@ -XXX,XX +XXX,XX @@ def create_mixed_wrapper(func: FuncDecl) -> str: | ||
43 | {func.co_ret}{name}({ func.gen_list('{name}') }); | ||
44 | }} else {{ | ||
45 | {struct_name} s = {{ | ||
46 | - .poll_state.ctx = {func.ctx}, | ||
47 | + .poll_state.ctx = qemu_get_current_aio_context(), | ||
48 | .poll_state.in_progress = true, | ||
49 | |||
50 | { func.gen_block(' .{name} = {name},') } | ||
51 | @@ -XXX,XX +XXX,XX @@ def create_co_wrapper(func: FuncDecl) -> str: | ||
52 | {func.return_type} {func.name}({ func.gen_list('{decl}') }) | ||
53 | {{ | ||
54 | {struct_name} s = {{ | ||
55 | - .poll_state.ctx = {func.ctx}, | ||
56 | + .poll_state.ctx = qemu_get_current_aio_context(), | ||
57 | .poll_state.in_progress = true, | ||
58 | |||
59 | { func.gen_block(' .{name} = {name},') } | ||
31 | -- | 60 | -- |
32 | 2.40.0 | 61 | 2.41.0 |
33 | |||
34 | diff view generated by jsdifflib |