1 | The following changes since commit 8cb41fda78c7ebde0dd248c6afe1d336efb0de50: | 1 | The following changes since commit 005ad32358f12fe9313a4a01918a55e60d4f39e5: |
---|---|---|---|
2 | 2 | ||
3 | Merge remote-tracking branch 'remotes/philmd/tags/machine-20211101' into staging (2021-11-02 05:53:45 -0400) | 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 | git://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 a8951438946d72d74c9bdbdb38fce95aa2973a88: | 9 | for you to fetch changes up to 5d96864b73225ee61b0dad7e928f0cddf14270fc: |
10 | 10 | ||
11 | block/nvme: Extract nvme_free_queue() from nvme_free_queue_pair() (2021-11-02 15:49:13 +0100) | 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 | - Fail gracefully when blockdev-snapshot creates loops | 16 | - Graph locking part 4 (node management) |
17 | - ide: Fix IDENTIFY DEVICE for disks > 128 GiB | 17 | - qemu-img map: report compressed data blocks |
18 | - file-posix: Fix return value translation for AIO discards | 18 | - block-backend: process I/O in the current AioContext |
19 | - file-posix: add 'aio-max-batch' option | ||
20 | - rbd: implement bdrv_co_block_status | ||
21 | - Code cleanups and build fixes | ||
22 | 19 | ||
23 | ---------------------------------------------------------------- | 20 | ---------------------------------------------------------------- |
24 | Ari Sundholm (1): | 21 | Andrey Drobyshev via (2): |
25 | block/file-posix: Fix return value translation for AIO discards | 22 | block: add BDRV_BLOCK_COMPRESSED flag for bdrv_block_status() |
23 | qemu-img: map: report compressed data blocks | ||
26 | 24 | ||
27 | Fabrice Fontaine (1): | 25 | Kevin Wolf (21): |
28 | block/export/fuse.c: fix musl build | 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 | ||
29 | 47 | ||
30 | Hanna Reitz (1): | 48 | Stefan Hajnoczi (5): |
31 | block-backend: Silence clang -m32 compiler warning | 49 | block: remove AIOCBInfo->get_aio_context() |
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 | Kevin Wolf (1): | 55 | qapi/block-core.json | 6 +- |
34 | block: Fail gracefully when blockdev-snapshot creates loops | 56 | include/block/aio.h | 1 - |
35 | 57 | include/block/block-common.h | 7 + | |
36 | Peter Lieven (1): | 58 | include/block/block-global-state.h | 32 +- |
37 | block/rbd: implement bdrv_co_block_status | 59 | include/block/block-io.h | 1 - |
38 | 60 | include/block/block_int-common.h | 34 +- | |
39 | Philippe Mathieu-Daudé (3): | 61 | include/block/block_int-global-state.h | 14 +- |
40 | block/nvme: Automatically free qemu_memalign() with QEMU_AUTO_VFREE | 62 | include/sysemu/block-backend-global-state.h | 4 +- |
41 | block/nvme: Display CQ/SQ pointer in nvme_free_queue_pair() | 63 | block.c | 348 +++++++--- |
42 | block/nvme: Extract nvme_free_queue() from nvme_free_queue_pair() | 64 | block/blklogwrites.c | 4 + |
43 | 65 | block/blkverify.c | 2 + | |
44 | Samuel Thibault (1): | 66 | block/block-backend.c | 64 +- |
45 | ide: Cap LBA28 capacity announcement to 2^28-1 | 67 | block/copy-before-write.c | 10 +- |
46 | 68 | block/crypto.c | 6 +- | |
47 | Stefano Garzarella (3): | 69 | block/graph-lock.c | 26 +- |
48 | file-posix: add `aio-max-batch` option | 70 | block/io.c | 23 +- |
49 | linux-aio: add `dev_max_batch` parameter to laio_co_submit() | 71 | block/mirror.c | 8 + |
50 | linux-aio: add `dev_max_batch` parameter to laio_io_unplug() | 72 | block/preallocate.c | 133 ++-- |
51 | 73 | block/qcow.c | 5 +- | |
52 | qapi/block-core.json | 7 +++ | 74 | block/qcow2.c | 7 +- |
53 | include/block/raw-aio.h | 6 ++- | 75 | block/quorum.c | 23 +- |
54 | block.c | 10 ++++ | 76 | block/replication.c | 9 + |
55 | block/block-backend.c | 2 +- | 77 | block/snapshot.c | 2 + |
56 | block/export/fuse.c | 4 ++ | 78 | block/stream.c | 20 +- |
57 | block/file-posix.c | 18 ++++++-- | 79 | block/vmdk.c | 15 + |
58 | block/linux-aio.c | 38 ++++++++++----- | 80 | blockdev.c | 23 +- |
59 | block/nvme.c | 22 +++++---- | 81 | blockjob.c | 2 + |
60 | block/rbd.c | 112 +++++++++++++++++++++++++++++++++++++++++++++ | 82 | hw/nvme/ctrl.c | 7 - |
61 | hw/ide/core.c | 8 +++- | 83 | qemu-img.c | 8 +- |
62 | block/trace-events | 2 +- | 84 | softmmu/dma-helpers.c | 8 - |
63 | tests/qemu-iotests/085 | 31 ++++++++++++- | 85 | tests/unit/test-bdrv-drain.c | 31 +- |
64 | tests/qemu-iotests/085.out | 33 +++++++++++-- | 86 | tests/unit/test-bdrv-graph-mod.c | 20 + |
65 | 13 files changed, 258 insertions(+), 35 deletions(-) | 87 | tests/unit/test-block-iothread.c | 3 + |
66 | 88 | util/thread-pool.c | 8 - | |
67 | 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 |
1 | From: Peter Lieven <pl@kamp.de> | 1 | It's essentially the same code in preallocate_check_perm() and |
---|---|---|---|
2 | preallocate_close(), except that the latter ignores errors. | ||
2 | 3 | ||
3 | the qemu rbd driver currently lacks support for bdrv_co_block_status. | 4 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
4 | This results mainly in incorrect progress during block operations (e.g. | 5 | Reviewed-by: Eric Blake <eblake@redhat.com> |
5 | qemu-img convert with an rbd image as source). | 6 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
6 | 7 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | |
7 | This patch utilizes the rbd_diff_iterate2 call from librbd to detect | 8 | Message-ID: <20230911094620.45040-3-kwolf@redhat.com> |
8 | allocated and unallocated (all zero areas). | ||
9 | |||
10 | To avoid querying the ceph OSDs for the answer this is only done if | ||
11 | the image has the fast-diff feature which depends on the object-map and | ||
12 | exclusive-lock features. In this case it is guaranteed that the information | ||
13 | is present in memory in the librbd client and thus very fast. | ||
14 | |||
15 | If fast-diff is not available all areas are reported to be allocated | ||
16 | which is the current behaviour if bdrv_co_block_status is not implemented. | ||
17 | |||
18 | Signed-off-by: Peter Lieven <pl@kamp.de> | ||
19 | Message-Id: <20211012152231.24868-1-pl@kamp.de> | ||
20 | Reviewed-by: Ilya Dryomov <idryomov@gmail.com> | ||
21 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 9 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
22 | --- | 10 | --- |
23 | block/rbd.c | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++++ | 11 | block/preallocate.c | 48 +++++++++++++++++++++------------------------ |
24 | 1 file changed, 112 insertions(+) | 12 | 1 file changed, 22 insertions(+), 26 deletions(-) |
25 | 13 | ||
26 | diff --git a/block/rbd.c b/block/rbd.c | 14 | diff --git a/block/preallocate.c b/block/preallocate.c |
27 | index XXXXXXX..XXXXXXX 100644 | 15 | index XXXXXXX..XXXXXXX 100644 |
28 | --- a/block/rbd.c | 16 | --- a/block/preallocate.c |
29 | +++ b/block/rbd.c | 17 | +++ b/block/preallocate.c |
30 | @@ -XXX,XX +XXX,XX @@ typedef struct RBDTask { | 18 | @@ -XXX,XX +XXX,XX @@ static int preallocate_open(BlockDriverState *bs, QDict *options, int flags, |
31 | int64_t ret; | 19 | return 0; |
32 | } RBDTask; | ||
33 | |||
34 | +typedef struct RBDDiffIterateReq { | ||
35 | + uint64_t offs; | ||
36 | + uint64_t bytes; | ||
37 | + bool exists; | ||
38 | +} RBDDiffIterateReq; | ||
39 | + | ||
40 | static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx, | ||
41 | BlockdevOptionsRbd *opts, bool cache, | ||
42 | const char *keypairs, const char *secretid, | ||
43 | @@ -XXX,XX +XXX,XX @@ static ImageInfoSpecific *qemu_rbd_get_specific_info(BlockDriverState *bs, | ||
44 | return spec_info; | ||
45 | } | 20 | } |
46 | 21 | ||
47 | +/* | 22 | -static void preallocate_close(BlockDriverState *bs) |
48 | + * rbd_diff_iterate2 allows to interrupt the exection by returning a negative | 23 | +static int preallocate_truncate_to_real_size(BlockDriverState *bs, Error **errp) |
49 | + * value in the callback routine. Choose a value that does not conflict with | 24 | { |
50 | + * an existing exitcode and return it if we want to prematurely stop the | 25 | - int ret; |
51 | + * execution because we detected a change in the allocation status. | 26 | BDRVPreallocateState *s = bs->opaque; |
52 | + */ | 27 | - |
53 | +#define QEMU_RBD_EXIT_DIFF_ITERATE2 -9000 | 28 | - if (s->data_end < 0) { |
54 | + | 29 | - return; |
55 | +static int qemu_rbd_diff_iterate_cb(uint64_t offs, size_t len, | 30 | - } |
56 | + int exists, void *opaque) | 31 | + int ret; |
57 | +{ | 32 | |
58 | + RBDDiffIterateReq *req = opaque; | 33 | if (s->file_end < 0) { |
59 | + | 34 | s->file_end = bdrv_getlength(bs->file->bs); |
60 | + assert(req->offs + req->bytes <= offs); | 35 | if (s->file_end < 0) { |
61 | + /* | 36 | - return; |
62 | + * we do not diff against a snapshot so we should never receive a callback | 37 | + error_setg_errno(errp, -s->file_end, "Failed to get file length"); |
63 | + * for a hole. | 38 | + return s->file_end; |
64 | + */ | 39 | } |
65 | + assert(exists); | 40 | } |
66 | + | 41 | |
67 | + if (!req->exists && offs > req->offs) { | 42 | if (s->data_end < s->file_end) { |
68 | + /* | 43 | ret = bdrv_truncate(bs->file, s->data_end, true, PREALLOC_MODE_OFF, 0, |
69 | + * we started in an unallocated area and hit the first allocated | 44 | NULL); |
70 | + * block. req->bytes must be set to the length of the unallocated area | 45 | - s->file_end = ret < 0 ? ret : s->data_end; |
71 | + * before the allocated area. stop further processing. | 46 | + if (ret < 0) { |
72 | + */ | 47 | + error_setg_errno(errp, -ret, "Failed to drop preallocation"); |
73 | + req->bytes = offs - req->offs; | 48 | + s->file_end = ret; |
74 | + return QEMU_RBD_EXIT_DIFF_ITERATE2; | 49 | + return ret; |
50 | + } | ||
51 | + s->file_end = s->data_end; | ||
75 | + } | 52 | + } |
76 | + | ||
77 | + if (req->exists && offs > req->offs + req->bytes) { | ||
78 | + /* | ||
79 | + * we started in an allocated area and jumped over an unallocated area, | ||
80 | + * req->bytes contains the length of the allocated area before the | ||
81 | + * unallocated area. stop further processing. | ||
82 | + */ | ||
83 | + return QEMU_RBD_EXIT_DIFF_ITERATE2; | ||
84 | + } | ||
85 | + | ||
86 | + req->bytes += len; | ||
87 | + req->exists = true; | ||
88 | + | 53 | + |
89 | + return 0; | 54 | + return 0; |
90 | +} | 55 | +} |
91 | + | 56 | + |
92 | +static int coroutine_fn qemu_rbd_co_block_status(BlockDriverState *bs, | 57 | +static void preallocate_close(BlockDriverState *bs) |
93 | + bool want_zero, int64_t offset, | ||
94 | + int64_t bytes, int64_t *pnum, | ||
95 | + int64_t *map, | ||
96 | + BlockDriverState **file) | ||
97 | +{ | 58 | +{ |
98 | + BDRVRBDState *s = bs->opaque; | 59 | + BDRVPreallocateState *s = bs->opaque; |
99 | + int status, r; | ||
100 | + RBDDiffIterateReq req = { .offs = offset }; | ||
101 | + uint64_t features, flags; | ||
102 | + | 60 | + |
103 | + assert(offset + bytes <= s->image_size); | 61 | + if (s->data_end >= 0) { |
104 | + | 62 | + preallocate_truncate_to_real_size(bs, NULL); |
105 | + /* default to all sectors allocated */ | 63 | } |
106 | + status = BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID; | 64 | } |
107 | + *map = offset; | 65 | |
108 | + *file = bs; | 66 | @@ -XXX,XX +XXX,XX @@ static int preallocate_check_perm(BlockDriverState *bs, |
109 | + *pnum = bytes; | 67 | * We should truncate in check_perm, as in set_perm bs->file->perm will |
110 | + | 68 | * be already changed, and we should not violate it. |
111 | + /* check if RBD image supports fast-diff */ | 69 | */ |
112 | + r = rbd_get_features(s->image, &features); | 70 | - if (s->file_end < 0) { |
113 | + if (r < 0) { | 71 | - s->file_end = bdrv_getlength(bs->file->bs); |
114 | + return status; | 72 | - if (s->file_end < 0) { |
115 | + } | 73 | - error_setg(errp, "Failed to get file length"); |
116 | + if (!(features & RBD_FEATURE_FAST_DIFF)) { | 74 | - return s->file_end; |
117 | + return status; | 75 | - } |
118 | + } | 76 | - } |
119 | + | 77 | - |
120 | + /* check if RBD fast-diff result is valid */ | 78 | - if (s->data_end < s->file_end) { |
121 | + r = rbd_get_flags(s->image, &flags); | 79 | - int ret = bdrv_truncate(bs->file, s->data_end, true, |
122 | + if (r < 0) { | 80 | - PREALLOC_MODE_OFF, 0, NULL); |
123 | + return status; | 81 | - if (ret < 0) { |
124 | + } | 82 | - error_setg(errp, "Failed to drop preallocation"); |
125 | + if (flags & RBD_FLAG_FAST_DIFF_INVALID) { | 83 | - s->file_end = ret; |
126 | + return status; | 84 | - return ret; |
127 | + } | 85 | - } |
128 | + | 86 | - s->file_end = s->data_end; |
129 | + r = rbd_diff_iterate2(s->image, NULL, offset, bytes, true, true, | 87 | - } |
130 | + qemu_rbd_diff_iterate_cb, &req); | 88 | + return preallocate_truncate_to_real_size(bs, errp); |
131 | + if (r < 0 && r != QEMU_RBD_EXIT_DIFF_ITERATE2) { | 89 | } |
132 | + return status; | 90 | |
133 | + } | 91 | return 0; |
134 | + assert(req.bytes <= bytes); | ||
135 | + if (!req.exists) { | ||
136 | + if (r == 0) { | ||
137 | + /* | ||
138 | + * rbd_diff_iterate2 does not invoke callbacks for unallocated | ||
139 | + * areas. This here catches the case where no callback was | ||
140 | + * invoked at all (req.bytes == 0). | ||
141 | + */ | ||
142 | + assert(req.bytes == 0); | ||
143 | + req.bytes = bytes; | ||
144 | + } | ||
145 | + status = BDRV_BLOCK_ZERO | BDRV_BLOCK_OFFSET_VALID; | ||
146 | + } | ||
147 | + | ||
148 | + *pnum = req.bytes; | ||
149 | + return status; | ||
150 | +} | ||
151 | + | ||
152 | static int64_t qemu_rbd_getlength(BlockDriverState *bs) | ||
153 | { | ||
154 | BDRVRBDState *s = bs->opaque; | ||
155 | @@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_rbd = { | ||
156 | #ifdef LIBRBD_SUPPORTS_WRITE_ZEROES | ||
157 | .bdrv_co_pwrite_zeroes = qemu_rbd_co_pwrite_zeroes, | ||
158 | #endif | ||
159 | + .bdrv_co_block_status = qemu_rbd_co_block_status, | ||
160 | |||
161 | .bdrv_snapshot_create = qemu_rbd_snap_create, | ||
162 | .bdrv_snapshot_delete = qemu_rbd_snap_remove, | ||
163 | -- | 92 | -- |
164 | 2.31.1 | 93 | 2.41.0 |
165 | |||
166 | diff view generated by jsdifflib |
1 | From: Stefano Garzarella <sgarzare@redhat.com> | 1 | When the permission related BlockDriver callbacks are called, we are in |
---|---|---|---|
2 | 2 | the middle of an operation traversing the block graph. Polling in such a | |
3 | This new parameter can be used by block devices to limit the | 3 | place is a very bad idea because the graph could change in unexpected |
4 | Linux AIO batch size more than the limit set by the AIO context. | 4 | ways. In the future, callers will also hold the graph lock, which is |
5 | 5 | likely to turn polling into a deadlock. | |
6 | file-posix backend supports this, passing its `aio-max-batch` option | 6 | |
7 | previously added. | 7 | So we need to get rid of calls to functions like bdrv_getlength() or |
8 | 8 | bdrv_truncate() there as these functions poll internally. They are | |
9 | Add an helper function to calculate the maximum batch size. | 9 | currently used so that when no parent has write/resize permissions on |
10 | 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> | ||
11 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | 26 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> |
12 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | 27 | Message-ID: <20230911094620.45040-4-kwolf@redhat.com> |
13 | Signed-off-by: Stefano Garzarella <sgarzare@redhat.com> | ||
14 | Message-Id: <20211026162346.253081-3-sgarzare@redhat.com> | ||
15 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 28 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
16 | --- | 29 | --- |
17 | include/block/raw-aio.h | 3 ++- | 30 | block/preallocate.c | 89 +++++++++++++++++++++++++++++++++++---------- |
18 | block/file-posix.c | 3 ++- | 31 | 1 file changed, 69 insertions(+), 20 deletions(-) |
19 | block/linux-aio.c | 30 ++++++++++++++++++++++-------- | 32 | |
20 | 3 files changed, 26 insertions(+), 10 deletions(-) | 33 | diff --git a/block/preallocate.c b/block/preallocate.c |
21 | |||
22 | diff --git a/include/block/raw-aio.h b/include/block/raw-aio.h | ||
23 | index XXXXXXX..XXXXXXX 100644 | 34 | index XXXXXXX..XXXXXXX 100644 |
24 | --- a/include/block/raw-aio.h | 35 | --- a/block/preallocate.c |
25 | +++ b/include/block/raw-aio.h | 36 | +++ b/block/preallocate.c |
26 | @@ -XXX,XX +XXX,XX @@ typedef struct LinuxAioState LinuxAioState; | 37 | @@ -XXX,XX +XXX,XX @@ typedef struct BDRVPreallocateState { |
27 | LinuxAioState *laio_init(Error **errp); | 38 | * be invalid (< 0) when we don't have both exclusive BLK_PERM_RESIZE and |
28 | void laio_cleanup(LinuxAioState *s); | 39 | * BLK_PERM_WRITE permissions on file child. |
29 | int coroutine_fn laio_co_submit(BlockDriverState *bs, LinuxAioState *s, int fd, | 40 | */ |
30 | - uint64_t offset, QEMUIOVector *qiov, int type); | 41 | + |
31 | + uint64_t offset, QEMUIOVector *qiov, int type, | 42 | + /* Gives up the resize permission on children when parents don't need it */ |
32 | + uint64_t dev_max_batch); | 43 | + QEMUBH *drop_resize_bh; |
33 | void laio_detach_aio_context(LinuxAioState *s, AioContext *old_context); | 44 | } BDRVPreallocateState; |
34 | void laio_attach_aio_context(LinuxAioState *s, AioContext *new_context); | 45 | |
35 | void laio_io_plug(BlockDriverState *bs, LinuxAioState *s); | 46 | +static int preallocate_drop_resize(BlockDriverState *bs, Error **errp); |
36 | diff --git a/block/file-posix.c b/block/file-posix.c | 47 | +static void preallocate_drop_resize_bh(void *opaque); |
37 | index XXXXXXX..XXXXXXX 100644 | 48 | + |
38 | --- a/block/file-posix.c | 49 | #define PREALLOCATE_OPT_PREALLOC_ALIGN "prealloc-align" |
39 | +++ b/block/file-posix.c | 50 | #define PREALLOCATE_OPT_PREALLOC_SIZE "prealloc-size" |
40 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_prw(BlockDriverState *bs, uint64_t offset, | 51 | static QemuOptsList runtime_opts = { |
41 | } else if (s->use_linux_aio) { | 52 | @@ -XXX,XX +XXX,XX @@ static int preallocate_open(BlockDriverState *bs, QDict *options, int flags, |
42 | LinuxAioState *aio = aio_get_linux_aio(bdrv_get_aio_context(bs)); | 53 | * For this to work, mark them invalid. |
43 | assert(qiov->size == bytes); | 54 | */ |
44 | - return laio_co_submit(bs, aio, s->fd, offset, qiov, type); | 55 | s->file_end = s->zero_start = s->data_end = -EINVAL; |
45 | + return laio_co_submit(bs, aio, s->fd, offset, qiov, type, | 56 | + s->drop_resize_bh = qemu_bh_new(preallocate_drop_resize_bh, bs); |
46 | + s->aio_max_batch); | 57 | |
47 | #endif | 58 | ret = bdrv_open_file_child(NULL, options, "file", bs, errp); |
48 | } | 59 | if (ret < 0) { |
49 | 60 | @@ -XXX,XX +XXX,XX @@ static void preallocate_close(BlockDriverState *bs) | |
50 | diff --git a/block/linux-aio.c b/block/linux-aio.c | 61 | { |
51 | index XXXXXXX..XXXXXXX 100644 | 62 | BDRVPreallocateState *s = bs->opaque; |
52 | --- a/block/linux-aio.c | 63 | |
53 | +++ b/block/linux-aio.c | 64 | + qemu_bh_cancel(s->drop_resize_bh); |
54 | @@ -XXX,XX +XXX,XX @@ static void ioq_submit(LinuxAioState *s) | 65 | + qemu_bh_delete(s->drop_resize_bh); |
55 | } | 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; | ||
56 | } | 100 | } |
57 | 101 | ||
58 | +static uint64_t laio_max_batch(LinuxAioState *s, uint64_t dev_max_batch) | 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) | ||
59 | +{ | 145 | +{ |
60 | + uint64_t max_batch = s->aio_context->aio_max_batch ?: DEFAULT_MAX_BATCH; | 146 | + /* |
61 | + | 147 | + * In case of errors, we'll simply keep the exclusive lock on the image |
62 | + /* | 148 | + * indefinitely. |
63 | + * AIO context can be shared between multiple block devices, so | 149 | + */ |
64 | + * `dev_max_batch` allows reducing the batch size for latency-sensitive | 150 | + preallocate_drop_resize(opaque, NULL); |
65 | + * devices. | ||
66 | + */ | ||
67 | + max_batch = MIN_NON_ZERO(dev_max_batch, max_batch); | ||
68 | + | ||
69 | + /* limit the batch with the number of available events */ | ||
70 | + max_batch = MIN_NON_ZERO(MAX_EVENTS - s->io_q.in_flight, max_batch); | ||
71 | + | ||
72 | + return max_batch; | ||
73 | +} | 151 | +} |
74 | + | 152 | + |
75 | void laio_io_plug(BlockDriverState *bs, LinuxAioState *s) | 153 | static void preallocate_set_perm(BlockDriverState *bs, |
76 | { | 154 | uint64_t perm, uint64_t shared) |
77 | s->io_q.plugged++; | 155 | { |
78 | @@ -XXX,XX +XXX,XX @@ void laio_io_unplug(BlockDriverState *bs, LinuxAioState *s) | 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 | } | ||
79 | } | 175 | } |
80 | 176 | ||
81 | static int laio_do_submit(int fd, struct qemu_laiocb *laiocb, off_t offset, | 177 | @@ -XXX,XX +XXX,XX @@ static void preallocate_child_perm(BlockDriverState *bs, BdrvChild *c, |
82 | - int type) | 178 | BdrvChildRole role, BlockReopenQueue *reopen_queue, |
83 | + int type, uint64_t dev_max_batch) | 179 | uint64_t perm, uint64_t shared, uint64_t *nperm, uint64_t *nshared) |
84 | { | 180 | { |
85 | LinuxAioState *s = laiocb->ctx; | 181 | + BDRVPreallocateState *s = bs->opaque; |
86 | struct iocb *iocbs = &laiocb->iocb; | 182 | + |
87 | QEMUIOVector *qiov = laiocb->qiov; | 183 | bdrv_default_perms(bs, c, role, reopen_queue, perm, shared, nperm, nshared); |
88 | - int64_t max_batch = s->aio_context->aio_max_batch ?: DEFAULT_MAX_BATCH; | 184 | |
89 | - | 185 | - if (can_write_resize(perm)) { |
90 | - /* limit the batch with the number of available events */ | 186 | - /* This should come by default, but let's enforce: */ |
91 | - max_batch = MIN_NON_ZERO(MAX_EVENTS - s->io_q.in_flight, max_batch); | 187 | + /* |
92 | 188 | + * We need exclusive write and resize permissions on the child not only when | |
93 | switch (type) { | 189 | + * the parent can write to it, but also after the parent gave up write |
94 | case QEMU_AIO_WRITE: | 190 | + * permissions until preallocate_drop_resize() has completed. |
95 | @@ -XXX,XX +XXX,XX @@ static int laio_do_submit(int fd, struct qemu_laiocb *laiocb, off_t offset, | 191 | + */ |
96 | s->io_q.in_queue++; | 192 | + if (can_write_resize(perm) || s->data_end != -EINVAL) { |
97 | if (!s->io_q.blocked && | 193 | *nperm |= BLK_PERM_WRITE | BLK_PERM_RESIZE; |
98 | (!s->io_q.plugged || | 194 | |
99 | - s->io_q.in_queue >= max_batch)) { | 195 | /* |
100 | + s->io_q.in_queue >= laio_max_batch(s, dev_max_batch))) { | 196 | @@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_preallocate_filter = { |
101 | ioq_submit(s); | 197 | .bdrv_co_flush = preallocate_co_flush, |
102 | } | 198 | .bdrv_co_truncate = preallocate_co_truncate, |
103 | 199 | ||
104 | @@ -XXX,XX +XXX,XX @@ static int laio_do_submit(int fd, struct qemu_laiocb *laiocb, off_t offset, | 200 | - .bdrv_check_perm = preallocate_check_perm, |
105 | } | 201 | .bdrv_set_perm = preallocate_set_perm, |
106 | 202 | .bdrv_child_perm = preallocate_child_perm, | |
107 | int coroutine_fn laio_co_submit(BlockDriverState *bs, LinuxAioState *s, int fd, | 203 | |
108 | - uint64_t offset, QEMUIOVector *qiov, int type) | ||
109 | + uint64_t offset, QEMUIOVector *qiov, int type, | ||
110 | + uint64_t dev_max_batch) | ||
111 | { | ||
112 | int ret; | ||
113 | struct qemu_laiocb laiocb = { | ||
114 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn laio_co_submit(BlockDriverState *bs, LinuxAioState *s, int fd, | ||
115 | .qiov = qiov, | ||
116 | }; | ||
117 | |||
118 | - ret = laio_do_submit(fd, &laiocb, offset, type); | ||
119 | + ret = laio_do_submit(fd, &laiocb, offset, type, dev_max_batch); | ||
120 | if (ret < 0) { | ||
121 | return ret; | ||
122 | } | ||
123 | -- | 204 | -- |
124 | 2.31.1 | 205 | 2.41.0 |
125 | |||
126 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | The documentation for bdrv_append() says that the caller must hold the | ||
2 | AioContext lock for bs_top. Change all callers to actually adhere to the | ||
3 | contract. | ||
1 | 4 | ||
5 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
6 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
7 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
8 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
9 | Message-ID: <20230911094620.45040-5-kwolf@redhat.com> | ||
10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
11 | --- | ||
12 | tests/unit/test-bdrv-drain.c | 3 +++ | ||
13 | tests/unit/test-bdrv-graph-mod.c | 6 ++++++ | ||
14 | tests/unit/test-block-iothread.c | 3 +++ | ||
15 | 3 files changed, 12 insertions(+) | ||
16 | |||
17 | diff --git a/tests/unit/test-bdrv-drain.c b/tests/unit/test-bdrv-drain.c | ||
18 | index XXXXXXX..XXXXXXX 100644 | ||
19 | --- a/tests/unit/test-bdrv-drain.c | ||
20 | +++ b/tests/unit/test-bdrv-drain.c | ||
21 | @@ -XXX,XX +XXX,XX @@ static void test_append_to_drained(void) | ||
22 | g_assert_cmpint(base_s->drain_count, ==, 1); | ||
23 | g_assert_cmpint(base->in_flight, ==, 0); | ||
24 | |||
25 | + aio_context_acquire(qemu_get_aio_context()); | ||
26 | bdrv_append(overlay, base, &error_abort); | ||
27 | + aio_context_release(qemu_get_aio_context()); | ||
28 | + | ||
29 | g_assert_cmpint(base->in_flight, ==, 0); | ||
30 | g_assert_cmpint(overlay->in_flight, ==, 0); | ||
31 | |||
32 | diff --git a/tests/unit/test-bdrv-graph-mod.c b/tests/unit/test-bdrv-graph-mod.c | ||
33 | index XXXXXXX..XXXXXXX 100644 | ||
34 | --- a/tests/unit/test-bdrv-graph-mod.c | ||
35 | +++ b/tests/unit/test-bdrv-graph-mod.c | ||
36 | @@ -XXX,XX +XXX,XX @@ static void test_update_perm_tree(void) | ||
37 | bdrv_attach_child(filter, bs, "child", &child_of_bds, | ||
38 | BDRV_CHILD_DATA, &error_abort); | ||
39 | |||
40 | + aio_context_acquire(qemu_get_aio_context()); | ||
41 | ret = bdrv_append(filter, bs, NULL); | ||
42 | g_assert_cmpint(ret, <, 0); | ||
43 | + aio_context_release(qemu_get_aio_context()); | ||
44 | |||
45 | bdrv_unref(filter); | ||
46 | blk_unref(root); | ||
47 | @@ -XXX,XX +XXX,XX @@ static void test_should_update_child(void) | ||
48 | g_assert(target->backing->bs == bs); | ||
49 | bdrv_attach_child(filter, target, "target", &child_of_bds, | ||
50 | BDRV_CHILD_DATA, &error_abort); | ||
51 | + aio_context_acquire(qemu_get_aio_context()); | ||
52 | bdrv_append(filter, bs, &error_abort); | ||
53 | + aio_context_release(qemu_get_aio_context()); | ||
54 | g_assert(target->backing->bs == bs); | ||
55 | |||
56 | bdrv_unref(filter); | ||
57 | @@ -XXX,XX +XXX,XX @@ static void test_append_greedy_filter(void) | ||
58 | BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, | ||
59 | &error_abort); | ||
60 | |||
61 | + aio_context_acquire(qemu_get_aio_context()); | ||
62 | bdrv_append(fl, base, &error_abort); | ||
63 | + aio_context_release(qemu_get_aio_context()); | ||
64 | bdrv_unref(fl); | ||
65 | bdrv_unref(top); | ||
66 | } | ||
67 | diff --git a/tests/unit/test-block-iothread.c b/tests/unit/test-block-iothread.c | ||
68 | index XXXXXXX..XXXXXXX 100644 | ||
69 | --- a/tests/unit/test-block-iothread.c | ||
70 | +++ b/tests/unit/test-block-iothread.c | ||
71 | @@ -XXX,XX +XXX,XX @@ static void test_propagate_mirror(void) | ||
72 | &error_abort); | ||
73 | |||
74 | /* Start a mirror job */ | ||
75 | + aio_context_acquire(main_ctx); | ||
76 | mirror_start("job0", src, target, NULL, JOB_DEFAULT, 0, 0, 0, | ||
77 | MIRROR_SYNC_MODE_NONE, MIRROR_OPEN_BACKING_CHAIN, false, | ||
78 | BLOCKDEV_ON_ERROR_REPORT, BLOCKDEV_ON_ERROR_REPORT, | ||
79 | false, "filter_node", MIRROR_COPY_MODE_BACKGROUND, | ||
80 | &error_abort); | ||
81 | + aio_context_release(main_ctx); | ||
82 | + | ||
83 | WITH_JOB_LOCK_GUARD() { | ||
84 | job = job_get_locked("job0"); | ||
85 | } | ||
86 | -- | ||
87 | 2.41.0 | diff view generated by jsdifflib |
1 | From: Philippe Mathieu-Daudé <philmd@redhat.com> | 1 | bdrv_unref() is called by a lot of places that need to hold the graph |
---|---|---|---|
2 | lock (it naturally happens in the context of operations that change the | ||
3 | graph). However, bdrv_unref() takes the graph writer lock internally, so | ||
4 | it can't actually be called while already holding a graph lock without | ||
5 | causing a deadlock. | ||
2 | 6 | ||
3 | Instead of duplicating code, extract the common helper to free | 7 | bdrv_unref() also can't just become GRAPH_WRLOCK because it drains the |
4 | a single queue. | 8 | node before closing it, and draining requires that the graph is |
9 | unlocked. | ||
5 | 10 | ||
6 | Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com> | 11 | The solution is to defer deleting the node until we don't hold the lock |
7 | Message-Id: <20211006164931.172349-4-philmd@redhat.com> | 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> | ||
8 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | 30 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> |
9 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 31 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
10 | --- | 32 | --- |
11 | block/nvme.c | 9 +++++++-- | 33 | include/block/block-global-state.h | 1 + |
12 | 1 file changed, 7 insertions(+), 2 deletions(-) | 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(-) | ||
13 | 38 | ||
14 | diff --git a/block/nvme.c b/block/nvme.c | 39 | diff --git a/include/block/block-global-state.h b/include/block/block-global-state.h |
15 | index XXXXXXX..XXXXXXX 100644 | 40 | index XXXXXXX..XXXXXXX 100644 |
16 | --- a/block/nvme.c | 41 | --- a/include/block/block-global-state.h |
17 | +++ b/block/nvme.c | 42 | +++ b/include/block/block-global-state.h |
18 | @@ -XXX,XX +XXX,XX @@ static bool nvme_init_queue(BDRVNVMeState *s, NVMeQueue *q, | 43 | @@ -XXX,XX +XXX,XX @@ void bdrv_img_create(const char *filename, const char *fmt, |
19 | return r == 0; | 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 | } | ||
20 | } | 57 | } |
21 | 58 | ||
22 | +static void nvme_free_queue(NVMeQueue *q) | 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) | ||
23 | +{ | 68 | +{ |
24 | + qemu_vfree(q->queue); | 69 | + if (!bs) { |
70 | + return; | ||
71 | + } | ||
72 | + aio_bh_schedule_oneshot(qemu_get_aio_context(), | ||
73 | + (QEMUBHFunc *) bdrv_unref, bs); | ||
25 | +} | 74 | +} |
26 | + | 75 | + |
27 | static void nvme_free_queue_pair(NVMeQueuePair *q) | 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) | ||
28 | { | 85 | { |
29 | trace_nvme_free_queue_pair(q->index, q, &q->cq, &q->sq); | 86 | GLOBAL_STATE_CODE(); |
30 | if (q->completion_bh) { | 87 | - QEMU_LOCK_GUARD(&aio_context_list_lock); |
31 | qemu_bh_delete(q->completion_bh); | 88 | assert(qatomic_read(&has_writer)); |
32 | } | 89 | |
33 | + nvme_free_queue(&q->sq); | 90 | + WITH_QEMU_LOCK_GUARD(&aio_context_list_lock) { |
34 | + nvme_free_queue(&q->cq); | 91 | + /* |
35 | qemu_vfree(q->prp_list_pages); | 92 | + * No need for memory barriers, this works in pair with |
36 | - qemu_vfree(q->sq.queue); | 93 | + * the slow path of rdlock() and both take the lock. |
37 | - qemu_vfree(q->cq.queue); | 94 | + */ |
38 | qemu_mutex_destroy(&q->lock); | 95 | + qatomic_store_release(&has_writer, 0); |
39 | g_free(q); | 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()); | ||
40 | } | 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 | ||
41 | -- | 147 | -- |
42 | 2.31.1 | 148 | 2.41.0 |
43 | |||
44 | 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 |
1 | From: Philippe Mathieu-Daudé <philmd@redhat.com> | 1 | The function reads the parents list, so it needs to hold the graph lock. |
---|---|---|---|
2 | 2 | ||
3 | Since commit 4d324c0bf65 ("introduce QEMU_AUTO_VFREE") buffers | 3 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
4 | allocated by qemu_memalign() can automatically freed when using | 4 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
5 | the QEMU_AUTO_VFREE macro. Use it to simplify a bit. | ||
6 | |||
7 | Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com> | ||
8 | Message-Id: <20211006164931.172349-2-philmd@redhat.com> | ||
9 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | 5 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> |
6 | Message-ID: <20230911094620.45040-14-kwolf@redhat.com> | ||
10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
11 | --- | 8 | --- |
12 | block/nvme.c | 11 ++++------- | 9 | include/block/block_int-common.h | 6 ++--- |
13 | 1 file changed, 4 insertions(+), 7 deletions(-) | 10 | include/block/block_int-global-state.h | 8 +++--- |
11 | include/sysemu/block-backend-global-state.h | 4 +-- | ||
12 | block.c | 28 +++++++++++++-------- | ||
13 | block/block-backend.c | 26 ++++++++++++++----- | ||
14 | block/crypto.c | 6 +++-- | ||
15 | block/mirror.c | 8 ++++++ | ||
16 | block/vmdk.c | 2 ++ | ||
17 | tests/unit/test-bdrv-graph-mod.c | 4 +++ | ||
18 | 9 files changed, 66 insertions(+), 26 deletions(-) | ||
14 | 19 | ||
15 | diff --git a/block/nvme.c b/block/nvme.c | 20 | diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h |
16 | index XXXXXXX..XXXXXXX 100644 | 21 | index XXXXXXX..XXXXXXX 100644 |
17 | --- a/block/nvme.c | 22 | --- a/include/block/block_int-common.h |
18 | +++ b/block/nvme.c | 23 | +++ b/include/block/block_int-common.h |
19 | @@ -XXX,XX +XXX,XX @@ static bool nvme_identify(BlockDriverState *bs, int namespace, Error **errp) | 24 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { |
20 | { | 25 | */ |
21 | BDRVNVMeState *s = bs->opaque; | 26 | void (*bdrv_cancel_in_flight)(BlockDriverState *bs); |
22 | bool ret = false; | 27 | |
23 | - union { | 28 | - int (*bdrv_inactivate)(BlockDriverState *bs); |
24 | + QEMU_AUTO_VFREE union { | 29 | + int GRAPH_RDLOCK_PTR (*bdrv_inactivate)(BlockDriverState *bs); |
25 | NvmeIdCtrl ctrl; | 30 | |
26 | NvmeIdNs ns; | 31 | int (*bdrv_snapshot_create)(BlockDriverState *bs, |
27 | - } *id; | 32 | QEMUSnapshotInfo *sn_info); |
28 | + } *id = NULL; | 33 | @@ -XXX,XX +XXX,XX @@ struct BdrvChildClass { |
29 | NvmeLBAF *lbaf; | 34 | * when migration is completing) and it can start/stop requesting |
30 | uint16_t oncs; | 35 | * permissions and doing I/O on it. |
31 | int r; | 36 | */ |
32 | @@ -XXX,XX +XXX,XX @@ static bool nvme_identify(BlockDriverState *bs, int namespace, Error **errp) | 37 | - void (*activate)(BdrvChild *child, Error **errp); |
33 | s->blkshift = lbaf->ds; | 38 | - int (*inactivate)(BdrvChild *child); |
34 | out: | 39 | + void GRAPH_RDLOCK_PTR (*activate)(BdrvChild *child, Error **errp); |
35 | qemu_vfio_dma_unmap(s->vfio, id); | 40 | + int GRAPH_RDLOCK_PTR (*inactivate)(BdrvChild *child); |
36 | - qemu_vfree(id); | 41 | |
37 | 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) | ||
38 | return ret; | 281 | return ret; |
39 | } | 282 | } |
40 | @@ -XXX,XX +XXX,XX @@ static int nvme_co_prw(BlockDriverState *bs, uint64_t offset, uint64_t bytes, | 283 | |
41 | { | 284 | -static void |
42 | BDRVNVMeState *s = bs->opaque; | 285 | +static void GRAPH_RDLOCK |
43 | int r; | 286 | block_crypto_amend_cleanup(BlockDriverState *bs) |
44 | - uint8_t *buf = NULL; | 287 | { |
45 | + QEMU_AUTO_VFREE uint8_t *buf = NULL; | 288 | BlockCrypto *crypto = bs->opaque; |
46 | QEMUIOVector local_qiov; | 289 | @@ -XXX,XX +XXX,XX @@ block_crypto_amend_options_luks(BlockDriverState *bs, |
47 | size_t len = QEMU_ALIGN_UP(bytes, qemu_real_host_page_size); | 290 | QCryptoBlockAmendOptions *amend_options = NULL; |
48 | assert(QEMU_IS_ALIGNED(offset, s->page_size)); | 291 | int ret = -EINVAL; |
49 | @@ -XXX,XX +XXX,XX @@ static int nvme_co_prw(BlockDriverState *bs, uint64_t offset, uint64_t bytes, | 292 | |
50 | if (!r && !is_write) { | 293 | + assume_graph_lock(); /* FIXME */ |
51 | qemu_iovec_from_buf(qiov, 0, buf, bytes); | 294 | + |
52 | } | 295 | assert(crypto); |
53 | - qemu_vfree(buf); | 296 | assert(crypto->block); |
54 | return r; | 297 | |
55 | } | 298 | diff --git a/block/mirror.c b/block/mirror.c |
56 | 299 | index XXXXXXX..XXXXXXX 100644 | |
57 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn nvme_co_pdiscard(BlockDriverState *bs, | 300 | --- a/block/mirror.c |
58 | BDRVNVMeState *s = bs->opaque; | 301 | +++ b/block/mirror.c |
59 | NVMeQueuePair *ioq = s->queues[INDEX_IO(0)]; | 302 | @@ -XXX,XX +XXX,XX @@ static int mirror_exit_common(Job *job) |
60 | NVMeRequest *req; | 303 | * mirror_top_bs from now on, so keep it drained. */ |
61 | - NvmeDsmRange *buf; | 304 | bdrv_drained_begin(mirror_top_bs); |
62 | + QEMU_AUTO_VFREE NvmeDsmRange *buf = NULL; | 305 | bs_opaque->stop = true; |
63 | QEMUIOVector local_qiov; | 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; | ||
64 | int ret; | 317 | int ret; |
65 | 318 | ||
66 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn nvme_co_pdiscard(BlockDriverState *bs, | 319 | + GLOBAL_STATE_CODE(); |
67 | trace_nvme_dsm_done(s, offset, bytes, ret); | 320 | + |
68 | out: | 321 | if (granularity == 0) { |
69 | qemu_iovec_destroy(&local_qiov); | 322 | granularity = bdrv_get_default_bitmap_granularity(target); |
70 | - qemu_vfree(buf); | 323 | } |
71 | return ret; | 324 | @@ -XXX,XX +XXX,XX @@ fail: |
72 | 325 | } | |
73 | } | 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 | |||
74 | -- | 370 | -- |
75 | 2.31.1 | 371 | 2.41.0 |
76 | |||
77 | diff view generated by jsdifflib |
1 | From: Stefano Garzarella <sgarzare@redhat.com> | 1 | The function reads the parents list, so it needs to hold the graph lock. |
---|---|---|---|
2 | 2 | ||
3 | Between the submission of a request and the unplug, other devices | 3 | This happens to result in BlockDriver.bdrv_set_perm() to be called with |
4 | with larger limits may have been queued new requests without flushing | 4 | the graph lock held. For consistency, make it the same for all of the |
5 | the batch. | 5 | BlockDriver callbacks for updating permissions and annotate the function |
6 | pointers with GRAPH_RDLOCK_PTR. | ||
6 | 7 | ||
7 | Using the new `dev_max_batch` parameter, laio_io_unplug() can check | 8 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
8 | if the batch exceeds the device limit to flush the current batch. | 9 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
9 | |||
10 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | 10 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> |
11 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | 11 | Message-ID: <20230911094620.45040-15-kwolf@redhat.com> |
12 | Signed-off-by: Stefano Garzarella <sgarzare@redhat.com> | ||
13 | Message-Id: <20211026162346.253081-4-sgarzare@redhat.com> | ||
14 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
15 | --- | 13 | --- |
16 | include/block/raw-aio.h | 3 ++- | 14 | include/block/block_int-common.h | 9 ++++--- |
17 | block/file-posix.c | 2 +- | 15 | include/block/block_int-global-state.h | 4 +-- |
18 | block/linux-aio.c | 8 +++++--- | 16 | block.c | 35 ++++++++++++++++++++------ |
19 | 3 files changed, 8 insertions(+), 5 deletions(-) | 17 | blockdev.c | 6 +++++ |
18 | 4 files changed, 40 insertions(+), 14 deletions(-) | ||
20 | 19 | ||
21 | diff --git a/include/block/raw-aio.h b/include/block/raw-aio.h | 20 | diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h |
22 | index XXXXXXX..XXXXXXX 100644 | 21 | index XXXXXXX..XXXXXXX 100644 |
23 | --- a/include/block/raw-aio.h | 22 | --- a/include/block/block_int-common.h |
24 | +++ b/include/block/raw-aio.h | 23 | +++ b/include/block/block_int-common.h |
25 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn laio_co_submit(BlockDriverState *bs, LinuxAioState *s, int fd, | 24 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { |
26 | void laio_detach_aio_context(LinuxAioState *s, AioContext *old_context); | 25 | * If both conditions are met, 0 is returned. Otherwise, -errno is returned |
27 | void laio_attach_aio_context(LinuxAioState *s, AioContext *new_context); | 26 | * and errp is set to an error describing the conflict. |
28 | void laio_io_plug(BlockDriverState *bs, LinuxAioState *s); | 27 | */ |
29 | -void laio_io_unplug(BlockDriverState *bs, LinuxAioState *s); | 28 | - int (*bdrv_check_perm)(BlockDriverState *bs, uint64_t perm, |
30 | +void laio_io_unplug(BlockDriverState *bs, LinuxAioState *s, | 29 | - uint64_t shared, Error **errp); |
31 | + uint64_t dev_max_batch); | 30 | + int GRAPH_RDLOCK_PTR (*bdrv_check_perm)(BlockDriverState *bs, uint64_t perm, |
32 | #endif | 31 | + uint64_t shared, Error **errp); |
33 | /* io_uring.c - Linux io_uring implementation */ | 32 | |
34 | #ifdef CONFIG_LINUX_IO_URING | 33 | /** |
35 | diff --git a/block/file-posix.c b/block/file-posix.c | 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 | ||
36 | index XXXXXXX..XXXXXXX 100644 | 55 | index XXXXXXX..XXXXXXX 100644 |
37 | --- a/block/file-posix.c | 56 | --- a/include/block/block_int-global-state.h |
38 | +++ b/block/file-posix.c | 57 | +++ b/include/block/block_int-global-state.h |
39 | @@ -XXX,XX +XXX,XX @@ static void raw_aio_unplug(BlockDriverState *bs) | 58 | @@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs, |
40 | #ifdef CONFIG_LINUX_AIO | 59 | void *opaque, Error **errp); |
41 | if (s->use_linux_aio) { | 60 | void bdrv_root_unref_child(BdrvChild *child); |
42 | LinuxAioState *aio = aio_get_linux_aio(bdrv_get_aio_context(bs)); | 61 | |
43 | - laio_io_unplug(bs, aio); | 62 | -void bdrv_get_cumulative_perm(BlockDriverState *bs, uint64_t *perm, |
44 | + laio_io_unplug(bs, aio, s->aio_max_batch); | 63 | - uint64_t *shared_perm); |
45 | } | 64 | +void GRAPH_RDLOCK bdrv_get_cumulative_perm(BlockDriverState *bs, uint64_t *perm, |
46 | #endif | 65 | + uint64_t *shared_perm); |
47 | #ifdef CONFIG_LINUX_IO_URING | 66 | |
48 | diff --git a/block/linux-aio.c b/block/linux-aio.c | 67 | /** |
68 | * Sets a BdrvChild's permissions. Avoid if the parent is a BDS; use | ||
69 | diff --git a/block.c b/block.c | ||
49 | index XXXXXXX..XXXXXXX 100644 | 70 | index XXXXXXX..XXXXXXX 100644 |
50 | --- a/block/linux-aio.c | 71 | --- a/block.c |
51 | +++ b/block/linux-aio.c | 72 | +++ b/block.c |
52 | @@ -XXX,XX +XXX,XX @@ void laio_io_plug(BlockDriverState *bs, LinuxAioState *s) | 73 | @@ -XXX,XX +XXX,XX @@ static void bdrv_child_set_perm(BdrvChild *c, uint64_t perm, |
53 | s->io_q.plugged++; | 74 | tran_add(tran, &bdrv_child_set_pem_drv, s); |
54 | } | 75 | } |
55 | 76 | ||
56 | -void laio_io_unplug(BlockDriverState *bs, LinuxAioState *s) | 77 | -static void bdrv_drv_set_perm_commit(void *opaque) |
57 | +void laio_io_unplug(BlockDriverState *bs, LinuxAioState *s, | 78 | +static void GRAPH_RDLOCK bdrv_drv_set_perm_commit(void *opaque) |
58 | + uint64_t dev_max_batch) | ||
59 | { | 79 | { |
60 | assert(s->io_q.plugged); | 80 | BlockDriverState *bs = opaque; |
61 | - if (--s->io_q.plugged == 0 && | 81 | uint64_t cumulative_perms, cumulative_shared_perms; |
62 | - !s->io_q.blocked && !QSIMPLEQ_EMPTY(&s->io_q.pending)) { | 82 | @@ -XXX,XX +XXX,XX @@ static void bdrv_drv_set_perm_commit(void *opaque) |
63 | + if (s->io_q.in_queue >= laio_max_batch(s, dev_max_batch) || | ||
64 | + (--s->io_q.plugged == 0 && | ||
65 | + !s->io_q.blocked && !QSIMPLEQ_EMPTY(&s->io_q.pending))) { | ||
66 | ioq_submit(s); | ||
67 | } | 83 | } |
68 | } | 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 | } | ||
69 | -- | 182 | -- |
70 | 2.31.1 | 183 | 2.41.0 |
71 | |||
72 | 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 |
1 | From: Philippe Mathieu-Daudé <philmd@redhat.com> | 1 | The function reads the parents list, so it needs to hold the graph lock. |
---|---|---|---|
2 | 2 | ||
3 | For debugging purpose it is helpful to know the CQ/SQ pointers. | 3 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
4 | We already have a trace event in nvme_free_queue_pair(), extend | 4 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
5 | it to report these pointer addresses. | 5 | Message-ID: <20230911094620.45040-18-kwolf@redhat.com> |
6 | |||
7 | Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com> | ||
8 | Message-Id: <20211006164931.172349-3-philmd@redhat.com> | ||
9 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | 6 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> |
10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
11 | --- | 8 | --- |
12 | block/nvme.c | 2 +- | 9 | block.c | 2 ++ |
13 | block/trace-events | 2 +- | 10 | 1 file changed, 2 insertions(+) |
14 | 2 files changed, 2 insertions(+), 2 deletions(-) | ||
15 | 11 | ||
16 | diff --git a/block/nvme.c b/block/nvme.c | 12 | diff --git a/block.c b/block.c |
17 | index XXXXXXX..XXXXXXX 100644 | 13 | index XXXXXXX..XXXXXXX 100644 |
18 | --- a/block/nvme.c | 14 | --- a/block.c |
19 | +++ b/block/nvme.c | 15 | +++ b/block.c |
20 | @@ -XXX,XX +XXX,XX @@ static bool nvme_init_queue(BDRVNVMeState *s, NVMeQueue *q, | 16 | @@ -XXX,XX +XXX,XX @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base, |
21 | 17 | backing_file_str = base->filename; | |
22 | static void nvme_free_queue_pair(NVMeQueuePair *q) | ||
23 | { | ||
24 | - trace_nvme_free_queue_pair(q->index, q); | ||
25 | + trace_nvme_free_queue_pair(q->index, q, &q->cq, &q->sq); | ||
26 | if (q->completion_bh) { | ||
27 | qemu_bh_delete(q->completion_bh); | ||
28 | } | 18 | } |
29 | diff --git a/block/trace-events b/block/trace-events | 19 | |
30 | index XXXXXXX..XXXXXXX 100644 | 20 | + bdrv_graph_rdlock_main_loop(); |
31 | --- a/block/trace-events | 21 | QLIST_FOREACH(c, &top->parents, next_parent) { |
32 | +++ b/block/trace-events | 22 | updated_children = g_slist_prepend(updated_children, c); |
33 | @@ -XXX,XX +XXX,XX @@ nvme_dsm_done(void *s, int64_t offset, int64_t bytes, int ret) "s %p offset 0x%" | 23 | } |
34 | nvme_dma_map_flush(void *s) "s %p" | 24 | + bdrv_graph_rdunlock_main_loop(); |
35 | nvme_free_req_queue_wait(void *s, unsigned q_index) "s %p q #%u" | 25 | |
36 | nvme_create_queue_pair(unsigned q_index, void *q, size_t size, void *aio_context, int fd) "index %u q %p size %zu aioctx %p fd %d" | 26 | /* |
37 | -nvme_free_queue_pair(unsigned q_index, void *q) "index %u q %p" | 27 | * It seems correct to pass detach_subchain=true here, but it triggers |
38 | +nvme_free_queue_pair(unsigned q_index, void *q, void *cq, void *sq) "index %u q %p cq %p sq %p" | ||
39 | nvme_cmd_map_qiov(void *s, void *cmd, void *req, void *qiov, int entries) "s %p cmd %p req %p qiov %p entries %d" | ||
40 | nvme_cmd_map_qiov_pages(void *s, int i, uint64_t page) "s %p page[%d] 0x%"PRIx64 | ||
41 | nvme_cmd_map_qiov_iov(void *s, int i, void *page, int pages) "s %p iov[%d] %p pages %d" | ||
42 | -- | 28 | -- |
43 | 2.31.1 | 29 | 2.41.0 |
44 | |||
45 | diff view generated by jsdifflib |
1 | From: Fabrice Fontaine <fontaine.fabrice@gmail.com> | 1 | The function reads the parents list, so it needs to hold the graph lock. |
---|---|---|---|
2 | 2 | ||
3 | Include linux/falloc.h if CONFIG_FALLOCATE_ZERO_RANGE is defined to fix | 3 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
4 | https://gitlab.com/qemu-project/qemu/-/commit/50482fda98bd62e072c30b7ea73c985c4e9d9bbb | 4 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
5 | and avoid the following build failure on musl: | 5 | Message-ID: <20230911094620.45040-19-kwolf@redhat.com> |
6 | 6 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | |
7 | ../block/export/fuse.c: In function 'fuse_fallocate': | ||
8 | ../block/export/fuse.c:643:21: error: 'FALLOC_FL_ZERO_RANGE' undeclared (first use in this function) | ||
9 | 643 | else if (mode & FALLOC_FL_ZERO_RANGE) { | ||
10 | | ^~~~~~~~~~~~~~~~~~~~ | ||
11 | |||
12 | Fixes: | ||
13 | - http://autobuild.buildroot.org/results/be24433a429fda681fb66698160132c1c99bc53b | ||
14 | |||
15 | Fixes: 50482fda98b ("block/export/fuse.c: fix musl build") | ||
16 | Signed-off-by: Fabrice Fontaine <fontaine.fabrice@gmail.com> | ||
17 | Message-Id: <20211022095209.1319671-1-fontaine.fabrice@gmail.com> | ||
18 | Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> | ||
19 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
20 | --- | 8 | --- |
21 | block/export/fuse.c | 4 ++++ | 9 | block.c | 4 ++++ |
22 | 1 file changed, 4 insertions(+) | 10 | 1 file changed, 4 insertions(+) |
23 | 11 | ||
24 | diff --git a/block/export/fuse.c b/block/export/fuse.c | 12 | diff --git a/block.c b/block.c |
25 | index XXXXXXX..XXXXXXX 100644 | 13 | index XXXXXXX..XXXXXXX 100644 |
26 | --- a/block/export/fuse.c | 14 | --- a/block.c |
27 | +++ b/block/export/fuse.c | 15 | +++ b/block.c |
28 | @@ -XXX,XX +XXX,XX @@ | 16 | @@ -XXX,XX +XXX,XX @@ static bool bdrv_change_aio_context(BlockDriverState *bs, AioContext *ctx, |
29 | #include <fuse.h> | 17 | return true; |
30 | #include <fuse_lowlevel.h> | 18 | } |
31 | 19 | ||
32 | +#if defined(CONFIG_FALLOCATE_ZERO_RANGE) | 20 | + bdrv_graph_rdlock_main_loop(); |
33 | +#include <linux/falloc.h> | 21 | QLIST_FOREACH(c, &bs->parents, next_parent) { |
34 | +#endif | 22 | if (!bdrv_parent_change_aio_context(c, ctx, visited, tran, errp)) { |
35 | + | 23 | + bdrv_graph_rdunlock_main_loop(); |
36 | #ifdef __linux__ | 24 | return false; |
37 | #include <linux/fs.h> | 25 | } |
38 | #endif | 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) { | ||
39 | -- | 38 | -- |
40 | 2.31.1 | 39 | 2.41.0 |
41 | |||
42 | diff view generated by jsdifflib |
1 | Using blockdev-snapshot to append a node as an overlay to itself, or to | 1 | Instead of taking the writer lock internally, require callers to already |
---|---|---|---|
2 | any of its parents, causes crashes. Catch the condition and return an | 2 | hold it when calling bdrv_root_unref_child(). These callers will |
3 | error for these cases instead. | 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 | Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1824363 | ||
6 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
7 | Message-Id: <20211018134714.48438-1-kwolf@redhat.com> | 8 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
8 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 9 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> |
10 | Message-ID: <20230911094620.45040-20-kwolf@redhat.com> | ||
9 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
10 | --- | 12 | --- |
11 | block.c | 10 ++++++++++ | 13 | include/block/block_int-global-state.h | 2 +- |
12 | tests/qemu-iotests/085 | 31 ++++++++++++++++++++++++++++++- | 14 | block.c | 6 +++--- |
13 | tests/qemu-iotests/085.out | 33 ++++++++++++++++++++++++++++++--- | 15 | block/block-backend.c | 3 +++ |
14 | 3 files changed, 70 insertions(+), 4 deletions(-) | 16 | blockjob.c | 2 ++ |
17 | 4 files changed, 9 insertions(+), 4 deletions(-) | ||
15 | 18 | ||
19 | diff --git a/include/block/block_int-global-state.h b/include/block/block_int-global-state.h | ||
20 | index XXXXXXX..XXXXXXX 100644 | ||
21 | --- a/include/block/block_int-global-state.h | ||
22 | +++ b/include/block/block_int-global-state.h | ||
23 | @@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs, | ||
24 | BdrvChildRole child_role, | ||
25 | uint64_t perm, uint64_t shared_perm, | ||
26 | void *opaque, Error **errp); | ||
27 | -void bdrv_root_unref_child(BdrvChild *child); | ||
28 | +void GRAPH_WRLOCK bdrv_root_unref_child(BdrvChild *child); | ||
29 | |||
30 | void GRAPH_RDLOCK bdrv_get_cumulative_perm(BlockDriverState *bs, uint64_t *perm, | ||
31 | uint64_t *shared_perm); | ||
16 | diff --git a/block.c b/block.c | 32 | diff --git a/block.c b/block.c |
17 | index XXXXXXX..XXXXXXX 100644 | 33 | index XXXXXXX..XXXXXXX 100644 |
18 | --- a/block.c | 34 | --- a/block.c |
19 | +++ b/block.c | 35 | +++ b/block.c |
20 | @@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_open_inherit(const char *filename, | 36 | @@ -XXX,XX +XXX,XX @@ void bdrv_root_unref_child(BdrvChild *child) |
21 | BdrvChildRole child_role, | 37 | BlockDriverState *child_bs = child->bs; |
22 | Error **errp); | 38 | |
23 | 39 | GLOBAL_STATE_CODE(); | |
24 | +static bool bdrv_recurse_has_child(BlockDriverState *bs, | 40 | - bdrv_graph_wrlock(NULL); |
25 | + BlockDriverState *child); | 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); | ||
51 | } | ||
52 | |||
53 | typedef struct BdrvSetInheritsFrom { | ||
54 | @@ -XXX,XX +XXX,XX @@ void bdrv_unref_child(BlockDriverState *parent, BdrvChild *child) | ||
55 | return; | ||
56 | } | ||
57 | |||
58 | + bdrv_graph_wrlock(NULL); | ||
59 | bdrv_unset_inherits_from(parent, child, NULL); | ||
60 | bdrv_root_unref_child(child); | ||
61 | + bdrv_graph_wrunlock(); | ||
62 | } | ||
63 | |||
64 | |||
65 | diff --git a/block/block-backend.c b/block/block-backend.c | ||
66 | index XXXXXXX..XXXXXXX 100644 | ||
67 | --- a/block/block-backend.c | ||
68 | +++ b/block/block-backend.c | ||
69 | @@ -XXX,XX +XXX,XX @@ void blk_remove_bs(BlockBackend *blk) | ||
70 | blk_drain(blk); | ||
71 | root = blk->root; | ||
72 | blk->root = NULL; | ||
26 | + | 73 | + |
27 | static void bdrv_replace_child_noperm(BdrvChild *child, | 74 | + bdrv_graph_wrlock(NULL); |
28 | BlockDriverState *new_bs); | 75 | bdrv_root_unref_child(root); |
29 | static void bdrv_remove_file_or_backing_child(BlockDriverState *bs, | 76 | + bdrv_graph_wrunlock(); |
30 | @@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_noperm(BdrvChild *child, | ||
31 | int drain_saldo; | ||
32 | |||
33 | assert(!child->frozen); | ||
34 | + assert(old_bs != new_bs); | ||
35 | |||
36 | if (old_bs && new_bs) { | ||
37 | assert(bdrv_get_aio_context(old_bs) == bdrv_get_aio_context(new_bs)); | ||
38 | @@ -XXX,XX +XXX,XX @@ static int bdrv_attach_child_noperm(BlockDriverState *parent_bs, | ||
39 | |||
40 | assert(parent_bs->drv); | ||
41 | |||
42 | + if (bdrv_recurse_has_child(child_bs, parent_bs)) { | ||
43 | + error_setg(errp, "Making '%s' a %s child of '%s' would create a cycle", | ||
44 | + child_bs->node_name, child_name, parent_bs->node_name); | ||
45 | + return -EINVAL; | ||
46 | + } | ||
47 | + | ||
48 | bdrv_get_cumulative_perm(parent_bs, &perm, &shared_perm); | ||
49 | bdrv_child_perm(parent_bs, child_bs, NULL, child_role, NULL, | ||
50 | perm, shared_perm, &perm, &shared_perm); | ||
51 | diff --git a/tests/qemu-iotests/085 b/tests/qemu-iotests/085 | ||
52 | index XXXXXXX..XXXXXXX 100755 | ||
53 | --- a/tests/qemu-iotests/085 | ||
54 | +++ b/tests/qemu-iotests/085 | ||
55 | @@ -XXX,XX +XXX,XX @@ do_blockdev_add() | ||
56 | } | 77 | } |
57 | 78 | ||
58 | # ${1}: unique identifier for the snapshot filename | 79 | /* |
59 | -add_snapshot_image() | 80 | diff --git a/blockjob.c b/blockjob.c |
60 | +create_snapshot_image() | 81 | index XXXXXXX..XXXXXXX 100644 |
61 | { | 82 | --- a/blockjob.c |
62 | base_image="${TEST_DIR}/$((${1}-1))-${snapshot_virt0}" | 83 | +++ b/blockjob.c |
63 | snapshot_file="${TEST_DIR}/${1}-${snapshot_virt0}" | 84 | @@ -XXX,XX +XXX,XX @@ void block_job_remove_all_bdrv(BlockJob *job) |
64 | TEST_IMG=$snapshot_file _make_test_img -u -b "${base_image}" -F $IMGFMT "$size" | 85 | * one to make sure that such a concurrent access does not attempt |
65 | +} | 86 | * to process an already freed BdrvChild. |
66 | + | 87 | */ |
67 | +# ${1}: unique identifier for the snapshot filename | 88 | + bdrv_graph_wrlock(NULL); |
68 | +add_snapshot_image() | 89 | while (job->nodes) { |
69 | +{ | 90 | GSList *l = job->nodes; |
70 | + snapshot_file="${TEST_DIR}/${1}-${snapshot_virt0}" | 91 | BdrvChild *c = l->data; |
71 | + create_snapshot_image "$1" | 92 | @@ -XXX,XX +XXX,XX @@ void block_job_remove_all_bdrv(BlockJob *job) |
72 | do_blockdev_add "$1" "'backing': null, " "${snapshot_file}" | 93 | |
94 | g_slist_free_1(l); | ||
95 | } | ||
96 | + bdrv_graph_wrunlock(); | ||
73 | } | 97 | } |
74 | 98 | ||
75 | @@ -XXX,XX +XXX,XX @@ _make_test_img -b "${TEST_IMG}.base" -F $IMGFMT "$size" | 99 | bool block_job_has_bdrv(BlockJob *job, BlockDriverState *bs) |
76 | do_blockdev_add ${SNAPSHOTS} "" "${TEST_IMG}" | ||
77 | blockdev_snapshot ${SNAPSHOTS} error | ||
78 | |||
79 | +echo | ||
80 | +echo === Invalid command - creating loops === | ||
81 | +echo | ||
82 | + | ||
83 | +SNAPSHOTS=$((${SNAPSHOTS}+1)) | ||
84 | +add_snapshot_image ${SNAPSHOTS} | ||
85 | + | ||
86 | +_send_qemu_cmd $h "{ 'execute': 'blockdev-snapshot', | ||
87 | + 'arguments': { 'node':'snap_${SNAPSHOTS}', | ||
88 | + 'overlay':'snap_${SNAPSHOTS}' } | ||
89 | + }" "error" | ||
90 | + | ||
91 | +SNAPSHOTS=$((${SNAPSHOTS}+1)) | ||
92 | +create_snapshot_image ${SNAPSHOTS} | ||
93 | +do_blockdev_add ${SNAPSHOTS} "'backing': 'snap_$((${SNAPSHOTS}-1))', " \ | ||
94 | + "${TEST_DIR}/${SNAPSHOTS}-${snapshot_virt0}" | ||
95 | + | ||
96 | +_send_qemu_cmd $h "{ 'execute': 'blockdev-snapshot', | ||
97 | + 'arguments': { 'node':'snap_${SNAPSHOTS}', | ||
98 | + 'overlay':'snap_$((${SNAPSHOTS}-1))' } | ||
99 | + }" "error" | ||
100 | + | ||
101 | echo | ||
102 | echo === Invalid command - The node does not exist === | ||
103 | echo | ||
104 | diff --git a/tests/qemu-iotests/085.out b/tests/qemu-iotests/085.out | ||
105 | index XXXXXXX..XXXXXXX 100644 | ||
106 | --- a/tests/qemu-iotests/085.out | ||
107 | +++ b/tests/qemu-iotests/085.out | ||
108 | @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/ | ||
109 | 'overlay':'snap_13' } } | ||
110 | {"error": {"class": "GenericError", "desc": "The overlay already has a backing image"}} | ||
111 | |||
112 | +=== Invalid command - creating loops === | ||
113 | + | ||
114 | +Formatting 'TEST_DIR/14-snapshot-v0.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/13-snapshot-v0.IMGFMT backing_fmt=IMGFMT | ||
115 | +{ 'execute': 'blockdev-add', 'arguments': | ||
116 | + { 'driver': 'IMGFMT', 'node-name': 'snap_14', 'backing': null, | ||
117 | + 'file': | ||
118 | + { 'driver': 'file', 'filename': 'TEST_DIR/14-snapshot-v0.IMGFMT', | ||
119 | + 'node-name': 'file_14' } } } | ||
120 | +{"return": {}} | ||
121 | +{ 'execute': 'blockdev-snapshot', | ||
122 | + 'arguments': { 'node':'snap_14', | ||
123 | + 'overlay':'snap_14' } | ||
124 | + } | ||
125 | +{"error": {"class": "GenericError", "desc": "Making 'snap_14' a backing child of 'snap_14' would create a cycle"}} | ||
126 | +Formatting 'TEST_DIR/15-snapshot-v0.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/14-snapshot-v0.IMGFMT backing_fmt=IMGFMT | ||
127 | +{ 'execute': 'blockdev-add', 'arguments': | ||
128 | + { 'driver': 'IMGFMT', 'node-name': 'snap_15', 'backing': 'snap_14', | ||
129 | + 'file': | ||
130 | + { 'driver': 'file', 'filename': 'TEST_DIR/15-snapshot-v0.IMGFMT', | ||
131 | + 'node-name': 'file_15' } } } | ||
132 | +{"return": {}} | ||
133 | +{ 'execute': 'blockdev-snapshot', | ||
134 | + 'arguments': { 'node':'snap_15', | ||
135 | + 'overlay':'snap_14' } | ||
136 | + } | ||
137 | +{"error": {"class": "GenericError", "desc": "Making 'snap_15' a backing child of 'snap_14' would create a cycle"}} | ||
138 | + | ||
139 | === Invalid command - The node does not exist === | ||
140 | |||
141 | { 'execute': 'blockdev-snapshot', | ||
142 | 'arguments': { 'node': 'virtio0', | ||
143 | - 'overlay':'snap_14' } } | ||
144 | -{"error": {"class": "GenericError", "desc": "Cannot find device='snap_14' nor node-name='snap_14'"}} | ||
145 | + 'overlay':'snap_16' } } | ||
146 | +{"error": {"class": "GenericError", "desc": "Cannot find device='snap_16' nor node-name='snap_16'"}} | ||
147 | { 'execute': 'blockdev-snapshot', | ||
148 | 'arguments': { 'node':'nodevice', | ||
149 | - 'overlay':'snap_13' } | ||
150 | + 'overlay':'snap_15' } | ||
151 | } | ||
152 | {"error": {"class": "GenericError", "desc": "Cannot find device='nodevice' nor node-name='nodevice'"}} | ||
153 | *** done | ||
154 | -- | 100 | -- |
155 | 2.31.1 | 101 | 2.41.0 |
156 | |||
157 | 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 |
1 | From: Stefano Garzarella <sgarzare@redhat.com> | 1 | From: Andrey Drobyshev via <qemu-block@nongnu.org> |
---|---|---|---|
2 | 2 | ||
3 | Commit d7ddd0a161 ("linux-aio: limit the batch size using | 3 | Right now "qemu-img map" reports compressed blocks as containing data |
4 | `aio-max-batch` parameter") added a way to limit the batch size | 4 | but having no host offset. This is not very informative. Instead, |
5 | of Linux AIO backend for the entire AIO context. | 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(). | ||
6 | 8 | ||
7 | The same AIO context can be shared by multiple devices, so | 9 | Also update the expected qemu-iotests outputs to contain the new field. |
8 | latency-sensitive devices may want to limit the batch size even | ||
9 | more to avoid increasing latency. | ||
10 | 10 | ||
11 | For this reason we add the `aio-max-batch` option to the file | 11 | Signed-off-by: Andrey Drobyshev <andrey.drobyshev@virtuozzo.com> |
12 | backend, which will be used by the next commits to limit the size of | 12 | Message-ID: <20230907210226.953821-3-andrey.drobyshev@virtuozzo.com> |
13 | batches including requests generated by this device. | ||
14 | |||
15 | Suggested-by: Kevin Wolf <kwolf@redhat.com> | ||
16 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | 13 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> |
17 | Signed-off-by: Stefano Garzarella <sgarzare@redhat.com> | ||
18 | Message-Id: <20211026162346.253081-2-sgarzare@redhat.com> | ||
19 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
20 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 14 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
21 | --- | 15 | --- |
22 | qapi/block-core.json | 7 +++++++ | 16 | qapi/block-core.json | 6 +- |
23 | block/file-posix.c | 9 +++++++++ | 17 | qemu-img.c | 8 +- |
24 | 2 files changed, 16 insertions(+) | 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(-) | ||
25 | 33 | ||
26 | diff --git a/qapi/block-core.json b/qapi/block-core.json | 34 | diff --git a/qapi/block-core.json b/qapi/block-core.json |
27 | index XXXXXXX..XXXXXXX 100644 | 35 | index XXXXXXX..XXXXXXX 100644 |
28 | --- a/qapi/block-core.json | 36 | --- a/qapi/block-core.json |
29 | +++ b/qapi/block-core.json | 37 | +++ b/qapi/block-core.json |
30 | @@ -XXX,XX +XXX,XX @@ | 38 | @@ -XXX,XX +XXX,XX @@ |
31 | # for this device (default: none, forward the commands via SG_IO; | 39 | # |
32 | # since 2.11) | 40 | # @zero: whether the virtual blocks read as zeroes |
33 | # @aio: AIO backend (default: threads) (since: 2.8) | 41 | # |
34 | +# @aio-max-batch: maximum number of requests to batch together into a single | 42 | +# @compressed: true if the data is stored compressed (since 8.2) |
35 | +# submission in the AIO backend. The smallest value between | 43 | +# |
36 | +# this and the aio-max-batch value of the IOThread object is | 44 | # @depth: number of layers (0 = top image, 1 = top image's backing |
37 | +# chosen. | 45 | # file, ..., n - 1 = bottom image (where n is the number of images |
38 | +# 0 means that the AIO backend will handle it automatically. | 46 | # in the chain)) before reaching one for which the range is |
39 | +# (default: 0, since 6.2) | ||
40 | # @locking: whether to enable file locking. If set to 'auto', only enable | ||
41 | # when Open File Descriptor (OFD) locking API is available | ||
42 | # (default: auto, since 2.10) | ||
43 | @@ -XXX,XX +XXX,XX @@ | 47 | @@ -XXX,XX +XXX,XX @@ |
44 | '*pr-manager': 'str', | 48 | ## |
45 | '*locking': 'OnOffAuto', | 49 | { 'struct': 'MapEntry', |
46 | '*aio': 'BlockdevAioOptions', | 50 | 'data': {'start': 'int', 'length': 'int', 'data': 'bool', |
47 | + '*aio-max-batch': 'int', | 51 | - 'zero': 'bool', 'depth': 'int', 'present': 'bool', |
48 | '*drop-cache': {'type': 'bool', | 52 | - '*offset': 'int', '*filename': 'str' } } |
49 | 'if': 'CONFIG_LINUX'}, | 53 | + 'zero': 'bool', 'compressed': 'bool', 'depth': 'int', |
50 | '*x-check-cache-dropped': { 'type': 'bool', | 54 | + 'present': 'bool', '*offset': 'int', '*filename': 'str' } } |
51 | diff --git a/block/file-posix.c b/block/file-posix.c | 55 | |
56 | ## | ||
57 | # @BlockdevCacheInfo: | ||
58 | diff --git a/qemu-img.c b/qemu-img.c | ||
52 | index XXXXXXX..XXXXXXX 100644 | 59 | index XXXXXXX..XXXXXXX 100644 |
53 | --- a/block/file-posix.c | 60 | --- a/qemu-img.c |
54 | +++ b/block/file-posix.c | 61 | +++ b/qemu-img.c |
55 | @@ -XXX,XX +XXX,XX @@ typedef struct BDRVRawState { | 62 | @@ -XXX,XX +XXX,XX @@ static int dump_map_entry(OutputFormat output_format, MapEntry *e, |
56 | uint64_t locked_perm; | 63 | case OFORMAT_JSON: |
57 | uint64_t locked_shared_perm; | 64 | printf("{ \"start\": %"PRId64", \"length\": %"PRId64"," |
58 | 65 | " \"depth\": %"PRId64", \"present\": %s, \"zero\": %s," | |
59 | + uint64_t aio_max_batch; | 66 | - " \"data\": %s", e->start, e->length, e->depth, |
60 | + | 67 | + " \"data\": %s, \"compressed\": %s", |
61 | int perm_change_fd; | 68 | + e->start, e->length, e->depth, |
62 | int perm_change_flags; | 69 | e->present ? "true" : "false", |
63 | BDRVReopenState *reopen_state; | 70 | e->zero ? "true" : "false", |
64 | @@ -XXX,XX +XXX,XX @@ static QemuOptsList raw_runtime_opts = { | 71 | - e->data ? "true" : "false"); |
65 | .type = QEMU_OPT_STRING, | 72 | + e->data ? "true" : "false", |
66 | .help = "host AIO implementation (threads, native, io_uring)", | 73 | + e->compressed ? "true" : "false"); |
67 | }, | 74 | if (e->has_offset) { |
68 | + { | 75 | printf(", \"offset\": %"PRId64"", e->offset); |
69 | + .name = "aio-max-batch", | 76 | } |
70 | + .type = QEMU_OPT_NUMBER, | 77 | @@ -XXX,XX +XXX,XX @@ static int get_block_status(BlockDriverState *bs, int64_t offset, |
71 | + .help = "AIO max batch size (0 = auto handled by AIO backend, default: 0)", | 78 | .length = bytes, |
72 | + }, | 79 | .data = !!(ret & BDRV_BLOCK_DATA), |
73 | { | 80 | .zero = !!(ret & BDRV_BLOCK_ZERO), |
74 | .name = "locking", | 81 | + .compressed = !!(ret & BDRV_BLOCK_COMPRESSED), |
75 | .type = QEMU_OPT_STRING, | 82 | .offset = map, |
76 | @@ -XXX,XX +XXX,XX @@ static int raw_open_common(BlockDriverState *bs, QDict *options, | 83 | .has_offset = has_offset, |
77 | s->use_linux_io_uring = (aio == BLOCKDEV_AIO_OPTIONS_IO_URING); | 84 | .depth = depth, |
78 | #endif | 85 | @@ -XXX,XX +XXX,XX @@ static inline bool entry_mergeable(const MapEntry *curr, const MapEntry *next) |
79 | 86 | } | |
80 | + s->aio_max_batch = qemu_opt_get_number(opts, "aio-max-batch", 0); | 87 | if (curr->zero != next->zero || |
81 | + | 88 | curr->data != next->data || |
82 | locking = qapi_enum_parse(&OnOffAuto_lookup, | 89 | + curr->compressed != next->compressed || |
83 | qemu_opt_get(opts, "locking"), | 90 | curr->depth != next->depth || |
84 | ON_OFF_AUTO_AUTO, &local_err); | 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 | |||
85 | -- | 2133 | -- |
86 | 2.31.1 | 2134 | 2.41.0 |
87 | |||
88 | 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 |
New patch | |||
---|---|---|---|
1 | From: Stefan Hajnoczi <stefanha@redhat.com> | ||
1 | 2 | ||
3 | This patch fixes a race condition in test-bdrv-drain that is difficult | ||
4 | to reproduce. test-bdrv-drain sometimes fails without an error message | ||
5 | on the block pull request sent by Kevin Wolf on Sep 4, 2023. I was able | ||
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. | ||
9 | |||
10 | I do not know why "block-backend: process I/O in the current AioContext" | ||
11 | exposes this bug. It might be related to the fact that the test's preadv | ||
12 | request runs in the main thread instead of IOThread a after my commit. | ||
13 | That might simply change the timing of the test. | ||
14 | |||
15 | Now on to the race condition in test-bdrv-drain. The main thread | ||
16 | schedules a BH in IOThread a and then drains the BDS: | ||
17 | |||
18 | aio_bh_schedule_oneshot(ctx_a, test_iothread_main_thread_bh, &data); | ||
19 | |||
20 | /* The request is running on the IOThread a. Draining its block device | ||
21 | * will make sure that it has completed as far as the BDS is concerned, | ||
22 | * but the drain in this thread can continue immediately after | ||
23 | * bdrv_dec_in_flight() and aio_ret might be assigned only slightly | ||
24 | * later. */ | ||
25 | do_drain_begin(drain_type, bs); | ||
26 | |||
27 | If the BH completes before do_drain_begin() then there is nothing to | ||
28 | worry about. | ||
29 | |||
30 | If the BH invokes bdrv_flush() before do_drain_begin(), then | ||
31 | do_drain_begin() waits for it to complete. | ||
32 | |||
33 | The problematic case is when do_drain_begin() runs before the BH enters | ||
34 | bdrv_flush(). Then do_drain_begin() misses the BH and the drain | ||
35 | mechanism has failed in quiescing I/O. | ||
36 | |||
37 | Fix this by incrementing the in_flight counter so that do_drain_begin() | ||
38 | waits for test_iothread_main_thread_bh(). | ||
39 | |||
40 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
41 | Message-ID: <20230912231037.826804-3-stefanha@redhat.com> | ||
42 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
43 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
44 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
45 | --- | ||
46 | tests/unit/test-bdrv-drain.c | 8 ++++++++ | ||
47 | 1 file changed, 8 insertions(+) | ||
48 | |||
49 | diff --git a/tests/unit/test-bdrv-drain.c b/tests/unit/test-bdrv-drain.c | ||
50 | index XXXXXXX..XXXXXXX 100644 | ||
51 | --- a/tests/unit/test-bdrv-drain.c | ||
52 | +++ b/tests/unit/test-bdrv-drain.c | ||
53 | @@ -XXX,XX +XXX,XX @@ static void test_iothread_main_thread_bh(void *opaque) | ||
54 | * executed during drain, otherwise this would deadlock. */ | ||
55 | aio_context_acquire(bdrv_get_aio_context(data->bs)); | ||
56 | bdrv_flush(data->bs); | ||
57 | + bdrv_dec_in_flight(data->bs); /* incremented by test_iothread_common() */ | ||
58 | aio_context_release(bdrv_get_aio_context(data->bs)); | ||
59 | } | ||
60 | |||
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 | ||
75 | -- | ||
76 | 2.41.0 | diff view generated by jsdifflib |
1 | From: Samuel Thibault <samuel.thibault@ens-lyon.org> | 1 | From: Stefan Hajnoczi <stefanha@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | The LBA28 capacity (at offsets 60/61 of identification) is supposed to | 3 | Switch blk_aio_*() APIs over to multi-queue by using |
4 | express the maximum size supported by LBA28 commands. If the device is | 4 | qemu_get_current_aio_context() instead of blk_get_aio_context(). This |
5 | larger than this, we have to cap it to 2^28-1. | 5 | change will allow devices to process I/O in multiple IOThreads in the |
6 | future. | ||
6 | 7 | ||
7 | At least NetBSD happens to be using this value to determine whether to use | 8 | I audited existing blk_aio_*() callers: |
8 | LBA28 or LBA48 for its commands, using LBA28 for sectors that don't need | 9 | - migration/block.c: blk_mig_lock() protects the data accessed by the |
9 | LBA48. This commit thus fixes NetBSD access to disks larger than 128GiB. | 10 | completion callback. |
11 | - The remaining emulated devices and exports run with | ||
12 | qemu_get_aio_context() == blk_get_aio_context(). | ||
10 | 13 | ||
11 | Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org> | 14 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> |
12 | Message-Id: <20210824104344.3878849-1-samuel.thibault@ens-lyon.org> | 15 | Message-ID: <20230912231037.826804-4-stefanha@redhat.com> |
16 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
17 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
13 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 18 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
14 | --- | 19 | --- |
15 | hw/ide/core.c | 8 ++++++-- | 20 | block/block-backend.c | 6 +++--- |
16 | 1 file changed, 6 insertions(+), 2 deletions(-) | 21 | 1 file changed, 3 insertions(+), 3 deletions(-) |
17 | 22 | ||
18 | diff --git a/hw/ide/core.c b/hw/ide/core.c | 23 | diff --git a/block/block-backend.c b/block/block-backend.c |
19 | index XXXXXXX..XXXXXXX 100644 | 24 | index XXXXXXX..XXXXXXX 100644 |
20 | --- a/hw/ide/core.c | 25 | --- a/block/block-backend.c |
21 | +++ b/hw/ide/core.c | 26 | +++ b/block/block-backend.c |
22 | @@ -XXX,XX +XXX,XX @@ static void put_le16(uint16_t *p, unsigned int v) | 27 | @@ -XXX,XX +XXX,XX @@ BlockAIOCB *blk_abort_aio_request(BlockBackend *blk, |
23 | static void ide_identify_size(IDEState *s) | 28 | acb->blk = blk; |
24 | { | 29 | acb->ret = ret; |
25 | uint16_t *p = (uint16_t *)s->identify_data; | 30 | |
26 | - put_le16(p + 60, s->nb_sectors); | 31 | - replay_bh_schedule_oneshot_event(blk_get_aio_context(blk), |
27 | - put_le16(p + 61, s->nb_sectors >> 16); | 32 | + replay_bh_schedule_oneshot_event(qemu_get_current_aio_context(), |
28 | + int64_t nb_sectors_lba28 = s->nb_sectors; | 33 | error_callback_bh, acb); |
29 | + if (nb_sectors_lba28 >= 1 << 28) { | 34 | return &acb->common; |
30 | + nb_sectors_lba28 = (1 << 28) - 1; | 35 | } |
31 | + } | 36 | @@ -XXX,XX +XXX,XX @@ static BlockAIOCB *blk_aio_prwv(BlockBackend *blk, int64_t offset, |
32 | + put_le16(p + 60, nb_sectors_lba28); | 37 | acb->has_returned = false; |
33 | + put_le16(p + 61, nb_sectors_lba28 >> 16); | 38 | |
34 | put_le16(p + 100, s->nb_sectors); | 39 | co = qemu_coroutine_create(co_entry, acb); |
35 | put_le16(p + 101, s->nb_sectors >> 16); | 40 | - aio_co_enter(blk_get_aio_context(blk), co); |
36 | put_le16(p + 102, s->nb_sectors >> 32); | 41 | + aio_co_enter(qemu_get_current_aio_context(), co); |
42 | |||
43 | acb->has_returned = true; | ||
44 | if (acb->rwco.ret != NOT_DONE) { | ||
45 | - replay_bh_schedule_oneshot_event(blk_get_aio_context(blk), | ||
46 | + replay_bh_schedule_oneshot_event(qemu_get_current_aio_context(), | ||
47 | blk_aio_complete_bh, acb); | ||
48 | } | ||
49 | |||
37 | -- | 50 | -- |
38 | 2.31.1 | 51 | 2.41.0 |
39 | |||
40 | diff view generated by jsdifflib |
1 | From: Hanna Reitz <hreitz@redhat.com> | 1 | From: Stefan Hajnoczi <stefanha@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Similarly to e7e588d432d31ecebc26358e47201dd108db964c, there is a | 3 | Process zoned requests in the current thread's AioContext instead of in |
4 | warning in block/block-backend.c that qiov->size <= INT64_MAX is always | 4 | the BlockBackend's AioContext. |
5 | true on machines where size_t is narrower than a uint64_t. In said | ||
6 | commit, we silenced this warning by casting to uint64_t. | ||
7 | 5 | ||
8 | The commit introducing this warning here | 6 | There is no need to use the BlockBackend's AioContext thanks to CoMutex |
9 | (a93d81c84afa717b0a1a6947524d8d1fbfd6bbf5) anticipated it and so tried | 7 | bs->wps->colock, which protects zone metadata. |
10 | to address it the same way. However, it only did so in one of two | ||
11 | places where this comparison occurs, and so we still need to fix up the | ||
12 | other one. | ||
13 | 8 | ||
14 | Fixes: a93d81c84afa717b0a1a6947524d8d1fbfd6bbf5 | 9 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> |
15 | ("block-backend: convert blk_aio_ functions to int64_t bytes | 10 | Message-ID: <20230912231037.826804-5-stefanha@redhat.com> |
16 | paramter") | 11 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> |
17 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | 12 | Reviewed-by: Eric Blake <eblake@redhat.com> |
18 | Message-Id: <20211026090745.30800-1-hreitz@redhat.com> | ||
19 | Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> | ||
20 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 13 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
21 | --- | 14 | --- |
22 | block/block-backend.c | 2 +- | 15 | block/block-backend.c | 12 ++++++------ |
23 | 1 file changed, 1 insertion(+), 1 deletion(-) | 16 | 1 file changed, 6 insertions(+), 6 deletions(-) |
24 | 17 | ||
25 | diff --git a/block/block-backend.c b/block/block-backend.c | 18 | diff --git a/block/block-backend.c b/block/block-backend.c |
26 | index XXXXXXX..XXXXXXX 100644 | 19 | index XXXXXXX..XXXXXXX 100644 |
27 | --- a/block/block-backend.c | 20 | --- a/block/block-backend.c |
28 | +++ b/block/block-backend.c | 21 | +++ b/block/block-backend.c |
29 | @@ -XXX,XX +XXX,XX @@ BlockAIOCB *blk_aio_pwritev(BlockBackend *blk, int64_t offset, | 22 | @@ -XXX,XX +XXX,XX @@ BlockAIOCB *blk_aio_zone_report(BlockBackend *blk, int64_t offset, |
30 | QEMUIOVector *qiov, BdrvRequestFlags flags, | 23 | acb->has_returned = false; |
31 | BlockCompletionFunc *cb, void *opaque) | 24 | |
32 | { | 25 | co = qemu_coroutine_create(blk_aio_zone_report_entry, acb); |
33 | - assert(qiov->size <= INT64_MAX); | 26 | - aio_co_enter(blk_get_aio_context(blk), co); |
34 | + assert((uint64_t)qiov->size <= INT64_MAX); | 27 | + aio_co_enter(qemu_get_current_aio_context(), co); |
35 | return blk_aio_prwv(blk, offset, qiov->size, qiov, | 28 | |
36 | blk_aio_write_entry, flags, cb, opaque); | 29 | acb->has_returned = true; |
37 | } | 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); | ||
34 | } | ||
35 | |||
36 | @@ -XXX,XX +XXX,XX @@ BlockAIOCB *blk_aio_zone_mgmt(BlockBackend *blk, BlockZoneOp op, | ||
37 | acb->has_returned = false; | ||
38 | |||
39 | co = qemu_coroutine_create(blk_aio_zone_mgmt_entry, acb); | ||
40 | - aio_co_enter(blk_get_aio_context(blk), co); | ||
41 | + aio_co_enter(qemu_get_current_aio_context(), co); | ||
42 | |||
43 | acb->has_returned = true; | ||
44 | if (acb->rwco.ret != NOT_DONE) { | ||
45 | - replay_bh_schedule_oneshot_event(blk_get_aio_context(blk), | ||
46 | + replay_bh_schedule_oneshot_event(qemu_get_current_aio_context(), | ||
47 | blk_aio_complete_bh, acb); | ||
48 | } | ||
49 | |||
50 | @@ -XXX,XX +XXX,XX @@ BlockAIOCB *blk_aio_zone_append(BlockBackend *blk, int64_t *offset, | ||
51 | acb->has_returned = false; | ||
52 | |||
53 | co = qemu_coroutine_create(blk_aio_zone_append_entry, acb); | ||
54 | - aio_co_enter(blk_get_aio_context(blk), co); | ||
55 | + aio_co_enter(qemu_get_current_aio_context(), co); | ||
56 | acb->has_returned = true; | ||
57 | if (acb->rwco.ret != NOT_DONE) { | ||
58 | - replay_bh_schedule_oneshot_event(blk_get_aio_context(blk), | ||
59 | + replay_bh_schedule_oneshot_event(qemu_get_current_aio_context(), | ||
60 | blk_aio_complete_bh, acb); | ||
61 | } | ||
62 | |||
38 | -- | 63 | -- |
39 | 2.31.1 | 64 | 2.41.0 |
40 | |||
41 | diff view generated by jsdifflib |
1 | From: Ari Sundholm <ari@tuxera.com> | 1 | From: Stefan Hajnoczi <stefanha@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | AIO discards regressed as a result of the following commit: | 3 | Use qemu_get_current_aio_context() in mixed wrappers and coroutine |
4 | 0dfc7af2 block/file-posix: Optimize for macOS | 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. | ||
5 | 7 | ||
6 | When trying to run blkdiscard within a Linux guest, the request would | 8 | Most wrappers are IO_CODE where it's safe to use the current AioContext |
7 | fail, with some errors in dmesg: | 9 | nowadays. BlockDrivers and the core block layer use their own locks and |
10 | no longer depend on the AioContext lock for thread-safety. | ||
8 | 11 | ||
9 | ---- [ snip ] ---- | 12 | The bdrv_create() wrapper invokes GLOBAL_STATE code. Using the current |
10 | [ 4.010070] sd 2:0:0:0: [sda] tag#0 FAILED Result: hostbyte=DID_OK | 13 | AioContext is safe because this code is only called with the BQL held |
11 | driverbyte=DRIVER_SENSE | 14 | from the main loop thread. |
12 | [ 4.011061] sd 2:0:0:0: [sda] tag#0 Sense Key : Aborted Command | ||
13 | [current] | ||
14 | [ 4.011061] sd 2:0:0:0: [sda] tag#0 Add. Sense: I/O process | ||
15 | terminated | ||
16 | [ 4.011061] sd 2:0:0:0: [sda] tag#0 CDB: Unmap/Read sub-channel 42 | ||
17 | 00 00 00 00 00 00 00 18 00 | ||
18 | [ 4.011061] blk_update_request: I/O error, dev sda, sector 0 | ||
19 | ---- [ snip ] ---- | ||
20 | 15 | ||
21 | This turns out to be a result of a flaw in changes to the error value | 16 | The output of qemu-iotests 051 is sensitive to event loop activity. |
22 | translation logic in handle_aiocb_discard(). The default return value | 17 | Update the output because the monitor BH runs at a different time, |
23 | may be left untranslated in some configurations, and the wrong variable | 18 | causing prompts to be printed differently in the output. |
24 | is used in one translation. | ||
25 | 19 | ||
26 | Fix both issues. | 20 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> |
27 | 21 | Message-ID: <20230912231037.826804-6-stefanha@redhat.com> | |
28 | Fixes: 0dfc7af2b28 ("block/file-posix: Optimize for macOS") | 22 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> |
29 | Cc: qemu-stable@nongnu.org | 23 | Reviewed-by: Eric Blake <eblake@redhat.com> |
30 | Signed-off-by: Ari Sundholm <ari@tuxera.com> | ||
31 | Signed-off-by: Emil Karlson <jkarlson@tuxera.com> | ||
32 | Reviewed-by: Akihiko Odaki <akihiko.odaki@gmail.com> | ||
33 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
34 | Message-Id: <20211019110954.4170931-1-ari@tuxera.com> | ||
35 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 24 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
36 | --- | 25 | --- |
37 | block/file-posix.c | 4 ++-- | 26 | scripts/block-coroutine-wrapper.py | 6 ++---- |
38 | 1 file changed, 2 insertions(+), 2 deletions(-) | 27 | 1 file changed, 2 insertions(+), 4 deletions(-) |
39 | 28 | ||
40 | diff --git a/block/file-posix.c b/block/file-posix.c | 29 | diff --git a/scripts/block-coroutine-wrapper.py b/scripts/block-coroutine-wrapper.py |
41 | index XXXXXXX..XXXXXXX 100644 | 30 | index XXXXXXX..XXXXXXX 100644 |
42 | --- a/block/file-posix.c | 31 | --- a/scripts/block-coroutine-wrapper.py |
43 | +++ b/block/file-posix.c | 32 | +++ b/scripts/block-coroutine-wrapper.py |
44 | @@ -XXX,XX +XXX,XX @@ static int handle_aiocb_copy_range(void *opaque) | 33 | @@ -XXX,XX +XXX,XX @@ def __init__(self, wrapper_type: str, return_type: str, name: str, |
45 | static int handle_aiocb_discard(void *opaque) | 34 | raise ValueError(f"no_co function can't be rdlock: {self.name}") |
46 | { | 35 | self.target_name = f'{subsystem}_{subname}' |
47 | RawPosixAIOData *aiocb = opaque; | 36 | |
48 | - int ret = -EOPNOTSUPP; | 37 | - self.ctx = self.gen_ctx() |
49 | + int ret = -ENOTSUP; | 38 | - |
50 | BDRVRawState *s = aiocb->bs->opaque; | 39 | self.get_result = 's->ret = ' |
51 | 40 | self.ret = 'return s.ret;' | |
52 | if (!s->has_discard) { | 41 | self.co_ret = 'return ' |
53 | @@ -XXX,XX +XXX,XX @@ static int handle_aiocb_discard(void *opaque) | 42 | @@ -XXX,XX +XXX,XX @@ def create_mixed_wrapper(func: FuncDecl) -> str: |
54 | #ifdef CONFIG_FALLOCATE_PUNCH_HOLE | 43 | {func.co_ret}{name}({ func.gen_list('{name}') }); |
55 | ret = do_fallocate(s->fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, | 44 | }} else {{ |
56 | aiocb->aio_offset, aiocb->aio_nbytes); | 45 | {struct_name} s = {{ |
57 | - ret = translate_err(-errno); | 46 | - .poll_state.ctx = {func.ctx}, |
58 | + ret = translate_err(ret); | 47 | + .poll_state.ctx = qemu_get_current_aio_context(), |
59 | #elif defined(__APPLE__) && (__MACH__) | 48 | .poll_state.in_progress = true, |
60 | fpunchhole_t fpunchhole; | 49 | |
61 | fpunchhole.fp_flags = 0; | 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},') } | ||
62 | -- | 60 | -- |
63 | 2.31.1 | 61 | 2.41.0 |
64 | |||
65 | diff view generated by jsdifflib |