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