1 | The following changes since commit e3debd5e7d0ce031356024878a0a18b9d109354a: | 1 | The following changes since commit 005ad32358f12fe9313a4a01918a55e60d4f39e5: |
---|---|---|---|
2 | 2 | ||
3 | Merge tag 'pull-request-2023-03-24' of https://gitlab.com/thuth/qemu into staging (2023-03-24 16:08:46 +0000) | 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 d8fbf9aa85aed64450907580a1d70583f097e9df: | 9 | for you to fetch changes up to 5d96864b73225ee61b0dad7e928f0cddf14270fc: |
10 | 10 | ||
11 | block/export: Fix graph locking in blk_get_geometry() call (2023-03-27 15:16:05 +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 | - aio-posix: Fix race during epoll upgrade | 16 | - Graph locking part 4 (node management) |
17 | - vhost-user-blk/VDUSE export: Fix a potential deadlock and an assertion | 17 | - qemu-img map: report compressed data blocks |
18 | failure when the export runs in an iothread | 18 | - block-backend: process I/O in the current AioContext |
19 | - NBD server: Push pending frames after sending reply to fix performance | ||
20 | especially when used with TLS | ||
21 | 19 | ||
22 | ---------------------------------------------------------------- | 20 | ---------------------------------------------------------------- |
23 | Florian Westphal (1): | 21 | Andrey Drobyshev via (2): |
24 | nbd/server: push pending frames after sending reply | 22 | block: add BDRV_BLOCK_COMPRESSED flag for bdrv_block_status() |
23 | qemu-img: map: report compressed data blocks | ||
25 | 24 | ||
26 | Kevin Wolf (1): | 25 | Kevin Wolf (21): |
27 | block/export: Fix graph locking in blk_get_geometry() call | 26 | block: Remove unused BlockReopenQueueEntry.perms_checked |
27 | preallocate: Factor out preallocate_truncate_to_real_size() | ||
28 | preallocate: Don't poll during permission updates | ||
29 | block: Take AioContext lock for bdrv_append() more consistently | ||
30 | block: Introduce bdrv_schedule_unref() | ||
31 | block-coroutine-wrapper: Add no_co_wrapper_bdrv_wrlock functions | ||
32 | block-coroutine-wrapper: Allow arbitrary parameter names | ||
33 | block: Mark bdrv_replace_child_noperm() GRAPH_WRLOCK | ||
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 | ||
28 | 47 | ||
29 | Stefan Hajnoczi (2): | 48 | Stefan Hajnoczi (5): |
30 | block/export: only acquire AioContext once for vhost_user_server_stop() | 49 | block: remove AIOCBInfo->get_aio_context() |
31 | aio-posix: fix race between epoll upgrade and aio_set_fd_handler() | 50 | test-bdrv-drain: avoid race with BH in IOThread drain test |
51 | block-backend: process I/O in the current AioContext | ||
52 | block-backend: process zoned requests in the current AioContext | ||
53 | block-coroutine-wrapper: use qemu_get_current_aio_context() | ||
32 | 54 | ||
33 | include/block/block-io.h | 4 +++- | 55 | qapi/block-core.json | 6 +- |
34 | include/sysemu/block-backend-io.h | 5 ++++- | 56 | include/block/aio.h | 1 - |
35 | block.c | 5 +++-- | 57 | include/block/block-common.h | 7 + |
36 | block/block-backend.c | 7 +++++-- | 58 | include/block/block-global-state.h | 32 +- |
37 | block/export/virtio-blk-handler.c | 7 ++++--- | 59 | include/block/block-io.h | 1 - |
38 | nbd/server.c | 3 +++ | 60 | include/block/block_int-common.h | 34 +- |
39 | util/fdmon-epoll.c | 25 ++++++++++++++++++------- | 61 | include/block/block_int-global-state.h | 14 +- |
40 | util/vhost-user-server.c | 5 +---- | 62 | include/sysemu/block-backend-global-state.h | 4 +- |
41 | 8 files changed, 41 insertions(+), 20 deletions(-) | 63 | block.c | 348 +++++++--- |
64 | block/blklogwrites.c | 4 + | ||
65 | block/blkverify.c | 2 + | ||
66 | block/block-backend.c | 64 +- | ||
67 | block/copy-before-write.c | 10 +- | ||
68 | block/crypto.c | 6 +- | ||
69 | block/graph-lock.c | 26 +- | ||
70 | block/io.c | 23 +- | ||
71 | block/mirror.c | 8 + | ||
72 | block/preallocate.c | 133 ++-- | ||
73 | block/qcow.c | 5 +- | ||
74 | block/qcow2.c | 7 +- | ||
75 | block/quorum.c | 23 +- | ||
76 | block/replication.c | 9 + | ||
77 | block/snapshot.c | 2 + | ||
78 | block/stream.c | 20 +- | ||
79 | block/vmdk.c | 15 + | ||
80 | blockdev.c | 23 +- | ||
81 | blockjob.c | 2 + | ||
82 | hw/nvme/ctrl.c | 7 - | ||
83 | qemu-img.c | 8 +- | ||
84 | softmmu/dma-helpers.c | 8 - | ||
85 | tests/unit/test-bdrv-drain.c | 31 +- | ||
86 | tests/unit/test-bdrv-graph-mod.c | 20 + | ||
87 | tests/unit/test-block-iothread.c | 3 + | ||
88 | util/thread-pool.c | 8 - | ||
89 | scripts/block-coroutine-wrapper.py | 24 +- | ||
90 | tests/qemu-iotests/051.pc.out | 6 +- | ||
91 | tests/qemu-iotests/122.out | 84 +-- | ||
92 | tests/qemu-iotests/146.out | 780 +++++++++++------------ | ||
93 | tests/qemu-iotests/154.out | 194 +++--- | ||
94 | tests/qemu-iotests/179.out | 178 +++--- | ||
95 | tests/qemu-iotests/209.out | 4 +- | ||
96 | tests/qemu-iotests/221.out | 16 +- | ||
97 | tests/qemu-iotests/223.out | 60 +- | ||
98 | tests/qemu-iotests/241.out | 10 +- | ||
99 | tests/qemu-iotests/244.out | 24 +- | ||
100 | tests/qemu-iotests/252.out | 10 +- | ||
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 |
New patch | |||
---|---|---|---|
1 | This field has been unused since commit 72373e40fbc ('block: | ||
2 | bdrv_reopen_multiple: refresh permissions on updated graph'). | ||
3 | Remove it. | ||
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-2-kwolf@redhat.com> | ||
10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
11 | --- | ||
12 | block.c | 1 - | ||
13 | 1 file changed, 1 deletion(-) | ||
14 | |||
15 | diff --git a/block.c b/block.c | ||
16 | index XXXXXXX..XXXXXXX 100644 | ||
17 | --- a/block.c | ||
18 | +++ b/block.c | ||
19 | @@ -XXX,XX +XXX,XX @@ static int bdrv_fill_options(QDict **options, const char *filename, | ||
20 | |||
21 | typedef struct BlockReopenQueueEntry { | ||
22 | bool prepared; | ||
23 | - bool perms_checked; | ||
24 | BDRVReopenState state; | ||
25 | QTAILQ_ENTRY(BlockReopenQueueEntry) entry; | ||
26 | } BlockReopenQueueEntry; | ||
27 | -- | ||
28 | 2.41.0 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | It's essentially the same code in preallocate_check_perm() and | ||
2 | preallocate_close(), except that the latter ignores errors. | ||
1 | 3 | ||
4 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
5 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
6 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
7 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
8 | Message-ID: <20230911094620.45040-3-kwolf@redhat.com> | ||
9 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
10 | --- | ||
11 | block/preallocate.c | 48 +++++++++++++++++++++------------------------ | ||
12 | 1 file changed, 22 insertions(+), 26 deletions(-) | ||
13 | |||
14 | diff --git a/block/preallocate.c b/block/preallocate.c | ||
15 | index XXXXXXX..XXXXXXX 100644 | ||
16 | --- a/block/preallocate.c | ||
17 | +++ b/block/preallocate.c | ||
18 | @@ -XXX,XX +XXX,XX @@ static int preallocate_open(BlockDriverState *bs, QDict *options, int flags, | ||
19 | return 0; | ||
20 | } | ||
21 | |||
22 | -static void preallocate_close(BlockDriverState *bs) | ||
23 | +static int preallocate_truncate_to_real_size(BlockDriverState *bs, Error **errp) | ||
24 | { | ||
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); | ||
63 | } | ||
64 | } | ||
65 | |||
66 | @@ -XXX,XX +XXX,XX @@ static int preallocate_check_perm(BlockDriverState *bs, | ||
67 | * We should truncate in check_perm, as in set_perm bs->file->perm will | ||
68 | * be already changed, and we should not violate it. | ||
69 | */ | ||
70 | - if (s->file_end < 0) { | ||
71 | - s->file_end = bdrv_getlength(bs->file->bs); | ||
72 | - if (s->file_end < 0) { | ||
73 | - error_setg(errp, "Failed to get file length"); | ||
74 | - return s->file_end; | ||
75 | - } | ||
76 | - } | ||
77 | - | ||
78 | - if (s->data_end < s->file_end) { | ||
79 | - int ret = bdrv_truncate(bs->file, s->data_end, true, | ||
80 | - PREALLOC_MODE_OFF, 0, NULL); | ||
81 | - if (ret < 0) { | ||
82 | - error_setg(errp, "Failed to drop preallocation"); | ||
83 | - s->file_end = ret; | ||
84 | - return ret; | ||
85 | - } | ||
86 | - s->file_end = s->data_end; | ||
87 | - } | ||
88 | + return preallocate_truncate_to_real_size(bs, errp); | ||
89 | } | ||
90 | |||
91 | return 0; | ||
92 | -- | ||
93 | 2.41.0 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | 1 | When the permission related BlockDriver callbacks are called, we are in | |
2 | the middle of an operation traversing the block graph. Polling in such a | ||
3 | place is a very bad idea because the graph could change in unexpected | ||
4 | ways. In the future, callers will also hold the graph lock, which is | ||
5 | likely to turn polling into a deadlock. | ||
6 | |||
7 | So we need to get rid of calls to functions like bdrv_getlength() or | ||
8 | bdrv_truncate() there as these functions poll internally. They are | ||
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> | ||
28 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
29 | --- | ||
30 | block/preallocate.c | 89 +++++++++++++++++++++++++++++++++++---------- | ||
31 | 1 file changed, 69 insertions(+), 20 deletions(-) | ||
32 | |||
33 | diff --git a/block/preallocate.c b/block/preallocate.c | ||
34 | index XXXXXXX..XXXXXXX 100644 | ||
35 | --- a/block/preallocate.c | ||
36 | +++ b/block/preallocate.c | ||
37 | @@ -XXX,XX +XXX,XX @@ typedef struct BDRVPreallocateState { | ||
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; | ||
100 | } | ||
101 | |||
102 | -static int preallocate_check_perm(BlockDriverState *bs, | ||
103 | - uint64_t perm, uint64_t shared, Error **errp) | ||
104 | +static int preallocate_drop_resize(BlockDriverState *bs, Error **errp) | ||
105 | { | ||
106 | BDRVPreallocateState *s = bs->opaque; | ||
107 | + int ret; | ||
108 | |||
109 | - if (s->data_end >= 0 && !can_write_resize(perm)) { | ||
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; | ||
142 | } | ||
143 | |||
144 | +static void preallocate_drop_resize_bh(void *opaque) | ||
145 | +{ | ||
146 | + /* | ||
147 | + * In case of errors, we'll simply keep the exclusive lock on the image | ||
148 | + * indefinitely. | ||
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); | ||
174 | } | ||
175 | } | ||
176 | |||
177 | @@ -XXX,XX +XXX,XX @@ static void preallocate_child_perm(BlockDriverState *bs, BdrvChild *c, | ||
178 | BdrvChildRole role, BlockReopenQueue *reopen_queue, | ||
179 | uint64_t perm, uint64_t shared, uint64_t *nperm, uint64_t *nshared) | ||
180 | { | ||
181 | + BDRVPreallocateState *s = bs->opaque; | ||
182 | + | ||
183 | bdrv_default_perms(bs, c, role, reopen_queue, perm, shared, nperm, nshared); | ||
184 | |||
185 | - if (can_write_resize(perm)) { | ||
186 | - /* This should come by default, but let's enforce: */ | ||
187 | + /* | ||
188 | + * We need exclusive write and resize permissions on the child not only when | ||
189 | + * the parent can write to it, but also after the parent gave up write | ||
190 | + * permissions until preallocate_drop_resize() has completed. | ||
191 | + */ | ||
192 | + if (can_write_resize(perm) || s->data_end != -EINVAL) { | ||
193 | *nperm |= BLK_PERM_WRITE | BLK_PERM_RESIZE; | ||
194 | |||
195 | /* | ||
196 | @@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_preallocate_filter = { | ||
197 | .bdrv_co_flush = preallocate_co_flush, | ||
198 | .bdrv_co_truncate = preallocate_co_truncate, | ||
199 | |||
200 | - .bdrv_check_perm = preallocate_check_perm, | ||
201 | .bdrv_set_perm = preallocate_set_perm, | ||
202 | .bdrv_child_perm = preallocate_child_perm, | ||
203 | |||
204 | -- | ||
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 |
New patch | |||
---|---|---|---|
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. | ||
1 | 6 | ||
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. | ||
10 | |||
11 | The solution is to defer deleting the node until we don't hold the lock | ||
12 | any more and draining is possible again. | ||
13 | |||
14 | Note that keeping images open for longer than necessary can create | ||
15 | problems, too: You can't open an image again before it is really closed | ||
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(). | ||
19 | |||
20 | In order to solve this problem, make sure to run the deferred unref in | ||
21 | bdrv_graph_wrunlock(), i.e. the first possible place where we can drain | ||
22 | again. This is also why bdrv_schedule_unref() is marked GRAPH_WRLOCK. | ||
23 | |||
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. | ||
27 | |||
28 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
29 | Message-ID: <20230911094620.45040-6-kwolf@redhat.com> | ||
30 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
31 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
32 | --- | ||
33 | include/block/block-global-state.h | 1 + | ||
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(-) | ||
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; | ||
79 | diff --git a/block/graph-lock.c b/block/graph-lock.c | ||
80 | index XXXXXXX..XXXXXXX 100644 | ||
81 | --- a/block/graph-lock.c | ||
82 | +++ b/block/graph-lock.c | ||
83 | @@ -XXX,XX +XXX,XX @@ void bdrv_graph_wrlock(BlockDriverState *bs) | ||
84 | void bdrv_graph_wrunlock(void) | ||
85 | { | ||
86 | GLOBAL_STATE_CODE(); | ||
87 | - QEMU_LOCK_GUARD(&aio_context_list_lock); | ||
88 | assert(qatomic_read(&has_writer)); | ||
89 | |||
90 | + WITH_QEMU_LOCK_GUARD(&aio_context_list_lock) { | ||
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 | ||
147 | -- | ||
148 | 2.41.0 | 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 |
New patch | |||
---|---|---|---|
1 | Don't assume specific parameter names like 'bs' or 'blk' in the | ||
2 | generated code, but use the actual name. | ||
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-8-kwolf@redhat.com> | ||
8 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
9 | --- | ||
10 | scripts/block-coroutine-wrapper.py | 7 ++++--- | ||
11 | 1 file changed, 4 insertions(+), 3 deletions(-) | ||
12 | |||
13 | diff --git a/scripts/block-coroutine-wrapper.py b/scripts/block-coroutine-wrapper.py | ||
14 | index XXXXXXX..XXXXXXX 100644 | ||
15 | --- a/scripts/block-coroutine-wrapper.py | ||
16 | +++ b/scripts/block-coroutine-wrapper.py | ||
17 | @@ -XXX,XX +XXX,XX @@ def __init__(self, wrapper_type: str, return_type: str, name: str, | ||
18 | |||
19 | def gen_ctx(self, prefix: str = '') -> str: | ||
20 | t = self.args[0].type | ||
21 | + name = self.args[0].name | ||
22 | if t == 'BlockDriverState *': | ||
23 | - return f'bdrv_get_aio_context({prefix}bs)' | ||
24 | + return f'bdrv_get_aio_context({prefix}{name})' | ||
25 | elif t == 'BdrvChild *': | ||
26 | - return f'bdrv_get_aio_context({prefix}child->bs)' | ||
27 | + return f'bdrv_get_aio_context({prefix}{name}->bs)' | ||
28 | elif t == 'BlockBackend *': | ||
29 | - return f'blk_get_aio_context({prefix}blk)' | ||
30 | + return f'blk_get_aio_context({prefix}{name})' | ||
31 | else: | ||
32 | return 'qemu_get_aio_context()' | ||
33 | |||
34 | -- | ||
35 | 2.41.0 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
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. | ||
1 | 6 | ||
7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
8 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
9 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
10 | Message-ID: <20230911094620.45040-9-kwolf@redhat.com> | ||
11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
12 | --- | ||
13 | block.c | 26 +++++++++++++++++++------- | ||
14 | 1 file changed, 19 insertions(+), 7 deletions(-) | ||
15 | |||
16 | diff --git a/block.c b/block.c | ||
17 | index XXXXXXX..XXXXXXX 100644 | ||
18 | --- a/block.c | ||
19 | +++ b/block.c | ||
20 | @@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_open_inherit(const char *filename, | ||
21 | static bool bdrv_recurse_has_child(BlockDriverState *bs, | ||
22 | BlockDriverState *child); | ||
23 | |||
24 | -static void bdrv_replace_child_noperm(BdrvChild *child, | ||
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) | ||
42 | } | ||
43 | assert(s->child->quiesced_parent); | ||
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) { | ||
121 | -- | ||
122 | 2.41.0 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | 1 | Instead of taking the writer lock internally, require callers to already | |
2 | hold it when calling bdrv_replace_child_tran(). 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. | ||
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> | ||
22 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
23 | --- | ||
24 | block.c | 78 ++++++++++++++++++++++++++++++++++++--------------------- | ||
25 | 1 file changed, 50 insertions(+), 28 deletions(-) | ||
26 | |||
27 | diff --git a/block.c b/block.c | ||
28 | index XXXXXXX..XXXXXXX 100644 | ||
29 | --- a/block.c | ||
30 | +++ b/block.c | ||
31 | @@ -XXX,XX +XXX,XX @@ static bool bdrv_recurse_has_child(BlockDriverState *bs, | ||
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 */ | ||
61 | } | ||
62 | |||
63 | @@ -XXX,XX +XXX,XX @@ static int bdrv_set_file_or_backing_noperm(BlockDriverState *parent_bs, | ||
64 | } | ||
65 | |||
66 | if (child) { | ||
67 | + bdrv_drained_begin(child->bs); | ||
68 | + bdrv_graph_wrlock(NULL); | ||
69 | + | ||
70 | bdrv_unset_inherits_from(parent_bs, child, tran); | ||
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)); | ||
80 | } | ||
81 | |||
82 | -static bool should_update_child(BdrvChild *c, BlockDriverState *to) | ||
83 | +static bool GRAPH_RDLOCK should_update_child(BdrvChild *c, BlockDriverState *to) | ||
84 | { | ||
85 | GQueue *queue; | ||
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, | ||
127 | - Error **errp) | ||
128 | +/* | ||
129 | + * Both @from and @to (if non-NULL) must be drained. @to must be kept drained | ||
130 | + * until the transaction is completed. | ||
131 | + */ | ||
132 | +static int GRAPH_WRLOCK | ||
133 | +bdrv_replace_node_noperm(BlockDriverState *from, | ||
134 | + BlockDriverState *to, | ||
135 | + bool auto_skip, Transaction *tran, | ||
136 | + Error **errp) | ||
137 | { | ||
138 | BdrvChild *c, *next; | ||
139 | |||
140 | GLOBAL_STATE_CODE(); | ||
141 | |||
142 | - bdrv_drained_begin(from); | ||
143 | - bdrv_drained_begin(to); | ||
144 | - tran_add(tran, &undrain_on_clean, from); | ||
145 | - tran_add(tran, &undrain_on_clean, to); | ||
146 | + assert(from->quiesce_counter); | ||
147 | + assert(to->quiesce_counter); | ||
148 | |||
149 | QLIST_FOREACH_SAFE(c, &from->parents, next_parent, next) { | ||
150 | assert(c->bs == from); | ||
151 | @@ -XXX,XX +XXX,XX @@ static int bdrv_replace_node_common(BlockDriverState *from, | ||
152 | assert(qemu_get_current_aio_context() == qemu_get_aio_context()); | ||
153 | assert(bdrv_get_aio_context(from) == bdrv_get_aio_context(to)); | ||
154 | bdrv_drained_begin(from); | ||
155 | + bdrv_drained_begin(to); | ||
156 | + | ||
157 | + bdrv_graph_wrlock(to); | ||
158 | |||
159 | /* | ||
160 | * Do the replacement without permission update. | ||
161 | @@ -XXX,XX +XXX,XX @@ static int bdrv_replace_node_common(BlockDriverState *from, | ||
162 | } | ||
163 | |||
164 | if (detach_subchain) { | ||
165 | + /* to_cow_parent is already drained because from is drained */ | ||
166 | bdrv_remove_child(bdrv_filter_or_cow_child(to_cow_parent), tran); | ||
167 | } | ||
168 | |||
169 | @@ -XXX,XX +XXX,XX @@ static int bdrv_replace_node_common(BlockDriverState *from, | ||
170 | ret = 0; | ||
171 | |||
172 | out: | ||
173 | + bdrv_graph_wrunlock(); | ||
174 | tran_finalize(tran, ret); | ||
175 | |||
176 | + bdrv_drained_end(to); | ||
177 | bdrv_drained_end(from); | ||
178 | bdrv_unref(from); | ||
179 | |||
180 | @@ -XXX,XX +XXX,XX @@ int bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top, | ||
181 | BdrvChild *child; | ||
182 | Transaction *tran = tran_new(); | ||
183 | AioContext *old_context, *new_context = NULL; | ||
184 | + bool drained = false; | ||
185 | |||
186 | GLOBAL_STATE_CODE(); | ||
187 | |||
188 | @@ -XXX,XX +XXX,XX @@ int bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top, | ||
189 | aio_context_acquire(new_context); | ||
190 | } | ||
191 | |||
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(); | ||
199 | if (ret < 0) { | ||
200 | goto out; | ||
201 | } | ||
202 | @@ -XXX,XX +XXX,XX @@ out: | ||
203 | bdrv_refresh_limits(bs_top, NULL, NULL); | ||
204 | bdrv_graph_rdunlock_main_loop(); | ||
205 | |||
206 | + if (drained) { | ||
207 | + bdrv_drained_end(bs_top); | ||
208 | + bdrv_drained_end(bs_new); | ||
209 | + } | ||
210 | + | ||
211 | if (new_context && old_context != new_context) { | ||
212 | aio_context_release(new_context); | ||
213 | aio_context_acquire(old_context); | ||
214 | @@ -XXX,XX +XXX,XX @@ int bdrv_replace_child_bs(BdrvChild *child, BlockDriverState *new_bs, | ||
215 | bdrv_ref(old_bs); | ||
216 | bdrv_drained_begin(old_bs); | ||
217 | bdrv_drained_begin(new_bs); | ||
218 | + bdrv_graph_wrlock(new_bs); | ||
219 | |||
220 | bdrv_replace_child_tran(child, new_bs, tran); | ||
221 | |||
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); | ||
229 | |||
230 | -- | ||
231 | 2.41.0 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
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. | ||
1 | 6 | ||
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. | ||
13 | |||
14 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
15 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
16 | Message-ID: <20230911094620.45040-11-kwolf@redhat.com> | ||
17 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
18 | --- | ||
19 | block.c | 133 +++++++++++++++++++++++++++++++------------------ | ||
20 | block/stream.c | 20 ++++++-- | ||
21 | 2 files changed, 100 insertions(+), 53 deletions(-) | ||
22 | |||
23 | diff --git a/block.c b/block.c | ||
24 | index XXXXXXX..XXXXXXX 100644 | ||
25 | --- a/block.c | ||
26 | +++ b/block.c | ||
27 | @@ -XXX,XX +XXX,XX @@ static TransactionActionDrv bdrv_attach_child_common_drv = { | ||
28 | * @child_bs can move to a different AioContext in this function. Callers must | ||
29 | * make sure that their AioContext locking is still correct after this. | ||
30 | */ | ||
31 | -static BdrvChild *bdrv_attach_child_common(BlockDriverState *child_bs, | ||
32 | - const char *child_name, | ||
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, | ||
267 | BdrvChild *child; | ||
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 | } | ||
390 | -- | ||
391 | 2.41.0 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | 1 | In previous patches, we changed some transactionable functions to be | |
2 | marked as GRAPH_WRLOCK, but required that tran_finalize() is still | ||
3 | called without the lock. This was because all callbacks that can be in | ||
4 | the same transaction need to follow the same convention. | ||
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> | ||
18 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
19 | --- | ||
20 | block.c | 61 +++++++++++++++++++++++++++++++++++++++++---------------- | ||
21 | 1 file changed, 44 insertions(+), 17 deletions(-) | ||
22 | |||
23 | diff --git a/block.c b/block.c | ||
24 | index XXXXXXX..XXXXXXX 100644 | ||
25 | --- a/block.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, | ||
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(); | ||
166 | return ret; | ||
167 | } | ||
168 | |||
169 | @@ -XXX,XX +XXX,XX @@ int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp) | ||
170 | aio_context_release(ctx); | ||
171 | } | ||
172 | |||
173 | + bdrv_graph_wrlock(NULL); | ||
174 | tran_commit(tran); | ||
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); | ||
265 | -- | ||
266 | 2.41.0 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
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. | ||
1 | 6 | ||
7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
8 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
9 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
10 | Message-ID: <20230911094620.45040-13-kwolf@redhat.com> | ||
11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
12 | --- | ||
13 | include/block/block-global-state.h | 14 ++++++++------ | ||
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(-) | ||
20 | |||
21 | diff --git a/include/block/block-global-state.h b/include/block/block-global-state.h | ||
22 | index XXXXXXX..XXXXXXX 100644 | ||
23 | --- a/include/block/block-global-state.h | ||
24 | +++ b/include/block/block-global-state.h | ||
25 | @@ -XXX,XX +XXX,XX @@ void no_coroutine_fn bdrv_unref(BlockDriverState *bs); | ||
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, | ||
104 | return; | ||
105 | } | ||
106 | |||
107 | + bdrv_graph_wrlock(bs); | ||
108 | + | ||
109 | bdrv_ref(hidden_disk->bs); | ||
110 | s->hidden_disk = bdrv_attach_child(bs, hidden_disk->bs, "hidden disk", | ||
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); | ||
295 | -- | ||
296 | 2.41.0 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | The function reads the parents list, so it needs to hold the graph lock. | ||
1 | 2 | ||
3 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
4 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
5 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
6 | Message-ID: <20230911094620.45040-14-kwolf@redhat.com> | ||
7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
8 | --- | ||
9 | include/block/block_int-common.h | 6 ++--- | ||
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(-) | ||
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 | |||
298 | diff --git a/block/mirror.c b/block/mirror.c | ||
299 | index XXXXXXX..XXXXXXX 100644 | ||
300 | --- a/block/mirror.c | ||
301 | +++ b/block/mirror.c | ||
302 | @@ -XXX,XX +XXX,XX @@ static int mirror_exit_common(Job *job) | ||
303 | * mirror_top_bs from now on, so keep it drained. */ | ||
304 | bdrv_drained_begin(mirror_top_bs); | ||
305 | bs_opaque->stop = true; | ||
306 | + | ||
307 | + bdrv_graph_rdlock_main_loop(); | ||
308 | bdrv_child_refresh_perms(mirror_top_bs, mirror_top_bs->backing, | ||
309 | &error_abort); | ||
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); | ||
346 | if (ret < 0) { | ||
347 | return 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 | |||
370 | -- | ||
371 | 2.41.0 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | The function reads the parents list, so it needs to hold the graph lock. | ||
1 | 2 | ||
3 | This happens to result in BlockDriver.bdrv_set_perm() to be called with | ||
4 | the graph lock held. For consistency, make it the same for all of the | ||
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> | ||
12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
13 | --- | ||
14 | include/block/block_int-common.h | 9 ++++--- | ||
15 | include/block/block_int-global-state.h | 4 +-- | ||
16 | block.c | 35 ++++++++++++++++++++------ | ||
17 | blockdev.c | 6 +++++ | ||
18 | 4 files changed, 40 insertions(+), 14 deletions(-) | ||
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 | * If both conditions are met, 0 is returned. Otherwise, -errno is returned | ||
26 | * and errp is set to an error describing the conflict. | ||
27 | */ | ||
28 | - int (*bdrv_check_perm)(BlockDriverState *bs, uint64_t perm, | ||
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) | ||
79 | { | ||
80 | BlockDriverState *bs = opaque; | ||
81 | uint64_t cumulative_perms, cumulative_shared_perms; | ||
82 | @@ -XXX,XX +XXX,XX @@ static void bdrv_drv_set_perm_commit(void *opaque) | ||
83 | } | ||
84 | } | ||
85 | |||
86 | -static void bdrv_drv_set_perm_abort(void *opaque) | ||
87 | +static void GRAPH_RDLOCK bdrv_drv_set_perm_abort(void *opaque) | ||
88 | { | ||
89 | BlockDriverState *bs = opaque; | ||
90 | GLOBAL_STATE_CODE(); | ||
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 | ||
159 | index XXXXXXX..XXXXXXX 100644 | ||
160 | --- a/blockdev.c | ||
161 | +++ b/blockdev.c | ||
162 | @@ -XXX,XX +XXX,XX @@ static void external_snapshot_action(TransactionAction *action, | ||
163 | AioContext *aio_context; | ||
164 | uint64_t perm, shared; | ||
165 | |||
166 | + /* TODO We'll eventually have to take a writer lock in this function */ | ||
167 | + GRAPH_RDLOCK_GUARD_MAINLOOP(); | ||
168 | + | ||
169 | tran_add(tran, &external_snapshot_drv, state); | ||
170 | |||
171 | /* 'blockdev-snapshot' and 'blockdev-snapshot-sync' have similar | ||
172 | @@ -XXX,XX +XXX,XX @@ void qmp_block_commit(const char *job_id, const char *device, | ||
173 | int job_flags = JOB_DEFAULT; | ||
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 | } | ||
182 | -- | ||
183 | 2.41.0 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
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. | ||
1 | 4 | ||
5 | The callers of bdrv_child_perm() conveniently already hold the lock. | ||
6 | |||
7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
8 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
9 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
10 | Message-ID: <20230911094620.45040-16-kwolf@redhat.com> | ||
11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
12 | --- | ||
13 | include/block/block_int-common.h | 10 +++++----- | ||
14 | block.c | 11 ++++++----- | ||
15 | block/copy-before-write.c | 10 +++++----- | ||
16 | 3 files changed, 16 insertions(+), 15 deletions(-) | ||
17 | |||
18 | diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h | ||
19 | index XXXXXXX..XXXXXXX 100644 | ||
20 | --- a/include/block/block_int-common.h | ||
21 | +++ b/include/block/block_int-common.h | ||
22 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | ||
23 | * permissions, but those that will be needed after applying the | ||
24 | * @reopen_queue. | ||
25 | */ | ||
26 | - void (*bdrv_child_perm)(BlockDriverState *bs, BdrvChild *c, | ||
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; | ||
45 | } | ||
46 | |||
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 | /* | ||
82 | -- | ||
83 | 2.41.0 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | The function reads the parents list, so it needs to hold the graph lock. | ||
1 | 2 | ||
3 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
4 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
5 | Message-ID: <20230911094620.45040-18-kwolf@redhat.com> | ||
6 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
8 | --- | ||
9 | block.c | 2 ++ | ||
10 | 1 file changed, 2 insertions(+) | ||
11 | |||
12 | diff --git a/block.c b/block.c | ||
13 | index XXXXXXX..XXXXXXX 100644 | ||
14 | --- a/block.c | ||
15 | +++ b/block.c | ||
16 | @@ -XXX,XX +XXX,XX @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base, | ||
17 | backing_file_str = base->filename; | ||
18 | } | ||
19 | |||
20 | + bdrv_graph_rdlock_main_loop(); | ||
21 | QLIST_FOREACH(c, &top->parents, next_parent) { | ||
22 | updated_children = g_slist_prepend(updated_children, c); | ||
23 | } | ||
24 | + bdrv_graph_rdunlock_main_loop(); | ||
25 | |||
26 | /* | ||
27 | * It seems correct to pass detach_subchain=true here, but it triggers | ||
28 | -- | ||
29 | 2.41.0 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | The function reads the parents list, so it needs to hold the graph lock. | ||
1 | 2 | ||
3 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
4 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
5 | Message-ID: <20230911094620.45040-19-kwolf@redhat.com> | ||
6 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
8 | --- | ||
9 | block.c | 4 ++++ | ||
10 | 1 file changed, 4 insertions(+) | ||
11 | |||
12 | diff --git a/block.c b/block.c | ||
13 | index XXXXXXX..XXXXXXX 100644 | ||
14 | --- a/block.c | ||
15 | +++ b/block.c | ||
16 | @@ -XXX,XX +XXX,XX @@ static bool bdrv_change_aio_context(BlockDriverState *bs, AioContext *ctx, | ||
17 | return true; | ||
18 | } | ||
19 | |||
20 | + bdrv_graph_rdlock_main_loop(); | ||
21 | QLIST_FOREACH(c, &bs->parents, next_parent) { | ||
22 | if (!bdrv_parent_change_aio_context(c, ctx, visited, tran, errp)) { | ||
23 | + bdrv_graph_rdunlock_main_loop(); | ||
24 | return false; | ||
25 | } | ||
26 | } | ||
27 | |||
28 | QLIST_FOREACH(c, &bs->children, next) { | ||
29 | if (!bdrv_child_change_aio_context(c, ctx, visited, tran, errp)) { | ||
30 | + bdrv_graph_rdunlock_main_loop(); | ||
31 | return false; | ||
32 | } | ||
33 | } | ||
34 | + bdrv_graph_rdunlock_main_loop(); | ||
35 | |||
36 | state = g_new(BdrvStateSetAioContext, 1); | ||
37 | *state = (BdrvStateSetAioContext) { | ||
38 | -- | ||
39 | 2.41.0 | diff view generated by jsdifflib |
1 | blk_get_geometry() eventually calls bdrv_nb_sectors(), which is a | 1 | Instead of taking the writer lock internally, require callers to already |
---|---|---|---|
2 | co_wrapper_mixed_bdrv_rdlock. This means that when it is called from | 2 | hold it when calling bdrv_root_unref_child(). These callers will |
3 | coroutine context, it already assume to have the graph locked. | 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. | ||
4 | 6 | ||
5 | However, virtio_blk_sect_range_ok() in block/export/virtio-blk-handler.c | ||
6 | (used by vhost-user-blk and VDUSE exports) runs in a coroutine, but | ||
7 | doesn't take the graph lock - blk_*() functions are generally expected | ||
8 | to do that internally. This causes an assertion failure when accessing | ||
9 | an export for the first time if it runs in an iothread. | ||
10 | |||
11 | This is an example of the crash: | ||
12 | |||
13 | $ ./storage-daemon/qemu-storage-daemon --object iothread,id=th0 --blockdev file,filename=/home/kwolf/images/hd.img,node-name=disk --export vhost-user-blk,addr.type=unix,addr.path=/tmp/vhost.sock,node-name=disk,id=exp0,iothread=th0 | ||
14 | qemu-storage-daemon: ../block/graph-lock.c:268: void assert_bdrv_graph_readable(void): Assertion `qemu_in_main_thread() || reader_count()' failed. | ||
15 | |||
16 | (gdb) bt | ||
17 | #0 0x00007ffff6eafe5c in __pthread_kill_implementation () from /lib64/libc.so.6 | ||
18 | #1 0x00007ffff6e5fa76 in raise () from /lib64/libc.so.6 | ||
19 | #2 0x00007ffff6e497fc in abort () from /lib64/libc.so.6 | ||
20 | #3 0x00007ffff6e4971b in __assert_fail_base.cold () from /lib64/libc.so.6 | ||
21 | #4 0x00007ffff6e58656 in __assert_fail () from /lib64/libc.so.6 | ||
22 | #5 0x00005555556337a3 in assert_bdrv_graph_readable () at ../block/graph-lock.c:268 | ||
23 | #6 0x00005555555fd5a2 in bdrv_co_nb_sectors (bs=0x5555564c5ef0) at ../block.c:5847 | ||
24 | #7 0x00005555555ee949 in bdrv_nb_sectors (bs=0x5555564c5ef0) at block/block-gen.c:256 | ||
25 | #8 0x00005555555fd6b9 in bdrv_get_geometry (bs=0x5555564c5ef0, nb_sectors_ptr=0x7fffef7fedd0) at ../block.c:5884 | ||
26 | #9 0x000055555562ad6d in blk_get_geometry (blk=0x5555564cb200, nb_sectors_ptr=0x7fffef7fedd0) at ../block/block-backend.c:1624 | ||
27 | #10 0x00005555555ddb74 in virtio_blk_sect_range_ok (blk=0x5555564cb200, block_size=512, sector=0, size=512) at ../block/export/virtio-blk-handler.c:44 | ||
28 | #11 0x00005555555dd80d in virtio_blk_process_req (handler=0x5555564cbb98, in_iov=0x7fffe8003830, out_iov=0x7fffe8003860, in_num=1, out_num=0) at ../block/export/virtio-blk-handler.c:189 | ||
29 | #12 0x00005555555dd546 in vu_blk_virtio_process_req (opaque=0x7fffe8003800) at ../block/export/vhost-user-blk-server.c:66 | ||
30 | #13 0x00005555557bf4a1 in coroutine_trampoline (i0=-402635264, i1=32767) at ../util/coroutine-ucontext.c:177 | ||
31 | #14 0x00007ffff6e75c20 in ?? () from /lib64/libc.so.6 | ||
32 | #15 0x00007fffefffa870 in ?? () | ||
33 | #16 0x0000000000000000 in ?? () | ||
34 | |||
35 | Fix this by creating a new blk_co_get_geometry() that takes the lock, | ||
36 | and changing blk_get_geometry() to be a co_wrapper_mixed around it. | ||
37 | |||
38 | To make the resulting code cleaner, virtio-blk-handler.c can directly | ||
39 | call the coroutine version now (though that wouldn't be necessary for | ||
40 | fixing the bug, taking the lock in blk_co_get_geometry() is what fixes | ||
41 | it). | ||
42 | |||
43 | Fixes: 8ab8140a04cf771d63e9754d6ba6c1e676bfe507 | ||
44 | Reported-by: Lukáš Doktor <ldoktor@redhat.com> | ||
45 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
46 | Message-Id: <20230327113959.60071-1-kwolf@redhat.com> | ||
47 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | 8 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
9 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
10 | Message-ID: <20230911094620.45040-20-kwolf@redhat.com> | ||
48 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
49 | --- | 12 | --- |
50 | include/block/block-io.h | 4 +++- | 13 | include/block/block_int-global-state.h | 2 +- |
51 | include/sysemu/block-backend-io.h | 5 ++++- | 14 | block.c | 6 +++--- |
52 | block.c | 5 +++-- | 15 | block/block-backend.c | 3 +++ |
53 | block/block-backend.c | 7 +++++-- | 16 | blockjob.c | 2 ++ |
54 | block/export/virtio-blk-handler.c | 7 ++++--- | 17 | 4 files changed, 9 insertions(+), 4 deletions(-) |
55 | 5 files changed, 19 insertions(+), 9 deletions(-) | ||
56 | 18 | ||
57 | diff --git a/include/block/block-io.h b/include/block/block-io.h | 19 | diff --git a/include/block/block_int-global-state.h b/include/block/block_int-global-state.h |
58 | index XXXXXXX..XXXXXXX 100644 | 20 | index XXXXXXX..XXXXXXX 100644 |
59 | --- a/include/block/block-io.h | 21 | --- a/include/block/block_int-global-state.h |
60 | +++ b/include/block/block-io.h | 22 | +++ b/include/block/block_int-global-state.h |
61 | @@ -XXX,XX +XXX,XX @@ int64_t co_wrapper bdrv_get_allocated_file_size(BlockDriverState *bs); | 23 | @@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs, |
62 | 24 | BdrvChildRole child_role, | |
63 | BlockMeasureInfo *bdrv_measure(BlockDriver *drv, QemuOpts *opts, | 25 | uint64_t perm, uint64_t shared_perm, |
64 | BlockDriverState *in_bs, Error **errp); | 26 | void *opaque, Error **errp); |
65 | -void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr); | 27 | -void bdrv_root_unref_child(BdrvChild *child); |
66 | + | 28 | +void GRAPH_WRLOCK bdrv_root_unref_child(BdrvChild *child); |
67 | +void coroutine_fn GRAPH_RDLOCK | 29 | |
68 | +bdrv_co_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr); | 30 | void GRAPH_RDLOCK bdrv_get_cumulative_perm(BlockDriverState *bs, uint64_t *perm, |
69 | 31 | uint64_t *shared_perm); | |
70 | int coroutine_fn GRAPH_RDLOCK | ||
71 | bdrv_co_delete_file(BlockDriverState *bs, Error **errp); | ||
72 | diff --git a/include/sysemu/block-backend-io.h b/include/sysemu/block-backend-io.h | ||
73 | index XXXXXXX..XXXXXXX 100644 | ||
74 | --- a/include/sysemu/block-backend-io.h | ||
75 | +++ b/include/sysemu/block-backend-io.h | ||
76 | @@ -XXX,XX +XXX,XX @@ void co_wrapper blk_eject(BlockBackend *blk, bool eject_flag); | ||
77 | int64_t coroutine_fn blk_co_getlength(BlockBackend *blk); | ||
78 | int64_t co_wrapper_mixed blk_getlength(BlockBackend *blk); | ||
79 | |||
80 | -void blk_get_geometry(BlockBackend *blk, uint64_t *nb_sectors_ptr); | ||
81 | +void coroutine_fn blk_co_get_geometry(BlockBackend *blk, | ||
82 | + uint64_t *nb_sectors_ptr); | ||
83 | +void co_wrapper_mixed blk_get_geometry(BlockBackend *blk, | ||
84 | + uint64_t *nb_sectors_ptr); | ||
85 | |||
86 | int64_t coroutine_fn blk_co_nb_sectors(BlockBackend *blk); | ||
87 | int64_t co_wrapper_mixed blk_nb_sectors(BlockBackend *blk); | ||
88 | diff --git a/block.c b/block.c | 32 | diff --git a/block.c b/block.c |
89 | index XXXXXXX..XXXXXXX 100644 | 33 | index XXXXXXX..XXXXXXX 100644 |
90 | --- a/block.c | 34 | --- a/block.c |
91 | +++ b/block.c | 35 | +++ b/block.c |
92 | @@ -XXX,XX +XXX,XX @@ int64_t coroutine_fn bdrv_co_getlength(BlockDriverState *bs) | 36 | @@ -XXX,XX +XXX,XX @@ void bdrv_root_unref_child(BdrvChild *child) |
37 | BlockDriverState *child_bs = child->bs; | ||
38 | |||
39 | GLOBAL_STATE_CODE(); | ||
40 | - bdrv_graph_wrlock(NULL); | ||
41 | bdrv_replace_child_noperm(child, NULL); | ||
42 | bdrv_child_free(child); | ||
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); | ||
93 | } | 51 | } |
94 | 52 | ||
95 | /* return 0 as number of sectors if no device present or error */ | 53 | typedef struct BdrvSetInheritsFrom { |
96 | -void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr) | 54 | @@ -XXX,XX +XXX,XX @@ void bdrv_unref_child(BlockDriverState *parent, BdrvChild *child) |
97 | +void coroutine_fn bdrv_co_get_geometry(BlockDriverState *bs, | 55 | return; |
98 | + uint64_t *nb_sectors_ptr) | 56 | } |
99 | { | 57 | |
100 | - int64_t nb_sectors = bdrv_nb_sectors(bs); | 58 | + bdrv_graph_wrlock(NULL); |
101 | + int64_t nb_sectors = bdrv_co_nb_sectors(bs); | 59 | bdrv_unset_inherits_from(parent, child, NULL); |
102 | IO_CODE(); | 60 | bdrv_root_unref_child(child); |
103 | 61 | + bdrv_graph_wrunlock(); | |
104 | *nb_sectors_ptr = nb_sectors < 0 ? 0 : nb_sectors; | 62 | } |
63 | |||
64 | |||
105 | diff --git a/block/block-backend.c b/block/block-backend.c | 65 | diff --git a/block/block-backend.c b/block/block-backend.c |
106 | index XXXXXXX..XXXXXXX 100644 | 66 | index XXXXXXX..XXXXXXX 100644 |
107 | --- a/block/block-backend.c | 67 | --- a/block/block-backend.c |
108 | +++ b/block/block-backend.c | 68 | +++ b/block/block-backend.c |
109 | @@ -XXX,XX +XXX,XX @@ int64_t coroutine_fn blk_co_getlength(BlockBackend *blk) | 69 | @@ -XXX,XX +XXX,XX @@ void blk_remove_bs(BlockBackend *blk) |
110 | return bdrv_co_getlength(blk_bs(blk)); | 70 | blk_drain(blk); |
71 | root = blk->root; | ||
72 | blk->root = NULL; | ||
73 | + | ||
74 | + bdrv_graph_wrlock(NULL); | ||
75 | bdrv_root_unref_child(root); | ||
76 | + bdrv_graph_wrunlock(); | ||
111 | } | 77 | } |
112 | 78 | ||
113 | -void blk_get_geometry(BlockBackend *blk, uint64_t *nb_sectors_ptr) | 79 | /* |
114 | +void coroutine_fn blk_co_get_geometry(BlockBackend *blk, | 80 | diff --git a/blockjob.c b/blockjob.c |
115 | + uint64_t *nb_sectors_ptr) | 81 | index XXXXXXX..XXXXXXX 100644 |
116 | { | 82 | --- a/blockjob.c |
117 | IO_CODE(); | 83 | +++ b/blockjob.c |
118 | + GRAPH_RDLOCK_GUARD(); | 84 | @@ -XXX,XX +XXX,XX @@ void block_job_remove_all_bdrv(BlockJob *job) |
119 | + | 85 | * one to make sure that such a concurrent access does not attempt |
120 | if (!blk_bs(blk)) { | 86 | * to process an already freed BdrvChild. |
121 | *nb_sectors_ptr = 0; | 87 | */ |
122 | } else { | 88 | + bdrv_graph_wrlock(NULL); |
123 | - bdrv_get_geometry(blk_bs(blk), nb_sectors_ptr); | 89 | while (job->nodes) { |
124 | + bdrv_co_get_geometry(blk_bs(blk), nb_sectors_ptr); | 90 | GSList *l = job->nodes; |
91 | BdrvChild *c = l->data; | ||
92 | @@ -XXX,XX +XXX,XX @@ void block_job_remove_all_bdrv(BlockJob *job) | ||
93 | |||
94 | g_slist_free_1(l); | ||
125 | } | 95 | } |
96 | + bdrv_graph_wrunlock(); | ||
126 | } | 97 | } |
127 | 98 | ||
128 | diff --git a/block/export/virtio-blk-handler.c b/block/export/virtio-blk-handler.c | 99 | bool block_job_has_bdrv(BlockJob *job, BlockDriverState *bs) |
129 | index XXXXXXX..XXXXXXX 100644 | ||
130 | --- a/block/export/virtio-blk-handler.c | ||
131 | +++ b/block/export/virtio-blk-handler.c | ||
132 | @@ -XXX,XX +XXX,XX @@ struct virtio_blk_inhdr { | ||
133 | unsigned char status; | ||
134 | }; | ||
135 | |||
136 | -static bool virtio_blk_sect_range_ok(BlockBackend *blk, uint32_t block_size, | ||
137 | - uint64_t sector, size_t size) | ||
138 | +static bool coroutine_fn | ||
139 | +virtio_blk_sect_range_ok(BlockBackend *blk, uint32_t block_size, | ||
140 | + uint64_t sector, size_t size) | ||
141 | { | ||
142 | uint64_t nb_sectors; | ||
143 | uint64_t total_sectors; | ||
144 | @@ -XXX,XX +XXX,XX @@ static bool virtio_blk_sect_range_ok(BlockBackend *blk, uint32_t block_size, | ||
145 | if ((sector << VIRTIO_BLK_SECTOR_BITS) % block_size) { | ||
146 | return false; | ||
147 | } | ||
148 | - blk_get_geometry(blk, &total_sectors); | ||
149 | + blk_co_get_geometry(blk, &total_sectors); | ||
150 | if (sector > total_sectors || nb_sectors > total_sectors - sector) { | ||
151 | return false; | ||
152 | } | ||
153 | -- | 100 | -- |
154 | 2.39.2 | 101 | 2.41.0 |
155 | |||
156 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
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. | ||
1 | 5 | ||
6 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
7 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
8 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
9 | Message-ID: <20230911094620.45040-21-kwolf@redhat.com> | ||
10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
11 | --- | ||
12 | include/block/block-global-state.h | 7 ++++++- | ||
13 | block.c | 11 +++++++---- | ||
14 | block/blklogwrites.c | 4 ++++ | ||
15 | block/blkverify.c | 2 ++ | ||
16 | block/qcow2.c | 4 +++- | ||
17 | block/quorum.c | 6 ++++++ | ||
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(-) | ||
23 | |||
24 | diff --git a/include/block/block-global-state.h b/include/block/block-global-state.h | ||
25 | index XXXXXXX..XXXXXXX 100644 | ||
26 | --- a/include/block/block-global-state.h | ||
27 | +++ b/include/block/block-global-state.h | ||
28 | @@ -XXX,XX +XXX,XX @@ void bdrv_ref(BlockDriverState *bs); | ||
29 | void no_coroutine_fn bdrv_unref(BlockDriverState *bs); | ||
30 | void coroutine_fn no_co_wrapper bdrv_co_unref(BlockDriverState *bs); | ||
31 | void GRAPH_WRLOCK bdrv_schedule_unref(BlockDriverState *bs); | ||
32 | -void bdrv_unref_child(BlockDriverState *parent, BdrvChild *child); | ||
33 | + | ||
34 | +void GRAPH_WRLOCK | ||
35 | +bdrv_unref_child(BlockDriverState *parent, BdrvChild *child); | ||
36 | + | ||
37 | +void coroutine_fn no_co_wrapper_bdrv_wrlock | ||
38 | +bdrv_co_unref_child(BlockDriverState *parent, BdrvChild *child); | ||
39 | |||
40 | BdrvChild * GRAPH_WRLOCK | ||
41 | bdrv_attach_child(BlockDriverState *parent_bs, | ||
42 | diff --git a/block.c b/block.c | ||
43 | index XXXXXXX..XXXXXXX 100644 | ||
44 | --- a/block.c | ||
45 | +++ b/block.c | ||
46 | @@ -XXX,XX +XXX,XX @@ bdrv_open_driver(BlockDriverState *bs, BlockDriver *drv, const char *node_name, | ||
47 | open_failed: | ||
48 | bs->drv = NULL; | ||
49 | if (bs->file != NULL) { | ||
50 | + bdrv_graph_wrlock(NULL); | ||
51 | bdrv_unref_child(bs, bs->file); | ||
52 | + bdrv_graph_wrunlock(); | ||
53 | assert(!bs->file); | ||
54 | } | ||
55 | g_free(bs->opaque); | ||
56 | @@ -XXX,XX +XXX,XX @@ static void bdrv_set_inherits_from(BlockDriverState *bs, | ||
57 | * @root that point to @root, where necessary. | ||
58 | * @tran is allowed to be NULL. In this case no rollback is possible | ||
59 | */ | ||
60 | -static void bdrv_unset_inherits_from(BlockDriverState *root, BdrvChild *child, | ||
61 | - Transaction *tran) | ||
62 | +static void GRAPH_WRLOCK | ||
63 | +bdrv_unset_inherits_from(BlockDriverState *root, BdrvChild *child, | ||
64 | + Transaction *tran) | ||
65 | { | ||
66 | BdrvChild *c; | ||
67 | |||
68 | @@ -XXX,XX +XXX,XX @@ void bdrv_unref_child(BlockDriverState *parent, BdrvChild *child) | ||
69 | return; | ||
70 | } | ||
71 | |||
72 | - bdrv_graph_wrlock(NULL); | ||
73 | bdrv_unset_inherits_from(parent, child, NULL); | ||
74 | bdrv_root_unref_child(child); | ||
75 | - bdrv_graph_wrunlock(); | ||
76 | } | ||
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) | ||
106 | { | ||
107 | BDRVBlkLogWritesState *s = bs->opaque; | ||
108 | |||
109 | + bdrv_graph_wrlock(NULL); | ||
110 | bdrv_unref_child(bs, s->log_file); | ||
111 | s->log_file = NULL; | ||
112 | + bdrv_graph_wrunlock(); | ||
113 | } | ||
114 | |||
115 | static int64_t coroutine_fn GRAPH_RDLOCK | ||
116 | diff --git a/block/blkverify.c b/block/blkverify.c | ||
117 | index XXXXXXX..XXXXXXX 100644 | ||
118 | --- a/block/blkverify.c | ||
119 | +++ b/block/blkverify.c | ||
120 | @@ -XXX,XX +XXX,XX @@ static void blkverify_close(BlockDriverState *bs) | ||
121 | { | ||
122 | BDRVBlkverifyState *s = bs->opaque; | ||
123 | |||
124 | + bdrv_graph_wrlock(NULL); | ||
125 | bdrv_unref_child(bs, s->test_file); | ||
126 | s->test_file = NULL; | ||
127 | + bdrv_graph_wrunlock(); | ||
128 | } | ||
129 | |||
130 | static int64_t coroutine_fn GRAPH_RDLOCK | ||
131 | diff --git a/block/qcow2.c b/block/qcow2.c | ||
132 | index XXXXXXX..XXXXXXX 100644 | ||
133 | --- a/block/qcow2.c | ||
134 | +++ b/block/qcow2.c | ||
135 | @@ -XXX,XX +XXX,XX @@ qcow2_do_open(BlockDriverState *bs, QDict *options, int flags, | ||
136 | g_free(s->image_data_file); | ||
137 | if (open_data_file && has_data_file(bs)) { | ||
138 | bdrv_graph_co_rdunlock(); | ||
139 | - bdrv_unref_child(bs, s->data_file); | ||
140 | + bdrv_co_unref_child(bs, s->data_file); | ||
141 | bdrv_graph_co_rdlock(); | ||
142 | s->data_file = NULL; | ||
143 | } | ||
144 | @@ -XXX,XX +XXX,XX @@ static void qcow2_do_close(BlockDriverState *bs, bool close_data_file) | ||
145 | g_free(s->image_backing_format); | ||
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) | ||
291 | { | ||
292 | BdrvChild *c, *next_c; | ||
293 | + | ||
294 | + bdrv_graph_wrlock(NULL); | ||
295 | QLIST_FOREACH_SAFE(c, &bs->children, next, next_c) { | ||
296 | bdrv_unref_child(bs, c); | ||
297 | } | ||
298 | + bdrv_graph_wrunlock(); | ||
299 | } | ||
300 | |||
301 | static int coroutine_fn GRAPH_RDLOCK | ||
302 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn test_co_delete_by_drain(void *opaque) | ||
303 | } else { | ||
304 | BdrvChild *c, *next_c; | ||
305 | QLIST_FOREACH_SAFE(c, &bs->children, next, next_c) { | ||
306 | - bdrv_unref_child(bs, c); | ||
307 | + bdrv_co_unref_child(bs, c); | ||
308 | } | ||
309 | } | ||
310 | |||
311 | @@ -XXX,XX +XXX,XX @@ static void detach_indirect_bh(void *opaque) | ||
312 | struct detach_by_parent_data *data = opaque; | ||
313 | |||
314 | bdrv_dec_in_flight(data->child_b->bs); | ||
315 | + | ||
316 | + bdrv_graph_wrlock(NULL); | ||
317 | bdrv_unref_child(data->parent_b, data->child_b); | ||
318 | |||
319 | bdrv_ref(data->c); | ||
320 | - bdrv_graph_wrlock(NULL); | ||
321 | data->child_c = bdrv_attach_child(data->parent_b, data->c, "PB-C", | ||
322 | &child_of_bds, BDRV_CHILD_DATA, | ||
323 | &error_abort); | ||
324 | -- | ||
325 | 2.41.0 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
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. | ||
1 | 5 | ||
6 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
7 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
8 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
9 | Message-ID: <20230911094620.45040-22-kwolf@redhat.com> | ||
10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
11 | --- | ||
12 | include/block/block-global-state.h | 8 +++++--- | ||
13 | include/block/block_int-common.h | 9 +++++---- | ||
14 | block/quorum.c | 23 ++++++----------------- | ||
15 | blockdev.c | 17 +++++++++++------ | ||
16 | 4 files changed, 27 insertions(+), 30 deletions(-) | ||
17 | |||
18 | diff --git a/include/block/block-global-state.h b/include/block/block-global-state.h | ||
19 | index XXXXXXX..XXXXXXX 100644 | ||
20 | --- a/include/block/block-global-state.h | ||
21 | +++ b/include/block/block-global-state.h | ||
22 | @@ -XXX,XX +XXX,XX @@ int bdrv_try_change_aio_context(BlockDriverState *bs, AioContext *ctx, | ||
23 | int bdrv_probe_blocksizes(BlockDriverState *bs, BlockSizes *bsz); | ||
24 | int bdrv_probe_geometry(BlockDriverState *bs, HDGeometry *geo); | ||
25 | |||
26 | -void bdrv_add_child(BlockDriverState *parent, BlockDriverState *child, | ||
27 | - Error **errp); | ||
28 | -void bdrv_del_child(BlockDriverState *parent, BdrvChild *child, Error **errp); | ||
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 | /** | ||
36 | * | ||
37 | diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h | ||
38 | index XXXXXXX..XXXXXXX 100644 | ||
39 | --- a/include/block/block_int-common.h | ||
40 | +++ b/include/block/block_int-common.h | ||
41 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | ||
42 | */ | ||
43 | int (*bdrv_probe_geometry)(BlockDriverState *bs, HDGeometry *geo); | ||
44 | |||
45 | - void (*bdrv_add_child)(BlockDriverState *parent, BlockDriverState *child, | ||
46 | - Error **errp); | ||
47 | - void (*bdrv_del_child)(BlockDriverState *parent, BdrvChild *child, | ||
48 | - Error **errp); | ||
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) | ||
186 | -- | ||
187 | 2.41.0 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Andrey Drobyshev via <qemu-block@nongnu.org> | ||
1 | 2 | ||
3 | Functions qcow2_get_host_offset(), get_cluster_offset(), | ||
4 | vmdk_co_block_status() explicitly report compressed cluster types when data | ||
5 | is compressed. However, this information is never passed further. Let's | ||
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. | ||
10 | |||
11 | This new flag is only being utilized by qcow, qcow2 and vmdk formats, as only | ||
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> | ||
18 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
19 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
20 | --- | ||
21 | include/block/block-common.h | 3 +++ | ||
22 | block/qcow.c | 5 ++++- | ||
23 | block/qcow2.c | 3 +++ | ||
24 | block/vmdk.c | 2 ++ | ||
25 | 4 files changed, 12 insertions(+), 1 deletion(-) | ||
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 | |||
78 | diff --git a/block/vmdk.c b/block/vmdk.c | ||
79 | index XXXXXXX..XXXXXXX 100644 | ||
80 | --- a/block/vmdk.c | ||
81 | +++ b/block/vmdk.c | ||
82 | @@ -XXX,XX +XXX,XX @@ vmdk_co_block_status(BlockDriverState *bs, bool want_zero, | ||
83 | if (extent->flat) { | ||
84 | ret |= BDRV_BLOCK_RECURSE; | ||
85 | } | ||
86 | + } else { | ||
87 | + ret |= BDRV_BLOCK_COMPRESSED; | ||
88 | } | ||
89 | *file = extent->file->bs; | ||
90 | break; | ||
91 | -- | ||
92 | 2.41.0 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Andrey Drobyshev via <qemu-block@nongnu.org> | ||
1 | 2 | ||
3 | Right now "qemu-img map" reports compressed blocks as containing data | ||
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> | ||
13 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
14 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
15 | --- | ||
16 | qapi/block-core.json | 6 +- | ||
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(-) | ||
33 | |||
34 | diff --git a/qapi/block-core.json b/qapi/block-core.json | ||
35 | index XXXXXXX..XXXXXXX 100644 | ||
36 | --- a/qapi/block-core.json | ||
37 | +++ b/qapi/block-core.json | ||
38 | @@ -XXX,XX +XXX,XX @@ | ||
39 | # | ||
40 | # @zero: whether the virtual blocks read as zeroes | ||
41 | # | ||
42 | +# @compressed: true if the data is stored compressed (since 8.2) | ||
43 | +# | ||
44 | # @depth: number of layers (0 = top image, 1 = top image's backing | ||
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 === | ||
2132 | |||
2133 | -- | ||
2134 | 2.41.0 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | 1 | From: Stefan Hajnoczi <stefanha@redhat.com> | |
2 | |||
3 | The synchronous bdrv_aio_cancel() function needs the acb's AioContext so | ||
4 | it can call aio_poll() to wait for cancellation. | ||
5 | |||
6 | It turns out that all users run under the BQL in the main AioContext, so | ||
7 | this callback is not needed. | ||
8 | |||
9 | Remove the callback, mark bdrv_aio_cancel() GLOBAL_STATE_CODE just like | ||
10 | its blk_aio_cancel() caller, and poll the main loop AioContext. | ||
11 | |||
12 | The purpose of this cleanup is to identify bdrv_aio_cancel() as an API | ||
13 | that does not work with the multi-queue block layer. | ||
14 | |||
15 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
16 | Message-ID: <20230912231037.826804-2-stefanha@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> | ||
20 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
21 | --- | ||
22 | include/block/aio.h | 1 - | ||
23 | include/block/block-global-state.h | 2 ++ | ||
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 */ | ||
69 | diff --git a/block/block-backend.c b/block/block-backend.c | ||
70 | index XXXXXXX..XXXXXXX 100644 | ||
71 | --- a/block/block-backend.c | ||
72 | +++ b/block/block-backend.c | ||
73 | @@ -XXX,XX +XXX,XX @@ | ||
74 | |||
75 | #define NOT_DONE 0x7fffffff /* used while emulated sync operation in progress */ | ||
76 | |||
77 | -static AioContext *blk_aiocb_get_aio_context(BlockAIOCB *acb); | ||
78 | - | ||
79 | typedef struct BlockBackendAioNotifier { | ||
80 | void (*attached_aio_context)(AioContext *new_context, void *opaque); | ||
81 | void (*detach_aio_context)(void *opaque); | ||
82 | @@ -XXX,XX +XXX,XX @@ typedef struct BlockBackendAIOCB { | ||
83 | } BlockBackendAIOCB; | ||
84 | |||
85 | static const AIOCBInfo block_backend_aiocb_info = { | ||
86 | - .get_aio_context = blk_aiocb_get_aio_context, | ||
87 | .aiocb_size = sizeof(BlockBackendAIOCB), | ||
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) | ||
195 | } | ||
196 | } | ||
197 | |||
198 | -static AioContext *dma_get_aio_context(BlockAIOCB *acb) | ||
199 | -{ | ||
200 | - DMAAIOCB *dbs = container_of(acb, DMAAIOCB, common); | ||
201 | - | ||
202 | - return dbs->ctx; | ||
203 | -} | ||
204 | - | ||
205 | static const AIOCBInfo dma_aiocb_info = { | ||
206 | .aiocb_size = sizeof(DMAAIOCB), | ||
207 | .cancel_async = dma_aio_cancel, | ||
208 | - .get_aio_context = dma_get_aio_context, | ||
209 | }; | ||
210 | |||
211 | BlockAIOCB *dma_blk_io(AioContext *ctx, | ||
212 | diff --git a/util/thread-pool.c b/util/thread-pool.c | ||
213 | index XXXXXXX..XXXXXXX 100644 | ||
214 | --- a/util/thread-pool.c | ||
215 | +++ b/util/thread-pool.c | ||
216 | @@ -XXX,XX +XXX,XX @@ static void thread_pool_cancel(BlockAIOCB *acb) | ||
217 | |||
218 | } | ||
219 | |||
220 | -static AioContext *thread_pool_get_aio_context(BlockAIOCB *acb) | ||
221 | -{ | ||
222 | - ThreadPoolElement *elem = (ThreadPoolElement *)acb; | ||
223 | - ThreadPool *pool = elem->pool; | ||
224 | - return pool->ctx; | ||
225 | -} | ||
226 | - | ||
227 | static const AIOCBInfo thread_pool_aiocb_info = { | ||
228 | .aiocb_size = sizeof(ThreadPoolElement), | ||
229 | .cancel_async = thread_pool_cancel, | ||
230 | - .get_aio_context = thread_pool_get_aio_context, | ||
231 | }; | ||
232 | |||
233 | BlockAIOCB *thread_pool_submit_aio(ThreadPoolFunc *func, void *arg, | ||
234 | -- | ||
235 | 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 | If another thread calls aio_set_fd_handler() while the IOThread event | 3 | This patch fixes a race condition in test-bdrv-drain that is difficult |
4 | loop is upgrading from ppoll(2) to epoll(7) then we might miss new | 4 | to reproduce. test-bdrv-drain sometimes fails without an error message |
5 | AioHandlers. The epollfd will not monitor the new AioHandler's fd, | 5 | on the block pull request sent by Kevin Wolf on Sep 4, 2023. I was able |
6 | resulting in hangs. | 6 | to reproduce it locally and found that "block-backend: process I/O in |
7 | the current AioContext" (in this patch series) is the first commit where | ||
8 | it reproduces. | ||
7 | 9 | ||
8 | Take the AioHandler list lock while upgrading to epoll. This prevents | 10 | I do not know why "block-backend: process I/O in the current AioContext" |
9 | AioHandlers from changing while epoll is being set up. If we cannot lock | 11 | exposes this bug. It might be related to the fact that the test's preadv |
10 | because we're in a nested event loop, then don't upgrade to epoll (it | 12 | request runs in the main thread instead of IOThread a after my commit. |
11 | will happen next time we're not in a nested call). | 13 | That might simply change the timing of the test. |
12 | 14 | ||
13 | The downside to taking the lock is that the aio_set_fd_handler() thread | 15 | Now on to the race condition in test-bdrv-drain. The main thread |
14 | has to wait until the epoll upgrade is finished, which involves many | 16 | schedules a BH in IOThread a and then drains the BDS: |
15 | epoll_ctl(2) system calls. However, this scenario is rare and I couldn't | ||
16 | think of another solution that is still simple. | ||
17 | 17 | ||
18 | Reported-by: Qing Wang <qinwang@redhat.com> | 18 | aio_bh_schedule_oneshot(ctx_a, test_iothread_main_thread_bh, &data); |
19 | Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=2090998 | 19 | |
20 | Cc: Paolo Bonzini <pbonzini@redhat.com> | 20 | /* The request is running on the IOThread a. Draining its block device |
21 | Cc: Fam Zheng <fam@euphon.net> | 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(). | ||
39 | |||
22 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> | 40 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> |
23 | Message-Id: <20230323144859.1338495-1-stefanha@redhat.com> | 41 | Message-ID: <20230912231037.826804-3-stefanha@redhat.com> |
42 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
24 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | 43 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> |
25 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 44 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
26 | --- | 45 | --- |
27 | util/fdmon-epoll.c | 25 ++++++++++++++++++------- | 46 | tests/unit/test-bdrv-drain.c | 8 ++++++++ |
28 | 1 file changed, 18 insertions(+), 7 deletions(-) | 47 | 1 file changed, 8 insertions(+) |
29 | 48 | ||
30 | diff --git a/util/fdmon-epoll.c b/util/fdmon-epoll.c | 49 | diff --git a/tests/unit/test-bdrv-drain.c b/tests/unit/test-bdrv-drain.c |
31 | index XXXXXXX..XXXXXXX 100644 | 50 | index XXXXXXX..XXXXXXX 100644 |
32 | --- a/util/fdmon-epoll.c | 51 | --- a/tests/unit/test-bdrv-drain.c |
33 | +++ b/util/fdmon-epoll.c | 52 | +++ b/tests/unit/test-bdrv-drain.c |
34 | @@ -XXX,XX +XXX,XX @@ static bool fdmon_epoll_try_enable(AioContext *ctx) | 53 | @@ -XXX,XX +XXX,XX @@ static void test_iothread_main_thread_bh(void *opaque) |
35 | 54 | * executed during drain, otherwise this would deadlock. */ | |
36 | bool fdmon_epoll_try_upgrade(AioContext *ctx, unsigned npfd) | 55 | aio_context_acquire(bdrv_get_aio_context(data->bs)); |
37 | { | 56 | bdrv_flush(data->bs); |
38 | + bool ok; | 57 | + bdrv_dec_in_flight(data->bs); /* incremented by test_iothread_common() */ |
39 | + | 58 | aio_context_release(bdrv_get_aio_context(data->bs)); |
40 | if (ctx->epollfd < 0) { | ||
41 | return false; | ||
42 | } | ||
43 | @@ -XXX,XX +XXX,XX @@ bool fdmon_epoll_try_upgrade(AioContext *ctx, unsigned npfd) | ||
44 | return false; | ||
45 | } | ||
46 | |||
47 | - if (npfd >= EPOLL_ENABLE_THRESHOLD) { | ||
48 | - if (fdmon_epoll_try_enable(ctx)) { | ||
49 | - return true; | ||
50 | - } else { | ||
51 | - fdmon_epoll_disable(ctx); | ||
52 | - } | ||
53 | + if (npfd < EPOLL_ENABLE_THRESHOLD) { | ||
54 | + return false; | ||
55 | + } | ||
56 | + | ||
57 | + /* The list must not change while we add fds to epoll */ | ||
58 | + if (!qemu_lockcnt_dec_if_lock(&ctx->list_lock)) { | ||
59 | + return false; | ||
60 | + } | ||
61 | + | ||
62 | + ok = fdmon_epoll_try_enable(ctx); | ||
63 | + | ||
64 | + qemu_lockcnt_inc_and_unlock(&ctx->list_lock); | ||
65 | + | ||
66 | + if (!ok) { | ||
67 | + fdmon_epoll_disable(ctx); | ||
68 | } | ||
69 | - return false; | ||
70 | + return ok; | ||
71 | } | 59 | } |
72 | 60 | ||
73 | void fdmon_epoll_setup(AioContext *ctx) | 61 | @@ -XXX,XX +XXX,XX @@ static void test_iothread_common(enum drain_type drain_type, int drain_thread) |
62 | aio_context_acquire(ctx_a); | ||
63 | } | ||
64 | |||
65 | + /* | ||
66 | + * Increment in_flight so that do_drain_begin() waits for | ||
67 | + * test_iothread_main_thread_bh(). This prevents the race between | ||
68 | + * test_iothread_main_thread_bh() in IOThread a and do_drain_begin() in | ||
69 | + * this thread. test_iothread_main_thread_bh() decrements in_flight. | ||
70 | + */ | ||
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 | ||
74 | -- | 75 | -- |
75 | 2.39.2 | 76 | 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 | vhost_user_server_stop() uses AIO_WAIT_WHILE(). AIO_WAIT_WHILE() | 3 | Switch blk_aio_*() APIs over to multi-queue by using |
4 | requires that AioContext is only acquired once. | 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 | Since blk_exp_request_shutdown() already acquires the AioContext it | 8 | I audited existing blk_aio_*() callers: |
7 | shouldn't be acquired again in vhost_user_server_stop(). | 9 | - migration/block.c: blk_mig_lock() protects the data accessed by the |
10 | completion callback. | ||
11 | - The remaining emulated devices and exports run with | ||
12 | qemu_get_aio_context() == blk_get_aio_context(). | ||
8 | 13 | ||
9 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> | 14 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> |
10 | Message-Id: <20230323145853.1345527-1-stefanha@redhat.com> | 15 | Message-ID: <20230912231037.826804-4-stefanha@redhat.com> |
11 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | 16 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> |
17 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 18 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
13 | --- | 19 | --- |
14 | util/vhost-user-server.c | 5 +---- | 20 | block/block-backend.c | 6 +++--- |
15 | 1 file changed, 1 insertion(+), 4 deletions(-) | 21 | 1 file changed, 3 insertions(+), 3 deletions(-) |
16 | 22 | ||
17 | diff --git a/util/vhost-user-server.c b/util/vhost-user-server.c | 23 | diff --git a/block/block-backend.c b/block/block-backend.c |
18 | index XXXXXXX..XXXXXXX 100644 | 24 | index XXXXXXX..XXXXXXX 100644 |
19 | --- a/util/vhost-user-server.c | 25 | --- a/block/block-backend.c |
20 | +++ b/util/vhost-user-server.c | 26 | +++ b/block/block-backend.c |
21 | @@ -XXX,XX +XXX,XX @@ static void vu_accept(QIONetListener *listener, QIOChannelSocket *sioc, | 27 | @@ -XXX,XX +XXX,XX @@ BlockAIOCB *blk_abort_aio_request(BlockBackend *blk, |
22 | aio_context_release(server->ctx); | 28 | acb->blk = blk; |
29 | acb->ret = ret; | ||
30 | |||
31 | - replay_bh_schedule_oneshot_event(blk_get_aio_context(blk), | ||
32 | + replay_bh_schedule_oneshot_event(qemu_get_current_aio_context(), | ||
33 | error_callback_bh, acb); | ||
34 | return &acb->common; | ||
23 | } | 35 | } |
24 | 36 | @@ -XXX,XX +XXX,XX @@ static BlockAIOCB *blk_aio_prwv(BlockBackend *blk, int64_t offset, | |
25 | +/* server->ctx acquired by caller */ | 37 | acb->has_returned = false; |
26 | void vhost_user_server_stop(VuServer *server) | 38 | |
27 | { | 39 | co = qemu_coroutine_create(co_entry, acb); |
28 | - aio_context_acquire(server->ctx); | 40 | - aio_co_enter(blk_get_aio_context(blk), co); |
29 | - | 41 | + aio_co_enter(qemu_get_current_aio_context(), co); |
30 | qemu_bh_delete(server->restart_listener_bh); | 42 | |
31 | server->restart_listener_bh = NULL; | 43 | acb->has_returned = true; |
32 | 44 | if (acb->rwco.ret != NOT_DONE) { | |
33 | @@ -XXX,XX +XXX,XX @@ void vhost_user_server_stop(VuServer *server) | 45 | - replay_bh_schedule_oneshot_event(blk_get_aio_context(blk), |
34 | AIO_WAIT_WHILE(server->ctx, server->co_trip); | 46 | + replay_bh_schedule_oneshot_event(qemu_get_current_aio_context(), |
47 | blk_aio_complete_bh, acb); | ||
35 | } | 48 | } |
36 | 49 | ||
37 | - aio_context_release(server->ctx); | ||
38 | - | ||
39 | if (server->listener) { | ||
40 | qio_net_listener_disconnect(server->listener); | ||
41 | object_unref(OBJECT(server->listener)); | ||
42 | -- | 50 | -- |
43 | 2.39.2 | 51 | 2.41.0 | diff view generated by jsdifflib |
1 | From: Florian Westphal <fw@strlen.de> | 1 | From: Stefan Hajnoczi <stefanha@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | qemu-nbd doesn't set TCP_NODELAY on the tcp socket. | 3 | Process zoned requests in the current thread's AioContext instead of in |
4 | the BlockBackend's AioContext. | ||
4 | 5 | ||
5 | Kernel waits for more data and avoids transmission of small packets. | 6 | There is no need to use the BlockBackend's AioContext thanks to CoMutex |
6 | Without TLS this is barely noticeable, but with TLS this really shows. | 7 | bs->wps->colock, which protects zone metadata. |
7 | 8 | ||
8 | Booting a VM via qemu-nbd on localhost (with tls) takes more than | 9 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> |
9 | 2 minutes on my system. tcpdump shows frequent wait periods, where no | 10 | Message-ID: <20230912231037.826804-5-stefanha@redhat.com> |
10 | packets get sent for a 40ms period. | 11 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> |
11 | |||
12 | Add explicit (un)corking when processing (and responding to) requests. | ||
13 | "TCP_CORK, &zero" after earlier "CORK, &one" will flush pending data. | ||
14 | |||
15 | VM Boot time: | ||
16 | main: no tls: 23s, with tls: 2m45s | ||
17 | patched: no tls: 14s, with tls: 15s | ||
18 | |||
19 | VM Boot time, qemu-nbd via network (same lan): | ||
20 | main: no tls: 18s, with tls: 1m50s | ||
21 | patched: no tls: 17s, with tls: 18s | ||
22 | |||
23 | Future optimization: if we could detect if there is another pending | ||
24 | request we could defer the uncork operation because more data would be | ||
25 | appended. | ||
26 | |||
27 | Signed-off-by: Florian Westphal <fw@strlen.de> | ||
28 | Message-Id: <20230324104720.2498-1-fw@strlen.de> | ||
29 | Reviewed-by: Eric Blake <eblake@redhat.com> | 12 | Reviewed-by: Eric Blake <eblake@redhat.com> |
30 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
31 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 13 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
32 | --- | 14 | --- |
33 | nbd/server.c | 3 +++ | 15 | block/block-backend.c | 12 ++++++------ |
34 | 1 file changed, 3 insertions(+) | 16 | 1 file changed, 6 insertions(+), 6 deletions(-) |
35 | 17 | ||
36 | diff --git a/nbd/server.c b/nbd/server.c | 18 | diff --git a/block/block-backend.c b/block/block-backend.c |
37 | index XXXXXXX..XXXXXXX 100644 | 19 | index XXXXXXX..XXXXXXX 100644 |
38 | --- a/nbd/server.c | 20 | --- a/block/block-backend.c |
39 | +++ b/nbd/server.c | 21 | +++ b/block/block-backend.c |
40 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn void nbd_trip(void *opaque) | 22 | @@ -XXX,XX +XXX,XX @@ BlockAIOCB *blk_aio_zone_report(BlockBackend *blk, int64_t offset, |
41 | goto disconnect; | 23 | acb->has_returned = false; |
24 | |||
25 | co = qemu_coroutine_create(blk_aio_zone_report_entry, acb); | ||
26 | - aio_co_enter(blk_get_aio_context(blk), co); | ||
27 | + aio_co_enter(qemu_get_current_aio_context(), co); | ||
28 | |||
29 | acb->has_returned = true; | ||
30 | if (acb->rwco.ret != NOT_DONE) { | ||
31 | - replay_bh_schedule_oneshot_event(blk_get_aio_context(blk), | ||
32 | + replay_bh_schedule_oneshot_event(qemu_get_current_aio_context(), | ||
33 | blk_aio_complete_bh, acb); | ||
42 | } | 34 | } |
43 | 35 | ||
44 | + qio_channel_set_cork(client->ioc, true); | 36 | @@ -XXX,XX +XXX,XX @@ BlockAIOCB *blk_aio_zone_mgmt(BlockBackend *blk, BlockZoneOp op, |
45 | + | 37 | acb->has_returned = false; |
46 | if (ret < 0) { | 38 | |
47 | /* It wasn't -EIO, so, according to nbd_co_receive_request() | 39 | co = qemu_coroutine_create(blk_aio_zone_mgmt_entry, acb); |
48 | * semantics, we should return the error to the client. */ | 40 | - aio_co_enter(blk_get_aio_context(blk), co); |
49 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn void nbd_trip(void *opaque) | 41 | + aio_co_enter(qemu_get_current_aio_context(), co); |
50 | goto disconnect; | 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); | ||
51 | } | 48 | } |
52 | 49 | ||
53 | + qio_channel_set_cork(client->ioc, false); | 50 | @@ -XXX,XX +XXX,XX @@ BlockAIOCB *blk_aio_zone_append(BlockBackend *blk, int64_t *offset, |
54 | done: | 51 | acb->has_returned = false; |
55 | nbd_request_put(req); | 52 | |
56 | nbd_client_put(client); | 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 | } | ||
62 | |||
57 | -- | 63 | -- |
58 | 2.39.2 | 64 | 2.41.0 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Stefan Hajnoczi <stefanha@redhat.com> | ||
1 | 2 | ||
3 | Use qemu_get_current_aio_context() in mixed wrappers and coroutine | ||
4 | wrappers so that code runs in the caller's AioContext instead of moving | ||
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. | ||
7 | |||
8 | Most wrappers are IO_CODE where it's safe to use the current AioContext | ||
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> | ||
22 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
23 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
24 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
25 | --- | ||
26 | scripts/block-coroutine-wrapper.py | 6 ++---- | ||
27 | 1 file changed, 2 insertions(+), 4 deletions(-) | ||
28 | |||
29 | diff --git a/scripts/block-coroutine-wrapper.py b/scripts/block-coroutine-wrapper.py | ||
30 | index XXXXXXX..XXXXXXX 100644 | ||
31 | --- a/scripts/block-coroutine-wrapper.py | ||
32 | +++ b/scripts/block-coroutine-wrapper.py | ||
33 | @@ -XXX,XX +XXX,XX @@ def __init__(self, wrapper_type: str, return_type: str, name: str, | ||
34 | raise ValueError(f"no_co function can't be rdlock: {self.name}") | ||
35 | self.target_name = f'{subsystem}_{subname}' | ||
36 | |||
37 | - self.ctx = self.gen_ctx() | ||
38 | - | ||
39 | self.get_result = 's->ret = ' | ||
40 | self.ret = 'return s.ret;' | ||
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},') } | ||
60 | -- | ||
61 | 2.41.0 | diff view generated by jsdifflib |