1
The following changes since commit ac5f7bf8e208cd7893dbb1a9520559e569a4677c:
1
The following changes since commit 005ad32358f12fe9313a4a01918a55e60d4f39e5:
2
2
3
Merge tag 'migration-20230424-pull-request' of https://gitlab.com/juan.quintela/qemu into staging (2023-04-24 15:00:39 +0100)
3
Merge tag 'pull-tpm-2023-09-12-3' of https://github.com/stefanberger/qemu-tpm into staging (2023-09-13 13:41:57 -0400)
4
4
5
are available in the Git repository at:
5
are available in the Git repository at:
6
6
7
https://repo.or.cz/qemu/kevin.git tags/for-upstream
7
https://repo.or.cz/qemu/kevin.git tags/for-upstream
8
8
9
for you to fetch changes up to 8c1e8fb2e7fc2cbeb57703e143965a4cd3ad301a:
9
for you to fetch changes up to 5d96864b73225ee61b0dad7e928f0cddf14270fc:
10
10
11
block/monitor: Fix crash when executing HMP commit (2023-04-25 15:11:57 +0200)
11
block-coroutine-wrapper: use qemu_get_current_aio_context() (2023-09-15 15:49:14 +0200)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Block layer patches
14
Block layer patches
15
15
16
- Protect BlockBackend.queued_requests with its own lock
16
- Graph locking part 4 (node management)
17
- Switch to AIO_WAIT_WHILE_UNLOCKED() where possible
17
- qemu-img map: report compressed data blocks
18
- AioContext removal: LinuxAioState/LuringState/ThreadPool
18
- block-backend: process I/O in the current AioContext
19
- Add more coroutine_fn annotations, use bdrv/blk_co_*
20
- Fix crash when execute hmp_commit
21
19
22
----------------------------------------------------------------
20
----------------------------------------------------------------
23
Emanuele Giuseppe Esposito (4):
21
Andrey Drobyshev via (2):
24
linux-aio: use LinuxAioState from the running thread
22
block: add BDRV_BLOCK_COMPRESSED flag for bdrv_block_status()
25
io_uring: use LuringState from the running thread
23
qemu-img: map: report compressed data blocks
26
thread-pool: use ThreadPool from the running thread
27
thread-pool: avoid passing the pool parameter every time
28
24
29
Paolo Bonzini (9):
25
Kevin Wolf (21):
30
vvfat: mark various functions as coroutine_fn
26
block: Remove unused BlockReopenQueueEntry.perms_checked
31
blkdebug: add missing coroutine_fn annotation
27
preallocate: Factor out preallocate_truncate_to_real_size()
32
mirror: make mirror_flush a coroutine_fn, do not use co_wrappers
28
preallocate: Don't poll during permission updates
33
nbd: mark more coroutine_fns, do not use co_wrappers
29
block: Take AioContext lock for bdrv_append() more consistently
34
9pfs: mark more coroutine_fns
30
block: Introduce bdrv_schedule_unref()
35
qemu-pr-helper: mark more coroutine_fns
31
block-coroutine-wrapper: Add no_co_wrapper_bdrv_wrlock functions
36
tests: mark more coroutine_fns
32
block-coroutine-wrapper: Allow arbitrary parameter names
37
qcow2: mark various functions as coroutine_fn and GRAPH_RDLOCK
33
block: Mark bdrv_replace_child_noperm() GRAPH_WRLOCK
38
vmdk: make vmdk_is_cid_valid a coroutine_fn
34
block: Mark bdrv_replace_child_tran() GRAPH_WRLOCK
35
block: Mark bdrv_attach_child_common() GRAPH_WRLOCK
36
block: Call transaction callbacks with lock held
37
block: Mark bdrv_attach_child() GRAPH_WRLOCK
38
block: Mark bdrv_parent_perms_conflict() and callers GRAPH_RDLOCK
39
block: Mark bdrv_get_cumulative_perm() and callers GRAPH_RDLOCK
40
block: Mark bdrv_child_perm() GRAPH_RDLOCK
41
block: Mark bdrv_parent_cb_change_media() GRAPH_RDLOCK
42
block: Take graph rdlock in bdrv_drop_intermediate()
43
block: Take graph rdlock in bdrv_change_aio_context()
44
block: Mark bdrv_root_unref_child() GRAPH_WRLOCK
45
block: Mark bdrv_unref_child() GRAPH_WRLOCK
46
block: Mark bdrv_add/del_child() and caller GRAPH_WRLOCK
39
47
40
Stefan Hajnoczi (10):
48
Stefan Hajnoczi (5):
41
block: make BlockBackend->quiesce_counter atomic
49
block: remove AIOCBInfo->get_aio_context()
42
block: make BlockBackend->disable_request_queuing atomic
50
test-bdrv-drain: avoid race with BH in IOThread drain test
43
block: protect BlockBackend->queued_requests with a lock
51
block-backend: process I/O in the current AioContext
44
block: don't acquire AioContext lock in bdrv_drain_all()
52
block-backend: process zoned requests in the current AioContext
45
block: convert blk_exp_close_all_type() to AIO_WAIT_WHILE_UNLOCKED()
53
block-coroutine-wrapper: use qemu_get_current_aio_context()
46
block: convert bdrv_graph_wrlock() to AIO_WAIT_WHILE_UNLOCKED()
47
block: convert bdrv_drain_all_begin() to AIO_WAIT_WHILE_UNLOCKED()
48
hmp: convert handle_hmp_command() to AIO_WAIT_WHILE_UNLOCKED()
49
monitor: convert monitor_cleanup() to AIO_WAIT_WHILE_UNLOCKED()
50
block: add missing coroutine_fn to bdrv_sum_allocated_file_size()
51
54
52
Wang Liang (1):
55
qapi/block-core.json | 6 +-
53
block/monitor: Fix crash when executing HMP commit
56
include/block/aio.h | 1 -
54
57
include/block/block-common.h | 7 +
55
Wilfred Mallawa (1):
58
include/block/block-global-state.h | 32 +-
56
include/block: fixup typos
59
include/block/block-io.h | 1 -
57
60
include/block/block_int-common.h | 34 +-
58
block/qcow2.h | 15 +++++-----
61
include/block/block_int-global-state.h | 14 +-
59
hw/9pfs/9p.h | 4 +--
62
include/sysemu/block-backend-global-state.h | 4 +-
60
include/block/aio-wait.h | 2 +-
63
block.c | 348 +++++++---
61
include/block/aio.h | 8 ------
64
block/blklogwrites.c | 4 +
62
include/block/block_int-common.h | 2 +-
65
block/blkverify.c | 2 +
63
include/block/raw-aio.h | 33 +++++++++++++++-------
66
block/block-backend.c | 64 +-
64
include/block/thread-pool.h | 15 ++++++----
67
block/copy-before-write.c | 10 +-
65
include/sysemu/block-backend-io.h | 5 ++++
68
block/crypto.c | 6 +-
66
backends/tpm/tpm_backend.c | 4 +--
69
block/graph-lock.c | 26 +-
67
block.c | 2 +-
70
block/io.c | 23 +-
68
block/blkdebug.c | 4 +--
71
block/mirror.c | 8 +
69
block/block-backend.c | 45 ++++++++++++++++++------------
72
block/preallocate.c | 133 ++--
70
block/export/export.c | 2 +-
73
block/qcow.c | 5 +-
71
block/file-posix.c | 45 ++++++++++++------------------
74
block/qcow2.c | 7 +-
72
block/file-win32.c | 4 +--
75
block/quorum.c | 23 +-
73
block/graph-lock.c | 2 +-
76
block/replication.c | 9 +
74
block/io.c | 2 +-
77
block/snapshot.c | 2 +
75
block/io_uring.c | 23 ++++++++++------
78
block/stream.c | 20 +-
76
block/linux-aio.c | 29 ++++++++++++--------
79
block/vmdk.c | 15 +
77
block/mirror.c | 4 +--
80
blockdev.c | 23 +-
78
block/monitor/block-hmp-cmds.c | 10 ++++---
81
blockjob.c | 2 +
79
block/qcow2-bitmap.c | 2 +-
82
hw/nvme/ctrl.c | 7 -
80
block/qcow2-cluster.c | 21 ++++++++------
83
qemu-img.c | 8 +-
81
block/qcow2-refcount.c | 8 +++---
84
softmmu/dma-helpers.c | 8 -
82
block/qcow2-snapshot.c | 25 +++++++++--------
85
tests/unit/test-bdrv-drain.c | 31 +-
83
block/qcow2-threads.c | 3 +-
86
tests/unit/test-bdrv-graph-mod.c | 20 +
84
block/qcow2.c | 27 +++++++++---------
87
tests/unit/test-block-iothread.c | 3 +
85
block/vmdk.c | 2 +-
88
util/thread-pool.c | 8 -
86
block/vvfat.c | 58 ++++++++++++++++++++-------------------
89
scripts/block-coroutine-wrapper.py | 24 +-
87
hw/9pfs/codir.c | 6 ++--
90
tests/qemu-iotests/051.pc.out | 6 +-
88
hw/9pfs/coth.c | 3 +-
91
tests/qemu-iotests/122.out | 84 +--
89
hw/ppc/spapr_nvdimm.c | 6 ++--
92
tests/qemu-iotests/146.out | 780 +++++++++++------------
90
hw/virtio/virtio-pmem.c | 3 +-
93
tests/qemu-iotests/154.out | 194 +++---
91
monitor/hmp.c | 2 +-
94
tests/qemu-iotests/179.out | 178 +++---
92
monitor/monitor.c | 4 +--
95
tests/qemu-iotests/209.out | 4 +-
93
nbd/server.c | 48 ++++++++++++++++----------------
96
tests/qemu-iotests/221.out | 16 +-
94
scsi/pr-manager.c | 3 +-
97
tests/qemu-iotests/223.out | 60 +-
95
scsi/qemu-pr-helper.c | 25 ++++++++---------
98
tests/qemu-iotests/241.out | 10 +-
96
tests/unit/test-thread-pool.c | 14 ++++------
99
tests/qemu-iotests/244.out | 24 +-
97
util/thread-pool.c | 25 ++++++++---------
100
tests/qemu-iotests/252.out | 10 +-
98
40 files changed, 283 insertions(+), 262 deletions(-)
101
tests/qemu-iotests/253.out | 20 +-
102
tests/qemu-iotests/274.out | 48 +-
103
tests/qemu-iotests/tests/nbd-qemu-allocation.out | 16 +-
104
tests/qemu-iotests/tests/qemu-img-bitmaps.out | 24 +-
105
50 files changed, 1376 insertions(+), 1036 deletions(-)
diff view generated by jsdifflib
1
From: Emanuele Giuseppe Esposito <eesposit@redhat.com>
1
This field has been unused since commit 72373e40fbc ('block:
2
bdrv_reopen_multiple: refresh permissions on updated graph').
3
Remove it.
2
4
3
Remove usage of aio_context_acquire by always submitting asynchronous
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
AIO to the current thread's LuringState.
6
Reviewed-by: Eric Blake <eblake@redhat.com>
5
7
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
6
In order to prevent mistakes from the caller side, avoid passing LuringState
7
in luring_io_{plug/unplug} and luring_co_submit, and document the functions
8
to make clear that they work in the current thread's AioContext.
9
10
Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
11
Message-Id: <20230203131731.851116-3-eesposit@redhat.com>
12
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
13
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
9
Message-ID: <20230911094620.45040-2-kwolf@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
---
11
---
16
include/block/aio.h | 4 ----
12
block.c | 1 -
17
include/block/raw-aio.h | 15 +++++++++++----
13
1 file changed, 1 deletion(-)
18
block/file-posix.c | 12 ++++--------
19
block/io_uring.c | 23 +++++++++++++++--------
20
4 files changed, 30 insertions(+), 24 deletions(-)
21
14
22
diff --git a/include/block/aio.h b/include/block/aio.h
15
diff --git a/block.c b/block.c
23
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
24
--- a/include/block/aio.h
17
--- a/block.c
25
+++ b/include/block/aio.h
18
+++ b/block.c
26
@@ -XXX,XX +XXX,XX @@ struct AioContext {
19
@@ -XXX,XX +XXX,XX @@ static int bdrv_fill_options(QDict **options, const char *filename,
27
struct LinuxAioState *linux_aio;
20
28
#endif
21
typedef struct BlockReopenQueueEntry {
29
#ifdef CONFIG_LINUX_IO_URING
22
bool prepared;
30
- /*
23
- bool perms_checked;
31
- * State for Linux io_uring. Uses aio_context_acquire/release for
24
BDRVReopenState state;
32
- * locking.
25
QTAILQ_ENTRY(BlockReopenQueueEntry) entry;
33
- */
26
} BlockReopenQueueEntry;
34
struct LuringState *linux_io_uring;
35
36
/* State for file descriptor monitoring using Linux io_uring */
37
diff --git a/include/block/raw-aio.h b/include/block/raw-aio.h
38
index XXXXXXX..XXXXXXX 100644
39
--- a/include/block/raw-aio.h
40
+++ b/include/block/raw-aio.h
41
@@ -XXX,XX +XXX,XX @@ void laio_io_unplug(uint64_t dev_max_batch);
42
typedef struct LuringState LuringState;
43
LuringState *luring_init(Error **errp);
44
void luring_cleanup(LuringState *s);
45
-int coroutine_fn luring_co_submit(BlockDriverState *bs, LuringState *s, int fd,
46
- uint64_t offset, QEMUIOVector *qiov, int type);
47
+
48
+/* luring_co_submit: submit I/O requests in the thread's current AioContext. */
49
+int coroutine_fn luring_co_submit(BlockDriverState *bs, int fd, uint64_t offset,
50
+ QEMUIOVector *qiov, int type);
51
void luring_detach_aio_context(LuringState *s, AioContext *old_context);
52
void luring_attach_aio_context(LuringState *s, AioContext *new_context);
53
-void luring_io_plug(BlockDriverState *bs, LuringState *s);
54
-void luring_io_unplug(BlockDriverState *bs, LuringState *s);
55
+
56
+/*
57
+ * luring_io_plug/unplug work in the thread's current AioContext, therefore the
58
+ * caller must ensure that they are paired in the same IOThread.
59
+ */
60
+void luring_io_plug(void);
61
+void luring_io_unplug(void);
62
#endif
63
64
#ifdef _WIN32
65
diff --git a/block/file-posix.c b/block/file-posix.c
66
index XXXXXXX..XXXXXXX 100644
67
--- a/block/file-posix.c
68
+++ b/block/file-posix.c
69
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_prw(BlockDriverState *bs, uint64_t offset,
70
type |= QEMU_AIO_MISALIGNED;
71
#ifdef CONFIG_LINUX_IO_URING
72
} else if (s->use_linux_io_uring) {
73
- LuringState *aio = aio_get_linux_io_uring(bdrv_get_aio_context(bs));
74
assert(qiov->size == bytes);
75
- return luring_co_submit(bs, aio, s->fd, offset, qiov, type);
76
+ return luring_co_submit(bs, s->fd, offset, qiov, type);
77
#endif
78
#ifdef CONFIG_LINUX_AIO
79
} else if (s->use_linux_aio) {
80
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn raw_co_io_plug(BlockDriverState *bs)
81
#endif
82
#ifdef CONFIG_LINUX_IO_URING
83
if (s->use_linux_io_uring) {
84
- LuringState *aio = aio_get_linux_io_uring(bdrv_get_aio_context(bs));
85
- luring_io_plug(bs, aio);
86
+ luring_io_plug();
87
}
88
#endif
89
}
90
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn raw_co_io_unplug(BlockDriverState *bs)
91
#endif
92
#ifdef CONFIG_LINUX_IO_URING
93
if (s->use_linux_io_uring) {
94
- LuringState *aio = aio_get_linux_io_uring(bdrv_get_aio_context(bs));
95
- luring_io_unplug(bs, aio);
96
+ luring_io_unplug();
97
}
98
#endif
99
}
100
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_flush_to_disk(BlockDriverState *bs)
101
102
#ifdef CONFIG_LINUX_IO_URING
103
if (s->use_linux_io_uring) {
104
- LuringState *aio = aio_get_linux_io_uring(bdrv_get_aio_context(bs));
105
- return luring_co_submit(bs, aio, s->fd, 0, NULL, QEMU_AIO_FLUSH);
106
+ return luring_co_submit(bs, s->fd, 0, NULL, QEMU_AIO_FLUSH);
107
}
108
#endif
109
return raw_thread_pool_submit(bs, handle_aiocb_flush, &acb);
110
diff --git a/block/io_uring.c b/block/io_uring.c
111
index XXXXXXX..XXXXXXX 100644
112
--- a/block/io_uring.c
113
+++ b/block/io_uring.c
114
@@ -XXX,XX +XXX,XX @@
115
#include "qapi/error.h"
116
#include "trace.h"
117
118
+/* Only used for assertions. */
119
+#include "qemu/coroutine_int.h"
120
+
121
/* io_uring ring size */
122
#define MAX_ENTRIES 128
123
124
@@ -XXX,XX +XXX,XX @@ typedef struct LuringState {
125
126
struct io_uring ring;
127
128
- /* io queue for submit at batch. Protected by AioContext lock. */
129
+ /* No locking required, only accessed from AioContext home thread */
130
LuringQueue io_q;
131
132
- /* I/O completion processing. Only runs in I/O thread. */
133
QEMUBH *completion_bh;
134
} LuringState;
135
136
@@ -XXX,XX +XXX,XX @@ end:
137
* eventually runs later. Coroutines cannot be entered recursively
138
* so avoid doing that!
139
*/
140
+ assert(luringcb->co->ctx == s->aio_context);
141
if (!qemu_coroutine_entered(luringcb->co)) {
142
aio_co_wake(luringcb->co);
143
}
144
@@ -XXX,XX +XXX,XX @@ static int ioq_submit(LuringState *s)
145
146
static void luring_process_completions_and_submit(LuringState *s)
147
{
148
- aio_context_acquire(s->aio_context);
149
luring_process_completions(s);
150
151
if (!s->io_q.plugged && s->io_q.in_queue > 0) {
152
ioq_submit(s);
153
}
154
- aio_context_release(s->aio_context);
155
}
156
157
static void qemu_luring_completion_bh(void *opaque)
158
@@ -XXX,XX +XXX,XX @@ static void ioq_init(LuringQueue *io_q)
159
io_q->blocked = false;
160
}
161
162
-void luring_io_plug(BlockDriverState *bs, LuringState *s)
163
+void luring_io_plug(void)
164
{
165
+ AioContext *ctx = qemu_get_current_aio_context();
166
+ LuringState *s = aio_get_linux_io_uring(ctx);
167
trace_luring_io_plug(s);
168
s->io_q.plugged++;
169
}
170
171
-void luring_io_unplug(BlockDriverState *bs, LuringState *s)
172
+void luring_io_unplug(void)
173
{
174
+ AioContext *ctx = qemu_get_current_aio_context();
175
+ LuringState *s = aio_get_linux_io_uring(ctx);
176
assert(s->io_q.plugged);
177
trace_luring_io_unplug(s, s->io_q.blocked, s->io_q.plugged,
178
s->io_q.in_queue, s->io_q.in_flight);
179
@@ -XXX,XX +XXX,XX @@ static int luring_do_submit(int fd, LuringAIOCB *luringcb, LuringState *s,
180
return 0;
181
}
182
183
-int coroutine_fn luring_co_submit(BlockDriverState *bs, LuringState *s, int fd,
184
- uint64_t offset, QEMUIOVector *qiov, int type)
185
+int coroutine_fn luring_co_submit(BlockDriverState *bs, int fd, uint64_t offset,
186
+ QEMUIOVector *qiov, int type)
187
{
188
int ret;
189
+ AioContext *ctx = qemu_get_current_aio_context();
190
+ LuringState *s = aio_get_linux_io_uring(ctx);
191
LuringAIOCB luringcb = {
192
.co = qemu_coroutine_self(),
193
.ret = -EINPROGRESS,
194
--
27
--
195
2.40.0
28
2.41.0
diff view generated by jsdifflib
1
From: Paolo Bonzini <pbonzini@redhat.com>
1
It's essentially the same code in preallocate_check_perm() and
2
preallocate_close(), except that the latter ignores errors.
2
3
3
Functions that can do I/O are prime candidates for being coroutine_fns. Make the
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
change for those that are themselves called only from coroutine_fns.
5
Reviewed-by: Eric Blake <eblake@redhat.com>
5
6
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
6
In addition, coroutine_fns should do I/O using bdrv_co_*() functions, for
7
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
7
which it is required to hold the BlockDriverState graph lock. So also nnotate
8
Message-ID: <20230911094620.45040-3-kwolf@redhat.com>
8
functions on the I/O path with TSA attributes, making it possible to
9
switch them to use bdrv_co_*() functions.
10
11
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
12
Message-Id: <20230309084456.304669-2-pbonzini@redhat.com>
13
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
---
10
---
16
block/vvfat.c | 58 ++++++++++++++++++++++++++-------------------------
11
block/preallocate.c | 48 +++++++++++++++++++++------------------------
17
1 file changed, 30 insertions(+), 28 deletions(-)
12
1 file changed, 22 insertions(+), 26 deletions(-)
18
13
19
diff --git a/block/vvfat.c b/block/vvfat.c
14
diff --git a/block/preallocate.c b/block/preallocate.c
20
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
21
--- a/block/vvfat.c
16
--- a/block/preallocate.c
22
+++ b/block/vvfat.c
17
+++ b/block/preallocate.c
23
@@ -XXX,XX +XXX,XX @@ static BDRVVVFATState *vvv = NULL;
18
@@ -XXX,XX +XXX,XX @@ static int preallocate_open(BlockDriverState *bs, QDict *options, int flags,
24
#endif
25
26
static int enable_write_target(BlockDriverState *bs, Error **errp);
27
-static int is_consistent(BDRVVVFATState *s);
28
+static int coroutine_fn is_consistent(BDRVVVFATState *s);
29
30
static QemuOptsList runtime_opts = {
31
.name = "vvfat",
32
@@ -XXX,XX +XXX,XX @@ static void print_mapping(const mapping_t* mapping)
33
}
34
#endif
35
36
-static int vvfat_read(BlockDriverState *bs, int64_t sector_num,
37
- uint8_t *buf, int nb_sectors)
38
+static int coroutine_fn GRAPH_RDLOCK
39
+vvfat_read(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, int nb_sectors)
40
{
41
BDRVVVFATState *s = bs->opaque;
42
int i;
43
@@ -XXX,XX +XXX,XX @@ static int vvfat_read(BlockDriverState *bs, int64_t sector_num,
44
DLOG(fprintf(stderr, "sectors %" PRId64 "+%" PRId64
45
" allocated\n", sector_num,
46
n >> BDRV_SECTOR_BITS));
47
- if (bdrv_pread(s->qcow, sector_num * BDRV_SECTOR_SIZE, n,
48
- buf + i * 0x200, 0) < 0) {
49
+ if (bdrv_co_pread(s->qcow, sector_num * BDRV_SECTOR_SIZE, n,
50
+ buf + i * 0x200, 0) < 0) {
51
return -1;
52
}
53
i += (n >> BDRV_SECTOR_BITS) - 1;
54
@@ -XXX,XX +XXX,XX @@ static int vvfat_read(BlockDriverState *bs, int64_t sector_num,
55
return 0;
19
return 0;
56
}
20
}
57
21
58
-static int coroutine_fn
22
-static void preallocate_close(BlockDriverState *bs)
59
+static int coroutine_fn GRAPH_RDLOCK
23
+static int preallocate_truncate_to_real_size(BlockDriverState *bs, Error **errp)
60
vvfat_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
61
QEMUIOVector *qiov, BdrvRequestFlags flags)
62
{
24
{
63
@@ -XXX,XX +XXX,XX @@ static inline uint32_t modified_fat_get(BDRVVVFATState* s,
25
- int ret;
26
BDRVPreallocateState *s = bs->opaque;
27
-
28
- if (s->data_end < 0) {
29
- return;
30
- }
31
+ int ret;
32
33
if (s->file_end < 0) {
34
s->file_end = bdrv_getlength(bs->file->bs);
35
if (s->file_end < 0) {
36
- return;
37
+ error_setg_errno(errp, -s->file_end, "Failed to get file length");
38
+ return s->file_end;
39
}
40
}
41
42
if (s->data_end < s->file_end) {
43
ret = bdrv_truncate(bs->file, s->data_end, true, PREALLOC_MODE_OFF, 0,
44
NULL);
45
- s->file_end = ret < 0 ? ret : s->data_end;
46
+ if (ret < 0) {
47
+ error_setg_errno(errp, -ret, "Failed to drop preallocation");
48
+ s->file_end = ret;
49
+ return ret;
50
+ }
51
+ s->file_end = s->data_end;
52
+ }
53
+
54
+ return 0;
55
+}
56
+
57
+static void preallocate_close(BlockDriverState *bs)
58
+{
59
+ BDRVPreallocateState *s = bs->opaque;
60
+
61
+ if (s->data_end >= 0) {
62
+ preallocate_truncate_to_real_size(bs, NULL);
64
}
63
}
65
}
64
}
66
65
67
-static inline bool cluster_was_modified(BDRVVVFATState *s,
66
@@ -XXX,XX +XXX,XX @@ static int preallocate_check_perm(BlockDriverState *bs,
68
- uint32_t cluster_num)
67
* We should truncate in check_perm, as in set_perm bs->file->perm will
69
+static inline bool coroutine_fn GRAPH_RDLOCK
68
* be already changed, and we should not violate it.
70
+cluster_was_modified(BDRVVVFATState *s, uint32_t cluster_num)
69
*/
71
{
70
- if (s->file_end < 0) {
72
int was_modified = 0;
71
- s->file_end = bdrv_getlength(bs->file->bs);
73
int i;
72
- if (s->file_end < 0) {
74
@@ -XXX,XX +XXX,XX @@ typedef enum {
73
- error_setg(errp, "Failed to get file length");
75
* Further, the files/directories handled by this function are
74
- return s->file_end;
76
* assumed to be *not* deleted (and *only* those).
75
- }
77
*/
76
- }
78
-static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s,
77
-
79
- direntry_t* direntry, const char* path)
78
- if (s->data_end < s->file_end) {
80
+static uint32_t coroutine_fn GRAPH_RDLOCK
79
- int ret = bdrv_truncate(bs->file, s->data_end, true,
81
+get_cluster_count_for_direntry(BDRVVVFATState* s, direntry_t* direntry, const char* path)
80
- PREALLOC_MODE_OFF, 0, NULL);
82
{
81
- if (ret < 0) {
83
/*
82
- error_setg(errp, "Failed to drop preallocation");
84
* This is a little bit tricky:
83
- s->file_end = ret;
85
@@ -XXX,XX +XXX,XX @@ static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s,
84
- return ret;
86
if (res) {
85
- }
87
return -1;
86
- s->file_end = s->data_end;
88
}
87
- }
89
- res = bdrv_pwrite(s->qcow, offset * BDRV_SECTOR_SIZE,
88
+ return preallocate_truncate_to_real_size(bs, errp);
90
- BDRV_SECTOR_SIZE, s->cluster_buffer,
89
}
91
- 0);
90
92
+ res = bdrv_co_pwrite(s->qcow, offset * BDRV_SECTOR_SIZE,
93
+ BDRV_SECTOR_SIZE, s->cluster_buffer,
94
+ 0);
95
if (res < 0) {
96
return -2;
97
}
98
@@ -XXX,XX +XXX,XX @@ static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s,
99
* It returns 0 upon inconsistency or error, and the number of clusters
100
* used by the directory, its subdirectories and their files.
101
*/
102
-static int check_directory_consistency(BDRVVVFATState *s,
103
- int cluster_num, const char* path)
104
+static int coroutine_fn GRAPH_RDLOCK
105
+check_directory_consistency(BDRVVVFATState *s, int cluster_num, const char* path)
106
{
107
int ret = 0;
108
unsigned char* cluster = g_malloc(s->cluster_size);
109
@@ -XXX,XX +XXX,XX @@ DLOG(fprintf(stderr, "check direntry %d:\n", i); print_direntry(direntries + i))
110
}
111
112
/* returns 1 on success */
113
-static int is_consistent(BDRVVVFATState* s)
114
+static int coroutine_fn GRAPH_RDLOCK
115
+is_consistent(BDRVVVFATState* s)
116
{
117
int i, check;
118
int used_clusters_count = 0;
119
@@ -XXX,XX +XXX,XX @@ static int commit_mappings(BDRVVVFATState* s,
120
return 0;
91
return 0;
121
}
122
123
-static int commit_direntries(BDRVVVFATState* s,
124
- int dir_index, int parent_mapping_index)
125
+static int coroutine_fn GRAPH_RDLOCK
126
+commit_direntries(BDRVVVFATState* s, int dir_index, int parent_mapping_index)
127
{
128
direntry_t* direntry = array_get(&(s->directory), dir_index);
129
uint32_t first_cluster = dir_index == 0 ? 0 : begin_of_direntry(direntry);
130
@@ -XXX,XX +XXX,XX @@ static int commit_direntries(BDRVVVFATState* s,
131
132
/* commit one file (adjust contents, adjust mapping),
133
return first_mapping_index */
134
-static int commit_one_file(BDRVVVFATState* s,
135
- int dir_index, uint32_t offset)
136
+static int coroutine_fn GRAPH_RDLOCK
137
+commit_one_file(BDRVVVFATState* s, int dir_index, uint32_t offset)
138
{
139
direntry_t* direntry = array_get(&(s->directory), dir_index);
140
uint32_t c = begin_of_direntry(direntry);
141
@@ -XXX,XX +XXX,XX @@ static int handle_renames_and_mkdirs(BDRVVVFATState* s)
142
/*
143
* TODO: make sure that the short name is not matching *another* file
144
*/
145
-static int handle_commits(BDRVVVFATState* s)
146
+static int coroutine_fn GRAPH_RDLOCK handle_commits(BDRVVVFATState* s)
147
{
148
int i, fail = 0;
149
150
@@ -XXX,XX +XXX,XX @@ static int handle_deletes(BDRVVVFATState* s)
151
* - recurse direntries from root (using bs->bdrv_pread)
152
* - delete files corresponding to mappings marked as deleted
153
*/
154
-static int do_commit(BDRVVVFATState* s)
155
+static int coroutine_fn GRAPH_RDLOCK do_commit(BDRVVVFATState* s)
156
{
157
int ret = 0;
158
159
@@ -XXX,XX +XXX,XX @@ DLOG(checkpoint());
160
return 0;
161
}
162
163
-static int try_commit(BDRVVVFATState* s)
164
+static int coroutine_fn GRAPH_RDLOCK try_commit(BDRVVVFATState* s)
165
{
166
vvfat_close_current_file(s);
167
DLOG(checkpoint());
168
@@ -XXX,XX +XXX,XX @@ DLOG(checkpoint());
169
return do_commit(s);
170
}
171
172
-static int vvfat_write(BlockDriverState *bs, int64_t sector_num,
173
- const uint8_t *buf, int nb_sectors)
174
+static int coroutine_fn GRAPH_RDLOCK
175
+vvfat_write(BlockDriverState *bs, int64_t sector_num,
176
+ const uint8_t *buf, int nb_sectors)
177
{
178
BDRVVVFATState *s = bs->opaque;
179
int i, ret;
180
@@ -XXX,XX +XXX,XX @@ DLOG(checkpoint());
181
* Use qcow backend. Commit later.
182
*/
183
DLOG(fprintf(stderr, "Write to qcow backend: %d + %d\n", (int)sector_num, nb_sectors));
184
- ret = bdrv_pwrite(s->qcow, sector_num * BDRV_SECTOR_SIZE,
185
- nb_sectors * BDRV_SECTOR_SIZE, buf, 0);
186
+ ret = bdrv_co_pwrite(s->qcow, sector_num * BDRV_SECTOR_SIZE,
187
+ nb_sectors * BDRV_SECTOR_SIZE, buf, 0);
188
if (ret < 0) {
189
fprintf(stderr, "Error writing to qcow backend\n");
190
return ret;
191
@@ -XXX,XX +XXX,XX @@ DLOG(checkpoint());
192
return 0;
193
}
194
195
-static int coroutine_fn
196
+static int coroutine_fn GRAPH_RDLOCK
197
vvfat_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes,
198
QEMUIOVector *qiov, BdrvRequestFlags flags)
199
{
200
--
92
--
201
2.40.0
93
2.41.0
diff view generated by jsdifflib
1
From: Paolo Bonzini <pbonzini@redhat.com>
1
When the permission related BlockDriver callbacks are called, we are in
2
2
the middle of an operation traversing the block graph. Polling in such a
3
do_sgio can suspend via the coroutine function thread_pool_submit_co, so it
3
place is a very bad idea because the graph could change in unexpected
4
has to be coroutine_fn as well---and the same is true of all its direct and
4
ways. In the future, callers will also hold the graph lock, which is
5
indirect callers.
5
likely to turn polling into a deadlock.
6
6
7
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
7
So we need to get rid of calls to functions like bdrv_getlength() or
8
Message-Id: <20230309084456.304669-7-pbonzini@redhat.com>
8
bdrv_truncate() there as these functions poll internally. They are
9
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
9
currently used so that when no parent has write/resize permissions on
10
the image any more, the preallocate filter drops the extra preallocated
11
area in the image file and gives up write/resize permissions itself.
12
13
In order to achieve this without polling in .bdrv_check_perm, don't
14
immediately truncate the image, but only schedule a BH to do so. The
15
filter keeps the write/resize permissions a bit longer now until the BH
16
has executed.
17
18
There is one case in which delaying doesn't work: Reopening the image
19
read-only. In this case, bs->file will likely be reopened read-only,
20
too, so keeping write permissions a bit longer on it doesn't work. But
21
we can already cover this case in preallocate_reopen_prepare() and not
22
rely on the permission updates for it.
23
24
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
25
Reviewed-by: Eric Blake <eblake@redhat.com>
26
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
27
Message-ID: <20230911094620.45040-4-kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
28
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
29
---
12
scsi/qemu-pr-helper.c | 22 +++++++++++-----------
30
block/preallocate.c | 89 +++++++++++++++++++++++++++++++++++----------
13
1 file changed, 11 insertions(+), 11 deletions(-)
31
1 file changed, 69 insertions(+), 20 deletions(-)
14
32
15
diff --git a/scsi/qemu-pr-helper.c b/scsi/qemu-pr-helper.c
33
diff --git a/block/preallocate.c b/block/preallocate.c
16
index XXXXXXX..XXXXXXX 100644
34
index XXXXXXX..XXXXXXX 100644
17
--- a/scsi/qemu-pr-helper.c
35
--- a/block/preallocate.c
18
+++ b/scsi/qemu-pr-helper.c
36
+++ b/block/preallocate.c
19
@@ -XXX,XX +XXX,XX @@ static int do_sgio_worker(void *opaque)
37
@@ -XXX,XX +XXX,XX @@ typedef struct BDRVPreallocateState {
20
return status;
38
* be invalid (< 0) when we don't have both exclusive BLK_PERM_RESIZE and
39
* BLK_PERM_WRITE permissions on file child.
40
*/
41
+
42
+ /* Gives up the resize permission on children when parents don't need it */
43
+ QEMUBH *drop_resize_bh;
44
} BDRVPreallocateState;
45
46
+static int preallocate_drop_resize(BlockDriverState *bs, Error **errp);
47
+static void preallocate_drop_resize_bh(void *opaque);
48
+
49
#define PREALLOCATE_OPT_PREALLOC_ALIGN "prealloc-align"
50
#define PREALLOCATE_OPT_PREALLOC_SIZE "prealloc-size"
51
static QemuOptsList runtime_opts = {
52
@@ -XXX,XX +XXX,XX @@ static int preallocate_open(BlockDriverState *bs, QDict *options, int flags,
53
* For this to work, mark them invalid.
54
*/
55
s->file_end = s->zero_start = s->data_end = -EINVAL;
56
+ s->drop_resize_bh = qemu_bh_new(preallocate_drop_resize_bh, bs);
57
58
ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
59
if (ret < 0) {
60
@@ -XXX,XX +XXX,XX @@ static void preallocate_close(BlockDriverState *bs)
61
{
62
BDRVPreallocateState *s = bs->opaque;
63
64
+ qemu_bh_cancel(s->drop_resize_bh);
65
+ qemu_bh_delete(s->drop_resize_bh);
66
+
67
if (s->data_end >= 0) {
68
preallocate_truncate_to_real_size(bs, NULL);
69
}
70
@@ -XXX,XX +XXX,XX @@ static int preallocate_reopen_prepare(BDRVReopenState *reopen_state,
71
BlockReopenQueue *queue, Error **errp)
72
{
73
PreallocateOpts *opts = g_new0(PreallocateOpts, 1);
74
+ int ret;
75
76
if (!preallocate_absorb_opts(opts, reopen_state->options,
77
reopen_state->bs->file->bs, errp)) {
78
@@ -XXX,XX +XXX,XX @@ static int preallocate_reopen_prepare(BDRVReopenState *reopen_state,
79
return -EINVAL;
80
}
81
82
+ /*
83
+ * Drop the preallocation already here if reopening read-only. The child
84
+ * might also be reopened read-only and then scheduling a BH during the
85
+ * permission update is too late.
86
+ */
87
+ if ((reopen_state->flags & BDRV_O_RDWR) == 0) {
88
+ ret = preallocate_drop_resize(reopen_state->bs, errp);
89
+ if (ret < 0) {
90
+ g_free(opts);
91
+ return ret;
92
+ }
93
+ }
94
+
95
reopen_state->opaque = opts;
96
97
return 0;
98
@@ -XXX,XX +XXX,XX @@ preallocate_co_getlength(BlockDriverState *bs)
99
return ret;
21
}
100
}
22
101
23
-static int do_sgio(int fd, const uint8_t *cdb, uint8_t *sense,
102
-static int preallocate_check_perm(BlockDriverState *bs,
24
- uint8_t *buf, int *sz, int dir)
103
- uint64_t perm, uint64_t shared, Error **errp)
25
+static int coroutine_fn do_sgio(int fd, const uint8_t *cdb, uint8_t *sense,
104
+static int preallocate_drop_resize(BlockDriverState *bs, Error **errp)
26
+ uint8_t *buf, int *sz, int dir)
105
{
27
{
106
BDRVPreallocateState *s = bs->opaque;
28
int r;
107
+ int ret;
29
108
30
@@ -XXX,XX +XXX,XX @@ static SCSISense mpath_generic_sense(int r)
109
- if (s->data_end >= 0 && !can_write_resize(perm)) {
31
}
110
- /*
111
- * Lose permissions.
112
- * We should truncate in check_perm, as in set_perm bs->file->perm will
113
- * be already changed, and we should not violate it.
114
- */
115
- return preallocate_truncate_to_real_size(bs, errp);
116
+ if (s->data_end < 0) {
117
+ return 0;
118
+ }
119
+
120
+ /*
121
+ * Before switching children to be read-only, truncate them to remove
122
+ * the preallocation and let them have the real size.
123
+ */
124
+ ret = preallocate_truncate_to_real_size(bs, errp);
125
+ if (ret < 0) {
126
+ return ret;
127
}
128
129
+ /*
130
+ * We'll drop our permissions and will allow other users to take write and
131
+ * resize permissions (see preallocate_child_perm). Anyone will be able to
132
+ * change the child, so mark all states invalid. We'll regain control if a
133
+ * parent requests write access again.
134
+ */
135
+ s->data_end = s->file_end = s->zero_start = -EINVAL;
136
+
137
+ bdrv_graph_rdlock_main_loop();
138
+ bdrv_child_refresh_perms(bs, bs->file, NULL);
139
+ bdrv_graph_rdunlock_main_loop();
140
+
141
return 0;
32
}
142
}
33
143
34
-static int mpath_reconstruct_sense(int fd, int r, uint8_t *sense)
144
+static void preallocate_drop_resize_bh(void *opaque)
35
+static int coroutine_fn mpath_reconstruct_sense(int fd, int r, uint8_t *sense)
145
+{
36
{
146
+ /*
37
switch (r) {
147
+ * In case of errors, we'll simply keep the exclusive lock on the image
38
case MPATH_PR_SUCCESS:
148
+ * indefinitely.
39
@@ -XXX,XX +XXX,XX @@ static int mpath_reconstruct_sense(int fd, int r, uint8_t *sense)
149
+ */
150
+ preallocate_drop_resize(opaque, NULL);
151
+}
152
+
153
static void preallocate_set_perm(BlockDriverState *bs,
154
uint64_t perm, uint64_t shared)
155
{
156
BDRVPreallocateState *s = bs->opaque;
157
158
if (can_write_resize(perm)) {
159
+ qemu_bh_cancel(s->drop_resize_bh);
160
if (s->data_end < 0) {
161
s->data_end = s->file_end = s->zero_start =
162
- bdrv_getlength(bs->file->bs);
163
+ bs->file->bs->total_sectors * BDRV_SECTOR_SIZE;
164
}
165
} else {
166
- /*
167
- * We drop our permissions, as well as allow shared
168
- * permissions (see preallocate_child_perm), anyone will be able to
169
- * change the child, so mark all states invalid. We'll regain control if
170
- * get good permissions back.
171
- */
172
- s->data_end = s->file_end = s->zero_start = -EINVAL;
173
+ qemu_bh_schedule(s->drop_resize_bh);
40
}
174
}
41
}
175
}
42
176
43
-static int multipath_pr_in(int fd, const uint8_t *cdb, uint8_t *sense,
177
@@ -XXX,XX +XXX,XX @@ static void preallocate_child_perm(BlockDriverState *bs, BdrvChild *c,
44
- uint8_t *data, int sz)
178
BdrvChildRole role, BlockReopenQueue *reopen_queue,
45
+static int coroutine_fn multipath_pr_in(int fd, const uint8_t *cdb, uint8_t *sense,
179
uint64_t perm, uint64_t shared, uint64_t *nperm, uint64_t *nshared)
46
+ uint8_t *data, int sz)
180
{
47
{
181
+ BDRVPreallocateState *s = bs->opaque;
48
int rq_servact = cdb[1];
182
+
49
struct prin_resp resp;
183
bdrv_default_perms(bs, c, role, reopen_queue, perm, shared, nperm, nshared);
50
@@ -XXX,XX +XXX,XX @@ static int multipath_pr_in(int fd, const uint8_t *cdb, uint8_t *sense,
184
51
return mpath_reconstruct_sense(fd, r, sense);
185
- if (can_write_resize(perm)) {
52
}
186
- /* This should come by default, but let's enforce: */
53
187
+ /*
54
-static int multipath_pr_out(int fd, const uint8_t *cdb, uint8_t *sense,
188
+ * We need exclusive write and resize permissions on the child not only when
55
- const uint8_t *param, int sz)
189
+ * the parent can write to it, but also after the parent gave up write
56
+static int coroutine_fn multipath_pr_out(int fd, const uint8_t *cdb, uint8_t *sense,
190
+ * permissions until preallocate_drop_resize() has completed.
57
+ const uint8_t *param, int sz)
191
+ */
58
{
192
+ if (can_write_resize(perm) || s->data_end != -EINVAL) {
59
int rq_servact = cdb[1];
193
*nperm |= BLK_PERM_WRITE | BLK_PERM_RESIZE;
60
int rq_scope = cdb[2] >> 4;
194
61
@@ -XXX,XX +XXX,XX @@ static int multipath_pr_out(int fd, const uint8_t *cdb, uint8_t *sense,
195
/*
62
}
196
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_preallocate_filter = {
63
#endif
197
.bdrv_co_flush = preallocate_co_flush,
64
198
.bdrv_co_truncate = preallocate_co_truncate,
65
-static int do_pr_in(int fd, const uint8_t *cdb, uint8_t *sense,
199
66
- uint8_t *data, int *resp_sz)
200
- .bdrv_check_perm = preallocate_check_perm,
67
+static int coroutine_fn do_pr_in(int fd, const uint8_t *cdb, uint8_t *sense,
201
.bdrv_set_perm = preallocate_set_perm,
68
+ uint8_t *data, int *resp_sz)
202
.bdrv_child_perm = preallocate_child_perm,
69
{
70
#ifdef CONFIG_MPATH
71
if (is_mpath(fd)) {
72
@@ -XXX,XX +XXX,XX @@ static int do_pr_in(int fd, const uint8_t *cdb, uint8_t *sense,
73
SG_DXFER_FROM_DEV);
74
}
75
76
-static int do_pr_out(int fd, const uint8_t *cdb, uint8_t *sense,
77
- const uint8_t *param, int sz)
78
+static int coroutine_fn do_pr_out(int fd, const uint8_t *cdb, uint8_t *sense,
79
+ const uint8_t *param, int sz)
80
{
81
int resp_sz;
82
203
83
--
204
--
84
2.40.0
205
2.41.0
diff view generated by jsdifflib
New patch
1
The documentation for bdrv_append() says that the caller must hold the
2
AioContext lock for bs_top. Change all callers to actually adhere to the
3
contract.
1
4
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
9
Message-ID: <20230911094620.45040-5-kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
12
tests/unit/test-bdrv-drain.c | 3 +++
13
tests/unit/test-bdrv-graph-mod.c | 6 ++++++
14
tests/unit/test-block-iothread.c | 3 +++
15
3 files changed, 12 insertions(+)
16
17
diff --git a/tests/unit/test-bdrv-drain.c b/tests/unit/test-bdrv-drain.c
18
index XXXXXXX..XXXXXXX 100644
19
--- a/tests/unit/test-bdrv-drain.c
20
+++ b/tests/unit/test-bdrv-drain.c
21
@@ -XXX,XX +XXX,XX @@ static void test_append_to_drained(void)
22
g_assert_cmpint(base_s->drain_count, ==, 1);
23
g_assert_cmpint(base->in_flight, ==, 0);
24
25
+ aio_context_acquire(qemu_get_aio_context());
26
bdrv_append(overlay, base, &error_abort);
27
+ aio_context_release(qemu_get_aio_context());
28
+
29
g_assert_cmpint(base->in_flight, ==, 0);
30
g_assert_cmpint(overlay->in_flight, ==, 0);
31
32
diff --git a/tests/unit/test-bdrv-graph-mod.c b/tests/unit/test-bdrv-graph-mod.c
33
index XXXXXXX..XXXXXXX 100644
34
--- a/tests/unit/test-bdrv-graph-mod.c
35
+++ b/tests/unit/test-bdrv-graph-mod.c
36
@@ -XXX,XX +XXX,XX @@ static void test_update_perm_tree(void)
37
bdrv_attach_child(filter, bs, "child", &child_of_bds,
38
BDRV_CHILD_DATA, &error_abort);
39
40
+ aio_context_acquire(qemu_get_aio_context());
41
ret = bdrv_append(filter, bs, NULL);
42
g_assert_cmpint(ret, <, 0);
43
+ aio_context_release(qemu_get_aio_context());
44
45
bdrv_unref(filter);
46
blk_unref(root);
47
@@ -XXX,XX +XXX,XX @@ static void test_should_update_child(void)
48
g_assert(target->backing->bs == bs);
49
bdrv_attach_child(filter, target, "target", &child_of_bds,
50
BDRV_CHILD_DATA, &error_abort);
51
+ aio_context_acquire(qemu_get_aio_context());
52
bdrv_append(filter, bs, &error_abort);
53
+ aio_context_release(qemu_get_aio_context());
54
g_assert(target->backing->bs == bs);
55
56
bdrv_unref(filter);
57
@@ -XXX,XX +XXX,XX @@ static void test_append_greedy_filter(void)
58
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
59
&error_abort);
60
61
+ aio_context_acquire(qemu_get_aio_context());
62
bdrv_append(fl, base, &error_abort);
63
+ aio_context_release(qemu_get_aio_context());
64
bdrv_unref(fl);
65
bdrv_unref(top);
66
}
67
diff --git a/tests/unit/test-block-iothread.c b/tests/unit/test-block-iothread.c
68
index XXXXXXX..XXXXXXX 100644
69
--- a/tests/unit/test-block-iothread.c
70
+++ b/tests/unit/test-block-iothread.c
71
@@ -XXX,XX +XXX,XX @@ static void test_propagate_mirror(void)
72
&error_abort);
73
74
/* Start a mirror job */
75
+ aio_context_acquire(main_ctx);
76
mirror_start("job0", src, target, NULL, JOB_DEFAULT, 0, 0, 0,
77
MIRROR_SYNC_MODE_NONE, MIRROR_OPEN_BACKING_CHAIN, false,
78
BLOCKDEV_ON_ERROR_REPORT, BLOCKDEV_ON_ERROR_REPORT,
79
false, "filter_node", MIRROR_COPY_MODE_BACKGROUND,
80
&error_abort);
81
+ aio_context_release(main_ctx);
82
+
83
WITH_JOB_LOCK_GUARD() {
84
job = job_get_locked("job0");
85
}
86
--
87
2.41.0
diff view generated by jsdifflib
1
From: Stefan Hajnoczi <stefanha@redhat.com>
1
bdrv_unref() is called by a lot of places that need to hold the graph
2
lock (it naturally happens in the context of operations that change the
3
graph). However, bdrv_unref() takes the graph writer lock internally, so
4
it can't actually be called while already holding a graph lock without
5
causing a deadlock.
2
6
3
The following conversion is safe and does not change behavior:
7
bdrv_unref() also can't just become GRAPH_WRLOCK because it drains the
8
node before closing it, and draining requires that the graph is
9
unlocked.
4
10
5
GLOBAL_STATE_CODE();
11
The solution is to defer deleting the node until we don't hold the lock
6
...
12
any more and draining is possible again.
7
- AIO_WAIT_WHILE(qemu_get_aio_context(), ...);
8
+ AIO_WAIT_WHILE_UNLOCKED(NULL, ...);
9
13
10
Since we're in GLOBAL_STATE_CODE(), qemu_get_aio_context() is our home
14
Note that keeping images open for longer than necessary can create
11
thread's AioContext. Thus AIO_WAIT_WHILE() does not unlock the
15
problems, too: You can't open an image again before it is really closed
12
AioContext:
16
(if image locking didn't prevent it, it would cause corruption).
17
Reopening an image immediately happens at least during bdrv_open() and
18
bdrv_co_create().
13
19
14
if (ctx_ && in_aio_context_home_thread(ctx_)) { \
20
In order to solve this problem, make sure to run the deferred unref in
15
while ((cond)) { \
21
bdrv_graph_wrunlock(), i.e. the first possible place where we can drain
16
aio_poll(ctx_, true); \
22
again. This is also why bdrv_schedule_unref() is marked GRAPH_WRLOCK.
17
waited_ = true; \
18
} \
19
23
20
And that means AIO_WAIT_WHILE_UNLOCKED(NULL, ...) can be substituted.
24
The output of iotest 051 is updated because the additional polling
25
changes the order of HMP output, resulting in a new "(qemu)" prompt in
26
the test output that was previously on a separate line and filtered out.
21
27
22
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
28
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
23
Tested-by: Philippe Mathieu-Daudé <philmd@linaro.org>
29
Message-ID: <20230911094620.45040-6-kwolf@redhat.com>
24
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
30
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
25
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
26
Message-Id: <20230309190855.414275-4-stefanha@redhat.com>
27
Reviewed-by: Wilfred Mallawa <wilfred.mallawa@wdc.com>
28
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
31
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
29
---
32
---
30
block/graph-lock.c | 2 +-
33
include/block/block-global-state.h | 1 +
31
1 file changed, 1 insertion(+), 1 deletion(-)
34
block.c | 17 +++++++++++++++++
35
block/graph-lock.c | 26 +++++++++++++++++++-------
36
tests/qemu-iotests/051.pc.out | 6 +++---
37
4 files changed, 40 insertions(+), 10 deletions(-)
32
38
39
diff --git a/include/block/block-global-state.h b/include/block/block-global-state.h
40
index XXXXXXX..XXXXXXX 100644
41
--- a/include/block/block-global-state.h
42
+++ b/include/block/block-global-state.h
43
@@ -XXX,XX +XXX,XX @@ void bdrv_img_create(const char *filename, const char *fmt,
44
void bdrv_ref(BlockDriverState *bs);
45
void no_coroutine_fn bdrv_unref(BlockDriverState *bs);
46
void coroutine_fn no_co_wrapper bdrv_co_unref(BlockDriverState *bs);
47
+void GRAPH_WRLOCK bdrv_schedule_unref(BlockDriverState *bs);
48
void bdrv_unref_child(BlockDriverState *parent, BdrvChild *child);
49
BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs,
50
BlockDriverState *child_bs,
51
diff --git a/block.c b/block.c
52
index XXXXXXX..XXXXXXX 100644
53
--- a/block.c
54
+++ b/block.c
55
@@ -XXX,XX +XXX,XX @@ void bdrv_unref(BlockDriverState *bs)
56
}
57
}
58
59
+/*
60
+ * Release a BlockDriverState reference while holding the graph write lock.
61
+ *
62
+ * Calling bdrv_unref() directly is forbidden while holding the graph lock
63
+ * because bdrv_close() both involves polling and taking the graph lock
64
+ * internally. bdrv_schedule_unref() instead delays decreasing the refcount and
65
+ * possibly closing @bs until the graph lock is released.
66
+ */
67
+void bdrv_schedule_unref(BlockDriverState *bs)
68
+{
69
+ if (!bs) {
70
+ return;
71
+ }
72
+ aio_bh_schedule_oneshot(qemu_get_aio_context(),
73
+ (QEMUBHFunc *) bdrv_unref, bs);
74
+}
75
+
76
struct BdrvOpBlocker {
77
Error *reason;
78
QLIST_ENTRY(BdrvOpBlocker) list;
33
diff --git a/block/graph-lock.c b/block/graph-lock.c
79
diff --git a/block/graph-lock.c b/block/graph-lock.c
34
index XXXXXXX..XXXXXXX 100644
80
index XXXXXXX..XXXXXXX 100644
35
--- a/block/graph-lock.c
81
--- a/block/graph-lock.c
36
+++ b/block/graph-lock.c
82
+++ b/block/graph-lock.c
37
@@ -XXX,XX +XXX,XX @@ void bdrv_graph_wrlock(void)
83
@@ -XXX,XX +XXX,XX @@ void bdrv_graph_wrlock(BlockDriverState *bs)
38
* reader lock.
84
void bdrv_graph_wrunlock(void)
39
*/
85
{
40
qatomic_set(&has_writer, 0);
86
GLOBAL_STATE_CODE();
41
- AIO_WAIT_WHILE(qemu_get_aio_context(), reader_count() >= 1);
87
- QEMU_LOCK_GUARD(&aio_context_list_lock);
42
+ AIO_WAIT_WHILE_UNLOCKED(NULL, reader_count() >= 1);
88
assert(qatomic_read(&has_writer));
43
qatomic_set(&has_writer, 1);
89
44
90
+ WITH_QEMU_LOCK_GUARD(&aio_context_list_lock) {
45
/*
91
+ /*
92
+ * No need for memory barriers, this works in pair with
93
+ * the slow path of rdlock() and both take the lock.
94
+ */
95
+ qatomic_store_release(&has_writer, 0);
96
+
97
+ /* Wake up all coroutines that are waiting to read the graph */
98
+ qemu_co_enter_all(&reader_queue, &aio_context_list_lock);
99
+ }
100
+
101
/*
102
- * No need for memory barriers, this works in pair with
103
- * the slow path of rdlock() and both take the lock.
104
+ * Run any BHs that were scheduled during the wrlock section and that
105
+ * callers might expect to have finished (in particular, this is important
106
+ * for bdrv_schedule_unref()).
107
+ *
108
+ * Do this only after restarting coroutines so that nested event loops in
109
+ * BHs don't deadlock if their condition relies on the coroutine making
110
+ * progress.
111
*/
112
- qatomic_store_release(&has_writer, 0);
113
-
114
- /* Wake up all coroutine that are waiting to read the graph */
115
- qemu_co_enter_all(&reader_queue, &aio_context_list_lock);
116
+ aio_bh_poll(qemu_get_aio_context());
117
}
118
119
void coroutine_fn bdrv_graph_co_rdlock(void)
120
diff --git a/tests/qemu-iotests/051.pc.out b/tests/qemu-iotests/051.pc.out
121
index XXXXXXX..XXXXXXX 100644
122
--- a/tests/qemu-iotests/051.pc.out
123
+++ b/tests/qemu-iotests/051.pc.out
124
@@ -XXX,XX +XXX,XX @@ QEMU_PROG: -device scsi-hd,drive=disk: Device needs media, but drive is empty
125
126
Testing: -drive file=TEST_DIR/t.qcow2,if=none,node-name=disk -object iothread,id=thread0 -device virtio-scsi,iothread=thread0,id=virtio-scsi0 -device scsi-hd,bus=virtio-scsi0.0,drive=disk,share-rw=on -device ide-hd,drive=disk,share-rw=on
127
QEMU X.Y.Z monitor - type 'help' for more information
128
-QEMU_PROG: -device ide-hd,drive=disk,share-rw=on: Cannot change iothread of active block backend
129
+(qemu) QEMU_PROG: -device ide-hd,drive=disk,share-rw=on: Cannot change iothread of active block backend
130
131
Testing: -drive file=TEST_DIR/t.qcow2,if=none,node-name=disk -object iothread,id=thread0 -device virtio-scsi,iothread=thread0,id=virtio-scsi0 -device scsi-hd,bus=virtio-scsi0.0,drive=disk,share-rw=on -device virtio-blk-pci,drive=disk,share-rw=on
132
QEMU X.Y.Z monitor - type 'help' for more information
133
-QEMU_PROG: -device virtio-blk-pci,drive=disk,share-rw=on: Cannot change iothread of active block backend
134
+(qemu) QEMU_PROG: -device virtio-blk-pci,drive=disk,share-rw=on: Cannot change iothread of active block backend
135
136
Testing: -drive file=TEST_DIR/t.qcow2,if=none,node-name=disk -object iothread,id=thread0 -device virtio-scsi,iothread=thread0,id=virtio-scsi0 -device scsi-hd,bus=virtio-scsi0.0,drive=disk,share-rw=on -device lsi53c895a,id=lsi0 -device scsi-hd,bus=lsi0.0,drive=disk,share-rw=on
137
QEMU X.Y.Z monitor - type 'help' for more information
138
@@ -XXX,XX +XXX,XX @@ QEMU X.Y.Z monitor - type 'help' for more information
139
140
Testing: -drive file=TEST_DIR/t.qcow2,if=none,node-name=disk -object iothread,id=thread0 -device virtio-scsi,iothread=thread0,id=virtio-scsi0 -device scsi-hd,bus=virtio-scsi0.0,drive=disk,share-rw=on -device virtio-blk-pci,drive=disk,iothread=thread0,share-rw=on
141
QEMU X.Y.Z monitor - type 'help' for more information
142
-QEMU_PROG: -device virtio-blk-pci,drive=disk,iothread=thread0,share-rw=on: Cannot change iothread of active block backend
143
+(qemu) QEMU_PROG: -device virtio-blk-pci,drive=disk,iothread=thread0,share-rw=on: Cannot change iothread of active block backend
144
145
Testing: -drive file=TEST_DIR/t.qcow2,if=none,node-name=disk -object iothread,id=thread0 -device virtio-scsi,iothread=thread0,id=virtio-scsi0 -device scsi-hd,bus=virtio-scsi0.0,drive=disk,share-rw=on -device virtio-scsi,id=virtio-scsi1,iothread=thread0 -device scsi-hd,bus=virtio-scsi1.0,drive=disk,share-rw=on
146
QEMU X.Y.Z monitor - type 'help' for more information
46
--
147
--
47
2.40.0
148
2.41.0
48
49
diff view generated by jsdifflib
New patch
1
Add a new wrapper type for GRAPH_WRLOCK functions that should be called
2
from coroutine context.
1
3
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
6
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
7
Message-ID: <20230911094620.45040-7-kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
10
include/block/block-common.h | 4 ++++
11
scripts/block-coroutine-wrapper.py | 11 +++++++++++
12
2 files changed, 15 insertions(+)
13
14
diff --git a/include/block/block-common.h b/include/block/block-common.h
15
index XXXXXXX..XXXXXXX 100644
16
--- a/include/block/block-common.h
17
+++ b/include/block/block-common.h
18
@@ -XXX,XX +XXX,XX @@
19
* function. The coroutine yields after scheduling the BH and is reentered when
20
* the wrapped function returns.
21
*
22
+ * A no_co_wrapper_bdrv_wrlock function is a no_co_wrapper function that
23
+ * automatically takes the graph wrlock when calling the wrapped function.
24
+ *
25
* If the first parameter of the function is a BlockDriverState, BdrvChild or
26
* BlockBackend pointer, the AioContext lock for it is taken in the wrapper.
27
*/
28
#define no_co_wrapper
29
+#define no_co_wrapper_bdrv_wrlock
30
31
#include "block/blockjob.h"
32
33
diff --git a/scripts/block-coroutine-wrapper.py b/scripts/block-coroutine-wrapper.py
34
index XXXXXXX..XXXXXXX 100644
35
--- a/scripts/block-coroutine-wrapper.py
36
+++ b/scripts/block-coroutine-wrapper.py
37
@@ -XXX,XX +XXX,XX @@ def __init__(self, wrapper_type: str, return_type: str, name: str,
38
self.args = [ParamDecl(arg.strip()) for arg in args.split(',')]
39
self.create_only_co = 'mixed' not in variant
40
self.graph_rdlock = 'bdrv_rdlock' in variant
41
+ self.graph_wrlock = 'bdrv_wrlock' in variant
42
43
self.wrapper_type = wrapper_type
44
45
if wrapper_type == 'co':
46
+ if self.graph_wrlock:
47
+ raise ValueError(f"co function can't be wrlock: {self.name}")
48
subsystem, subname = self.name.split('_', 1)
49
self.target_name = f'{subsystem}_co_{subname}'
50
else:
51
@@ -XXX,XX +XXX,XX @@ def gen_no_co_wrapper(func: FuncDecl) -> str:
52
name = func.target_name
53
struct_name = func.struct_name
54
55
+ graph_lock=''
56
+ graph_unlock=''
57
+ if func.graph_wrlock:
58
+ graph_lock=' bdrv_graph_wrlock(NULL);'
59
+ graph_unlock=' bdrv_graph_wrunlock();'
60
+
61
return f"""\
62
/*
63
* Wrappers for {name}
64
@@ -XXX,XX +XXX,XX @@ def gen_no_co_wrapper(func: FuncDecl) -> str:
65
{struct_name} *s = opaque;
66
AioContext *ctx = {func.gen_ctx('s->')};
67
68
+{graph_lock}
69
aio_context_acquire(ctx);
70
{func.get_result}{name}({ func.gen_list('s->{name}') });
71
aio_context_release(ctx);
72
+{graph_unlock}
73
74
aio_co_wake(s->co);
75
}}
76
--
77
2.41.0
diff view generated by jsdifflib
1
From: Stefan Hajnoczi <stefanha@redhat.com>
1
Don't assume specific parameter names like 'bs' or 'blk' in the
2
generated code, but use the actual name.
2
3
3
monitor_cleanup() is called from the main loop thread. Calling
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
AIO_WAIT_WHILE(qemu_get_aio_context(), ...) from the main loop thread is
5
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
5
equivalent to AIO_WAIT_WHILE_UNLOCKED(NULL, ...) because neither unlocks
6
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
6
the AioContext and the latter's assertion that we're in the main loop
7
Message-ID: <20230911094620.45040-8-kwolf@redhat.com>
7
succeeds.
8
9
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
10
Tested-by: Philippe Mathieu-Daudé <philmd@linaro.org>
11
Reviewed-by: Markus Armbruster <armbru@redhat.com>
12
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
13
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
14
Message-Id: <20230309190855.414275-7-stefanha@redhat.com>
15
Reviewed-by: Wilfred Mallawa <wilfred.mallawa@wdc.com>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
---
9
---
18
monitor/monitor.c | 4 ++--
10
scripts/block-coroutine-wrapper.py | 7 ++++---
19
1 file changed, 2 insertions(+), 2 deletions(-)
11
1 file changed, 4 insertions(+), 3 deletions(-)
20
12
21
diff --git a/monitor/monitor.c b/monitor/monitor.c
13
diff --git a/scripts/block-coroutine-wrapper.py b/scripts/block-coroutine-wrapper.py
22
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
23
--- a/monitor/monitor.c
15
--- a/scripts/block-coroutine-wrapper.py
24
+++ b/monitor/monitor.c
16
+++ b/scripts/block-coroutine-wrapper.py
25
@@ -XXX,XX +XXX,XX @@ void monitor_cleanup(void)
17
@@ -XXX,XX +XXX,XX @@ def __init__(self, wrapper_type: str, return_type: str, name: str,
26
* We need to poll both qemu_aio_context and iohandler_ctx to make
18
27
* sure that the dispatcher coroutine keeps making progress and
19
def gen_ctx(self, prefix: str = '') -> str:
28
* eventually terminates. qemu_aio_context is automatically
20
t = self.args[0].type
29
- * polled by calling AIO_WAIT_WHILE on it, but we must poll
21
+ name = self.args[0].name
30
+ * polled by calling AIO_WAIT_WHILE_UNLOCKED on it, but we must poll
22
if t == 'BlockDriverState *':
31
* iohandler_ctx manually.
23
- return f'bdrv_get_aio_context({prefix}bs)'
32
*
24
+ return f'bdrv_get_aio_context({prefix}{name})'
33
* Letting the iothread continue while shutting down the dispatcher
25
elif t == 'BdrvChild *':
34
@@ -XXX,XX +XXX,XX @@ void monitor_cleanup(void)
26
- return f'bdrv_get_aio_context({prefix}child->bs)'
35
aio_co_wake(qmp_dispatcher_co);
27
+ return f'bdrv_get_aio_context({prefix}{name}->bs)'
36
}
28
elif t == 'BlockBackend *':
37
29
- return f'blk_get_aio_context({prefix}blk)'
38
- AIO_WAIT_WHILE(qemu_get_aio_context(),
30
+ return f'blk_get_aio_context({prefix}{name})'
39
+ AIO_WAIT_WHILE_UNLOCKED(NULL,
31
else:
40
(aio_poll(iohandler_get_aio_context(), false),
32
return 'qemu_get_aio_context()'
41
qatomic_mb_read(&qmp_dispatcher_co_busy)));
42
33
43
--
34
--
44
2.40.0
35
2.41.0
45
46
diff view generated by jsdifflib
1
From: Stefan Hajnoczi <stefanha@redhat.com>
1
Instead of taking the writer lock internally, require callers to already
2
hold it when calling bdrv_replace_child_noperm(). These callers will
3
typically already hold the graph lock once the locking work is
4
completed, which means that they can't call functions that take it
5
internally.
2
6
3
The HMP monitor runs in the main loop thread. Calling
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
AIO_WAIT_WHILE(qemu_get_aio_context(), ...) from the main loop thread is
8
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
5
equivalent to AIO_WAIT_WHILE_UNLOCKED(NULL, ...) because neither unlocks
9
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
6
the AioContext and the latter's assertion that we're in the main loop
10
Message-ID: <20230911094620.45040-9-kwolf@redhat.com>
7
succeeds.
8
9
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
10
Tested-by: Philippe Mathieu-Daudé <philmd@linaro.org>
11
Reviewed-by: Markus Armbruster <armbru@redhat.com>
12
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
13
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
14
Message-Id: <20230309190855.414275-6-stefanha@redhat.com>
15
Reviewed-by: Wilfred Mallawa <wilfred.mallawa@wdc.com>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
---
12
---
18
monitor/hmp.c | 2 +-
13
block.c | 26 +++++++++++++++++++-------
19
1 file changed, 1 insertion(+), 1 deletion(-)
14
1 file changed, 19 insertions(+), 7 deletions(-)
20
15
21
diff --git a/monitor/hmp.c b/monitor/hmp.c
16
diff --git a/block.c b/block.c
22
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
23
--- a/monitor/hmp.c
18
--- a/block.c
24
+++ b/monitor/hmp.c
19
+++ b/block.c
25
@@ -XXX,XX +XXX,XX @@ void handle_hmp_command(MonitorHMP *mon, const char *cmdline)
20
@@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
26
Coroutine *co = qemu_coroutine_create(handle_hmp_command_co, &data);
21
static bool bdrv_recurse_has_child(BlockDriverState *bs,
27
monitor_set_cur(co, &mon->common);
22
BlockDriverState *child);
28
aio_co_enter(qemu_get_aio_context(), co);
23
29
- AIO_WAIT_WHILE(qemu_get_aio_context(), !data.done);
24
-static void bdrv_replace_child_noperm(BdrvChild *child,
30
+ AIO_WAIT_WHILE_UNLOCKED(NULL, !data.done);
25
- BlockDriverState *new_bs);
26
+static void GRAPH_WRLOCK
27
+bdrv_replace_child_noperm(BdrvChild *child, BlockDriverState *new_bs);
28
+
29
static void bdrv_remove_child(BdrvChild *child, Transaction *tran);
30
31
static int bdrv_reopen_prepare(BDRVReopenState *reopen_state,
32
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_abort(void *opaque)
33
BlockDriverState *new_bs = s->child->bs;
34
35
GLOBAL_STATE_CODE();
36
+ bdrv_graph_wrlock(s->old_bs);
37
+
38
/* old_bs reference is transparently moved from @s to @s->child */
39
if (!s->child->bs) {
40
/*
41
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_abort(void *opaque)
31
}
42
}
32
43
assert(s->child->quiesced_parent);
33
qobject_unref(qdict);
44
bdrv_replace_child_noperm(s->child, s->old_bs);
45
+
46
+ bdrv_graph_wrunlock();
47
bdrv_unref(new_bs);
48
}
49
50
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_tran(BdrvChild *child, BlockDriverState *new_bs,
51
if (new_bs) {
52
bdrv_ref(new_bs);
53
}
54
+
55
+ bdrv_graph_wrlock(new_bs);
56
bdrv_replace_child_noperm(child, new_bs);
57
+ bdrv_graph_wrunlock();
58
/* old_bs reference is transparently moved from @child to @s */
59
}
60
61
@@ -XXX,XX +XXX,XX @@ uint64_t bdrv_qapi_perm_to_blk_perm(BlockPermission qapi_perm)
62
* If @new_bs is non-NULL, the parent of @child must already be drained through
63
* @child and the caller must hold the AioContext lock for @new_bs.
64
*/
65
-static void bdrv_replace_child_noperm(BdrvChild *child,
66
- BlockDriverState *new_bs)
67
+static void GRAPH_WRLOCK
68
+bdrv_replace_child_noperm(BdrvChild *child, BlockDriverState *new_bs)
69
{
70
BlockDriverState *old_bs = child->bs;
71
int new_bs_quiesce_counter;
72
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_noperm(BdrvChild *child,
73
assert(bdrv_get_aio_context(old_bs) == bdrv_get_aio_context(new_bs));
74
}
75
76
- /* TODO Pull this up into the callers to avoid polling here */
77
- bdrv_graph_wrlock(new_bs);
78
if (old_bs) {
79
if (child->klass->detach) {
80
child->klass->detach(child);
81
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_noperm(BdrvChild *child,
82
child->klass->attach(child);
83
}
84
}
85
- bdrv_graph_wrunlock();
86
87
/*
88
* If the parent was drained through this BdrvChild previously, but new_bs
89
@@ -XXX,XX +XXX,XX @@ static void bdrv_attach_child_common_abort(void *opaque)
90
BlockDriverState *bs = s->child->bs;
91
92
GLOBAL_STATE_CODE();
93
+
94
+ bdrv_graph_wrlock(NULL);
95
bdrv_replace_child_noperm(s->child, NULL);
96
+ bdrv_graph_wrunlock();
97
98
if (bdrv_get_aio_context(bs) != s->old_child_ctx) {
99
bdrv_try_change_aio_context(bs, s->old_child_ctx, NULL, &error_abort);
100
@@ -XXX,XX +XXX,XX @@ static BdrvChild *bdrv_attach_child_common(BlockDriverState *child_bs,
101
* a problem, we already did this), but it will still poll until the parent
102
* is fully quiesced, so it will not be negatively affected either.
103
*/
104
+ bdrv_graph_wrlock(child_bs);
105
bdrv_parent_drained_begin_single(new_child);
106
bdrv_replace_child_noperm(new_child, child_bs);
107
+ bdrv_graph_wrunlock();
108
109
BdrvAttachChildCommonState *s = g_new(BdrvAttachChildCommonState, 1);
110
*s = (BdrvAttachChildCommonState) {
111
@@ -XXX,XX +XXX,XX @@ void bdrv_root_unref_child(BdrvChild *child)
112
BlockDriverState *child_bs = child->bs;
113
114
GLOBAL_STATE_CODE();
115
+ bdrv_graph_wrlock(NULL);
116
bdrv_replace_child_noperm(child, NULL);
117
+ bdrv_graph_wrunlock();
118
bdrv_child_free(child);
119
120
if (child_bs) {
34
--
121
--
35
2.40.0
122
2.41.0
36
37
diff view generated by jsdifflib
1
From: Paolo Bonzini <pbonzini@redhat.com>
1
Instead of taking the writer lock internally, require callers to already
2
2
hold it when calling bdrv_replace_child_tran(). These callers will
3
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
3
typically already hold the graph lock once the locking work is
4
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
4
completed, which means that they can't call functions that take it
5
internally.
6
7
While a graph lock is held, polling is not allowed. Therefore draining
8
the necessary nodes can no longer be done in bdrv_remove_child() and
9
bdrv_replace_node_noperm(), but the callers must already make sure that
10
they are drained.
11
12
Note that the transaction callbacks still take the lock internally, so
13
tran_finalize() must be called without the lock held. This is because
14
bdrv_append() also calls bdrv_attach_child_noperm(), which currently
15
requires to be called unlocked. Once it changes, the transaction
16
callbacks can be changed, too.
17
18
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
19
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
20
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
21
Message-ID: <20230911094620.45040-10-kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
22
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
---
23
---
7
nbd/server.c | 48 ++++++++++++++++++++++++------------------------
24
block.c | 78 ++++++++++++++++++++++++++++++++++++---------------------
8
1 file changed, 24 insertions(+), 24 deletions(-)
25
1 file changed, 50 insertions(+), 28 deletions(-)
9
26
10
diff --git a/nbd/server.c b/nbd/server.c
27
diff --git a/block.c b/block.c
11
index XXXXXXX..XXXXXXX 100644
28
index XXXXXXX..XXXXXXX 100644
12
--- a/nbd/server.c
29
--- a/block.c
13
+++ b/nbd/server.c
30
+++ b/block.c
14
@@ -XXX,XX +XXX,XX @@ nbd_read_eof(NBDClient *client, void *buffer, size_t size, Error **errp)
31
@@ -XXX,XX +XXX,XX @@ static bool bdrv_recurse_has_child(BlockDriverState *bs,
15
return 1;
32
static void GRAPH_WRLOCK
33
bdrv_replace_child_noperm(BdrvChild *child, BlockDriverState *new_bs);
34
35
-static void bdrv_remove_child(BdrvChild *child, Transaction *tran);
36
+static void GRAPH_WRLOCK
37
+bdrv_remove_child(BdrvChild *child, Transaction *tran);
38
39
static int bdrv_reopen_prepare(BDRVReopenState *reopen_state,
40
BlockReopenQueue *queue,
41
@@ -XXX,XX +XXX,XX @@ static TransactionActionDrv bdrv_replace_child_drv = {
42
*
43
* The function doesn't update permissions, caller is responsible for this.
44
*/
45
-static void bdrv_replace_child_tran(BdrvChild *child, BlockDriverState *new_bs,
46
- Transaction *tran)
47
+static void GRAPH_WRLOCK
48
+bdrv_replace_child_tran(BdrvChild *child, BlockDriverState *new_bs,
49
+ Transaction *tran)
50
{
51
BdrvReplaceChildState *s = g_new(BdrvReplaceChildState, 1);
52
53
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_tran(BdrvChild *child, BlockDriverState *new_bs,
54
bdrv_ref(new_bs);
55
}
56
57
- bdrv_graph_wrlock(new_bs);
58
bdrv_replace_child_noperm(child, new_bs);
59
- bdrv_graph_wrunlock();
60
/* old_bs reference is transparently moved from @child to @s */
16
}
61
}
17
62
18
-static int nbd_receive_request(NBDClient *client, NBDRequest *request,
63
@@ -XXX,XX +XXX,XX @@ static int bdrv_set_file_or_backing_noperm(BlockDriverState *parent_bs,
19
- Error **errp)
64
}
20
+static int coroutine_fn nbd_receive_request(NBDClient *client, NBDRequest *request,
65
21
+ Error **errp)
66
if (child) {
22
{
67
+ bdrv_drained_begin(child->bs);
23
uint8_t buf[NBD_REQUEST_SIZE];
68
+ bdrv_graph_wrlock(NULL);
24
uint32_t magic;
69
+
25
@@ -XXX,XX +XXX,XX @@ static inline void set_be_simple_reply(NBDSimpleReply *reply, uint64_t error,
70
bdrv_unset_inherits_from(parent_bs, child, tran);
26
stq_be_p(&reply->handle, handle);
71
bdrv_remove_child(child, tran);
72
+
73
+ bdrv_graph_wrunlock();
74
+ bdrv_drained_end(child->bs);
75
}
76
77
if (!child_bs) {
78
@@ -XXX,XX +XXX,XX @@ void bdrv_close_all(void)
79
assert(QTAILQ_EMPTY(&all_bdrv_states));
27
}
80
}
28
81
29
-static int nbd_co_send_simple_reply(NBDClient *client,
82
-static bool should_update_child(BdrvChild *c, BlockDriverState *to)
30
- uint64_t handle,
83
+static bool GRAPH_RDLOCK should_update_child(BdrvChild *c, BlockDriverState *to)
31
- uint32_t error,
84
{
32
- void *data,
85
GQueue *queue;
33
- size_t len,
86
GHashTable *found;
87
@@ -XXX,XX +XXX,XX @@ static TransactionActionDrv bdrv_remove_child_drv = {
88
.commit = bdrv_remove_child_commit,
89
};
90
91
-/* Function doesn't update permissions, caller is responsible for this. */
92
-static void bdrv_remove_child(BdrvChild *child, Transaction *tran)
93
+/*
94
+ * Function doesn't update permissions, caller is responsible for this.
95
+ *
96
+ * @child->bs (if non-NULL) must be drained.
97
+ */
98
+static void GRAPH_WRLOCK bdrv_remove_child(BdrvChild *child, Transaction *tran)
99
{
100
if (!child) {
101
return;
102
}
103
104
if (child->bs) {
105
- BlockDriverState *bs = child->bs;
106
- bdrv_drained_begin(bs);
107
+ assert(child->quiesced_parent);
108
bdrv_replace_child_tran(child, NULL, tran);
109
- bdrv_drained_end(bs);
110
}
111
112
tran_add(tran, &bdrv_remove_child_drv, child);
113
}
114
115
-static void undrain_on_clean_cb(void *opaque)
116
-{
117
- bdrv_drained_end(opaque);
118
-}
119
-
120
-static TransactionActionDrv undrain_on_clean = {
121
- .clean = undrain_on_clean_cb,
122
-};
123
-
124
-static int bdrv_replace_node_noperm(BlockDriverState *from,
125
- BlockDriverState *to,
126
- bool auto_skip, Transaction *tran,
34
- Error **errp)
127
- Error **errp)
35
+static int coroutine_fn nbd_co_send_simple_reply(NBDClient *client,
128
+/*
36
+ uint64_t handle,
129
+ * Both @from and @to (if non-NULL) must be drained. @to must be kept drained
37
+ uint32_t error,
130
+ * until the transaction is completed.
38
+ void *data,
131
+ */
39
+ size_t len,
132
+static int GRAPH_WRLOCK
40
+ Error **errp)
133
+bdrv_replace_node_noperm(BlockDriverState *from,
41
{
134
+ BlockDriverState *to,
42
NBDSimpleReply reply;
135
+ bool auto_skip, Transaction *tran,
43
int nbd_err = system_errno_to_nbd_errno(error);
136
+ Error **errp)
44
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn nbd_co_send_sparse_read(NBDClient *client,
137
{
45
stl_be_p(&chunk.length, pnum);
138
BdrvChild *c, *next;
46
ret = nbd_co_send_iov(client, iov, 1, errp);
139
47
} else {
140
GLOBAL_STATE_CODE();
48
- ret = blk_pread(exp->common.blk, offset + progress, pnum,
141
49
- data + progress, 0);
142
- bdrv_drained_begin(from);
50
+ ret = blk_co_pread(exp->common.blk, offset + progress, pnum,
143
- bdrv_drained_begin(to);
51
+ data + progress, 0);
144
- tran_add(tran, &undrain_on_clean, from);
52
if (ret < 0) {
145
- tran_add(tran, &undrain_on_clean, to);
53
error_setg_errno(errp, -ret, "reading from file failed");
146
+ assert(from->quiesce_counter);
54
break;
147
+ assert(to->quiesce_counter);
55
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn blockalloc_to_extents(BlockBackend *blk,
148
56
* @ea is converted to BE by the function
149
QLIST_FOREACH_SAFE(c, &from->parents, next_parent, next) {
57
* @last controls whether NBD_REPLY_FLAG_DONE is sent.
150
assert(c->bs == from);
58
*/
151
@@ -XXX,XX +XXX,XX @@ static int bdrv_replace_node_common(BlockDriverState *from,
59
-static int nbd_co_send_extents(NBDClient *client, uint64_t handle,
152
assert(qemu_get_current_aio_context() == qemu_get_aio_context());
60
- NBDExtentArray *ea,
153
assert(bdrv_get_aio_context(from) == bdrv_get_aio_context(to));
61
- bool last, uint32_t context_id, Error **errp)
154
bdrv_drained_begin(from);
62
+static int coroutine_fn
155
+ bdrv_drained_begin(to);
63
+nbd_co_send_extents(NBDClient *client, uint64_t handle, NBDExtentArray *ea,
156
+
64
+ bool last, uint32_t context_id, Error **errp)
157
+ bdrv_graph_wrlock(to);
65
{
158
66
NBDStructuredMeta chunk;
159
/*
67
struct iovec iov[] = {
160
* Do the replacement without permission update.
68
@@ -XXX,XX +XXX,XX @@ static void bitmap_to_extents(BdrvDirtyBitmap *bitmap,
161
@@ -XXX,XX +XXX,XX @@ static int bdrv_replace_node_common(BlockDriverState *from,
69
bdrv_dirty_bitmap_unlock(bitmap);
162
}
70
}
163
71
164
if (detach_subchain) {
72
-static int nbd_co_send_bitmap(NBDClient *client, uint64_t handle,
165
+ /* to_cow_parent is already drained because from is drained */
73
- BdrvDirtyBitmap *bitmap, uint64_t offset,
166
bdrv_remove_child(bdrv_filter_or_cow_child(to_cow_parent), tran);
74
- uint32_t length, bool dont_fragment, bool last,
167
}
75
- uint32_t context_id, Error **errp)
168
76
+static int coroutine_fn nbd_co_send_bitmap(NBDClient *client, uint64_t handle,
169
@@ -XXX,XX +XXX,XX @@ static int bdrv_replace_node_common(BlockDriverState *from,
77
+ BdrvDirtyBitmap *bitmap, uint64_t offset,
170
ret = 0;
78
+ uint32_t length, bool dont_fragment, bool last,
171
79
+ uint32_t context_id, Error **errp)
172
out:
80
{
173
+ bdrv_graph_wrunlock();
81
unsigned int nb_extents = dont_fragment ? 1 : NBD_MAX_BLOCK_STATUS_EXTENTS;
174
tran_finalize(tran, ret);
82
g_autoptr(NBDExtentArray) ea = nbd_extent_array_new(nb_extents);
175
83
@@ -XXX,XX +XXX,XX @@ static int nbd_co_send_bitmap(NBDClient *client, uint64_t handle,
176
+ bdrv_drained_end(to);
84
* to the client (although the caller may still need to disconnect after
177
bdrv_drained_end(from);
85
* reporting the error).
178
bdrv_unref(from);
86
*/
179
87
-static int nbd_co_receive_request(NBDRequestData *req, NBDRequest *request,
180
@@ -XXX,XX +XXX,XX @@ int bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top,
88
- Error **errp)
181
BdrvChild *child;
89
+static int coroutine_fn nbd_co_receive_request(NBDRequestData *req, NBDRequest *request,
182
Transaction *tran = tran_new();
90
+ Error **errp)
183
AioContext *old_context, *new_context = NULL;
91
{
184
+ bool drained = false;
92
NBDClient *client = req->client;
185
93
int valid_flags;
186
GLOBAL_STATE_CODE();
94
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int nbd_do_cmd_read(NBDClient *client, NBDRequest *request,
187
95
data, request->len, errp);
188
@@ -XXX,XX +XXX,XX @@ int bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top,
96
}
189
aio_context_acquire(new_context);
97
190
}
98
- ret = blk_pread(exp->common.blk, request->from, request->len, data, 0);
191
99
+ ret = blk_co_pread(exp->common.blk, request->from, request->len, data, 0);
192
+ bdrv_drained_begin(bs_new);
193
+ bdrv_drained_begin(bs_top);
194
+ drained = true;
195
+
196
+ bdrv_graph_wrlock(bs_new);
197
ret = bdrv_replace_node_noperm(bs_top, bs_new, true, tran, errp);
198
+ bdrv_graph_wrunlock();
100
if (ret < 0) {
199
if (ret < 0) {
101
return nbd_send_generic_reply(client, request->handle, ret,
200
goto out;
102
"reading from file failed", errp);
201
}
103
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int nbd_handle_request(NBDClient *client,
202
@@ -XXX,XX +XXX,XX @@ out:
104
if (request->flags & NBD_CMD_FLAG_FUA) {
203
bdrv_refresh_limits(bs_top, NULL, NULL);
105
flags |= BDRV_REQ_FUA;
204
bdrv_graph_rdunlock_main_loop();
106
}
205
107
- ret = blk_pwrite(exp->common.blk, request->from, request->len, data,
206
+ if (drained) {
108
- flags);
207
+ bdrv_drained_end(bs_top);
109
+ ret = blk_co_pwrite(exp->common.blk, request->from, request->len, data,
208
+ bdrv_drained_end(bs_new);
110
+ flags);
209
+ }
111
return nbd_send_generic_reply(client, request->handle, ret,
210
+
112
"writing to file failed", errp);
211
if (new_context && old_context != new_context) {
113
212
aio_context_release(new_context);
114
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int nbd_handle_request(NBDClient *client,
213
aio_context_acquire(old_context);
115
if (request->flags & NBD_CMD_FLAG_FAST_ZERO) {
214
@@ -XXX,XX +XXX,XX @@ int bdrv_replace_child_bs(BdrvChild *child, BlockDriverState *new_bs,
116
flags |= BDRV_REQ_NO_FALLBACK;
215
bdrv_ref(old_bs);
117
}
216
bdrv_drained_begin(old_bs);
118
- ret = blk_pwrite_zeroes(exp->common.blk, request->from, request->len,
217
bdrv_drained_begin(new_bs);
119
- flags);
218
+ bdrv_graph_wrlock(new_bs);
120
+ ret = blk_co_pwrite_zeroes(exp->common.blk, request->from, request->len,
219
121
+ flags);
220
bdrv_replace_child_tran(child, new_bs, tran);
122
return nbd_send_generic_reply(client, request->handle, ret,
221
123
"writing to file failed", errp);
222
@@ -XXX,XX +XXX,XX @@ int bdrv_replace_child_bs(BdrvChild *child, BlockDriverState *new_bs,
223
refresh_list = g_slist_prepend(refresh_list, new_bs);
224
225
ret = bdrv_list_refresh_perms(refresh_list, NULL, tran, errp);
226
+ bdrv_graph_wrunlock();
227
228
tran_finalize(tran, ret);
124
229
125
--
230
--
126
2.40.0
231
2.41.0
diff view generated by jsdifflib
1
From: Stefan Hajnoczi <stefanha@redhat.com>
1
Instead of taking the writer lock internally, require callers to already
2
hold it when calling bdrv_attach_child_common(). These callers will
3
typically already hold the graph lock once the locking work is
4
completed, which means that they can't call functions that take it
5
internally.
2
6
3
Not a coroutine_fn, you say?
7
Note that the transaction callbacks still take the lock internally, so
8
tran_finalize() must be called without the lock held. This is because
9
bdrv_append() also calls bdrv_replace_node_noperm(), which currently
10
requires the transaction callbacks to be called unlocked. In the next
11
step, both of them can be switched to locked tran_finalize() calls
12
together.
4
13
5
static int64_t bdrv_sum_allocated_file_size(BlockDriverState *bs)
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
{
15
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
7
BdrvChild *child;
16
Message-ID: <20230911094620.45040-11-kwolf@redhat.com>
8
int64_t child_size, sum = 0;
9
10
QLIST_FOREACH(child, &bs->children, next) {
11
if (child->role & (BDRV_CHILD_DATA | BDRV_CHILD_METADATA |
12
BDRV_CHILD_FILTERED))
13
{
14
child_size = bdrv_co_get_allocated_file_size(child->bs);
15
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
16
17
Well what do we have here?!
18
19
I rest my case, your honor.
20
21
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
22
Message-Id: <20230308211435.346375-1-stefanha@redhat.com>
23
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
24
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
25
---
18
---
26
block.c | 2 +-
19
block.c | 133 +++++++++++++++++++++++++++++++------------------
27
1 file changed, 1 insertion(+), 1 deletion(-)
20
block/stream.c | 20 ++++++--
21
2 files changed, 100 insertions(+), 53 deletions(-)
28
22
29
diff --git a/block.c b/block.c
23
diff --git a/block.c b/block.c
30
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
31
--- a/block.c
25
--- a/block.c
32
+++ b/block.c
26
+++ b/block.c
33
@@ -XXX,XX +XXX,XX @@ exit:
27
@@ -XXX,XX +XXX,XX @@ static TransactionActionDrv bdrv_attach_child_common_drv = {
34
* sums the size of all data-bearing children. (This excludes backing
28
* @child_bs can move to a different AioContext in this function. Callers must
35
* children.)
29
* make sure that their AioContext locking is still correct after this.
36
*/
30
*/
37
-static int64_t bdrv_sum_allocated_file_size(BlockDriverState *bs)
31
-static BdrvChild *bdrv_attach_child_common(BlockDriverState *child_bs,
38
+static int64_t coroutine_fn bdrv_sum_allocated_file_size(BlockDriverState *bs)
32
- const char *child_name,
39
{
33
- const BdrvChildClass *child_class,
34
- BdrvChildRole child_role,
35
- uint64_t perm, uint64_t shared_perm,
36
- void *opaque,
37
- Transaction *tran, Error **errp)
38
+static BdrvChild * GRAPH_WRLOCK
39
+bdrv_attach_child_common(BlockDriverState *child_bs,
40
+ const char *child_name,
41
+ const BdrvChildClass *child_class,
42
+ BdrvChildRole child_role,
43
+ uint64_t perm, uint64_t shared_perm,
44
+ void *opaque,
45
+ Transaction *tran, Error **errp)
46
{
47
BdrvChild *new_child;
48
AioContext *parent_ctx, *new_child_ctx;
49
@@ -XXX,XX +XXX,XX @@ static BdrvChild *bdrv_attach_child_common(BlockDriverState *child_bs,
50
* a problem, we already did this), but it will still poll until the parent
51
* is fully quiesced, so it will not be negatively affected either.
52
*/
53
- bdrv_graph_wrlock(child_bs);
54
bdrv_parent_drained_begin_single(new_child);
55
bdrv_replace_child_noperm(new_child, child_bs);
56
- bdrv_graph_wrunlock();
57
58
BdrvAttachChildCommonState *s = g_new(BdrvAttachChildCommonState, 1);
59
*s = (BdrvAttachChildCommonState) {
60
@@ -XXX,XX +XXX,XX @@ static BdrvChild *bdrv_attach_child_common(BlockDriverState *child_bs,
61
* @child_bs can move to a different AioContext in this function. Callers must
62
* make sure that their AioContext locking is still correct after this.
63
*/
64
-static BdrvChild *bdrv_attach_child_noperm(BlockDriverState *parent_bs,
65
- BlockDriverState *child_bs,
66
- const char *child_name,
67
- const BdrvChildClass *child_class,
68
- BdrvChildRole child_role,
69
- Transaction *tran,
70
- Error **errp)
71
+static BdrvChild * GRAPH_WRLOCK
72
+bdrv_attach_child_noperm(BlockDriverState *parent_bs,
73
+ BlockDriverState *child_bs,
74
+ const char *child_name,
75
+ const BdrvChildClass *child_class,
76
+ BdrvChildRole child_role,
77
+ Transaction *tran,
78
+ Error **errp)
79
{
80
uint64_t perm, shared_perm;
81
82
@@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
83
84
GLOBAL_STATE_CODE();
85
86
+ bdrv_graph_wrlock(child_bs);
87
+
88
child = bdrv_attach_child_common(child_bs, child_name, child_class,
89
child_role, perm, shared_perm, opaque,
90
tran, errp);
91
@@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
92
ret = bdrv_refresh_perms(child_bs, tran, errp);
93
94
out:
95
+ bdrv_graph_wrunlock();
96
tran_finalize(tran, ret);
97
98
bdrv_unref(child_bs);
99
@@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs,
100
101
GLOBAL_STATE_CODE();
102
103
+ bdrv_graph_wrlock(child_bs);
104
+
105
child = bdrv_attach_child_noperm(parent_bs, child_bs, child_name,
106
child_class, child_role, tran, errp);
107
if (!child) {
108
@@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs,
109
}
110
111
out:
112
+ bdrv_graph_wrunlock();
113
tran_finalize(tran, ret);
114
115
bdrv_unref(child_bs);
116
@@ -XXX,XX +XXX,XX @@ static BdrvChildRole bdrv_backing_role(BlockDriverState *bs)
117
* Sets the bs->backing or bs->file link of a BDS. A new reference is created;
118
* callers which don't need their own reference any more must call bdrv_unref().
119
*
120
+ * If the respective child is already present (i.e. we're detaching a node),
121
+ * that child node must be drained.
122
+ *
123
* Function doesn't update permissions, caller is responsible for this.
124
*
125
* The caller must hold the AioContext lock for @child_bs. Both @parent_bs and
126
* @child_bs can move to a different AioContext in this function. Callers must
127
* make sure that their AioContext locking is still correct after this.
128
*/
129
-static int bdrv_set_file_or_backing_noperm(BlockDriverState *parent_bs,
130
- BlockDriverState *child_bs,
131
- bool is_backing,
132
- Transaction *tran, Error **errp)
133
+static int GRAPH_WRLOCK
134
+bdrv_set_file_or_backing_noperm(BlockDriverState *parent_bs,
135
+ BlockDriverState *child_bs,
136
+ bool is_backing,
137
+ Transaction *tran, Error **errp)
138
{
139
bool update_inherits_from =
140
bdrv_inherits_from_recursive(child_bs, parent_bs);
141
@@ -XXX,XX +XXX,XX @@ static int bdrv_set_file_or_backing_noperm(BlockDriverState *parent_bs,
142
}
143
144
if (child) {
145
- bdrv_drained_begin(child->bs);
146
- bdrv_graph_wrlock(NULL);
147
-
148
+ assert(child->bs->quiesce_counter);
149
bdrv_unset_inherits_from(parent_bs, child, tran);
150
bdrv_remove_child(child, tran);
151
-
152
- bdrv_graph_wrunlock();
153
- bdrv_drained_end(child->bs);
154
}
155
156
if (!child_bs) {
157
@@ -XXX,XX +XXX,XX @@ static int bdrv_set_file_or_backing_noperm(BlockDriverState *parent_bs,
158
}
159
160
out:
161
- bdrv_graph_rdlock_main_loop();
162
bdrv_refresh_limits(parent_bs, tran, NULL);
163
- bdrv_graph_rdunlock_main_loop();
164
165
return 0;
166
}
167
@@ -XXX,XX +XXX,XX @@ out:
168
* The caller must hold the AioContext lock for @backing_hd. Both @bs and
169
* @backing_hd can move to a different AioContext in this function. Callers must
170
* make sure that their AioContext locking is still correct after this.
171
+ *
172
+ * If a backing child is already present (i.e. we're detaching a node), that
173
+ * child node must be drained.
174
*/
175
-static int bdrv_set_backing_noperm(BlockDriverState *bs,
176
- BlockDriverState *backing_hd,
177
- Transaction *tran, Error **errp)
178
+static int GRAPH_WRLOCK
179
+bdrv_set_backing_noperm(BlockDriverState *bs,
180
+ BlockDriverState *backing_hd,
181
+ Transaction *tran, Error **errp)
182
{
183
GLOBAL_STATE_CODE();
184
return bdrv_set_file_or_backing_noperm(bs, backing_hd, true, tran, errp);
185
@@ -XXX,XX +XXX,XX @@ int bdrv_set_backing_hd_drained(BlockDriverState *bs,
186
187
GLOBAL_STATE_CODE();
188
assert(bs->quiesce_counter > 0);
189
+ if (bs->backing) {
190
+ assert(bs->backing->bs->quiesce_counter > 0);
191
+ }
192
+ bdrv_graph_wrlock(backing_hd);
193
194
ret = bdrv_set_backing_noperm(bs, backing_hd, tran, errp);
195
if (ret < 0) {
196
@@ -XXX,XX +XXX,XX @@ int bdrv_set_backing_hd_drained(BlockDriverState *bs,
197
198
ret = bdrv_refresh_perms(bs, tran, errp);
199
out:
200
+ bdrv_graph_wrunlock();
201
tran_finalize(tran, ret);
202
return ret;
203
}
204
@@ -XXX,XX +XXX,XX @@ out:
205
int bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
206
Error **errp)
207
{
208
+ BlockDriverState *drain_bs = bs->backing ? bs->backing->bs : bs;
209
int ret;
210
GLOBAL_STATE_CODE();
211
212
- bdrv_drained_begin(bs);
213
+ bdrv_ref(drain_bs);
214
+ bdrv_drained_begin(drain_bs);
215
ret = bdrv_set_backing_hd_drained(bs, backing_hd, errp);
216
- bdrv_drained_end(bs);
217
+ bdrv_drained_end(drain_bs);
218
+ bdrv_unref(drain_bs);
219
220
return ret;
221
}
222
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp)
223
224
abort:
225
tran_abort(tran);
226
+
227
QTAILQ_FOREACH_SAFE(bs_entry, bs_queue, entry, next) {
228
if (bs_entry->prepared) {
229
ctx = bdrv_get_aio_context(bs_entry->state.bs);
230
@@ -XXX,XX +XXX,XX @@ static int bdrv_reopen_parse_file_or_backing(BDRVReopenState *reopen_state,
231
reopen_state->old_file_bs = old_child_bs;
232
}
233
234
+ if (old_child_bs) {
235
+ bdrv_ref(old_child_bs);
236
+ bdrv_drained_begin(old_child_bs);
237
+ }
238
+
239
old_ctx = bdrv_get_aio_context(bs);
240
ctx = bdrv_get_aio_context(new_child_bs);
241
if (old_ctx != ctx) {
242
@@ -XXX,XX +XXX,XX @@ static int bdrv_reopen_parse_file_or_backing(BDRVReopenState *reopen_state,
243
aio_context_acquire(ctx);
244
}
245
246
+ bdrv_graph_wrlock(new_child_bs);
247
+
248
ret = bdrv_set_file_or_backing_noperm(bs, new_child_bs, is_backing,
249
tran, errp);
250
251
+ bdrv_graph_wrunlock();
252
+
253
if (old_ctx != ctx) {
254
aio_context_release(ctx);
255
aio_context_acquire(old_ctx);
256
}
257
258
+ if (old_child_bs) {
259
+ bdrv_drained_end(old_child_bs);
260
+ bdrv_unref(old_child_bs);
261
+ }
262
+
263
return ret;
264
}
265
266
@@ -XXX,XX +XXX,XX @@ int bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top,
40
BdrvChild *child;
267
BdrvChild *child;
41
int64_t child_size, sum = 0;
268
Transaction *tran = tran_new();
269
AioContext *old_context, *new_context = NULL;
270
- bool drained = false;
271
272
GLOBAL_STATE_CODE();
273
274
assert(!bs_new->backing);
275
276
old_context = bdrv_get_aio_context(bs_top);
277
+ bdrv_drained_begin(bs_top);
278
+
279
+ /*
280
+ * bdrv_drained_begin() requires that only the AioContext of the drained
281
+ * node is locked, and at this point it can still differ from the AioContext
282
+ * of bs_top.
283
+ */
284
+ new_context = bdrv_get_aio_context(bs_new);
285
+ aio_context_release(old_context);
286
+ aio_context_acquire(new_context);
287
+ bdrv_drained_begin(bs_new);
288
+ aio_context_release(new_context);
289
+ aio_context_acquire(old_context);
290
+ new_context = NULL;
291
+
292
+ bdrv_graph_wrlock(bs_top);
293
294
child = bdrv_attach_child_noperm(bs_new, bs_top, "backing",
295
&child_of_bds, bdrv_backing_role(bs_new),
296
@@ -XXX,XX +XXX,XX @@ int bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top,
297
}
298
299
/*
300
- * bdrv_attach_child_noperm could change the AioContext of bs_top.
301
- * bdrv_replace_node_noperm calls bdrv_drained_begin, so let's temporarily
302
- * hold the new AioContext, since bdrv_drained_begin calls BDRV_POLL_WHILE
303
- * that assumes the new lock is taken.
304
+ * bdrv_attach_child_noperm could change the AioContext of bs_top and
305
+ * bs_new, but at least they are in the same AioContext now. This is the
306
+ * AioContext that we need to lock for the rest of the function.
307
*/
308
new_context = bdrv_get_aio_context(bs_top);
309
310
@@ -XXX,XX +XXX,XX @@ int bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top,
311
aio_context_acquire(new_context);
312
}
313
314
- bdrv_drained_begin(bs_new);
315
- bdrv_drained_begin(bs_top);
316
- drained = true;
317
-
318
- bdrv_graph_wrlock(bs_new);
319
ret = bdrv_replace_node_noperm(bs_top, bs_new, true, tran, errp);
320
- bdrv_graph_wrunlock();
321
if (ret < 0) {
322
goto out;
323
}
324
325
ret = bdrv_refresh_perms(bs_new, tran, errp);
326
out:
327
+ bdrv_graph_wrunlock();
328
tran_finalize(tran, ret);
329
330
bdrv_graph_rdlock_main_loop();
331
bdrv_refresh_limits(bs_top, NULL, NULL);
332
bdrv_graph_rdunlock_main_loop();
333
334
- if (drained) {
335
- bdrv_drained_end(bs_top);
336
- bdrv_drained_end(bs_new);
337
- }
338
+ bdrv_drained_end(bs_top);
339
+ bdrv_drained_end(bs_new);
340
341
if (new_context && old_context != new_context) {
342
aio_context_release(new_context);
343
diff --git a/block/stream.c b/block/stream.c
344
index XXXXXXX..XXXXXXX 100644
345
--- a/block/stream.c
346
+++ b/block/stream.c
347
@@ -XXX,XX +XXX,XX @@ static int stream_prepare(Job *job)
348
{
349
StreamBlockJob *s = container_of(job, StreamBlockJob, common.job);
350
BlockDriverState *unfiltered_bs = bdrv_skip_filters(s->target_bs);
351
+ BlockDriverState *unfiltered_bs_cow = bdrv_cow_bs(unfiltered_bs);
352
BlockDriverState *base;
353
BlockDriverState *unfiltered_base;
354
Error *local_err = NULL;
355
@@ -XXX,XX +XXX,XX @@ static int stream_prepare(Job *job)
356
s->cor_filter_bs = NULL;
357
358
/*
359
- * bdrv_set_backing_hd() requires that unfiltered_bs is drained. Drain
360
- * already here and use bdrv_set_backing_hd_drained() instead because
361
- * the polling during drained_begin() might change the graph, and if we do
362
- * this only later, we may end up working with the wrong base node (or it
363
- * might even have gone away by the time we want to use it).
364
+ * bdrv_set_backing_hd() requires that the unfiltered_bs and the COW child
365
+ * of unfiltered_bs is drained. Drain already here and use
366
+ * bdrv_set_backing_hd_drained() instead because the polling during
367
+ * drained_begin() might change the graph, and if we do this only later, we
368
+ * may end up working with the wrong base node (or it might even have gone
369
+ * away by the time we want to use it).
370
*/
371
bdrv_drained_begin(unfiltered_bs);
372
+ if (unfiltered_bs_cow) {
373
+ bdrv_ref(unfiltered_bs_cow);
374
+ bdrv_drained_begin(unfiltered_bs_cow);
375
+ }
376
377
base = bdrv_filter_or_cow_bs(s->above_base);
378
unfiltered_base = bdrv_skip_filters(base);
379
@@ -XXX,XX +XXX,XX @@ static int stream_prepare(Job *job)
380
}
381
382
out:
383
+ if (unfiltered_bs_cow) {
384
+ bdrv_drained_end(unfiltered_bs_cow);
385
+ bdrv_unref(unfiltered_bs_cow);
386
+ }
387
bdrv_drained_end(unfiltered_bs);
388
return ret;
389
}
42
--
390
--
43
2.40.0
391
2.41.0
diff view generated by jsdifflib
1
From: Paolo Bonzini <pbonzini@redhat.com>
1
In previous patches, we changed some transactionable functions to be
2
2
marked as GRAPH_WRLOCK, but required that tran_finalize() is still
3
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
3
called without the lock. This was because all callbacks that can be in
4
Message-Id: <20230309084456.304669-3-pbonzini@redhat.com>
4
the same transaction need to follow the same convention.
5
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
5
6
Now that we don't have conflicting requirements any more, we can switch
7
all of the transaction callbacks to be declared GRAPH_WRLOCK, too, and
8
call tran_finalize() with the lock held.
9
10
Document for each of these transactionable functions that the lock needs
11
to be held when completing the transaction, and make sure that all
12
callers down to the place where the transaction is finalised actually
13
have the writer lock.
14
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
17
Message-ID: <20230911094620.45040-12-kwolf@redhat.com>
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
18
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
---
19
---
8
block/blkdebug.c | 4 ++--
20
block.c | 61 +++++++++++++++++++++++++++++++++++++++++----------------
9
1 file changed, 2 insertions(+), 2 deletions(-)
21
1 file changed, 44 insertions(+), 17 deletions(-)
10
22
11
diff --git a/block/blkdebug.c b/block/blkdebug.c
23
diff --git a/block.c b/block.c
12
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
13
--- a/block/blkdebug.c
25
--- a/block.c
14
+++ b/block/blkdebug.c
26
+++ b/block.c
27
@@ -XXX,XX +XXX,XX @@ typedef struct BdrvReplaceChildState {
28
BlockDriverState *old_bs;
29
} BdrvReplaceChildState;
30
31
-static void bdrv_replace_child_commit(void *opaque)
32
+static void GRAPH_WRLOCK bdrv_replace_child_commit(void *opaque)
33
{
34
BdrvReplaceChildState *s = opaque;
35
GLOBAL_STATE_CODE();
36
37
- bdrv_unref(s->old_bs);
38
+ bdrv_schedule_unref(s->old_bs);
39
}
40
41
-static void bdrv_replace_child_abort(void *opaque)
42
+static void GRAPH_WRLOCK bdrv_replace_child_abort(void *opaque)
43
{
44
BdrvReplaceChildState *s = opaque;
45
BlockDriverState *new_bs = s->child->bs;
46
47
GLOBAL_STATE_CODE();
48
- bdrv_graph_wrlock(s->old_bs);
49
+ assert_bdrv_graph_writable();
50
51
/* old_bs reference is transparently moved from @s to @s->child */
52
if (!s->child->bs) {
53
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_abort(void *opaque)
54
assert(s->child->quiesced_parent);
55
bdrv_replace_child_noperm(s->child, s->old_bs);
56
57
- bdrv_graph_wrunlock();
58
bdrv_unref(new_bs);
59
}
60
61
@@ -XXX,XX +XXX,XX @@ static TransactionActionDrv bdrv_replace_child_drv = {
62
* Both @child->bs and @new_bs (if non-NULL) must be drained. @new_bs must be
63
* kept drained until the transaction is completed.
64
*
65
+ * After calling this function, the transaction @tran may only be completed
66
+ * while holding a writer lock for the graph.
67
+ *
68
* The function doesn't update permissions, caller is responsible for this.
69
*/
70
static void GRAPH_WRLOCK
71
@@ -XXX,XX +XXX,XX @@ typedef struct BdrvAttachChildCommonState {
72
AioContext *old_child_ctx;
73
} BdrvAttachChildCommonState;
74
75
-static void bdrv_attach_child_common_abort(void *opaque)
76
+static void GRAPH_WRLOCK bdrv_attach_child_common_abort(void *opaque)
77
{
78
BdrvAttachChildCommonState *s = opaque;
79
BlockDriverState *bs = s->child->bs;
80
81
GLOBAL_STATE_CODE();
82
+ assert_bdrv_graph_writable();
83
84
- bdrv_graph_wrlock(NULL);
85
bdrv_replace_child_noperm(s->child, NULL);
86
- bdrv_graph_wrunlock();
87
88
if (bdrv_get_aio_context(bs) != s->old_child_ctx) {
89
bdrv_try_change_aio_context(bs, s->old_child_ctx, NULL, &error_abort);
90
@@ -XXX,XX +XXX,XX @@ static void bdrv_attach_child_common_abort(void *opaque)
91
tran_commit(tran);
92
}
93
94
- bdrv_unref(bs);
95
+ bdrv_schedule_unref(bs);
96
bdrv_child_free(s->child);
97
}
98
99
@@ -XXX,XX +XXX,XX @@ static TransactionActionDrv bdrv_attach_child_common_drv = {
100
*
101
* Function doesn't update permissions, caller is responsible for this.
102
*
103
+ * After calling this function, the transaction @tran may only be completed
104
+ * while holding a writer lock for the graph.
105
+ *
106
* Returns new created child.
107
*
108
* The caller must hold the AioContext lock for @child_bs. Both @parent_bs and
109
@@ -XXX,XX +XXX,XX @@ bdrv_attach_child_common(BlockDriverState *child_bs,
110
* The caller must hold the AioContext lock for @child_bs. Both @parent_bs and
111
* @child_bs can move to a different AioContext in this function. Callers must
112
* make sure that their AioContext locking is still correct after this.
113
+ *
114
+ * After calling this function, the transaction @tran may only be completed
115
+ * while holding a writer lock for the graph.
116
*/
117
static BdrvChild * GRAPH_WRLOCK
118
bdrv_attach_child_noperm(BlockDriverState *parent_bs,
119
@@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
120
ret = bdrv_refresh_perms(child_bs, tran, errp);
121
122
out:
123
- bdrv_graph_wrunlock();
124
tran_finalize(tran, ret);
125
+ bdrv_graph_wrunlock();
126
127
bdrv_unref(child_bs);
128
129
@@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs,
130
}
131
132
out:
133
- bdrv_graph_wrunlock();
134
tran_finalize(tran, ret);
135
+ bdrv_graph_wrunlock();
136
137
bdrv_unref(child_bs);
138
139
@@ -XXX,XX +XXX,XX @@ static BdrvChildRole bdrv_backing_role(BlockDriverState *bs)
140
* The caller must hold the AioContext lock for @child_bs. Both @parent_bs and
141
* @child_bs can move to a different AioContext in this function. Callers must
142
* make sure that their AioContext locking is still correct after this.
143
+ *
144
+ * After calling this function, the transaction @tran may only be completed
145
+ * while holding a writer lock for the graph.
146
*/
147
static int GRAPH_WRLOCK
148
bdrv_set_file_or_backing_noperm(BlockDriverState *parent_bs,
15
@@ -XXX,XX +XXX,XX @@ out:
149
@@ -XXX,XX +XXX,XX @@ out:
150
*
151
* If a backing child is already present (i.e. we're detaching a node), that
152
* child node must be drained.
153
+ *
154
+ * After calling this function, the transaction @tran may only be completed
155
+ * while holding a writer lock for the graph.
156
*/
157
static int GRAPH_WRLOCK
158
bdrv_set_backing_noperm(BlockDriverState *bs,
159
@@ -XXX,XX +XXX,XX @@ int bdrv_set_backing_hd_drained(BlockDriverState *bs,
160
161
ret = bdrv_refresh_perms(bs, tran, errp);
162
out:
163
- bdrv_graph_wrunlock();
164
tran_finalize(tran, ret);
165
+ bdrv_graph_wrunlock();
16
return ret;
166
return ret;
17
}
167
}
18
168
19
-static int rule_check(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
169
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp)
20
- BlkdebugIOType iotype)
170
aio_context_release(ctx);
21
+static int coroutine_fn rule_check(BlockDriverState *bs, uint64_t offset,
171
}
22
+ uint64_t bytes, BlkdebugIOType iotype)
172
23
{
173
+ bdrv_graph_wrlock(NULL);
24
BDRVBlkdebugState *s = bs->opaque;
174
tran_commit(tran);
25
BlkdebugRule *rule = NULL;
175
+ bdrv_graph_wrunlock();
176
177
QTAILQ_FOREACH_REVERSE(bs_entry, bs_queue, entry) {
178
BlockDriverState *bs = bs_entry->state.bs;
179
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp)
180
goto cleanup;
181
182
abort:
183
+ bdrv_graph_wrlock(NULL);
184
tran_abort(tran);
185
+ bdrv_graph_wrunlock();
186
187
QTAILQ_FOREACH_SAFE(bs_entry, bs_queue, entry, next) {
188
if (bs_entry->prepared) {
189
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen_set_read_only(BlockDriverState *bs, bool read_only,
190
* true and reopen_state->new_backing_bs contains a pointer to the new
191
* backing BlockDriverState (or NULL).
192
*
193
+ * After calling this function, the transaction @tran may only be completed
194
+ * while holding a writer lock for the graph.
195
+ *
196
* Return 0 on success, otherwise return < 0 and set @errp.
197
*
198
* The caller must hold the AioContext lock of @reopen_state->bs.
199
@@ -XXX,XX +XXX,XX @@ static int bdrv_reopen_parse_file_or_backing(BDRVReopenState *reopen_state,
200
* commit() for any other BDS that have been left in a prepare() state
201
*
202
* The caller must hold the AioContext lock of @reopen_state->bs.
203
+ *
204
+ * After calling this function, the transaction @change_child_tran may only be
205
+ * completed while holding a writer lock for the graph.
206
*/
207
static int bdrv_reopen_prepare(BDRVReopenState *reopen_state,
208
BlockReopenQueue *queue,
209
@@ -XXX,XX +XXX,XX @@ static TransactionActionDrv bdrv_remove_child_drv = {
210
* Function doesn't update permissions, caller is responsible for this.
211
*
212
* @child->bs (if non-NULL) must be drained.
213
+ *
214
+ * After calling this function, the transaction @tran may only be completed
215
+ * while holding a writer lock for the graph.
216
*/
217
static void GRAPH_WRLOCK bdrv_remove_child(BdrvChild *child, Transaction *tran)
218
{
219
@@ -XXX,XX +XXX,XX @@ static void GRAPH_WRLOCK bdrv_remove_child(BdrvChild *child, Transaction *tran)
220
/*
221
* Both @from and @to (if non-NULL) must be drained. @to must be kept drained
222
* until the transaction is completed.
223
+ *
224
+ * After calling this function, the transaction @tran may only be completed
225
+ * while holding a writer lock for the graph.
226
*/
227
static int GRAPH_WRLOCK
228
bdrv_replace_node_noperm(BlockDriverState *from,
229
@@ -XXX,XX +XXX,XX @@ static int bdrv_replace_node_common(BlockDriverState *from,
230
ret = 0;
231
232
out:
233
- bdrv_graph_wrunlock();
234
tran_finalize(tran, ret);
235
+ bdrv_graph_wrunlock();
236
237
bdrv_drained_end(to);
238
bdrv_drained_end(from);
239
@@ -XXX,XX +XXX,XX @@ int bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top,
240
241
ret = bdrv_refresh_perms(bs_new, tran, errp);
242
out:
243
- bdrv_graph_wrunlock();
244
tran_finalize(tran, ret);
245
246
- bdrv_graph_rdlock_main_loop();
247
bdrv_refresh_limits(bs_top, NULL, NULL);
248
- bdrv_graph_rdunlock_main_loop();
249
+ bdrv_graph_wrunlock();
250
251
bdrv_drained_end(bs_top);
252
bdrv_drained_end(bs_new);
253
@@ -XXX,XX +XXX,XX @@ int bdrv_replace_child_bs(BdrvChild *child, BlockDriverState *new_bs,
254
refresh_list = g_slist_prepend(refresh_list, new_bs);
255
256
ret = bdrv_list_refresh_perms(refresh_list, NULL, tran, errp);
257
- bdrv_graph_wrunlock();
258
259
tran_finalize(tran, ret);
260
261
+ bdrv_graph_wrunlock();
262
bdrv_drained_end(old_bs);
263
bdrv_drained_end(new_bs);
264
bdrv_unref(old_bs);
26
--
265
--
27
2.40.0
266
2.41.0
diff view generated by jsdifflib
1
From: Wang Liang <wangliangzz@inspur.com>
1
Instead of taking the writer lock internally, require callers to already
2
hold it when calling bdrv_attach_child_common(). These callers will
3
typically already hold the graph lock once the locking work is
4
completed, which means that they can't call functions that take it
5
internally.
2
6
3
hmp_commit() calls blk_is_available() from a non-coroutine context (and in
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
the main loop). blk_is_available() is a co_wrapper_mixed_bdrv_rdlock
5
function, and in the non-coroutine context it calls AIO_WAIT_WHILE(),
6
which crashes if the aio_context lock is not taken before.
7
8
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1615
9
Signed-off-by: Wang Liang <wangliangzz@inspur.com>
10
Message-Id: <20230424103902.45265-1-wangliangzz@126.com>
11
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
8
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
12
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
9
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
10
Message-ID: <20230911094620.45040-13-kwolf@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
---
12
---
15
block/monitor/block-hmp-cmds.c | 10 ++++++----
13
include/block/block-global-state.h | 14 ++++++++------
16
1 file changed, 6 insertions(+), 4 deletions(-)
14
block.c | 7 +++----
15
block/quorum.c | 2 ++
16
block/replication.c | 6 ++++++
17
tests/unit/test-bdrv-drain.c | 14 ++++++++++++++
18
tests/unit/test-bdrv-graph-mod.c | 10 ++++++++++
19
6 files changed, 43 insertions(+), 10 deletions(-)
17
20
18
diff --git a/block/monitor/block-hmp-cmds.c b/block/monitor/block-hmp-cmds.c
21
diff --git a/include/block/block-global-state.h b/include/block/block-global-state.h
19
index XXXXXXX..XXXXXXX 100644
22
index XXXXXXX..XXXXXXX 100644
20
--- a/block/monitor/block-hmp-cmds.c
23
--- a/include/block/block-global-state.h
21
+++ b/block/monitor/block-hmp-cmds.c
24
+++ b/include/block/block-global-state.h
22
@@ -XXX,XX +XXX,XX @@ void hmp_commit(Monitor *mon, const QDict *qdict)
25
@@ -XXX,XX +XXX,XX @@ void no_coroutine_fn bdrv_unref(BlockDriverState *bs);
23
error_report("Device '%s' not found", device);
26
void coroutine_fn no_co_wrapper bdrv_co_unref(BlockDriverState *bs);
27
void GRAPH_WRLOCK bdrv_schedule_unref(BlockDriverState *bs);
28
void bdrv_unref_child(BlockDriverState *parent, BdrvChild *child);
29
-BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs,
30
- BlockDriverState *child_bs,
31
- const char *child_name,
32
- const BdrvChildClass *child_class,
33
- BdrvChildRole child_role,
34
- Error **errp);
35
+
36
+BdrvChild * GRAPH_WRLOCK
37
+bdrv_attach_child(BlockDriverState *parent_bs,
38
+ BlockDriverState *child_bs,
39
+ const char *child_name,
40
+ const BdrvChildClass *child_class,
41
+ BdrvChildRole child_role,
42
+ Error **errp);
43
44
bool bdrv_op_is_blocked(BlockDriverState *bs, BlockOpType op, Error **errp);
45
void bdrv_op_block(BlockDriverState *bs, BlockOpType op, Error *reason);
46
diff --git a/block.c b/block.c
47
index XXXXXXX..XXXXXXX 100644
48
--- a/block.c
49
+++ b/block.c
50
@@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs,
51
52
GLOBAL_STATE_CODE();
53
54
- bdrv_graph_wrlock(child_bs);
55
-
56
child = bdrv_attach_child_noperm(parent_bs, child_bs, child_name,
57
child_class, child_role, tran, errp);
58
if (!child) {
59
@@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs,
60
61
out:
62
tran_finalize(tran, ret);
63
- bdrv_graph_wrunlock();
64
65
- bdrv_unref(child_bs);
66
+ bdrv_schedule_unref(child_bs);
67
68
return ret < 0 ? NULL : child;
69
}
70
@@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_open_child(const char *filename,
71
return NULL;
72
}
73
74
+ bdrv_graph_wrlock(NULL);
75
ctx = bdrv_get_aio_context(bs);
76
aio_context_acquire(ctx);
77
child = bdrv_attach_child(parent, bs, bdref_key, child_class, child_role,
78
errp);
79
aio_context_release(ctx);
80
+ bdrv_graph_wrunlock();
81
82
return child;
83
}
84
diff --git a/block/quorum.c b/block/quorum.c
85
index XXXXXXX..XXXXXXX 100644
86
--- a/block/quorum.c
87
+++ b/block/quorum.c
88
@@ -XXX,XX +XXX,XX @@ static void quorum_add_child(BlockDriverState *bs, BlockDriverState *child_bs,
89
/* We can safely add the child now */
90
bdrv_ref(child_bs);
91
92
+ bdrv_graph_wrlock(child_bs);
93
child = bdrv_attach_child(bs, child_bs, indexstr, &child_of_bds,
94
BDRV_CHILD_DATA, errp);
95
+ bdrv_graph_wrunlock();
96
if (child == NULL) {
97
s->next_child_index--;
98
goto out;
99
diff --git a/block/replication.c b/block/replication.c
100
index XXXXXXX..XXXXXXX 100644
101
--- a/block/replication.c
102
+++ b/block/replication.c
103
@@ -XXX,XX +XXX,XX @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
24
return;
104
return;
25
}
105
}
26
- if (!blk_is_available(blk)) {
106
27
- error_report("Device '%s' has no medium", device);
107
+ bdrv_graph_wrlock(bs);
28
- return;
29
- }
30
31
bs = bdrv_skip_implicit_filters(blk_bs(blk));
32
aio_context = bdrv_get_aio_context(bs);
33
aio_context_acquire(aio_context);
34
35
+ if (!blk_is_available(blk)) {
36
+ error_report("Device '%s' has no medium", device);
37
+ aio_context_release(aio_context);
38
+ return;
39
+ }
40
+
108
+
41
ret = bdrv_commit(bs);
109
bdrv_ref(hidden_disk->bs);
42
110
s->hidden_disk = bdrv_attach_child(bs, hidden_disk->bs, "hidden disk",
43
aio_context_release(aio_context);
111
&child_of_bds, BDRV_CHILD_DATA,
112
&local_err);
113
if (local_err) {
114
error_propagate(errp, local_err);
115
+ bdrv_graph_wrunlock();
116
aio_context_release(aio_context);
117
return;
118
}
119
@@ -XXX,XX +XXX,XX @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
120
BDRV_CHILD_DATA, &local_err);
121
if (local_err) {
122
error_propagate(errp, local_err);
123
+ bdrv_graph_wrunlock();
124
aio_context_release(aio_context);
125
return;
126
}
127
128
+ bdrv_graph_wrunlock();
129
+
130
/* start backup job now */
131
error_setg(&s->blocker,
132
"Block device is in use by internal backup job");
133
diff --git a/tests/unit/test-bdrv-drain.c b/tests/unit/test-bdrv-drain.c
134
index XXXXXXX..XXXXXXX 100644
135
--- a/tests/unit/test-bdrv-drain.c
136
+++ b/tests/unit/test-bdrv-drain.c
137
@@ -XXX,XX +XXX,XX @@ static void do_test_delete_by_drain(bool detach_instead_of_delete,
138
139
null_bs = bdrv_open("null-co://", NULL, NULL, BDRV_O_RDWR | BDRV_O_PROTOCOL,
140
&error_abort);
141
+ bdrv_graph_wrlock(NULL);
142
bdrv_attach_child(bs, null_bs, "null-child", &child_of_bds,
143
BDRV_CHILD_DATA, &error_abort);
144
+ bdrv_graph_wrunlock();
145
146
/* This child will be the one to pass to requests through to, and
147
* it will stall until a drain occurs */
148
@@ -XXX,XX +XXX,XX @@ static void do_test_delete_by_drain(bool detach_instead_of_delete,
149
&error_abort);
150
child_bs->total_sectors = 65536 >> BDRV_SECTOR_BITS;
151
/* Takes our reference to child_bs */
152
+ bdrv_graph_wrlock(NULL);
153
tts->wait_child = bdrv_attach_child(bs, child_bs, "wait-child",
154
&child_of_bds,
155
BDRV_CHILD_DATA | BDRV_CHILD_PRIMARY,
156
&error_abort);
157
+ bdrv_graph_wrunlock();
158
159
/* This child is just there to be deleted
160
* (for detach_instead_of_delete == true) */
161
null_bs = bdrv_open("null-co://", NULL, NULL, BDRV_O_RDWR | BDRV_O_PROTOCOL,
162
&error_abort);
163
+ bdrv_graph_wrlock(NULL);
164
bdrv_attach_child(bs, null_bs, "null-child", &child_of_bds, BDRV_CHILD_DATA,
165
&error_abort);
166
+ bdrv_graph_wrunlock();
167
168
blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
169
blk_insert_bs(blk, bs, &error_abort);
170
@@ -XXX,XX +XXX,XX @@ static void detach_indirect_bh(void *opaque)
171
bdrv_unref_child(data->parent_b, data->child_b);
172
173
bdrv_ref(data->c);
174
+ bdrv_graph_wrlock(NULL);
175
data->child_c = bdrv_attach_child(data->parent_b, data->c, "PB-C",
176
&child_of_bds, BDRV_CHILD_DATA,
177
&error_abort);
178
+ bdrv_graph_wrunlock();
179
}
180
181
static void detach_by_parent_aio_cb(void *opaque, int ret)
182
@@ -XXX,XX +XXX,XX @@ static void test_detach_indirect(bool by_parent_cb)
183
/* Set child relationships */
184
bdrv_ref(b);
185
bdrv_ref(a);
186
+ bdrv_graph_wrlock(NULL);
187
child_b = bdrv_attach_child(parent_b, b, "PB-B", &child_of_bds,
188
BDRV_CHILD_DATA, &error_abort);
189
child_a = bdrv_attach_child(parent_b, a, "PB-A", &child_of_bds,
190
@@ -XXX,XX +XXX,XX @@ static void test_detach_indirect(bool by_parent_cb)
191
bdrv_attach_child(parent_a, a, "PA-A",
192
by_parent_cb ? &child_of_bds : &detach_by_driver_cb_class,
193
BDRV_CHILD_DATA, &error_abort);
194
+ bdrv_graph_wrunlock();
195
196
g_assert_cmpint(parent_a->refcnt, ==, 1);
197
g_assert_cmpint(parent_b->refcnt, ==, 1);
198
@@ -XXX,XX +XXX,XX @@ static void test_drop_intermediate_poll(void)
199
* Establish the chain last, so the chain links are the first
200
* elements in the BDS.parents lists
201
*/
202
+ bdrv_graph_wrlock(NULL);
203
for (i = 0; i < 3; i++) {
204
if (i) {
205
/* Takes the reference to chain[i - 1] */
206
@@ -XXX,XX +XXX,XX @@ static void test_drop_intermediate_poll(void)
207
&chain_child_class, BDRV_CHILD_COW, &error_abort);
208
}
209
}
210
+ bdrv_graph_wrunlock();
211
212
job = block_job_create("job", &test_simple_job_driver, NULL, job_node,
213
0, BLK_PERM_ALL, 0, 0, NULL, NULL, &error_abort);
214
@@ -XXX,XX +XXX,XX @@ static void do_test_replace_child_mid_drain(int old_drain_count,
215
new_child_bs->total_sectors = 1;
216
217
bdrv_ref(old_child_bs);
218
+ bdrv_graph_wrlock(NULL);
219
bdrv_attach_child(parent_bs, old_child_bs, "child", &child_of_bds,
220
BDRV_CHILD_COW, &error_abort);
221
+ bdrv_graph_wrunlock();
222
parent_s->setup_completed = true;
223
224
for (i = 0; i < old_drain_count; i++) {
225
diff --git a/tests/unit/test-bdrv-graph-mod.c b/tests/unit/test-bdrv-graph-mod.c
226
index XXXXXXX..XXXXXXX 100644
227
--- a/tests/unit/test-bdrv-graph-mod.c
228
+++ b/tests/unit/test-bdrv-graph-mod.c
229
@@ -XXX,XX +XXX,XX @@ static void test_update_perm_tree(void)
230
231
blk_insert_bs(root, bs, &error_abort);
232
233
+ bdrv_graph_wrlock(NULL);
234
bdrv_attach_child(filter, bs, "child", &child_of_bds,
235
BDRV_CHILD_DATA, &error_abort);
236
+ bdrv_graph_wrunlock();
237
238
aio_context_acquire(qemu_get_aio_context());
239
ret = bdrv_append(filter, bs, NULL);
240
@@ -XXX,XX +XXX,XX @@ static void test_should_update_child(void)
241
bdrv_set_backing_hd(target, bs, &error_abort);
242
243
g_assert(target->backing->bs == bs);
244
+ bdrv_graph_wrlock(NULL);
245
bdrv_attach_child(filter, target, "target", &child_of_bds,
246
BDRV_CHILD_DATA, &error_abort);
247
+ bdrv_graph_wrunlock();
248
aio_context_acquire(qemu_get_aio_context());
249
bdrv_append(filter, bs, &error_abort);
250
aio_context_release(qemu_get_aio_context());
251
@@ -XXX,XX +XXX,XX @@ static void test_parallel_exclusive_write(void)
252
*/
253
bdrv_ref(base);
254
255
+ bdrv_graph_wrlock(NULL);
256
bdrv_attach_child(top, fl1, "backing", &child_of_bds,
257
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
258
&error_abort);
259
@@ -XXX,XX +XXX,XX @@ static void test_parallel_exclusive_write(void)
260
bdrv_attach_child(fl2, base, "backing", &child_of_bds,
261
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
262
&error_abort);
263
+ bdrv_graph_wrunlock();
264
265
bdrv_replace_node(fl1, fl2, &error_abort);
266
267
@@ -XXX,XX +XXX,XX @@ static void test_parallel_perm_update(void)
268
*/
269
bdrv_ref(base);
270
271
+ bdrv_graph_wrlock(NULL);
272
bdrv_attach_child(top, ws, "file", &child_of_bds, BDRV_CHILD_DATA,
273
&error_abort);
274
c_fl1 = bdrv_attach_child(ws, fl1, "first", &child_of_bds,
275
@@ -XXX,XX +XXX,XX @@ static void test_parallel_perm_update(void)
276
bdrv_attach_child(fl2, base, "backing", &child_of_bds,
277
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
278
&error_abort);
279
+ bdrv_graph_wrunlock();
280
281
/* Select fl1 as first child to be active */
282
s->selected = c_fl1;
283
@@ -XXX,XX +XXX,XX @@ static void test_append_greedy_filter(void)
284
BlockDriverState *base = no_perm_node("base");
285
BlockDriverState *fl = exclusive_writer_node("fl1");
286
287
+ bdrv_graph_wrlock(NULL);
288
bdrv_attach_child(top, base, "backing", &child_of_bds,
289
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
290
&error_abort);
291
+ bdrv_graph_wrunlock();
292
293
aio_context_acquire(qemu_get_aio_context());
294
bdrv_append(fl, base, &error_abort);
44
--
295
--
45
2.40.0
296
2.41.0
diff view generated by jsdifflib
1
From: Paolo Bonzini <pbonzini@redhat.com>
1
The function reads the parents list, so it needs to hold the graph lock.
2
2
3
mirror_flush calls a mixed function blk_flush but it is only called
3
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
from mirror_run; so call the coroutine version and make mirror_flush
4
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
5
a coroutine_fn too.
5
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
6
6
Message-ID: <20230911094620.45040-14-kwolf@redhat.com>
7
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
8
Message-Id: <20230309084456.304669-4-pbonzini@redhat.com>
9
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
8
---
12
block/mirror.c | 4 ++--
9
include/block/block_int-common.h | 6 ++---
13
1 file changed, 2 insertions(+), 2 deletions(-)
10
include/block/block_int-global-state.h | 8 +++---
11
include/sysemu/block-backend-global-state.h | 4 +--
12
block.c | 28 +++++++++++++--------
13
block/block-backend.c | 26 ++++++++++++++-----
14
block/crypto.c | 6 +++--
15
block/mirror.c | 8 ++++++
16
block/vmdk.c | 2 ++
17
tests/unit/test-bdrv-graph-mod.c | 4 +++
18
9 files changed, 66 insertions(+), 26 deletions(-)
14
19
20
diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
21
index XXXXXXX..XXXXXXX 100644
22
--- a/include/block/block_int-common.h
23
+++ b/include/block/block_int-common.h
24
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
25
*/
26
void (*bdrv_cancel_in_flight)(BlockDriverState *bs);
27
28
- int (*bdrv_inactivate)(BlockDriverState *bs);
29
+ int GRAPH_RDLOCK_PTR (*bdrv_inactivate)(BlockDriverState *bs);
30
31
int (*bdrv_snapshot_create)(BlockDriverState *bs,
32
QEMUSnapshotInfo *sn_info);
33
@@ -XXX,XX +XXX,XX @@ struct BdrvChildClass {
34
* when migration is completing) and it can start/stop requesting
35
* permissions and doing I/O on it.
36
*/
37
- void (*activate)(BdrvChild *child, Error **errp);
38
- int (*inactivate)(BdrvChild *child);
39
+ void GRAPH_RDLOCK_PTR (*activate)(BdrvChild *child, Error **errp);
40
+ int GRAPH_RDLOCK_PTR (*inactivate)(BdrvChild *child);
41
42
void GRAPH_WRLOCK_PTR (*attach)(BdrvChild *child);
43
void GRAPH_WRLOCK_PTR (*detach)(BdrvChild *child);
44
diff --git a/include/block/block_int-global-state.h b/include/block/block_int-global-state.h
45
index XXXXXXX..XXXXXXX 100644
46
--- a/include/block/block_int-global-state.h
47
+++ b/include/block/block_int-global-state.h
48
@@ -XXX,XX +XXX,XX @@ void bdrv_get_cumulative_perm(BlockDriverState *bs, uint64_t *perm,
49
* bdrv_child_refresh_perms() instead and make the parent's
50
* .bdrv_child_perm() implementation return the correct values.
51
*/
52
-int bdrv_child_try_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared,
53
- Error **errp);
54
+int GRAPH_RDLOCK
55
+bdrv_child_try_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared,
56
+ Error **errp);
57
58
/**
59
* Calls bs->drv->bdrv_child_perm() and updates the child's permission
60
@@ -XXX,XX +XXX,XX @@ int bdrv_child_try_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared,
61
* values than before, but which will not result in the block layer
62
* automatically refreshing the permissions.
63
*/
64
-int bdrv_child_refresh_perms(BlockDriverState *bs, BdrvChild *c, Error **errp);
65
+int GRAPH_RDLOCK
66
+bdrv_child_refresh_perms(BlockDriverState *bs, BdrvChild *c, Error **errp);
67
68
bool GRAPH_RDLOCK bdrv_recurse_can_replace(BlockDriverState *bs,
69
BlockDriverState *to_replace);
70
diff --git a/include/sysemu/block-backend-global-state.h b/include/sysemu/block-backend-global-state.h
71
index XXXXXXX..XXXXXXX 100644
72
--- a/include/sysemu/block-backend-global-state.h
73
+++ b/include/sysemu/block-backend-global-state.h
74
@@ -XXX,XX +XXX,XX @@ int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, Error **errp);
75
int blk_replace_bs(BlockBackend *blk, BlockDriverState *new_bs, Error **errp);
76
bool bdrv_has_blk(BlockDriverState *bs);
77
bool bdrv_is_root_node(BlockDriverState *bs);
78
-int blk_set_perm(BlockBackend *blk, uint64_t perm, uint64_t shared_perm,
79
- Error **errp);
80
+int GRAPH_UNLOCKED blk_set_perm(BlockBackend *blk, uint64_t perm,
81
+ uint64_t shared_perm, Error **errp);
82
void blk_get_perm(BlockBackend *blk, uint64_t *perm, uint64_t *shared_perm);
83
84
void blk_iostatus_enable(BlockBackend *blk);
85
diff --git a/block.c b/block.c
86
index XXXXXXX..XXXXXXX 100644
87
--- a/block.c
88
+++ b/block.c
89
@@ -XXX,XX +XXX,XX @@ static bool bdrv_a_allow_b(BdrvChild *a, BdrvChild *b, Error **errp)
90
return false;
91
}
92
93
-static bool bdrv_parent_perms_conflict(BlockDriverState *bs, Error **errp)
94
+static bool GRAPH_RDLOCK
95
+bdrv_parent_perms_conflict(BlockDriverState *bs, Error **errp)
96
{
97
BdrvChild *a, *b;
98
GLOBAL_STATE_CODE();
99
@@ -XXX,XX +XXX,XX @@ static void bdrv_child_perm(BlockDriverState *bs, BlockDriverState *child_bs,
100
* simplest way to satisfy this criteria: use only result of
101
* bdrv_topological_dfs() or NULL as @list parameter.
102
*/
103
-static GSList *bdrv_topological_dfs(GSList *list, GHashTable *found,
104
- BlockDriverState *bs)
105
+static GSList * GRAPH_RDLOCK
106
+bdrv_topological_dfs(GSList *list, GHashTable *found, BlockDriverState *bs)
107
{
108
BdrvChild *child;
109
g_autoptr(GHashTable) local_found = NULL;
110
@@ -XXX,XX +XXX,XX @@ static int bdrv_node_refresh_perm(BlockDriverState *bs, BlockReopenQueue *q,
111
* @list is a product of bdrv_topological_dfs() (may be called several times) -
112
* a topologically sorted subgraph.
113
*/
114
-static int bdrv_do_refresh_perms(GSList *list, BlockReopenQueue *q,
115
- Transaction *tran, Error **errp)
116
+static int GRAPH_RDLOCK
117
+bdrv_do_refresh_perms(GSList *list, BlockReopenQueue *q, Transaction *tran,
118
+ Error **errp)
119
{
120
int ret;
121
BlockDriverState *bs;
122
@@ -XXX,XX +XXX,XX @@ static int bdrv_do_refresh_perms(GSList *list, BlockReopenQueue *q,
123
* topologically sorted. It's not a problem if some node occurs in the @list
124
* several times.
125
*/
126
-static int bdrv_list_refresh_perms(GSList *list, BlockReopenQueue *q,
127
- Transaction *tran, Error **errp)
128
+static int GRAPH_RDLOCK
129
+bdrv_list_refresh_perms(GSList *list, BlockReopenQueue *q, Transaction *tran,
130
+ Error **errp)
131
{
132
g_autoptr(GHashTable) found = g_hash_table_new(NULL, NULL);
133
g_autoptr(GSList) refresh_list = NULL;
134
@@ -XXX,XX +XXX,XX @@ char *bdrv_perm_names(uint64_t perm)
135
136
137
/* @tran is allowed to be NULL. In this case no rollback is possible */
138
-static int bdrv_refresh_perms(BlockDriverState *bs, Transaction *tran,
139
- Error **errp)
140
+static int GRAPH_RDLOCK
141
+bdrv_refresh_perms(BlockDriverState *bs, Transaction *tran, Error **errp)
142
{
143
int ret;
144
Transaction *local_tran = NULL;
145
@@ -XXX,XX +XXX,XX @@ void bdrv_root_unref_child(BdrvChild *child)
146
GLOBAL_STATE_CODE();
147
bdrv_graph_wrlock(NULL);
148
bdrv_replace_child_noperm(child, NULL);
149
- bdrv_graph_wrunlock();
150
bdrv_child_free(child);
151
152
if (child_bs) {
153
@@ -XXX,XX +XXX,XX @@ void bdrv_root_unref_child(BdrvChild *child)
154
NULL);
155
}
156
157
+ bdrv_graph_wrunlock();
158
bdrv_unref(child_bs);
159
}
160
161
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp)
162
* reconfiguring the fd and that's why it does it in raw_check_perm(), not
163
* in raw_reopen_prepare() which is called with "old" permissions.
164
*/
165
+ bdrv_graph_rdlock_main_loop();
166
ret = bdrv_list_refresh_perms(refresh_list, bs_queue, tran, errp);
167
+ bdrv_graph_rdunlock_main_loop();
168
+
169
if (ret < 0) {
170
goto abort;
171
}
172
@@ -XXX,XX +XXX,XX @@ int bdrv_activate(BlockDriverState *bs, Error **errp)
173
BdrvDirtyBitmap *bm;
174
175
GLOBAL_STATE_CODE();
176
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
177
178
if (!bs->drv) {
179
return -ENOMEDIUM;
180
@@ -XXX,XX +XXX,XX @@ static int bdrv_inactivate_recurse(BlockDriverState *bs)
181
uint64_t cumulative_perms, cumulative_shared_perms;
182
183
GLOBAL_STATE_CODE();
184
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
185
186
if (!bs->drv) {
187
return -ENOMEDIUM;
188
diff --git a/block/block-backend.c b/block/block-backend.c
189
index XXXXXXX..XXXXXXX 100644
190
--- a/block/block-backend.c
191
+++ b/block/block-backend.c
192
@@ -XXX,XX +XXX,XX @@ static QTAILQ_HEAD(, BlockBackend) block_backends =
193
static QTAILQ_HEAD(, BlockBackend) monitor_block_backends =
194
QTAILQ_HEAD_INITIALIZER(monitor_block_backends);
195
196
+static int coroutine_mixed_fn GRAPH_RDLOCK
197
+blk_set_perm_locked(BlockBackend *blk, uint64_t perm, uint64_t shared_perm,
198
+ Error **errp);
199
+
200
static void blk_root_inherit_options(BdrvChildRole role, bool parent_is_format,
201
int *child_flags, QDict *child_options,
202
int parent_flags, QDict *parent_options)
203
@@ -XXX,XX +XXX,XX @@ static void blk_vm_state_changed(void *opaque, bool running, RunState state)
204
*
205
* If an error is returned, the VM cannot be allowed to be resumed.
206
*/
207
-static void blk_root_activate(BdrvChild *child, Error **errp)
208
+static void GRAPH_RDLOCK blk_root_activate(BdrvChild *child, Error **errp)
209
{
210
BlockBackend *blk = child->opaque;
211
Error *local_err = NULL;
212
@@ -XXX,XX +XXX,XX @@ static void blk_root_activate(BdrvChild *child, Error **errp)
213
*/
214
saved_shared_perm = blk->shared_perm;
215
216
- blk_set_perm(blk, blk->perm, BLK_PERM_ALL, &local_err);
217
+ blk_set_perm_locked(blk, blk->perm, BLK_PERM_ALL, &local_err);
218
if (local_err) {
219
error_propagate(errp, local_err);
220
blk->disable_perm = true;
221
@@ -XXX,XX +XXX,XX @@ static void blk_root_activate(BdrvChild *child, Error **errp)
222
return;
223
}
224
225
- blk_set_perm(blk, blk->perm, blk->shared_perm, &local_err);
226
+ blk_set_perm_locked(blk, blk->perm, blk->shared_perm, &local_err);
227
if (local_err) {
228
error_propagate(errp, local_err);
229
blk->disable_perm = true;
230
@@ -XXX,XX +XXX,XX @@ static bool blk_can_inactivate(BlockBackend *blk)
231
return blk->force_allow_inactivate;
232
}
233
234
-static int blk_root_inactivate(BdrvChild *child)
235
+static int GRAPH_RDLOCK blk_root_inactivate(BdrvChild *child)
236
{
237
BlockBackend *blk = child->opaque;
238
239
@@ -XXX,XX +XXX,XX @@ int blk_replace_bs(BlockBackend *blk, BlockDriverState *new_bs, Error **errp)
240
/*
241
* Sets the permission bitmasks that the user of the BlockBackend needs.
242
*/
243
-int blk_set_perm(BlockBackend *blk, uint64_t perm, uint64_t shared_perm,
244
- Error **errp)
245
+static int coroutine_mixed_fn GRAPH_RDLOCK
246
+blk_set_perm_locked(BlockBackend *blk, uint64_t perm, uint64_t shared_perm,
247
+ Error **errp)
248
{
249
int ret;
250
GLOBAL_STATE_CODE();
251
@@ -XXX,XX +XXX,XX @@ int blk_set_perm(BlockBackend *blk, uint64_t perm, uint64_t shared_perm,
252
return 0;
253
}
254
255
+int blk_set_perm(BlockBackend *blk, uint64_t perm, uint64_t shared_perm,
256
+ Error **errp)
257
+{
258
+ GLOBAL_STATE_CODE();
259
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
260
+
261
+ return blk_set_perm_locked(blk, perm, shared_perm, errp);
262
+}
263
+
264
void blk_get_perm(BlockBackend *blk, uint64_t *perm, uint64_t *shared_perm)
265
{
266
GLOBAL_STATE_CODE();
267
diff --git a/block/crypto.c b/block/crypto.c
268
index XXXXXXX..XXXXXXX 100644
269
--- a/block/crypto.c
270
+++ b/block/crypto.c
271
@@ -XXX,XX +XXX,XX @@ block_crypto_get_specific_info_luks(BlockDriverState *bs, Error **errp)
272
return spec_info;
273
}
274
275
-static int
276
+static int GRAPH_RDLOCK
277
block_crypto_amend_prepare(BlockDriverState *bs, Error **errp)
278
{
279
BlockCrypto *crypto = bs->opaque;
280
@@ -XXX,XX +XXX,XX @@ block_crypto_amend_prepare(BlockDriverState *bs, Error **errp)
281
return ret;
282
}
283
284
-static void
285
+static void GRAPH_RDLOCK
286
block_crypto_amend_cleanup(BlockDriverState *bs)
287
{
288
BlockCrypto *crypto = bs->opaque;
289
@@ -XXX,XX +XXX,XX @@ block_crypto_amend_options_luks(BlockDriverState *bs,
290
QCryptoBlockAmendOptions *amend_options = NULL;
291
int ret = -EINVAL;
292
293
+ assume_graph_lock(); /* FIXME */
294
+
295
assert(crypto);
296
assert(crypto->block);
297
15
diff --git a/block/mirror.c b/block/mirror.c
298
diff --git a/block/mirror.c b/block/mirror.c
16
index XXXXXXX..XXXXXXX 100644
299
index XXXXXXX..XXXXXXX 100644
17
--- a/block/mirror.c
300
--- a/block/mirror.c
18
+++ b/block/mirror.c
301
+++ b/block/mirror.c
19
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn mirror_dirty_init(MirrorBlockJob *s)
302
@@ -XXX,XX +XXX,XX @@ static int mirror_exit_common(Job *job)
20
/* Called when going out of the streaming phase to flush the bulk of the
303
* mirror_top_bs from now on, so keep it drained. */
21
* data to the medium, or just before completing.
304
bdrv_drained_begin(mirror_top_bs);
22
*/
305
bs_opaque->stop = true;
23
-static int mirror_flush(MirrorBlockJob *s)
306
+
24
+static int coroutine_fn mirror_flush(MirrorBlockJob *s)
307
+ bdrv_graph_rdlock_main_loop();
25
{
308
bdrv_child_refresh_perms(mirror_top_bs, mirror_top_bs->backing,
26
- int ret = blk_flush(s->target);
309
&error_abort);
27
+ int ret = blk_co_flush(s->target);
310
+ bdrv_graph_rdunlock_main_loop();
311
+
312
if (!abort && s->backing_mode == MIRROR_SOURCE_BACKING_CHAIN) {
313
BlockDriverState *backing = s->is_none_mode ? src : s->base;
314
BlockDriverState *unfiltered_target = bdrv_skip_filters(target_bs);
315
@@ -XXX,XX +XXX,XX @@ static BlockJob *mirror_start_job(
316
uint64_t target_perms, target_shared_perms;
317
int ret;
318
319
+ GLOBAL_STATE_CODE();
320
+
321
if (granularity == 0) {
322
granularity = bdrv_get_default_bitmap_granularity(target);
323
}
324
@@ -XXX,XX +XXX,XX @@ fail:
325
}
326
327
bs_opaque->stop = true;
328
+ bdrv_graph_rdlock_main_loop();
329
bdrv_child_refresh_perms(mirror_top_bs, mirror_top_bs->backing,
330
&error_abort);
331
+ bdrv_graph_rdunlock_main_loop();
332
bdrv_replace_node(mirror_top_bs, mirror_top_bs->backing->bs, &error_abort);
333
334
bdrv_unref(mirror_top_bs);
335
diff --git a/block/vmdk.c b/block/vmdk.c
336
index XXXXXXX..XXXXXXX 100644
337
--- a/block/vmdk.c
338
+++ b/block/vmdk.c
339
@@ -XXX,XX +XXX,XX @@ static int vmdk_open(BlockDriverState *bs, QDict *options, int flags,
340
BDRVVmdkState *s = bs->opaque;
341
uint32_t magic;
342
343
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
344
+
345
ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
28
if (ret < 0) {
346
if (ret < 0) {
29
if (mirror_error_action(s, false, -ret) == BLOCK_ERROR_ACTION_REPORT) {
347
return ret;
30
s->ret = ret;
348
diff --git a/tests/unit/test-bdrv-graph-mod.c b/tests/unit/test-bdrv-graph-mod.c
349
index XXXXXXX..XXXXXXX 100644
350
--- a/tests/unit/test-bdrv-graph-mod.c
351
+++ b/tests/unit/test-bdrv-graph-mod.c
352
@@ -XXX,XX +XXX,XX @@ static void test_parallel_perm_update(void)
353
354
/* Select fl1 as first child to be active */
355
s->selected = c_fl1;
356
+
357
+ bdrv_graph_rdlock_main_loop();
358
+
359
bdrv_child_refresh_perms(top, top->children.lh_first, &error_abort);
360
361
assert(c_fl1->perm & BLK_PERM_WRITE);
362
@@ -XXX,XX +XXX,XX @@ static void test_parallel_perm_update(void)
363
assert(c_fl1->perm & BLK_PERM_WRITE);
364
assert(!(c_fl2->perm & BLK_PERM_WRITE));
365
366
+ bdrv_graph_rdunlock_main_loop();
367
bdrv_unref(top);
368
}
369
31
--
370
--
32
2.40.0
371
2.41.0
diff view generated by jsdifflib
1
From: Paolo Bonzini <pbonzini@redhat.com>
1
The function reads the parents list, so it needs to hold the graph lock.
2
2
3
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
3
This happens to result in BlockDriver.bdrv_set_perm() to be called with
4
Message-Id: <20230309084456.304669-6-pbonzini@redhat.com>
4
the graph lock held. For consistency, make it the same for all of the
5
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
5
BlockDriver callbacks for updating permissions and annotate the function
6
pointers with GRAPH_RDLOCK_PTR.
7
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
10
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
11
Message-ID: <20230911094620.45040-15-kwolf@redhat.com>
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
---
13
---
8
hw/9pfs/9p.h | 4 ++--
14
include/block/block_int-common.h | 9 ++++---
9
hw/9pfs/codir.c | 6 +++---
15
include/block/block_int-global-state.h | 4 +--
10
2 files changed, 5 insertions(+), 5 deletions(-)
16
block.c | 35 ++++++++++++++++++++------
17
blockdev.c | 6 +++++
18
4 files changed, 40 insertions(+), 14 deletions(-)
11
19
12
diff --git a/hw/9pfs/9p.h b/hw/9pfs/9p.h
20
diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
13
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX 100644
14
--- a/hw/9pfs/9p.h
22
--- a/include/block/block_int-common.h
15
+++ b/hw/9pfs/9p.h
23
+++ b/include/block/block_int-common.h
16
@@ -XXX,XX +XXX,XX @@ typedef struct V9fsDir {
24
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
17
QemuMutex readdir_mutex_L;
25
* If both conditions are met, 0 is returned. Otherwise, -errno is returned
18
} V9fsDir;
26
* and errp is set to an error describing the conflict.
19
27
*/
20
-static inline void v9fs_readdir_lock(V9fsDir *dir)
28
- int (*bdrv_check_perm)(BlockDriverState *bs, uint64_t perm,
21
+static inline void coroutine_fn v9fs_readdir_lock(V9fsDir *dir)
29
- uint64_t shared, Error **errp);
30
+ int GRAPH_RDLOCK_PTR (*bdrv_check_perm)(BlockDriverState *bs, uint64_t perm,
31
+ uint64_t shared, Error **errp);
32
33
/**
34
* Called to inform the driver that the set of cumulative set of used
35
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
36
* This function is only invoked after bdrv_check_perm(), so block drivers
37
* may rely on preparations made in their .bdrv_check_perm implementation.
38
*/
39
- void (*bdrv_set_perm)(BlockDriverState *bs, uint64_t perm, uint64_t shared);
40
+ void GRAPH_RDLOCK_PTR (*bdrv_set_perm)(
41
+ BlockDriverState *bs, uint64_t perm, uint64_t shared);
42
43
/*
44
* Called to inform the driver that after a previous bdrv_check_perm()
45
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
46
* This function can be called even for nodes that never saw a
47
* bdrv_check_perm() call. It is a no-op then.
48
*/
49
- void (*bdrv_abort_perm_update)(BlockDriverState *bs);
50
+ void GRAPH_RDLOCK_PTR (*bdrv_abort_perm_update)(BlockDriverState *bs);
51
52
/**
53
* Returns in @nperm and @nshared the permissions that the driver for @bs
54
diff --git a/include/block/block_int-global-state.h b/include/block/block_int-global-state.h
55
index XXXXXXX..XXXXXXX 100644
56
--- a/include/block/block_int-global-state.h
57
+++ b/include/block/block_int-global-state.h
58
@@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
59
void *opaque, Error **errp);
60
void bdrv_root_unref_child(BdrvChild *child);
61
62
-void bdrv_get_cumulative_perm(BlockDriverState *bs, uint64_t *perm,
63
- uint64_t *shared_perm);
64
+void GRAPH_RDLOCK bdrv_get_cumulative_perm(BlockDriverState *bs, uint64_t *perm,
65
+ uint64_t *shared_perm);
66
67
/**
68
* Sets a BdrvChild's permissions. Avoid if the parent is a BDS; use
69
diff --git a/block.c b/block.c
70
index XXXXXXX..XXXXXXX 100644
71
--- a/block.c
72
+++ b/block.c
73
@@ -XXX,XX +XXX,XX @@ static void bdrv_child_set_perm(BdrvChild *c, uint64_t perm,
74
tran_add(tran, &bdrv_child_set_pem_drv, s);
75
}
76
77
-static void bdrv_drv_set_perm_commit(void *opaque)
78
+static void GRAPH_RDLOCK bdrv_drv_set_perm_commit(void *opaque)
22
{
79
{
23
if (dir->proto_version == V9FS_PROTO_2000U) {
80
BlockDriverState *bs = opaque;
24
qemu_co_mutex_lock(&dir->readdir_mutex_u);
81
uint64_t cumulative_perms, cumulative_shared_perms;
25
@@ -XXX,XX +XXX,XX @@ static inline void v9fs_readdir_lock(V9fsDir *dir)
82
@@ -XXX,XX +XXX,XX @@ static void bdrv_drv_set_perm_commit(void *opaque)
26
}
83
}
27
}
84
}
28
85
29
-static inline void v9fs_readdir_unlock(V9fsDir *dir)
86
-static void bdrv_drv_set_perm_abort(void *opaque)
30
+static inline void coroutine_fn v9fs_readdir_unlock(V9fsDir *dir)
87
+static void GRAPH_RDLOCK bdrv_drv_set_perm_abort(void *opaque)
31
{
88
{
32
if (dir->proto_version == V9FS_PROTO_2000U) {
89
BlockDriverState *bs = opaque;
33
qemu_co_mutex_unlock(&dir->readdir_mutex_u);
90
GLOBAL_STATE_CODE();
34
diff --git a/hw/9pfs/codir.c b/hw/9pfs/codir.c
91
@@ -XXX,XX +XXX,XX @@ TransactionActionDrv bdrv_drv_set_perm_drv = {
92
.commit = bdrv_drv_set_perm_commit,
93
};
94
95
-static int bdrv_drv_set_perm(BlockDriverState *bs, uint64_t perm,
96
- uint64_t shared_perm, Transaction *tran,
97
- Error **errp)
98
+/*
99
+ * After calling this function, the transaction @tran may only be completed
100
+ * while holding a reader lock for the graph.
101
+ */
102
+static int GRAPH_RDLOCK
103
+bdrv_drv_set_perm(BlockDriverState *bs, uint64_t perm, uint64_t shared_perm,
104
+ Transaction *tran, Error **errp)
105
{
106
GLOBAL_STATE_CODE();
107
if (!bs->drv) {
108
@@ -XXX,XX +XXX,XX @@ bdrv_replace_child_tran(BdrvChild *child, BlockDriverState *new_bs,
109
/*
110
* Refresh permissions in @bs subtree. The function is intended to be called
111
* after some graph modification that was done without permission update.
112
+ *
113
+ * After calling this function, the transaction @tran may only be completed
114
+ * while holding a reader lock for the graph.
115
*/
116
-static int bdrv_node_refresh_perm(BlockDriverState *bs, BlockReopenQueue *q,
117
- Transaction *tran, Error **errp)
118
+static int GRAPH_RDLOCK
119
+bdrv_node_refresh_perm(BlockDriverState *bs, BlockReopenQueue *q,
120
+ Transaction *tran, Error **errp)
121
{
122
BlockDriver *drv = bs->drv;
123
BdrvChild *c;
124
@@ -XXX,XX +XXX,XX @@ static int bdrv_node_refresh_perm(BlockDriverState *bs, BlockReopenQueue *q,
125
/*
126
* @list is a product of bdrv_topological_dfs() (may be called several times) -
127
* a topologically sorted subgraph.
128
+ *
129
+ * After calling this function, the transaction @tran may only be completed
130
+ * while holding a reader lock for the graph.
131
*/
132
static int GRAPH_RDLOCK
133
bdrv_do_refresh_perms(GSList *list, BlockReopenQueue *q, Transaction *tran,
134
@@ -XXX,XX +XXX,XX @@ bdrv_do_refresh_perms(GSList *list, BlockReopenQueue *q, Transaction *tran,
135
* @list is any list of nodes. List is completed by all subtrees and
136
* topologically sorted. It's not a problem if some node occurs in the @list
137
* several times.
138
+ *
139
+ * After calling this function, the transaction @tran may only be completed
140
+ * while holding a reader lock for the graph.
141
*/
142
static int GRAPH_RDLOCK
143
bdrv_list_refresh_perms(GSList *list, BlockReopenQueue *q, Transaction *tran,
144
@@ -XXX,XX +XXX,XX @@ char *bdrv_perm_names(uint64_t perm)
145
}
146
147
148
-/* @tran is allowed to be NULL. In this case no rollback is possible */
149
+/*
150
+ * @tran is allowed to be NULL. In this case no rollback is possible.
151
+ *
152
+ * After calling this function, the transaction @tran may only be completed
153
+ * while holding a reader lock for the graph.
154
+ */
155
static int GRAPH_RDLOCK
156
bdrv_refresh_perms(BlockDriverState *bs, Transaction *tran, Error **errp)
157
{
158
diff --git a/blockdev.c b/blockdev.c
35
index XXXXXXX..XXXXXXX 100644
159
index XXXXXXX..XXXXXXX 100644
36
--- a/hw/9pfs/codir.c
160
--- a/blockdev.c
37
+++ b/hw/9pfs/codir.c
161
+++ b/blockdev.c
38
@@ -XXX,XX +XXX,XX @@ int coroutine_fn v9fs_co_readdir(V9fsPDU *pdu, V9fsFidState *fidp,
162
@@ -XXX,XX +XXX,XX @@ static void external_snapshot_action(TransactionAction *action,
39
*
163
AioContext *aio_context;
40
* See v9fs_co_readdir_many() (as its only user) below for details.
164
uint64_t perm, shared;
41
*/
165
42
-static int do_readdir_many(V9fsPDU *pdu, V9fsFidState *fidp,
166
+ /* TODO We'll eventually have to take a writer lock in this function */
43
- struct V9fsDirEnt **entries, off_t offset,
167
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
44
- int32_t maxsize, bool dostat)
168
+
45
+static int coroutine_fn
169
tran_add(tran, &external_snapshot_drv, state);
46
+do_readdir_many(V9fsPDU *pdu, V9fsFidState *fidp, struct V9fsDirEnt **entries,
170
47
+ off_t offset, int32_t maxsize, bool dostat)
171
/* 'blockdev-snapshot' and 'blockdev-snapshot-sync' have similar
48
{
172
@@ -XXX,XX +XXX,XX @@ void qmp_block_commit(const char *job_id, const char *device,
49
V9fsState *s = pdu->s;
173
int job_flags = JOB_DEFAULT;
50
V9fsString name;
174
uint64_t top_perm, top_shared;
175
176
+ /* TODO We'll eventually have to take a writer lock in this function */
177
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
178
+
179
if (!has_speed) {
180
speed = 0;
181
}
51
--
182
--
52
2.40.0
183
2.41.0
diff view generated by jsdifflib
1
From: Stefan Hajnoczi <stefanha@redhat.com>
1
This adds GRAPH_RDLOCK annotations to declare that callers of
2
bdrv_child_perm() need to hold a reader lock for the graph because
3
some implementations access the children list of a node.
2
4
3
There is no change in behavior. Switch to AIO_WAIT_WHILE_UNLOCKED()
5
The callers of bdrv_child_perm() conveniently already hold the lock.
4
instead of AIO_WAIT_WHILE() to document that this code has already been
5
audited and converted. The AioContext argument is already NULL so
6
aio_context_release() is never called anyway.
7
6
8
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Tested-by: Philippe Mathieu-Daudé <philmd@linaro.org>
8
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
10
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
9
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
11
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
10
Message-ID: <20230911094620.45040-16-kwolf@redhat.com>
12
Message-Id: <20230309190855.414275-3-stefanha@redhat.com>
13
Reviewed-by: Wilfred Mallawa <wilfred.mallawa@wdc.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
---
12
---
16
block/export/export.c | 2 +-
13
include/block/block_int-common.h | 10 +++++-----
17
1 file changed, 1 insertion(+), 1 deletion(-)
14
block.c | 11 ++++++-----
15
block/copy-before-write.c | 10 +++++-----
16
3 files changed, 16 insertions(+), 15 deletions(-)
18
17
19
diff --git a/block/export/export.c b/block/export/export.c
18
diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
20
index XXXXXXX..XXXXXXX 100644
19
index XXXXXXX..XXXXXXX 100644
21
--- a/block/export/export.c
20
--- a/include/block/block_int-common.h
22
+++ b/block/export/export.c
21
+++ b/include/block/block_int-common.h
23
@@ -XXX,XX +XXX,XX @@ void blk_exp_close_all_type(BlockExportType type)
22
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
24
blk_exp_request_shutdown(exp);
23
* permissions, but those that will be needed after applying the
25
}
24
* @reopen_queue.
26
25
*/
27
- AIO_WAIT_WHILE(NULL, blk_exp_has_type(type));
26
- void (*bdrv_child_perm)(BlockDriverState *bs, BdrvChild *c,
28
+ AIO_WAIT_WHILE_UNLOCKED(NULL, blk_exp_has_type(type));
27
- BdrvChildRole role,
28
- BlockReopenQueue *reopen_queue,
29
- uint64_t parent_perm, uint64_t parent_shared,
30
- uint64_t *nperm, uint64_t *nshared);
31
+ void GRAPH_RDLOCK_PTR (*bdrv_child_perm)(
32
+ BlockDriverState *bs, BdrvChild *c, BdrvChildRole role,
33
+ BlockReopenQueue *reopen_queue,
34
+ uint64_t parent_perm, uint64_t parent_shared,
35
+ uint64_t *nperm, uint64_t *nshared);
36
37
/**
38
* Register/unregister a buffer for I/O. For example, when the driver is
39
diff --git a/block.c b/block.c
40
index XXXXXXX..XXXXXXX 100644
41
--- a/block.c
42
+++ b/block.c
43
@@ -XXX,XX +XXX,XX @@ bdrv_parent_perms_conflict(BlockDriverState *bs, Error **errp)
44
return false;
29
}
45
}
30
46
31
void blk_exp_close_all(void)
47
-static void bdrv_child_perm(BlockDriverState *bs, BlockDriverState *child_bs,
48
- BdrvChild *c, BdrvChildRole role,
49
- BlockReopenQueue *reopen_queue,
50
- uint64_t parent_perm, uint64_t parent_shared,
51
- uint64_t *nperm, uint64_t *nshared)
52
+static void GRAPH_RDLOCK
53
+bdrv_child_perm(BlockDriverState *bs, BlockDriverState *child_bs,
54
+ BdrvChild *c, BdrvChildRole role,
55
+ BlockReopenQueue *reopen_queue,
56
+ uint64_t parent_perm, uint64_t parent_shared,
57
+ uint64_t *nperm, uint64_t *nshared)
58
{
59
assert(bs->drv && bs->drv->bdrv_child_perm);
60
GLOBAL_STATE_CODE();
61
diff --git a/block/copy-before-write.c b/block/copy-before-write.c
62
index XXXXXXX..XXXXXXX 100644
63
--- a/block/copy-before-write.c
64
+++ b/block/copy-before-write.c
65
@@ -XXX,XX +XXX,XX @@ static void cbw_refresh_filename(BlockDriverState *bs)
66
bs->file->bs->filename);
67
}
68
69
-static void cbw_child_perm(BlockDriverState *bs, BdrvChild *c,
70
- BdrvChildRole role,
71
- BlockReopenQueue *reopen_queue,
72
- uint64_t perm, uint64_t shared,
73
- uint64_t *nperm, uint64_t *nshared)
74
+static void GRAPH_RDLOCK
75
+cbw_child_perm(BlockDriverState *bs, BdrvChild *c, BdrvChildRole role,
76
+ BlockReopenQueue *reopen_queue,
77
+ uint64_t perm, uint64_t shared,
78
+ uint64_t *nperm, uint64_t *nshared)
79
{
80
if (!(role & BDRV_CHILD_FILTERED)) {
81
/*
32
--
82
--
33
2.40.0
83
2.41.0
34
35
diff view generated by jsdifflib
1
From: Emanuele Giuseppe Esposito <eesposit@redhat.com>
1
The function reads the parents list, so it needs to hold the graph lock.
2
2
3
Remove usage of aio_context_acquire by always submitting asynchronous
3
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
AIO to the current thread's LinuxAioState.
4
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
5
5
Message-ID: <20230911094620.45040-18-kwolf@redhat.com>
6
In order to prevent mistakes from the caller side, avoid passing LinuxAioState
7
in laio_io_{plug/unplug} and laio_co_submit, and document the functions
8
to make clear that they work in the current thread's AioContext.
9
10
Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
11
Message-Id: <20230203131731.851116-2-eesposit@redhat.com>
12
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
13
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
6
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
---
8
---
16
include/block/aio.h | 4 ----
9
block.c | 2 ++
17
include/block/raw-aio.h | 18 ++++++++++++------
10
1 file changed, 2 insertions(+)
18
include/sysemu/block-backend-io.h | 5 +++++
19
block/file-posix.c | 10 +++-------
20
block/linux-aio.c | 29 +++++++++++++++++------------
21
5 files changed, 37 insertions(+), 29 deletions(-)
22
11
23
diff --git a/include/block/aio.h b/include/block/aio.h
12
diff --git a/block.c b/block.c
24
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
25
--- a/include/block/aio.h
14
--- a/block.c
26
+++ b/include/block/aio.h
15
+++ b/block.c
27
@@ -XXX,XX +XXX,XX @@ struct AioContext {
16
@@ -XXX,XX +XXX,XX @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
28
struct ThreadPool *thread_pool;
17
backing_file_str = base->filename;
29
30
#ifdef CONFIG_LINUX_AIO
31
- /*
32
- * State for native Linux AIO. Uses aio_context_acquire/release for
33
- * locking.
34
- */
35
struct LinuxAioState *linux_aio;
36
#endif
37
#ifdef CONFIG_LINUX_IO_URING
38
diff --git a/include/block/raw-aio.h b/include/block/raw-aio.h
39
index XXXXXXX..XXXXXXX 100644
40
--- a/include/block/raw-aio.h
41
+++ b/include/block/raw-aio.h
42
@@ -XXX,XX +XXX,XX @@
43
typedef struct LinuxAioState LinuxAioState;
44
LinuxAioState *laio_init(Error **errp);
45
void laio_cleanup(LinuxAioState *s);
46
-int coroutine_fn laio_co_submit(BlockDriverState *bs, LinuxAioState *s, int fd,
47
- uint64_t offset, QEMUIOVector *qiov, int type,
48
- uint64_t dev_max_batch);
49
+
50
+/* laio_co_submit: submit I/O requests in the thread's current AioContext. */
51
+int coroutine_fn laio_co_submit(int fd, uint64_t offset, QEMUIOVector *qiov,
52
+ int type, uint64_t dev_max_batch);
53
+
54
void laio_detach_aio_context(LinuxAioState *s, AioContext *old_context);
55
void laio_attach_aio_context(LinuxAioState *s, AioContext *new_context);
56
-void laio_io_plug(BlockDriverState *bs, LinuxAioState *s);
57
-void laio_io_unplug(BlockDriverState *bs, LinuxAioState *s,
58
- uint64_t dev_max_batch);
59
+
60
+/*
61
+ * laio_io_plug/unplug work in the thread's current AioContext, therefore the
62
+ * caller must ensure that they are paired in the same IOThread.
63
+ */
64
+void laio_io_plug(void);
65
+void laio_io_unplug(uint64_t dev_max_batch);
66
#endif
67
/* io_uring.c - Linux io_uring implementation */
68
#ifdef CONFIG_LINUX_IO_URING
69
diff --git a/include/sysemu/block-backend-io.h b/include/sysemu/block-backend-io.h
70
index XXXXXXX..XXXXXXX 100644
71
--- a/include/sysemu/block-backend-io.h
72
+++ b/include/sysemu/block-backend-io.h
73
@@ -XXX,XX +XXX,XX @@ void blk_iostatus_set_err(BlockBackend *blk, int error);
74
int blk_get_max_iov(BlockBackend *blk);
75
int blk_get_max_hw_iov(BlockBackend *blk);
76
77
+/*
78
+ * blk_io_plug/unplug are thread-local operations. This means that multiple
79
+ * IOThreads can simultaneously call plug/unplug, but the caller must ensure
80
+ * that each unplug() is called in the same IOThread of the matching plug().
81
+ */
82
void coroutine_fn blk_co_io_plug(BlockBackend *blk);
83
void co_wrapper blk_io_plug(BlockBackend *blk);
84
85
diff --git a/block/file-posix.c b/block/file-posix.c
86
index XXXXXXX..XXXXXXX 100644
87
--- a/block/file-posix.c
88
+++ b/block/file-posix.c
89
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_prw(BlockDriverState *bs, uint64_t offset,
90
#endif
91
#ifdef CONFIG_LINUX_AIO
92
} else if (s->use_linux_aio) {
93
- LinuxAioState *aio = aio_get_linux_aio(bdrv_get_aio_context(bs));
94
assert(qiov->size == bytes);
95
- return laio_co_submit(bs, aio, s->fd, offset, qiov, type,
96
- s->aio_max_batch);
97
+ return laio_co_submit(s->fd, offset, qiov, type, s->aio_max_batch);
98
#endif
99
}
18
}
100
19
101
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn raw_co_io_plug(BlockDriverState *bs)
20
+ bdrv_graph_rdlock_main_loop();
102
BDRVRawState __attribute__((unused)) *s = bs->opaque;
21
QLIST_FOREACH(c, &top->parents, next_parent) {
103
#ifdef CONFIG_LINUX_AIO
22
updated_children = g_slist_prepend(updated_children, c);
104
if (s->use_linux_aio) {
105
- LinuxAioState *aio = aio_get_linux_aio(bdrv_get_aio_context(bs));
106
- laio_io_plug(bs, aio);
107
+ laio_io_plug();
108
}
23
}
109
#endif
24
+ bdrv_graph_rdunlock_main_loop();
110
#ifdef CONFIG_LINUX_IO_URING
25
111
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn raw_co_io_unplug(BlockDriverState *bs)
26
/*
112
BDRVRawState __attribute__((unused)) *s = bs->opaque;
27
* It seems correct to pass detach_subchain=true here, but it triggers
113
#ifdef CONFIG_LINUX_AIO
114
if (s->use_linux_aio) {
115
- LinuxAioState *aio = aio_get_linux_aio(bdrv_get_aio_context(bs));
116
- laio_io_unplug(bs, aio, s->aio_max_batch);
117
+ laio_io_unplug(s->aio_max_batch);
118
}
119
#endif
120
#ifdef CONFIG_LINUX_IO_URING
121
diff --git a/block/linux-aio.c b/block/linux-aio.c
122
index XXXXXXX..XXXXXXX 100644
123
--- a/block/linux-aio.c
124
+++ b/block/linux-aio.c
125
@@ -XXX,XX +XXX,XX @@
126
#include "qemu/coroutine.h"
127
#include "qapi/error.h"
128
129
+/* Only used for assertions. */
130
+#include "qemu/coroutine_int.h"
131
+
132
#include <libaio.h>
133
134
/*
135
@@ -XXX,XX +XXX,XX @@ struct LinuxAioState {
136
io_context_t ctx;
137
EventNotifier e;
138
139
- /* io queue for submit at batch. Protected by AioContext lock. */
140
+ /* No locking required, only accessed from AioContext home thread */
141
LaioQueue io_q;
142
-
143
- /* I/O completion processing. Only runs in I/O thread. */
144
QEMUBH *completion_bh;
145
int event_idx;
146
int event_max;
147
@@ -XXX,XX +XXX,XX @@ static void qemu_laio_process_completion(struct qemu_laiocb *laiocb)
148
* later. Coroutines cannot be entered recursively so avoid doing
149
* that!
150
*/
151
+ assert(laiocb->co->ctx == laiocb->ctx->aio_context);
152
if (!qemu_coroutine_entered(laiocb->co)) {
153
aio_co_wake(laiocb->co);
154
}
155
@@ -XXX,XX +XXX,XX @@ static void qemu_laio_process_completions(LinuxAioState *s)
156
157
static void qemu_laio_process_completions_and_submit(LinuxAioState *s)
158
{
159
- aio_context_acquire(s->aio_context);
160
qemu_laio_process_completions(s);
161
162
if (!s->io_q.plugged && !QSIMPLEQ_EMPTY(&s->io_q.pending)) {
163
ioq_submit(s);
164
}
165
- aio_context_release(s->aio_context);
166
}
167
168
static void qemu_laio_completion_bh(void *opaque)
169
@@ -XXX,XX +XXX,XX @@ static uint64_t laio_max_batch(LinuxAioState *s, uint64_t dev_max_batch)
170
return max_batch;
171
}
172
173
-void laio_io_plug(BlockDriverState *bs, LinuxAioState *s)
174
+void laio_io_plug(void)
175
{
176
+ AioContext *ctx = qemu_get_current_aio_context();
177
+ LinuxAioState *s = aio_get_linux_aio(ctx);
178
+
179
s->io_q.plugged++;
180
}
181
182
-void laio_io_unplug(BlockDriverState *bs, LinuxAioState *s,
183
- uint64_t dev_max_batch)
184
+void laio_io_unplug(uint64_t dev_max_batch)
185
{
186
+ AioContext *ctx = qemu_get_current_aio_context();
187
+ LinuxAioState *s = aio_get_linux_aio(ctx);
188
+
189
assert(s->io_q.plugged);
190
s->io_q.plugged--;
191
192
@@ -XXX,XX +XXX,XX @@ static int laio_do_submit(int fd, struct qemu_laiocb *laiocb, off_t offset,
193
return 0;
194
}
195
196
-int coroutine_fn laio_co_submit(BlockDriverState *bs, LinuxAioState *s, int fd,
197
- uint64_t offset, QEMUIOVector *qiov, int type,
198
- uint64_t dev_max_batch)
199
+int coroutine_fn laio_co_submit(int fd, uint64_t offset, QEMUIOVector *qiov,
200
+ int type, uint64_t dev_max_batch)
201
{
202
int ret;
203
+ AioContext *ctx = qemu_get_current_aio_context();
204
struct qemu_laiocb laiocb = {
205
.co = qemu_coroutine_self(),
206
.nbytes = qiov->size,
207
- .ctx = s,
208
+ .ctx = aio_get_linux_aio(ctx),
209
.ret = -EINPROGRESS,
210
.is_read = (type == QEMU_AIO_READ),
211
.qiov = qiov,
212
--
28
--
213
2.40.0
29
2.41.0
diff view generated by jsdifflib
1
From: Emanuele Giuseppe Esposito <eesposit@redhat.com>
1
The function reads the parents list, so it needs to hold the graph lock.
2
2
3
Use qemu_get_current_aio_context() where possible, since we always
3
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
submit work to the current thread anyways.
4
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
5
5
Message-ID: <20230911094620.45040-19-kwolf@redhat.com>
6
We want to also be sure that the thread submitting the work is
7
the same as the one processing the pool, to avoid adding
8
synchronization to the pool list.
9
10
Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
11
Message-Id: <20230203131731.851116-4-eesposit@redhat.com>
12
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
13
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
6
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
---
8
---
16
include/block/thread-pool.h | 5 +++++
9
block.c | 4 ++++
17
block/file-posix.c | 21 ++++++++++-----------
10
1 file changed, 4 insertions(+)
18
block/file-win32.c | 2 +-
19
block/qcow2-threads.c | 2 +-
20
util/thread-pool.c | 9 ++++-----
21
5 files changed, 21 insertions(+), 18 deletions(-)
22
11
23
diff --git a/include/block/thread-pool.h b/include/block/thread-pool.h
12
diff --git a/block.c b/block.c
24
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
25
--- a/include/block/thread-pool.h
14
--- a/block.c
26
+++ b/include/block/thread-pool.h
15
+++ b/block.c
27
@@ -XXX,XX +XXX,XX @@ typedef struct ThreadPool ThreadPool;
16
@@ -XXX,XX +XXX,XX @@ static bool bdrv_change_aio_context(BlockDriverState *bs, AioContext *ctx,
28
ThreadPool *thread_pool_new(struct AioContext *ctx);
17
return true;
29
void thread_pool_free(ThreadPool *pool);
30
31
+/*
32
+ * thread_pool_submit* API: submit I/O requests in the thread's
33
+ * current AioContext.
34
+ */
35
BlockAIOCB *thread_pool_submit_aio(ThreadPool *pool,
36
ThreadPoolFunc *func, void *arg,
37
BlockCompletionFunc *cb, void *opaque);
38
int coroutine_fn thread_pool_submit_co(ThreadPool *pool,
39
ThreadPoolFunc *func, void *arg);
40
void thread_pool_submit(ThreadPool *pool, ThreadPoolFunc *func, void *arg);
41
+
42
void thread_pool_update_params(ThreadPool *pool, struct AioContext *ctx);
43
44
#endif
45
diff --git a/block/file-posix.c b/block/file-posix.c
46
index XXXXXXX..XXXXXXX 100644
47
--- a/block/file-posix.c
48
+++ b/block/file-posix.c
49
@@ -XXX,XX +XXX,XX @@ out:
50
return result;
51
}
52
53
-static int coroutine_fn raw_thread_pool_submit(BlockDriverState *bs,
54
- ThreadPoolFunc func, void *arg)
55
+static int coroutine_fn raw_thread_pool_submit(ThreadPoolFunc func, void *arg)
56
{
57
/* @bs can be NULL, bdrv_get_aio_context() returns the main context then */
58
- ThreadPool *pool = aio_get_thread_pool(bdrv_get_aio_context(bs));
59
+ ThreadPool *pool = aio_get_thread_pool(qemu_get_current_aio_context());
60
return thread_pool_submit_co(pool, func, arg);
61
}
62
63
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_prw(BlockDriverState *bs, uint64_t offset,
64
};
65
66
assert(qiov->size == bytes);
67
- return raw_thread_pool_submit(bs, handle_aiocb_rw, &acb);
68
+ return raw_thread_pool_submit(handle_aiocb_rw, &acb);
69
}
70
71
static int coroutine_fn raw_co_preadv(BlockDriverState *bs, int64_t offset,
72
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_flush_to_disk(BlockDriverState *bs)
73
return luring_co_submit(bs, s->fd, 0, NULL, QEMU_AIO_FLUSH);
74
}
18
}
75
#endif
19
76
- return raw_thread_pool_submit(bs, handle_aiocb_flush, &acb);
20
+ bdrv_graph_rdlock_main_loop();
77
+ return raw_thread_pool_submit(handle_aiocb_flush, &acb);
21
QLIST_FOREACH(c, &bs->parents, next_parent) {
78
}
22
if (!bdrv_parent_change_aio_context(c, ctx, visited, tran, errp)) {
79
23
+ bdrv_graph_rdunlock_main_loop();
80
static void raw_aio_attach_aio_context(BlockDriverState *bs,
24
return false;
81
@@ -XXX,XX +XXX,XX @@ raw_regular_truncate(BlockDriverState *bs, int fd, int64_t offset,
82
},
83
};
84
85
- return raw_thread_pool_submit(bs, handle_aiocb_truncate, &acb);
86
+ return raw_thread_pool_submit(handle_aiocb_truncate, &acb);
87
}
88
89
static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset,
90
@@ -XXX,XX +XXX,XX @@ raw_do_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes,
91
acb.aio_type |= QEMU_AIO_BLKDEV;
92
}
93
94
- ret = raw_thread_pool_submit(bs, handle_aiocb_discard, &acb);
95
+ ret = raw_thread_pool_submit(handle_aiocb_discard, &acb);
96
raw_account_discard(s, bytes, ret);
97
return ret;
98
}
99
@@ -XXX,XX +XXX,XX @@ raw_do_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int64_t bytes,
100
handler = handle_aiocb_write_zeroes;
101
}
102
103
- return raw_thread_pool_submit(bs, handler, &acb);
104
+ return raw_thread_pool_submit(handler, &acb);
105
}
106
107
static int coroutine_fn raw_co_pwrite_zeroes(
108
@@ -XXX,XX +XXX,XX @@ raw_co_copy_range_to(BlockDriverState *bs,
109
},
110
};
111
112
- return raw_thread_pool_submit(bs, handle_aiocb_copy_range, &acb);
113
+ return raw_thread_pool_submit(handle_aiocb_copy_range, &acb);
114
}
115
116
BlockDriver bdrv_file = {
117
@@ -XXX,XX +XXX,XX @@ hdev_co_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
118
struct sg_io_hdr *io_hdr = buf;
119
if (io_hdr->cmdp[0] == PERSISTENT_RESERVE_OUT ||
120
io_hdr->cmdp[0] == PERSISTENT_RESERVE_IN) {
121
- return pr_manager_execute(s->pr_mgr, bdrv_get_aio_context(bs),
122
+ return pr_manager_execute(s->pr_mgr, qemu_get_current_aio_context(),
123
s->fd, io_hdr);
124
}
25
}
125
}
26
}
126
@@ -XXX,XX +XXX,XX @@ hdev_co_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
27
127
},
28
QLIST_FOREACH(c, &bs->children, next) {
128
};
29
if (!bdrv_child_change_aio_context(c, ctx, visited, tran, errp)) {
129
30
+ bdrv_graph_rdunlock_main_loop();
130
- return raw_thread_pool_submit(bs, handle_aiocb_ioctl, &acb);
31
return false;
131
+ return raw_thread_pool_submit(handle_aiocb_ioctl, &acb);
132
}
133
#endif /* linux */
134
135
diff --git a/block/file-win32.c b/block/file-win32.c
136
index XXXXXXX..XXXXXXX 100644
137
--- a/block/file-win32.c
138
+++ b/block/file-win32.c
139
@@ -XXX,XX +XXX,XX @@ static BlockAIOCB *paio_submit(BlockDriverState *bs, HANDLE hfile,
140
acb->aio_offset = offset;
141
142
trace_file_paio_submit(acb, opaque, offset, count, type);
143
- pool = aio_get_thread_pool(bdrv_get_aio_context(bs));
144
+ pool = aio_get_thread_pool(qemu_get_current_aio_context());
145
return thread_pool_submit_aio(pool, aio_worker, acb, cb, opaque);
146
}
147
148
diff --git a/block/qcow2-threads.c b/block/qcow2-threads.c
149
index XXXXXXX..XXXXXXX 100644
150
--- a/block/qcow2-threads.c
151
+++ b/block/qcow2-threads.c
152
@@ -XXX,XX +XXX,XX @@ qcow2_co_process(BlockDriverState *bs, ThreadPoolFunc *func, void *arg)
153
{
154
int ret;
155
BDRVQcow2State *s = bs->opaque;
156
- ThreadPool *pool = aio_get_thread_pool(bdrv_get_aio_context(bs));
157
+ ThreadPool *pool = aio_get_thread_pool(qemu_get_current_aio_context());
158
159
qemu_co_mutex_lock(&s->lock);
160
while (s->nb_threads >= QCOW2_MAX_THREADS) {
161
diff --git a/util/thread-pool.c b/util/thread-pool.c
162
index XXXXXXX..XXXXXXX 100644
163
--- a/util/thread-pool.c
164
+++ b/util/thread-pool.c
165
@@ -XXX,XX +XXX,XX @@ struct ThreadPoolElement {
166
/* Access to this list is protected by lock. */
167
QTAILQ_ENTRY(ThreadPoolElement) reqs;
168
169
- /* Access to this list is protected by the global mutex. */
170
+ /* This list is only written by the thread pool's mother thread. */
171
QLIST_ENTRY(ThreadPoolElement) all;
172
};
173
174
@@ -XXX,XX +XXX,XX @@ static void thread_pool_completion_bh(void *opaque)
175
ThreadPool *pool = opaque;
176
ThreadPoolElement *elem, *next;
177
178
- aio_context_acquire(pool->ctx);
179
restart:
180
QLIST_FOREACH_SAFE(elem, &pool->head, all, next) {
181
if (elem->state != THREAD_DONE) {
182
@@ -XXX,XX +XXX,XX @@ restart:
183
*/
184
qemu_bh_schedule(pool->completion_bh);
185
186
- aio_context_release(pool->ctx);
187
elem->common.cb(elem->common.opaque, elem->ret);
188
- aio_context_acquire(pool->ctx);
189
190
/* We can safely cancel the completion_bh here regardless of someone
191
* else having scheduled it meanwhile because we reenter the
192
@@ -XXX,XX +XXX,XX @@ restart:
193
qemu_aio_unref(elem);
194
}
32
}
195
}
33
}
196
- aio_context_release(pool->ctx);
34
+ bdrv_graph_rdunlock_main_loop();
197
}
35
198
36
state = g_new(BdrvStateSetAioContext, 1);
199
static void thread_pool_cancel(BlockAIOCB *acb)
37
*state = (BdrvStateSetAioContext) {
200
@@ -XXX,XX +XXX,XX @@ BlockAIOCB *thread_pool_submit_aio(ThreadPool *pool,
201
{
202
ThreadPoolElement *req;
203
204
+ /* Assert that the thread submitting work is the same running the pool */
205
+ assert(pool->ctx == qemu_get_current_aio_context());
206
+
207
req = qemu_aio_get(&thread_pool_aiocb_info, NULL, cb, opaque);
208
req->func = func;
209
req->arg = arg;
210
--
38
--
211
2.40.0
39
2.41.0
diff view generated by jsdifflib
1
From: Emanuele Giuseppe Esposito <eesposit@redhat.com>
1
Instead of taking the writer lock internally, require callers to already
2
hold it when calling bdrv_root_unref_child(). These callers will
3
typically already hold the graph lock once the locking work is
4
completed, which means that they can't call functions that take it
5
internally.
2
6
3
thread_pool_submit_aio() is always called on a pool taken from
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
qemu_get_current_aio_context(), and that is the only intended
8
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
5
use: each pool runs only in the same thread that is submitting
6
work to it, it can't run anywhere else.
7
8
Therefore simplify the thread_pool_submit* API and remove the
9
ThreadPool function parameter.
10
11
Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
12
Message-Id: <20230203131731.851116-5-eesposit@redhat.com>
13
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
14
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
9
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
10
Message-ID: <20230911094620.45040-20-kwolf@redhat.com>
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
---
12
---
17
include/block/thread-pool.h | 10 ++++------
13
include/block/block_int-global-state.h | 2 +-
18
backends/tpm/tpm_backend.c | 4 +---
14
block.c | 6 +++---
19
block/file-posix.c | 4 +---
15
block/block-backend.c | 3 +++
20
block/file-win32.c | 4 +---
16
blockjob.c | 2 ++
21
block/qcow2-threads.c | 3 +--
17
4 files changed, 9 insertions(+), 4 deletions(-)
22
hw/9pfs/coth.c | 3 +--
23
hw/ppc/spapr_nvdimm.c | 6 ++----
24
hw/virtio/virtio-pmem.c | 3 +--
25
scsi/pr-manager.c | 3 +--
26
scsi/qemu-pr-helper.c | 3 +--
27
tests/unit/test-thread-pool.c | 12 +++++-------
28
util/thread-pool.c | 16 ++++++++--------
29
12 files changed, 27 insertions(+), 44 deletions(-)
30
18
31
diff --git a/include/block/thread-pool.h b/include/block/thread-pool.h
19
diff --git a/include/block/block_int-global-state.h b/include/block/block_int-global-state.h
32
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
33
--- a/include/block/thread-pool.h
21
--- a/include/block/block_int-global-state.h
34
+++ b/include/block/thread-pool.h
22
+++ b/include/block/block_int-global-state.h
35
@@ -XXX,XX +XXX,XX @@ void thread_pool_free(ThreadPool *pool);
23
@@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
36
* thread_pool_submit* API: submit I/O requests in the thread's
24
BdrvChildRole child_role,
37
* current AioContext.
25
uint64_t perm, uint64_t shared_perm,
38
*/
26
void *opaque, Error **errp);
39
-BlockAIOCB *thread_pool_submit_aio(ThreadPool *pool,
27
-void bdrv_root_unref_child(BdrvChild *child);
40
- ThreadPoolFunc *func, void *arg,
28
+void GRAPH_WRLOCK bdrv_root_unref_child(BdrvChild *child);
41
- BlockCompletionFunc *cb, void *opaque);
29
42
-int coroutine_fn thread_pool_submit_co(ThreadPool *pool,
30
void GRAPH_RDLOCK bdrv_get_cumulative_perm(BlockDriverState *bs, uint64_t *perm,
43
- ThreadPoolFunc *func, void *arg);
31
uint64_t *shared_perm);
44
-void thread_pool_submit(ThreadPool *pool, ThreadPoolFunc *func, void *arg);
32
diff --git a/block.c b/block.c
45
+BlockAIOCB *thread_pool_submit_aio(ThreadPoolFunc *func, void *arg,
46
+ BlockCompletionFunc *cb, void *opaque);
47
+int coroutine_fn thread_pool_submit_co(ThreadPoolFunc *func, void *arg);
48
+void thread_pool_submit(ThreadPoolFunc *func, void *arg);
49
50
void thread_pool_update_params(ThreadPool *pool, struct AioContext *ctx);
51
52
diff --git a/backends/tpm/tpm_backend.c b/backends/tpm/tpm_backend.c
53
index XXXXXXX..XXXXXXX 100644
33
index XXXXXXX..XXXXXXX 100644
54
--- a/backends/tpm/tpm_backend.c
34
--- a/block.c
55
+++ b/backends/tpm/tpm_backend.c
35
+++ b/block.c
56
@@ -XXX,XX +XXX,XX @@ bool tpm_backend_had_startup_error(TPMBackend *s)
36
@@ -XXX,XX +XXX,XX @@ void bdrv_root_unref_child(BdrvChild *child)
57
37
BlockDriverState *child_bs = child->bs;
58
void tpm_backend_deliver_request(TPMBackend *s, TPMBackendCmd *cmd)
38
59
{
39
GLOBAL_STATE_CODE();
60
- ThreadPool *pool = aio_get_thread_pool(qemu_get_aio_context());
40
- bdrv_graph_wrlock(NULL);
61
-
41
bdrv_replace_child_noperm(child, NULL);
62
if (s->cmd != NULL) {
42
bdrv_child_free(child);
63
error_report("There is a TPM request pending");
43
44
@@ -XXX,XX +XXX,XX @@ void bdrv_root_unref_child(BdrvChild *child)
45
NULL);
46
}
47
48
- bdrv_graph_wrunlock();
49
- bdrv_unref(child_bs);
50
+ bdrv_schedule_unref(child_bs);
51
}
52
53
typedef struct BdrvSetInheritsFrom {
54
@@ -XXX,XX +XXX,XX @@ void bdrv_unref_child(BlockDriverState *parent, BdrvChild *child)
64
return;
55
return;
65
@@ -XXX,XX +XXX,XX @@ void tpm_backend_deliver_request(TPMBackend *s, TPMBackendCmd *cmd)
56
}
66
57
67
s->cmd = cmd;
58
+ bdrv_graph_wrlock(NULL);
68
object_ref(OBJECT(s));
59
bdrv_unset_inherits_from(parent, child, NULL);
69
- thread_pool_submit_aio(pool, tpm_backend_worker_thread, s,
60
bdrv_root_unref_child(child);
70
+ thread_pool_submit_aio(tpm_backend_worker_thread, s,
61
+ bdrv_graph_wrunlock();
71
tpm_backend_request_completed, s);
72
}
62
}
73
63
74
diff --git a/block/file-posix.c b/block/file-posix.c
64
65
diff --git a/block/block-backend.c b/block/block-backend.c
75
index XXXXXXX..XXXXXXX 100644
66
index XXXXXXX..XXXXXXX 100644
76
--- a/block/file-posix.c
67
--- a/block/block-backend.c
77
+++ b/block/file-posix.c
68
+++ b/block/block-backend.c
78
@@ -XXX,XX +XXX,XX @@ out:
69
@@ -XXX,XX +XXX,XX @@ void blk_remove_bs(BlockBackend *blk)
79
70
blk_drain(blk);
80
static int coroutine_fn raw_thread_pool_submit(ThreadPoolFunc func, void *arg)
71
root = blk->root;
81
{
72
blk->root = NULL;
82
- /* @bs can be NULL, bdrv_get_aio_context() returns the main context then */
73
+
83
- ThreadPool *pool = aio_get_thread_pool(qemu_get_current_aio_context());
74
+ bdrv_graph_wrlock(NULL);
84
- return thread_pool_submit_co(pool, func, arg);
75
bdrv_root_unref_child(root);
85
+ return thread_pool_submit_co(func, arg);
76
+ bdrv_graph_wrunlock();
86
}
77
}
87
78
88
/*
79
/*
89
diff --git a/block/file-win32.c b/block/file-win32.c
80
diff --git a/blockjob.c b/blockjob.c
90
index XXXXXXX..XXXXXXX 100644
81
index XXXXXXX..XXXXXXX 100644
91
--- a/block/file-win32.c
82
--- a/blockjob.c
92
+++ b/block/file-win32.c
83
+++ b/blockjob.c
93
@@ -XXX,XX +XXX,XX @@ static BlockAIOCB *paio_submit(BlockDriverState *bs, HANDLE hfile,
84
@@ -XXX,XX +XXX,XX @@ void block_job_remove_all_bdrv(BlockJob *job)
94
BlockCompletionFunc *cb, void *opaque, int type)
85
* one to make sure that such a concurrent access does not attempt
95
{
86
* to process an already freed BdrvChild.
96
RawWin32AIOData *acb = g_new(RawWin32AIOData, 1);
87
*/
97
- ThreadPool *pool;
88
+ bdrv_graph_wrlock(NULL);
98
89
while (job->nodes) {
99
acb->bs = bs;
90
GSList *l = job->nodes;
100
acb->hfile = hfile;
91
BdrvChild *c = l->data;
101
@@ -XXX,XX +XXX,XX @@ static BlockAIOCB *paio_submit(BlockDriverState *bs, HANDLE hfile,
92
@@ -XXX,XX +XXX,XX @@ void block_job_remove_all_bdrv(BlockJob *job)
102
acb->aio_offset = offset;
93
103
94
g_slist_free_1(l);
104
trace_file_paio_submit(acb, opaque, offset, count, type);
95
}
105
- pool = aio_get_thread_pool(qemu_get_current_aio_context());
96
+ bdrv_graph_wrunlock();
106
- return thread_pool_submit_aio(pool, aio_worker, acb, cb, opaque);
107
+ return thread_pool_submit_aio(aio_worker, acb, cb, opaque);
108
}
97
}
109
98
110
int qemu_ftruncate64(int fd, int64_t length)
99
bool block_job_has_bdrv(BlockJob *job, BlockDriverState *bs)
111
diff --git a/block/qcow2-threads.c b/block/qcow2-threads.c
112
index XXXXXXX..XXXXXXX 100644
113
--- a/block/qcow2-threads.c
114
+++ b/block/qcow2-threads.c
115
@@ -XXX,XX +XXX,XX @@ qcow2_co_process(BlockDriverState *bs, ThreadPoolFunc *func, void *arg)
116
{
117
int ret;
118
BDRVQcow2State *s = bs->opaque;
119
- ThreadPool *pool = aio_get_thread_pool(qemu_get_current_aio_context());
120
121
qemu_co_mutex_lock(&s->lock);
122
while (s->nb_threads >= QCOW2_MAX_THREADS) {
123
@@ -XXX,XX +XXX,XX @@ qcow2_co_process(BlockDriverState *bs, ThreadPoolFunc *func, void *arg)
124
s->nb_threads++;
125
qemu_co_mutex_unlock(&s->lock);
126
127
- ret = thread_pool_submit_co(pool, func, arg);
128
+ ret = thread_pool_submit_co(func, arg);
129
130
qemu_co_mutex_lock(&s->lock);
131
s->nb_threads--;
132
diff --git a/hw/9pfs/coth.c b/hw/9pfs/coth.c
133
index XXXXXXX..XXXXXXX 100644
134
--- a/hw/9pfs/coth.c
135
+++ b/hw/9pfs/coth.c
136
@@ -XXX,XX +XXX,XX @@ static int coroutine_enter_func(void *arg)
137
void co_run_in_worker_bh(void *opaque)
138
{
139
Coroutine *co = opaque;
140
- thread_pool_submit_aio(aio_get_thread_pool(qemu_get_aio_context()),
141
- coroutine_enter_func, co, coroutine_enter_cb, co);
142
+ thread_pool_submit_aio(coroutine_enter_func, co, coroutine_enter_cb, co);
143
}
144
diff --git a/hw/ppc/spapr_nvdimm.c b/hw/ppc/spapr_nvdimm.c
145
index XXXXXXX..XXXXXXX 100644
146
--- a/hw/ppc/spapr_nvdimm.c
147
+++ b/hw/ppc/spapr_nvdimm.c
148
@@ -XXX,XX +XXX,XX @@ static int spapr_nvdimm_flush_post_load(void *opaque, int version_id)
149
{
150
SpaprNVDIMMDevice *s_nvdimm = (SpaprNVDIMMDevice *)opaque;
151
SpaprNVDIMMDeviceFlushState *state;
152
- ThreadPool *pool = aio_get_thread_pool(qemu_get_aio_context());
153
HostMemoryBackend *backend = MEMORY_BACKEND(PC_DIMM(s_nvdimm)->hostmem);
154
bool is_pmem = object_property_get_bool(OBJECT(backend), "pmem", NULL);
155
bool pmem_override = object_property_get_bool(OBJECT(s_nvdimm),
156
@@ -XXX,XX +XXX,XX @@ static int spapr_nvdimm_flush_post_load(void *opaque, int version_id)
157
}
158
159
QLIST_FOREACH(state, &s_nvdimm->pending_nvdimm_flush_states, node) {
160
- thread_pool_submit_aio(pool, flush_worker_cb, state,
161
+ thread_pool_submit_aio(flush_worker_cb, state,
162
spapr_nvdimm_flush_completion_cb, state);
163
}
164
165
@@ -XXX,XX +XXX,XX @@ static target_ulong h_scm_flush(PowerPCCPU *cpu, SpaprMachineState *spapr,
166
PCDIMMDevice *dimm;
167
HostMemoryBackend *backend = NULL;
168
SpaprNVDIMMDeviceFlushState *state;
169
- ThreadPool *pool = aio_get_thread_pool(qemu_get_aio_context());
170
int fd;
171
172
if (!drc || !drc->dev ||
173
@@ -XXX,XX +XXX,XX @@ static target_ulong h_scm_flush(PowerPCCPU *cpu, SpaprMachineState *spapr,
174
175
state->drcidx = drc_index;
176
177
- thread_pool_submit_aio(pool, flush_worker_cb, state,
178
+ thread_pool_submit_aio(flush_worker_cb, state,
179
spapr_nvdimm_flush_completion_cb, state);
180
181
continue_token = state->continue_token;
182
diff --git a/hw/virtio/virtio-pmem.c b/hw/virtio/virtio-pmem.c
183
index XXXXXXX..XXXXXXX 100644
184
--- a/hw/virtio/virtio-pmem.c
185
+++ b/hw/virtio/virtio-pmem.c
186
@@ -XXX,XX +XXX,XX @@ static void virtio_pmem_flush(VirtIODevice *vdev, VirtQueue *vq)
187
VirtIODeviceRequest *req_data;
188
VirtIOPMEM *pmem = VIRTIO_PMEM(vdev);
189
HostMemoryBackend *backend = MEMORY_BACKEND(pmem->memdev);
190
- ThreadPool *pool = aio_get_thread_pool(qemu_get_aio_context());
191
192
trace_virtio_pmem_flush_request();
193
req_data = virtqueue_pop(vq, sizeof(VirtIODeviceRequest));
194
@@ -XXX,XX +XXX,XX @@ static void virtio_pmem_flush(VirtIODevice *vdev, VirtQueue *vq)
195
req_data->fd = memory_region_get_fd(&backend->mr);
196
req_data->pmem = pmem;
197
req_data->vdev = vdev;
198
- thread_pool_submit_aio(pool, worker_cb, req_data, done_cb, req_data);
199
+ thread_pool_submit_aio(worker_cb, req_data, done_cb, req_data);
200
}
201
202
static void virtio_pmem_get_config(VirtIODevice *vdev, uint8_t *config)
203
diff --git a/scsi/pr-manager.c b/scsi/pr-manager.c
204
index XXXXXXX..XXXXXXX 100644
205
--- a/scsi/pr-manager.c
206
+++ b/scsi/pr-manager.c
207
@@ -XXX,XX +XXX,XX @@ static int pr_manager_worker(void *opaque)
208
int coroutine_fn pr_manager_execute(PRManager *pr_mgr, AioContext *ctx, int fd,
209
struct sg_io_hdr *hdr)
210
{
211
- ThreadPool *pool = aio_get_thread_pool(ctx);
212
PRManagerData data = {
213
.pr_mgr = pr_mgr,
214
.fd = fd,
215
@@ -XXX,XX +XXX,XX @@ int coroutine_fn pr_manager_execute(PRManager *pr_mgr, AioContext *ctx, int fd,
216
217
/* The matching object_unref is in pr_manager_worker. */
218
object_ref(OBJECT(pr_mgr));
219
- return thread_pool_submit_co(pool, pr_manager_worker, &data);
220
+ return thread_pool_submit_co(pr_manager_worker, &data);
221
}
222
223
bool pr_manager_is_connected(PRManager *pr_mgr)
224
diff --git a/scsi/qemu-pr-helper.c b/scsi/qemu-pr-helper.c
225
index XXXXXXX..XXXXXXX 100644
226
--- a/scsi/qemu-pr-helper.c
227
+++ b/scsi/qemu-pr-helper.c
228
@@ -XXX,XX +XXX,XX @@ static int do_sgio_worker(void *opaque)
229
static int do_sgio(int fd, const uint8_t *cdb, uint8_t *sense,
230
uint8_t *buf, int *sz, int dir)
231
{
232
- ThreadPool *pool = aio_get_thread_pool(qemu_get_aio_context());
233
int r;
234
235
PRHelperSGIOData data = {
236
@@ -XXX,XX +XXX,XX @@ static int do_sgio(int fd, const uint8_t *cdb, uint8_t *sense,
237
.dir = dir,
238
};
239
240
- r = thread_pool_submit_co(pool, do_sgio_worker, &data);
241
+ r = thread_pool_submit_co(do_sgio_worker, &data);
242
*sz = data.sz;
243
return r;
244
}
245
diff --git a/tests/unit/test-thread-pool.c b/tests/unit/test-thread-pool.c
246
index XXXXXXX..XXXXXXX 100644
247
--- a/tests/unit/test-thread-pool.c
248
+++ b/tests/unit/test-thread-pool.c
249
@@ -XXX,XX +XXX,XX @@
250
#include "qemu/main-loop.h"
251
252
static AioContext *ctx;
253
-static ThreadPool *pool;
254
static int active;
255
256
typedef struct {
257
@@ -XXX,XX +XXX,XX @@ static void done_cb(void *opaque, int ret)
258
static void test_submit(void)
259
{
260
WorkerTestData data = { .n = 0 };
261
- thread_pool_submit(pool, worker_cb, &data);
262
+ thread_pool_submit(worker_cb, &data);
263
while (data.n == 0) {
264
aio_poll(ctx, true);
265
}
266
@@ -XXX,XX +XXX,XX @@ static void test_submit(void)
267
static void test_submit_aio(void)
268
{
269
WorkerTestData data = { .n = 0, .ret = -EINPROGRESS };
270
- data.aiocb = thread_pool_submit_aio(pool, worker_cb, &data,
271
+ data.aiocb = thread_pool_submit_aio(worker_cb, &data,
272
done_cb, &data);
273
274
/* The callbacks are not called until after the first wait. */
275
@@ -XXX,XX +XXX,XX @@ static void co_test_cb(void *opaque)
276
active = 1;
277
data->n = 0;
278
data->ret = -EINPROGRESS;
279
- thread_pool_submit_co(pool, worker_cb, data);
280
+ thread_pool_submit_co(worker_cb, data);
281
282
/* The test continues in test_submit_co, after qemu_coroutine_enter... */
283
284
@@ -XXX,XX +XXX,XX @@ static void test_submit_many(void)
285
for (i = 0; i < 100; i++) {
286
data[i].n = 0;
287
data[i].ret = -EINPROGRESS;
288
- thread_pool_submit_aio(pool, worker_cb, &data[i], done_cb, &data[i]);
289
+ thread_pool_submit_aio(worker_cb, &data[i], done_cb, &data[i]);
290
}
291
292
active = 100;
293
@@ -XXX,XX +XXX,XX @@ static void do_test_cancel(bool sync)
294
for (i = 0; i < 100; i++) {
295
data[i].n = 0;
296
data[i].ret = -EINPROGRESS;
297
- data[i].aiocb = thread_pool_submit_aio(pool, long_cb, &data[i],
298
+ data[i].aiocb = thread_pool_submit_aio(long_cb, &data[i],
299
done_cb, &data[i]);
300
}
301
302
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
303
{
304
qemu_init_main_loop(&error_abort);
305
ctx = qemu_get_current_aio_context();
306
- pool = aio_get_thread_pool(ctx);
307
308
g_test_init(&argc, &argv, NULL);
309
g_test_add_func("/thread-pool/submit", test_submit);
310
diff --git a/util/thread-pool.c b/util/thread-pool.c
311
index XXXXXXX..XXXXXXX 100644
312
--- a/util/thread-pool.c
313
+++ b/util/thread-pool.c
314
@@ -XXX,XX +XXX,XX @@ static const AIOCBInfo thread_pool_aiocb_info = {
315
.get_aio_context = thread_pool_get_aio_context,
316
};
317
318
-BlockAIOCB *thread_pool_submit_aio(ThreadPool *pool,
319
- ThreadPoolFunc *func, void *arg,
320
- BlockCompletionFunc *cb, void *opaque)
321
+BlockAIOCB *thread_pool_submit_aio(ThreadPoolFunc *func, void *arg,
322
+ BlockCompletionFunc *cb, void *opaque)
323
{
324
ThreadPoolElement *req;
325
+ AioContext *ctx = qemu_get_current_aio_context();
326
+ ThreadPool *pool = aio_get_thread_pool(ctx);
327
328
/* Assert that the thread submitting work is the same running the pool */
329
assert(pool->ctx == qemu_get_current_aio_context());
330
@@ -XXX,XX +XXX,XX @@ static void thread_pool_co_cb(void *opaque, int ret)
331
aio_co_wake(co->co);
332
}
333
334
-int coroutine_fn thread_pool_submit_co(ThreadPool *pool, ThreadPoolFunc *func,
335
- void *arg)
336
+int coroutine_fn thread_pool_submit_co(ThreadPoolFunc *func, void *arg)
337
{
338
ThreadPoolCo tpc = { .co = qemu_coroutine_self(), .ret = -EINPROGRESS };
339
assert(qemu_in_coroutine());
340
- thread_pool_submit_aio(pool, func, arg, thread_pool_co_cb, &tpc);
341
+ thread_pool_submit_aio(func, arg, thread_pool_co_cb, &tpc);
342
qemu_coroutine_yield();
343
return tpc.ret;
344
}
345
346
-void thread_pool_submit(ThreadPool *pool, ThreadPoolFunc *func, void *arg)
347
+void thread_pool_submit(ThreadPoolFunc *func, void *arg)
348
{
349
- thread_pool_submit_aio(pool, func, arg, NULL, NULL);
350
+ thread_pool_submit_aio(func, arg, NULL, NULL);
351
}
352
353
void thread_pool_update_params(ThreadPool *pool, AioContext *ctx)
354
--
100
--
355
2.40.0
101
2.41.0
diff view generated by jsdifflib
1
From: Paolo Bonzini <pbonzini@redhat.com>
1
Instead of taking the writer lock internally, require callers to already
2
hold it when calling bdrv_unref_child(). These callers will typically
3
already hold the graph lock once the locking work is completed, which
4
means that they can't call functions that take it internally.
2
5
3
Functions that can do I/O (including calling bdrv_is_allocated
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
and bdrv_block_status functions) are prime candidates for being
7
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
5
coroutine_fns. Make the change for those that are themselves called
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
6
only from coroutine_fns. Also annotate that they are called with the
9
Message-ID: <20230911094620.45040-21-kwolf@redhat.com>
7
graph rdlock taken, thus allowing them to call bdrv_co_*() functions
8
for I/O.
9
10
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
11
Message-Id: <20230309084456.304669-9-pbonzini@redhat.com>
12
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
---
11
---
15
block/qcow2.h | 15 ++++++++-------
12
include/block/block-global-state.h | 7 ++++++-
16
block/qcow2-bitmap.c | 2 +-
13
block.c | 11 +++++++----
17
block/qcow2-cluster.c | 21 +++++++++++++--------
14
block/blklogwrites.c | 4 ++++
18
block/qcow2-refcount.c | 8 ++++----
15
block/blkverify.c | 2 ++
19
block/qcow2-snapshot.c | 25 +++++++++++++------------
16
block/qcow2.c | 4 +++-
20
block/qcow2.c | 27 ++++++++++++++-------------
17
block/quorum.c | 6 ++++++
21
6 files changed, 53 insertions(+), 45 deletions(-)
18
block/replication.c | 3 +++
19
block/snapshot.c | 2 ++
20
block/vmdk.c | 11 +++++++++++
21
tests/unit/test-bdrv-drain.c | 8 ++++++--
22
10 files changed, 50 insertions(+), 8 deletions(-)
22
23
23
diff --git a/block/qcow2.h b/block/qcow2.h
24
diff --git a/include/block/block-global-state.h b/include/block/block-global-state.h
24
index XXXXXXX..XXXXXXX 100644
25
index XXXXXXX..XXXXXXX 100644
25
--- a/block/qcow2.h
26
--- a/include/block/block-global-state.h
26
+++ b/block/qcow2.h
27
+++ b/include/block/block-global-state.h
27
@@ -XXX,XX +XXX,XX @@ int64_t qcow2_refcount_area(BlockDriverState *bs, uint64_t offset,
28
@@ -XXX,XX +XXX,XX @@ void bdrv_ref(BlockDriverState *bs);
28
uint64_t new_refblock_offset);
29
void no_coroutine_fn bdrv_unref(BlockDriverState *bs);
29
30
void coroutine_fn no_co_wrapper bdrv_co_unref(BlockDriverState *bs);
30
int64_t qcow2_alloc_clusters(BlockDriverState *bs, uint64_t size);
31
void GRAPH_WRLOCK bdrv_schedule_unref(BlockDriverState *bs);
31
-int64_t qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
32
-void bdrv_unref_child(BlockDriverState *parent, BdrvChild *child);
32
- int64_t nb_clusters);
33
+
33
-int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size);
34
+void GRAPH_WRLOCK
34
+int64_t coroutine_fn qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
35
+bdrv_unref_child(BlockDriverState *parent, BdrvChild *child);
35
+ int64_t nb_clusters);
36
+
36
+int64_t coroutine_fn qcow2_alloc_bytes(BlockDriverState *bs, int size);
37
+void coroutine_fn no_co_wrapper_bdrv_wrlock
37
void qcow2_free_clusters(BlockDriverState *bs,
38
+bdrv_co_unref_child(BlockDriverState *parent, BdrvChild *child);
38
int64_t offset, int64_t size,
39
39
enum qcow2_discard_type type);
40
BdrvChild * GRAPH_WRLOCK
40
@@ -XXX,XX +XXX,XX @@ int qcow2_change_refcount_order(BlockDriverState *bs, int refcount_order,
41
bdrv_attach_child(BlockDriverState *parent_bs,
41
BlockDriverAmendStatusCB *status_cb,
42
diff --git a/block.c b/block.c
42
void *cb_opaque, Error **errp);
43
index XXXXXXX..XXXXXXX 100644
43
int coroutine_fn GRAPH_RDLOCK qcow2_shrink_reftable(BlockDriverState *bs);
44
--- a/block.c
44
-int64_t qcow2_get_last_cluster(BlockDriverState *bs, int64_t size);
45
+++ b/block.c
45
+int64_t coroutine_fn qcow2_get_last_cluster(BlockDriverState *bs, int64_t size);
46
@@ -XXX,XX +XXX,XX @@ bdrv_open_driver(BlockDriverState *bs, BlockDriver *drv, const char *node_name,
46
int coroutine_fn qcow2_detect_metadata_preallocation(BlockDriverState *bs);
47
open_failed:
47
48
bs->drv = NULL;
48
/* qcow2-cluster.c functions */
49
if (bs->file != NULL) {
49
@@ -XXX,XX +XXX,XX @@ void qcow2_parse_compressed_l2_entry(BlockDriverState *bs, uint64_t l2_entry,
50
+ bdrv_graph_wrlock(NULL);
50
int coroutine_fn GRAPH_RDLOCK
51
bdrv_unref_child(bs, bs->file);
51
qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m);
52
+ bdrv_graph_wrunlock();
52
53
assert(!bs->file);
53
-void qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m);
54
}
54
+void coroutine_fn qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m);
55
g_free(bs->opaque);
55
int qcow2_cluster_discard(BlockDriverState *bs, uint64_t offset,
56
@@ -XXX,XX +XXX,XX @@ static void bdrv_set_inherits_from(BlockDriverState *bs,
56
uint64_t bytes, enum qcow2_discard_type type,
57
* @root that point to @root, where necessary.
57
bool full_discard);
58
* @tran is allowed to be NULL. In this case no rollback is possible
58
@@ -XXX,XX +XXX,XX @@ int qcow2_snapshot_load_tmp(BlockDriverState *bs,
59
*/
59
Error **errp);
60
-static void bdrv_unset_inherits_from(BlockDriverState *root, BdrvChild *child,
60
61
- Transaction *tran)
61
void qcow2_free_snapshots(BlockDriverState *bs);
62
+static void GRAPH_WRLOCK
62
-int qcow2_read_snapshots(BlockDriverState *bs, Error **errp);
63
+bdrv_unset_inherits_from(BlockDriverState *root, BdrvChild *child,
63
+int coroutine_fn GRAPH_RDLOCK
64
+ Transaction *tran)
64
+qcow2_read_snapshots(BlockDriverState *bs, Error **errp);
65
int qcow2_write_snapshots(BlockDriverState *bs);
66
67
int coroutine_fn GRAPH_RDLOCK
68
@@ -XXX,XX +XXX,XX @@ bool coroutine_fn qcow2_load_dirty_bitmaps(BlockDriverState *bs,
69
bool qcow2_get_bitmap_info_list(BlockDriverState *bs,
70
Qcow2BitmapInfoList **info_list, Error **errp);
71
int qcow2_reopen_bitmaps_rw(BlockDriverState *bs, Error **errp);
72
-int qcow2_truncate_bitmaps_check(BlockDriverState *bs, Error **errp);
73
+int coroutine_fn qcow2_truncate_bitmaps_check(BlockDriverState *bs, Error **errp);
74
bool qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs,
75
bool release_stored, Error **errp);
76
int qcow2_reopen_bitmaps_ro(BlockDriverState *bs, Error **errp);
77
diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c
78
index XXXXXXX..XXXXXXX 100644
79
--- a/block/qcow2-bitmap.c
80
+++ b/block/qcow2-bitmap.c
81
@@ -XXX,XX +XXX,XX @@ out:
82
}
83
84
/* Checks to see if it's safe to resize bitmaps */
85
-int qcow2_truncate_bitmaps_check(BlockDriverState *bs, Error **errp)
86
+int coroutine_fn qcow2_truncate_bitmaps_check(BlockDriverState *bs, Error **errp)
87
{
65
{
88
BDRVQcow2State *s = bs->opaque;
66
BdrvChild *c;
89
Qcow2BitmapList *bm_list;
67
90
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
68
@@ -XXX,XX +XXX,XX @@ void bdrv_unref_child(BlockDriverState *parent, BdrvChild *child)
91
index XXXXXXX..XXXXXXX 100644
69
return;
92
--- a/block/qcow2-cluster.c
70
}
93
+++ b/block/qcow2-cluster.c
71
94
@@ -XXX,XX +XXX,XX @@ err:
72
- bdrv_graph_wrlock(NULL);
95
* Frees the allocated clusters because the request failed and they won't
73
bdrv_unset_inherits_from(parent, child, NULL);
96
* actually be linked.
74
bdrv_root_unref_child(child);
97
*/
75
- bdrv_graph_wrunlock();
98
-void qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m)
76
}
99
+void coroutine_fn qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m)
77
78
79
@@ -XXX,XX +XXX,XX @@ static void bdrv_close(BlockDriverState *bs)
80
bs->drv = NULL;
81
}
82
83
+ bdrv_graph_wrlock(NULL);
84
QLIST_FOREACH_SAFE(child, &bs->children, next, next) {
85
bdrv_unref_child(bs, child);
86
}
87
+ bdrv_graph_wrunlock();
88
89
assert(!bs->backing);
90
assert(!bs->file);
91
diff --git a/block/blklogwrites.c b/block/blklogwrites.c
92
index XXXXXXX..XXXXXXX 100644
93
--- a/block/blklogwrites.c
94
+++ b/block/blklogwrites.c
95
@@ -XXX,XX +XXX,XX @@ static int blk_log_writes_open(BlockDriverState *bs, QDict *options, int flags,
96
ret = 0;
97
fail_log:
98
if (ret < 0) {
99
+ bdrv_graph_wrlock(NULL);
100
bdrv_unref_child(bs, s->log_file);
101
+ bdrv_graph_wrunlock();
102
s->log_file = NULL;
103
}
104
fail:
105
@@ -XXX,XX +XXX,XX @@ static void blk_log_writes_close(BlockDriverState *bs)
100
{
106
{
101
BDRVQcow2State *s = bs->opaque;
107
BDRVBlkLogWritesState *s = bs->opaque;
102
if (!has_data_file(bs) && !m->keep_old_clusters) {
108
103
@@ -XXX,XX +XXX,XX @@ void qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m)
109
+ bdrv_graph_wrlock(NULL);
104
*
110
bdrv_unref_child(bs, s->log_file);
105
* Returns 0 on success, -errno on failure.
111
s->log_file = NULL;
106
*/
112
+ bdrv_graph_wrunlock();
107
-static int calculate_l2_meta(BlockDriverState *bs, uint64_t host_cluster_offset,
113
}
108
- uint64_t guest_offset, unsigned bytes,
114
109
- uint64_t *l2_slice, QCowL2Meta **m, bool keep_old)
115
static int64_t coroutine_fn GRAPH_RDLOCK
110
+static int coroutine_fn calculate_l2_meta(BlockDriverState *bs,
116
diff --git a/block/blkverify.c b/block/blkverify.c
111
+ uint64_t host_cluster_offset,
117
index XXXXXXX..XXXXXXX 100644
112
+ uint64_t guest_offset, unsigned bytes,
118
--- a/block/blkverify.c
113
+ uint64_t *l2_slice, QCowL2Meta **m,
119
+++ b/block/blkverify.c
114
+ bool keep_old)
120
@@ -XXX,XX +XXX,XX @@ static void blkverify_close(BlockDriverState *bs)
115
{
121
{
116
BDRVQcow2State *s = bs->opaque;
122
BDRVBlkverifyState *s = bs->opaque;
117
int sc_index, l2_index = offset_to_l2_slice_index(s, guest_offset);
123
118
@@ -XXX,XX +XXX,XX @@ out:
124
+ bdrv_graph_wrlock(NULL);
119
* function has been waiting for another request and the allocation must be
125
bdrv_unref_child(bs, s->test_file);
120
* restarted, but the whole request should not be failed.
126
s->test_file = NULL;
121
*/
127
+ bdrv_graph_wrunlock();
122
-static int do_alloc_cluster_offset(BlockDriverState *bs, uint64_t guest_offset,
128
}
123
- uint64_t *host_offset, uint64_t *nb_clusters)
129
124
+static int coroutine_fn do_alloc_cluster_offset(BlockDriverState *bs,
130
static int64_t coroutine_fn GRAPH_RDLOCK
125
+ uint64_t guest_offset,
126
+ uint64_t *host_offset,
127
+ uint64_t *nb_clusters)
128
{
129
BDRVQcow2State *s = bs->opaque;
130
131
@@ -XXX,XX +XXX,XX @@ static int zero_in_l2_slice(BlockDriverState *bs, uint64_t offset,
132
return nb_clusters;
133
}
134
135
-static int zero_l2_subclusters(BlockDriverState *bs, uint64_t offset,
136
- unsigned nb_subclusters)
137
+static int coroutine_fn
138
+zero_l2_subclusters(BlockDriverState *bs, uint64_t offset,
139
+ unsigned nb_subclusters)
140
{
141
BDRVQcow2State *s = bs->opaque;
142
uint64_t *l2_slice;
143
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
144
index XXXXXXX..XXXXXXX 100644
145
--- a/block/qcow2-refcount.c
146
+++ b/block/qcow2-refcount.c
147
@@ -XXX,XX +XXX,XX @@ int64_t qcow2_alloc_clusters(BlockDriverState *bs, uint64_t size)
148
return offset;
149
}
150
151
-int64_t qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
152
- int64_t nb_clusters)
153
+int64_t coroutine_fn qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
154
+ int64_t nb_clusters)
155
{
156
BDRVQcow2State *s = bs->opaque;
157
uint64_t cluster_index, refcount;
158
@@ -XXX,XX +XXX,XX @@ int64_t qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
159
160
/* only used to allocate compressed sectors. We try to allocate
161
contiguous sectors. size must be <= cluster_size */
162
-int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size)
163
+int64_t coroutine_fn qcow2_alloc_bytes(BlockDriverState *bs, int size)
164
{
165
BDRVQcow2State *s = bs->opaque;
166
int64_t offset;
167
@@ -XXX,XX +XXX,XX @@ out:
168
return ret;
169
}
170
171
-int64_t qcow2_get_last_cluster(BlockDriverState *bs, int64_t size)
172
+int64_t coroutine_fn qcow2_get_last_cluster(BlockDriverState *bs, int64_t size)
173
{
174
BDRVQcow2State *s = bs->opaque;
175
int64_t i;
176
diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c
177
index XXXXXXX..XXXXXXX 100644
178
--- a/block/qcow2-snapshot.c
179
+++ b/block/qcow2-snapshot.c
180
@@ -XXX,XX +XXX,XX @@ void qcow2_free_snapshots(BlockDriverState *bs)
181
* qcow2_check_refcounts() does not do anything with snapshots'
182
* extra data.)
183
*/
184
-static int qcow2_do_read_snapshots(BlockDriverState *bs, bool repair,
185
- int *nb_clusters_reduced,
186
- int *extra_data_dropped,
187
- Error **errp)
188
+static coroutine_fn GRAPH_RDLOCK
189
+int qcow2_do_read_snapshots(BlockDriverState *bs, bool repair,
190
+ int *nb_clusters_reduced,
191
+ int *extra_data_dropped,
192
+ Error **errp)
193
{
194
BDRVQcow2State *s = bs->opaque;
195
QCowSnapshotHeader h;
196
@@ -XXX,XX +XXX,XX @@ static int qcow2_do_read_snapshots(BlockDriverState *bs, bool repair,
197
198
/* Read statically sized part of the snapshot header */
199
offset = ROUND_UP(offset, 8);
200
- ret = bdrv_pread(bs->file, offset, sizeof(h), &h, 0);
201
+ ret = bdrv_co_pread(bs->file, offset, sizeof(h), &h, 0);
202
if (ret < 0) {
203
error_setg_errno(errp, -ret, "Failed to read snapshot table");
204
goto fail;
205
@@ -XXX,XX +XXX,XX @@ static int qcow2_do_read_snapshots(BlockDriverState *bs, bool repair,
206
}
207
208
/* Read known extra data */
209
- ret = bdrv_pread(bs->file, offset,
210
- MIN(sizeof(extra), sn->extra_data_size), &extra, 0);
211
+ ret = bdrv_co_pread(bs->file, offset,
212
+ MIN(sizeof(extra), sn->extra_data_size), &extra, 0);
213
if (ret < 0) {
214
error_setg_errno(errp, -ret, "Failed to read snapshot table");
215
goto fail;
216
@@ -XXX,XX +XXX,XX @@ static int qcow2_do_read_snapshots(BlockDriverState *bs, bool repair,
217
/* Store unknown extra data */
218
unknown_extra_data_size = sn->extra_data_size - sizeof(extra);
219
sn->unknown_extra_data = g_malloc(unknown_extra_data_size);
220
- ret = bdrv_pread(bs->file, offset, unknown_extra_data_size,
221
- sn->unknown_extra_data, 0);
222
+ ret = bdrv_co_pread(bs->file, offset, unknown_extra_data_size,
223
+ sn->unknown_extra_data, 0);
224
if (ret < 0) {
225
error_setg_errno(errp, -ret,
226
"Failed to read snapshot table");
227
@@ -XXX,XX +XXX,XX @@ static int qcow2_do_read_snapshots(BlockDriverState *bs, bool repair,
228
229
/* Read snapshot ID */
230
sn->id_str = g_malloc(id_str_size + 1);
231
- ret = bdrv_pread(bs->file, offset, id_str_size, sn->id_str, 0);
232
+ ret = bdrv_co_pread(bs->file, offset, id_str_size, sn->id_str, 0);
233
if (ret < 0) {
234
error_setg_errno(errp, -ret, "Failed to read snapshot table");
235
goto fail;
236
@@ -XXX,XX +XXX,XX @@ static int qcow2_do_read_snapshots(BlockDriverState *bs, bool repair,
237
238
/* Read snapshot name */
239
sn->name = g_malloc(name_size + 1);
240
- ret = bdrv_pread(bs->file, offset, name_size, sn->name, 0);
241
+ ret = bdrv_co_pread(bs->file, offset, name_size, sn->name, 0);
242
if (ret < 0) {
243
error_setg_errno(errp, -ret, "Failed to read snapshot table");
244
goto fail;
245
@@ -XXX,XX +XXX,XX @@ fail:
246
return ret;
247
}
248
249
-int qcow2_read_snapshots(BlockDriverState *bs, Error **errp)
250
+int coroutine_fn qcow2_read_snapshots(BlockDriverState *bs, Error **errp)
251
{
252
return qcow2_do_read_snapshots(bs, false, NULL, NULL, errp);
253
}
254
diff --git a/block/qcow2.c b/block/qcow2.c
131
diff --git a/block/qcow2.c b/block/qcow2.c
255
index XXXXXXX..XXXXXXX 100644
132
index XXXXXXX..XXXXXXX 100644
256
--- a/block/qcow2.c
133
--- a/block/qcow2.c
257
+++ b/block/qcow2.c
134
+++ b/block/qcow2.c
258
@@ -XXX,XX +XXX,XX @@ qcow2_extract_crypto_opts(QemuOpts *opts, const char *fmt, Error **errp)
135
@@ -XXX,XX +XXX,XX @@ qcow2_do_open(BlockDriverState *bs, QDict *options, int flags,
259
* unknown magic is skipped (future extension this version knows nothing about)
136
g_free(s->image_data_file);
260
* return 0 upon success, non-0 otherwise
137
if (open_data_file && has_data_file(bs)) {
261
*/
138
bdrv_graph_co_rdunlock();
262
-static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
139
- bdrv_unref_child(bs, s->data_file);
263
- uint64_t end_offset, void **p_feature_table,
140
+ bdrv_co_unref_child(bs, s->data_file);
264
- int flags, bool *need_update_header,
141
bdrv_graph_co_rdlock();
265
- Error **errp)
142
s->data_file = NULL;
266
+static int coroutine_fn GRAPH_RDLOCK
143
}
267
+qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
144
@@ -XXX,XX +XXX,XX @@ static void qcow2_do_close(BlockDriverState *bs, bool close_data_file)
268
+ uint64_t end_offset, void **p_feature_table,
145
g_free(s->image_backing_format);
269
+ int flags, bool *need_update_header, Error **errp)
146
147
if (close_data_file && has_data_file(bs)) {
148
+ bdrv_graph_wrlock(NULL);
149
bdrv_unref_child(bs, s->data_file);
150
+ bdrv_graph_wrunlock();
151
s->data_file = NULL;
152
}
153
154
diff --git a/block/quorum.c b/block/quorum.c
155
index XXXXXXX..XXXXXXX 100644
156
--- a/block/quorum.c
157
+++ b/block/quorum.c
158
@@ -XXX,XX +XXX,XX @@ static int quorum_open(BlockDriverState *bs, QDict *options, int flags,
159
160
close_exit:
161
/* cleanup on error */
162
+ bdrv_graph_wrlock(NULL);
163
for (i = 0; i < s->num_children; i++) {
164
if (!opened[i]) {
165
continue;
166
}
167
bdrv_unref_child(bs, s->children[i]);
168
}
169
+ bdrv_graph_wrunlock();
170
g_free(s->children);
171
g_free(opened);
172
exit:
173
@@ -XXX,XX +XXX,XX @@ static void quorum_close(BlockDriverState *bs)
174
BDRVQuorumState *s = bs->opaque;
175
int i;
176
177
+ bdrv_graph_wrlock(NULL);
178
for (i = 0; i < s->num_children; i++) {
179
bdrv_unref_child(bs, s->children[i]);
180
}
181
+ bdrv_graph_wrunlock();
182
183
g_free(s->children);
184
}
185
@@ -XXX,XX +XXX,XX @@ static void quorum_del_child(BlockDriverState *bs, BdrvChild *child,
186
memmove(&s->children[i], &s->children[i + 1],
187
(s->num_children - i - 1) * sizeof(BdrvChild *));
188
s->children = g_renew(BdrvChild *, s->children, --s->num_children);
189
+ bdrv_graph_wrlock(NULL);
190
bdrv_unref_child(bs, child);
191
+ bdrv_graph_wrunlock();
192
193
quorum_refresh_flags(bs);
194
bdrv_drained_end(bs);
195
diff --git a/block/replication.c b/block/replication.c
196
index XXXXXXX..XXXXXXX 100644
197
--- a/block/replication.c
198
+++ b/block/replication.c
199
@@ -XXX,XX +XXX,XX @@ static void replication_done(void *opaque, int ret)
200
if (ret == 0) {
201
s->stage = BLOCK_REPLICATION_DONE;
202
203
+ bdrv_graph_wrlock(NULL);
204
bdrv_unref_child(bs, s->secondary_disk);
205
s->secondary_disk = NULL;
206
bdrv_unref_child(bs, s->hidden_disk);
207
s->hidden_disk = NULL;
208
+ bdrv_graph_wrunlock();
209
+
210
s->error = 0;
211
} else {
212
s->stage = BLOCK_REPLICATION_FAILOVER_FAILED;
213
diff --git a/block/snapshot.c b/block/snapshot.c
214
index XXXXXXX..XXXXXXX 100644
215
--- a/block/snapshot.c
216
+++ b/block/snapshot.c
217
@@ -XXX,XX +XXX,XX @@ int bdrv_snapshot_goto(BlockDriverState *bs,
218
}
219
220
/* .bdrv_open() will re-attach it */
221
+ bdrv_graph_wrlock(NULL);
222
bdrv_unref_child(bs, fallback);
223
+ bdrv_graph_wrunlock();
224
225
ret = bdrv_snapshot_goto(fallback_bs, snapshot_id, errp);
226
open_ret = drv->bdrv_open(bs, options, bs->open_flags, &local_err);
227
diff --git a/block/vmdk.c b/block/vmdk.c
228
index XXXXXXX..XXXXXXX 100644
229
--- a/block/vmdk.c
230
+++ b/block/vmdk.c
231
@@ -XXX,XX +XXX,XX @@ static void vmdk_free_extents(BlockDriverState *bs)
232
BDRVVmdkState *s = bs->opaque;
233
VmdkExtent *e;
234
235
+ bdrv_graph_wrlock(NULL);
236
for (i = 0; i < s->num_extents; i++) {
237
e = &s->extents[i];
238
g_free(e->l1_table);
239
@@ -XXX,XX +XXX,XX @@ static void vmdk_free_extents(BlockDriverState *bs)
240
bdrv_unref_child(bs, e->file);
241
}
242
}
243
+ bdrv_graph_wrunlock();
244
+
245
g_free(s->extents);
246
}
247
248
@@ -XXX,XX +XXX,XX @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
249
ret = vmdk_add_extent(bs, extent_file, true, sectors,
250
0, 0, 0, 0, 0, &extent, errp);
251
if (ret < 0) {
252
+ bdrv_graph_wrlock(NULL);
253
bdrv_unref_child(bs, extent_file);
254
+ bdrv_graph_wrunlock();
255
goto out;
256
}
257
extent->flat_start_offset = flat_offset << 9;
258
@@ -XXX,XX +XXX,XX @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
259
}
260
g_free(buf);
261
if (ret) {
262
+ bdrv_graph_wrlock(NULL);
263
bdrv_unref_child(bs, extent_file);
264
+ bdrv_graph_wrunlock();
265
goto out;
266
}
267
extent = &s->extents[s->num_extents - 1];
268
} else if (!strcmp(type, "SESPARSE")) {
269
ret = vmdk_open_se_sparse(bs, extent_file, bs->open_flags, errp);
270
if (ret) {
271
+ bdrv_graph_wrlock(NULL);
272
bdrv_unref_child(bs, extent_file);
273
+ bdrv_graph_wrunlock();
274
goto out;
275
}
276
extent = &s->extents[s->num_extents - 1];
277
} else {
278
error_setg(errp, "Unsupported extent type '%s'", type);
279
+ bdrv_graph_wrlock(NULL);
280
bdrv_unref_child(bs, extent_file);
281
+ bdrv_graph_wrunlock();
282
ret = -ENOTSUP;
283
goto out;
284
}
285
diff --git a/tests/unit/test-bdrv-drain.c b/tests/unit/test-bdrv-drain.c
286
index XXXXXXX..XXXXXXX 100644
287
--- a/tests/unit/test-bdrv-drain.c
288
+++ b/tests/unit/test-bdrv-drain.c
289
@@ -XXX,XX +XXX,XX @@ typedef struct BDRVTestTopState {
290
static void bdrv_test_top_close(BlockDriverState *bs)
270
{
291
{
271
BDRVQcow2State *s = bs->opaque;
292
BdrvChild *c, *next_c;
272
QCowExtension ext;
293
+
273
@@ -XXX,XX +XXX,XX @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
294
+ bdrv_graph_wrlock(NULL);
274
printf("attempting to read extended header in offset %lu\n", offset);
295
QLIST_FOREACH_SAFE(c, &bs->children, next, next_c) {
275
#endif
296
bdrv_unref_child(bs, c);
276
297
}
277
- ret = bdrv_pread(bs->file, offset, sizeof(ext), &ext, 0);
298
+ bdrv_graph_wrunlock();
278
+ ret = bdrv_co_pread(bs->file, offset, sizeof(ext), &ext, 0);
299
}
279
if (ret < 0) {
300
280
error_setg_errno(errp, -ret, "qcow2_read_extension: ERROR: "
301
static int coroutine_fn GRAPH_RDLOCK
281
"pread fail from offset %" PRIu64, offset);
302
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn test_co_delete_by_drain(void *opaque)
282
@@ -XXX,XX +XXX,XX @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
303
} else {
283
sizeof(bs->backing_format));
304
BdrvChild *c, *next_c;
284
return 2;
305
QLIST_FOREACH_SAFE(c, &bs->children, next, next_c) {
285
}
306
- bdrv_unref_child(bs, c);
286
- ret = bdrv_pread(bs->file, offset, ext.len, bs->backing_format, 0);
307
+ bdrv_co_unref_child(bs, c);
287
+ ret = bdrv_co_pread(bs->file, offset, ext.len, bs->backing_format, 0);
308
}
288
if (ret < 0) {
309
}
289
error_setg_errno(errp, -ret, "ERROR: ext_backing_format: "
310
290
"Could not read format name");
311
@@ -XXX,XX +XXX,XX @@ static void detach_indirect_bh(void *opaque)
291
@@ -XXX,XX +XXX,XX @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
312
struct detach_by_parent_data *data = opaque;
292
case QCOW2_EXT_MAGIC_FEATURE_TABLE:
313
293
if (p_feature_table != NULL) {
314
bdrv_dec_in_flight(data->child_b->bs);
294
void *feature_table = g_malloc0(ext.len + 2 * sizeof(Qcow2Feature));
315
+
295
- ret = bdrv_pread(bs->file, offset, ext.len, feature_table, 0);
316
+ bdrv_graph_wrlock(NULL);
296
+ ret = bdrv_co_pread(bs->file, offset, ext.len, feature_table, 0);
317
bdrv_unref_child(data->parent_b, data->child_b);
297
if (ret < 0) {
318
298
error_setg_errno(errp, -ret, "ERROR: ext_feature_table: "
319
bdrv_ref(data->c);
299
"Could not read table");
320
- bdrv_graph_wrlock(NULL);
300
@@ -XXX,XX +XXX,XX @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
321
data->child_c = bdrv_attach_child(data->parent_b, data->c, "PB-C",
301
return -EINVAL;
322
&child_of_bds, BDRV_CHILD_DATA,
302
}
323
&error_abort);
303
304
- ret = bdrv_pread(bs->file, offset, ext.len, &s->crypto_header, 0);
305
+ ret = bdrv_co_pread(bs->file, offset, ext.len, &s->crypto_header, 0);
306
if (ret < 0) {
307
error_setg_errno(errp, -ret,
308
"Unable to read CRYPTO header extension");
309
@@ -XXX,XX +XXX,XX @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
310
break;
311
}
312
313
- ret = bdrv_pread(bs->file, offset, ext.len, &bitmaps_ext, 0);
314
+ ret = bdrv_co_pread(bs->file, offset, ext.len, &bitmaps_ext, 0);
315
if (ret < 0) {
316
error_setg_errno(errp, -ret, "bitmaps_ext: "
317
"Could not read ext header");
318
@@ -XXX,XX +XXX,XX @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
319
case QCOW2_EXT_MAGIC_DATA_FILE:
320
{
321
s->image_data_file = g_malloc0(ext.len + 1);
322
- ret = bdrv_pread(bs->file, offset, ext.len, s->image_data_file, 0);
323
+ ret = bdrv_co_pread(bs->file, offset, ext.len, s->image_data_file, 0);
324
if (ret < 0) {
325
error_setg_errno(errp, -ret,
326
"ERROR: Could not read data file name");
327
@@ -XXX,XX +XXX,XX @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
328
uext->len = ext.len;
329
QLIST_INSERT_HEAD(&s->unknown_header_ext, uext, next);
330
331
- ret = bdrv_pread(bs->file, offset, uext->len, uext->data, 0);
332
+ ret = bdrv_co_pread(bs->file, offset, uext->len, uext->data, 0);
333
if (ret < 0) {
334
error_setg_errno(errp, -ret, "ERROR: unknown extension: "
335
"Could not read data");
336
@@ -XXX,XX +XXX,XX @@ static void qcow2_update_options_abort(BlockDriverState *bs,
337
qapi_free_QCryptoBlockOpenOptions(r->crypto_opts);
338
}
339
340
-static int qcow2_update_options(BlockDriverState *bs, QDict *options,
341
- int flags, Error **errp)
342
+static int coroutine_fn
343
+qcow2_update_options(BlockDriverState *bs, QDict *options, int flags,
344
+ Error **errp)
345
{
346
Qcow2ReopenState r = {};
347
int ret;
348
--
324
--
349
2.40.0
325
2.41.0
diff view generated by jsdifflib
1
From: Wilfred Mallawa <wilfred.mallawa@wdc.com>
1
The functions read the parents list in the generic block layer, so we
2
need to hold the graph lock already there. The BlockDriver
3
implementations actually modify the graph, so it has to be a writer
4
lock.
2
5
3
Fixup a few minor typos
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
7
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
5
Signed-off-by: Wilfred Mallawa <wilfred.mallawa@wdc.com>
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
6
Message-Id: <20230313003744.55476-1-wilfred.mallawa@opensource.wdc.com>
9
Message-ID: <20230911094620.45040-22-kwolf@redhat.com>
7
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
8
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
11
---
11
include/block/aio-wait.h | 2 +-
12
include/block/block-global-state.h | 8 +++++---
12
include/block/block_int-common.h | 2 +-
13
include/block/block_int-common.h | 9 +++++----
13
2 files changed, 2 insertions(+), 2 deletions(-)
14
block/quorum.c | 23 ++++++-----------------
15
blockdev.c | 17 +++++++++++------
16
4 files changed, 27 insertions(+), 30 deletions(-)
14
17
15
diff --git a/include/block/aio-wait.h b/include/block/aio-wait.h
18
diff --git a/include/block/block-global-state.h b/include/block/block-global-state.h
16
index XXXXXXX..XXXXXXX 100644
19
index XXXXXXX..XXXXXXX 100644
17
--- a/include/block/aio-wait.h
20
--- a/include/block/block-global-state.h
18
+++ b/include/block/aio-wait.h
21
+++ b/include/block/block-global-state.h
19
@@ -XXX,XX +XXX,XX @@ extern AioWait global_aio_wait;
22
@@ -XXX,XX +XXX,XX @@ int bdrv_try_change_aio_context(BlockDriverState *bs, AioContext *ctx,
20
* @ctx: the aio context, or NULL if multiple aio contexts (for which the
23
int bdrv_probe_blocksizes(BlockDriverState *bs, BlockSizes *bsz);
21
* caller does not hold a lock) are involved in the polling condition.
24
int bdrv_probe_geometry(BlockDriverState *bs, HDGeometry *geo);
22
* @cond: wait while this conditional expression is true
25
23
- * @unlock: whether to unlock and then lock again @ctx. This apples
26
-void bdrv_add_child(BlockDriverState *parent, BlockDriverState *child,
24
+ * @unlock: whether to unlock and then lock again @ctx. This applies
27
- Error **errp);
25
* only when waiting for another AioContext from the main loop.
28
-void bdrv_del_child(BlockDriverState *parent, BdrvChild *child, Error **errp);
26
* Otherwise it's ignored.
29
+void GRAPH_WRLOCK
30
+bdrv_add_child(BlockDriverState *parent, BlockDriverState *child, Error **errp);
31
+
32
+void GRAPH_WRLOCK
33
+bdrv_del_child(BlockDriverState *parent, BdrvChild *child, Error **errp);
34
35
/**
27
*
36
*
28
diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
37
diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
29
index XXXXXXX..XXXXXXX 100644
38
index XXXXXXX..XXXXXXX 100644
30
--- a/include/block/block_int-common.h
39
--- a/include/block/block_int-common.h
31
+++ b/include/block/block_int-common.h
40
+++ b/include/block/block_int-common.h
32
@@ -XXX,XX +XXX,XX @@ extern QemuOptsList bdrv_create_opts_simple;
41
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
33
/*
42
*/
34
* Common functions that are neither I/O nor Global State.
43
int (*bdrv_probe_geometry)(BlockDriverState *bs, HDGeometry *geo);
35
*
44
36
- * See include/block/block-commmon.h for more information about
45
- void (*bdrv_add_child)(BlockDriverState *parent, BlockDriverState *child,
37
+ * See include/block/block-common.h for more information about
46
- Error **errp);
38
* the Common API.
47
- void (*bdrv_del_child)(BlockDriverState *parent, BdrvChild *child,
39
*/
48
- Error **errp);
40
49
+ void GRAPH_WRLOCK_PTR (*bdrv_add_child)(
50
+ BlockDriverState *parent, BlockDriverState *child, Error **errp);
51
+
52
+ void GRAPH_WRLOCK_PTR (*bdrv_del_child)(
53
+ BlockDriverState *parent, BdrvChild *child, Error **errp);
54
55
/**
56
* Informs the block driver that a permission change is intended. The
57
diff --git a/block/quorum.c b/block/quorum.c
58
index XXXXXXX..XXXXXXX 100644
59
--- a/block/quorum.c
60
+++ b/block/quorum.c
61
@@ -XXX,XX +XXX,XX @@ static void quorum_close(BlockDriverState *bs)
62
g_free(s->children);
63
}
64
65
-static void quorum_add_child(BlockDriverState *bs, BlockDriverState *child_bs,
66
- Error **errp)
67
+static void GRAPH_WRLOCK
68
+quorum_add_child(BlockDriverState *bs, BlockDriverState *child_bs, Error **errp)
69
{
70
BDRVQuorumState *s = bs->opaque;
71
BdrvChild *child;
72
@@ -XXX,XX +XXX,XX @@ static void quorum_add_child(BlockDriverState *bs, BlockDriverState *child_bs,
73
}
74
s->next_child_index++;
75
76
- bdrv_drained_begin(bs);
77
-
78
/* We can safely add the child now */
79
bdrv_ref(child_bs);
80
81
- bdrv_graph_wrlock(child_bs);
82
child = bdrv_attach_child(bs, child_bs, indexstr, &child_of_bds,
83
BDRV_CHILD_DATA, errp);
84
- bdrv_graph_wrunlock();
85
if (child == NULL) {
86
s->next_child_index--;
87
- goto out;
88
+ return;
89
}
90
s->children = g_renew(BdrvChild *, s->children, s->num_children + 1);
91
s->children[s->num_children++] = child;
92
quorum_refresh_flags(bs);
93
-
94
-out:
95
- bdrv_drained_end(bs);
96
}
97
98
-static void quorum_del_child(BlockDriverState *bs, BdrvChild *child,
99
- Error **errp)
100
+static void GRAPH_WRLOCK
101
+quorum_del_child(BlockDriverState *bs, BdrvChild *child, Error **errp)
102
{
103
BDRVQuorumState *s = bs->opaque;
104
char indexstr[INDEXSTR_LEN];
105
@@ -XXX,XX +XXX,XX @@ static void quorum_del_child(BlockDriverState *bs, BdrvChild *child,
106
s->next_child_index--;
107
}
108
109
- bdrv_drained_begin(bs);
110
-
111
/* We can safely remove this child now */
112
memmove(&s->children[i], &s->children[i + 1],
113
(s->num_children - i - 1) * sizeof(BdrvChild *));
114
s->children = g_renew(BdrvChild *, s->children, --s->num_children);
115
- bdrv_graph_wrlock(NULL);
116
+
117
bdrv_unref_child(bs, child);
118
- bdrv_graph_wrunlock();
119
120
quorum_refresh_flags(bs);
121
- bdrv_drained_end(bs);
122
}
123
124
static void quorum_gather_child_options(BlockDriverState *bs, QDict *target,
125
diff --git a/blockdev.c b/blockdev.c
126
index XXXXXXX..XXXXXXX 100644
127
--- a/blockdev.c
128
+++ b/blockdev.c
129
@@ -XXX,XX +XXX,XX @@ out:
130
aio_context_release(aio_context);
131
}
132
133
-static BdrvChild *bdrv_find_child(BlockDriverState *parent_bs,
134
- const char *child_name)
135
+static BdrvChild * GRAPH_RDLOCK
136
+bdrv_find_child(BlockDriverState *parent_bs, const char *child_name)
137
{
138
BdrvChild *child;
139
140
@@ -XXX,XX +XXX,XX @@ void qmp_x_blockdev_change(const char *parent, const char *child,
141
BlockDriverState *parent_bs, *new_bs = NULL;
142
BdrvChild *p_child;
143
144
+ bdrv_graph_wrlock(NULL);
145
+
146
parent_bs = bdrv_lookup_bs(parent, parent, errp);
147
if (!parent_bs) {
148
- return;
149
+ goto out;
150
}
151
152
if (!child == !node) {
153
@@ -XXX,XX +XXX,XX @@ void qmp_x_blockdev_change(const char *parent, const char *child,
154
} else {
155
error_setg(errp, "Either child or node must be specified");
156
}
157
- return;
158
+ goto out;
159
}
160
161
if (child) {
162
@@ -XXX,XX +XXX,XX @@ void qmp_x_blockdev_change(const char *parent, const char *child,
163
if (!p_child) {
164
error_setg(errp, "Node '%s' does not have child '%s'",
165
parent, child);
166
- return;
167
+ goto out;
168
}
169
bdrv_del_child(parent_bs, p_child, errp);
170
}
171
@@ -XXX,XX +XXX,XX @@ void qmp_x_blockdev_change(const char *parent, const char *child,
172
new_bs = bdrv_find_node(node);
173
if (!new_bs) {
174
error_setg(errp, "Node '%s' not found", node);
175
- return;
176
+ goto out;
177
}
178
bdrv_add_child(parent_bs, new_bs, errp);
179
}
180
+
181
+out:
182
+ bdrv_graph_wrunlock();
183
}
184
185
BlockJobInfoList *qmp_query_block_jobs(Error **errp)
41
--
186
--
42
2.40.0
187
2.41.0
43
44
diff view generated by jsdifflib
1
From: Paolo Bonzini <pbonzini@redhat.com>
1
From: Andrey Drobyshev via <qemu-block@nongnu.org>
2
2
3
Functions that can do I/O are prime candidates for being coroutine_fns. Make the
3
Functions qcow2_get_host_offset(), get_cluster_offset(),
4
change for the one that is itself called only from coroutine_fns. Unfortunately
4
vmdk_co_block_status() explicitly report compressed cluster types when data
5
vmdk does not use a coroutine_fn for the bulk of the open (like qcow2 does) so
5
is compressed. However, this information is never passed further. Let's
6
vmdk_read_cid cannot have the same treatment.
6
make use of it by adding new BDRV_BLOCK_COMPRESSED flag for
7
bdrv_block_status(), so that caller may know that the data range is
8
compressed. In particular, we're going to use this flag to tweak
9
"qemu-img map" output.
7
10
8
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
11
This new flag is only being utilized by qcow, qcow2 and vmdk formats, as only
9
Message-Id: <20230309084456.304669-10-pbonzini@redhat.com>
12
those support compression.
13
14
Reviewed-by: Denis V. Lunev <den@openvz.org>
15
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
16
Signed-off-by: Andrey Drobyshev <andrey.drobyshev@virtuozzo.com>
17
Message-ID: <20230907210226.953821-2-andrey.drobyshev@virtuozzo.com>
10
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
18
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
19
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
20
---
13
block/vmdk.c | 2 +-
21
include/block/block-common.h | 3 +++
14
1 file changed, 1 insertion(+), 1 deletion(-)
22
block/qcow.c | 5 ++++-
23
block/qcow2.c | 3 +++
24
block/vmdk.c | 2 ++
25
4 files changed, 12 insertions(+), 1 deletion(-)
15
26
27
diff --git a/include/block/block-common.h b/include/block/block-common.h
28
index XXXXXXX..XXXXXXX 100644
29
--- a/include/block/block-common.h
30
+++ b/include/block/block-common.h
31
@@ -XXX,XX +XXX,XX @@ typedef enum {
32
* layer rather than any backing, set by block layer
33
* BDRV_BLOCK_EOF: the returned pnum covers through end of file for this
34
* layer, set by block layer
35
+ * BDRV_BLOCK_COMPRESSED: the underlying data is compressed; only valid for
36
+ * the formats supporting compression: qcow, qcow2
37
*
38
* Internal flags:
39
* BDRV_BLOCK_RAW: for use by passthrough drivers, such as raw, to request
40
@@ -XXX,XX +XXX,XX @@ typedef enum {
41
#define BDRV_BLOCK_ALLOCATED 0x10
42
#define BDRV_BLOCK_EOF 0x20
43
#define BDRV_BLOCK_RECURSE 0x40
44
+#define BDRV_BLOCK_COMPRESSED 0x80
45
46
typedef QTAILQ_HEAD(BlockReopenQueue, BlockReopenQueueEntry) BlockReopenQueue;
47
48
diff --git a/block/qcow.c b/block/qcow.c
49
index XXXXXXX..XXXXXXX 100644
50
--- a/block/qcow.c
51
+++ b/block/qcow.c
52
@@ -XXX,XX +XXX,XX @@ qcow_co_block_status(BlockDriverState *bs, bool want_zero,
53
if (!cluster_offset) {
54
return 0;
55
}
56
- if ((cluster_offset & QCOW_OFLAG_COMPRESSED) || s->crypto) {
57
+ if (cluster_offset & QCOW_OFLAG_COMPRESSED) {
58
+ return BDRV_BLOCK_DATA | BDRV_BLOCK_COMPRESSED;
59
+ }
60
+ if (s->crypto) {
61
return BDRV_BLOCK_DATA;
62
}
63
*map = cluster_offset | index_in_cluster;
64
diff --git a/block/qcow2.c b/block/qcow2.c
65
index XXXXXXX..XXXXXXX 100644
66
--- a/block/qcow2.c
67
+++ b/block/qcow2.c
68
@@ -XXX,XX +XXX,XX @@ qcow2_co_block_status(BlockDriverState *bs, bool want_zero, int64_t offset,
69
{
70
status |= BDRV_BLOCK_RECURSE;
71
}
72
+ if (type == QCOW2_SUBCLUSTER_COMPRESSED) {
73
+ status |= BDRV_BLOCK_COMPRESSED;
74
+ }
75
return status;
76
}
77
16
diff --git a/block/vmdk.c b/block/vmdk.c
78
diff --git a/block/vmdk.c b/block/vmdk.c
17
index XXXXXXX..XXXXXXX 100644
79
index XXXXXXX..XXXXXXX 100644
18
--- a/block/vmdk.c
80
--- a/block/vmdk.c
19
+++ b/block/vmdk.c
81
+++ b/block/vmdk.c
20
@@ -XXX,XX +XXX,XX @@ out:
82
@@ -XXX,XX +XXX,XX @@ vmdk_co_block_status(BlockDriverState *bs, bool want_zero,
21
return ret;
83
if (extent->flat) {
22
}
84
ret |= BDRV_BLOCK_RECURSE;
23
85
}
24
-static int vmdk_is_cid_valid(BlockDriverState *bs)
86
+ } else {
25
+static int coroutine_fn vmdk_is_cid_valid(BlockDriverState *bs)
87
+ ret |= BDRV_BLOCK_COMPRESSED;
26
{
88
}
27
BDRVVmdkState *s = bs->opaque;
89
*file = extent->file->bs;
28
uint32_t cur_pcid;
90
break;
29
--
91
--
30
2.40.0
92
2.41.0
diff view generated by jsdifflib
1
From: Paolo Bonzini <pbonzini@redhat.com>
1
From: Andrey Drobyshev via <qemu-block@nongnu.org>
2
2
3
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
3
Right now "qemu-img map" reports compressed blocks as containing data
4
Message-Id: <20230309084456.304669-8-pbonzini@redhat.com>
4
but having no host offset. This is not very informative. Instead,
5
let's add another boolean field named "compressed" in case JSON output
6
mode is specified. This is achieved by utilizing new allocation status
7
flag BDRV_BLOCK_COMPRESSED for bdrv_block_status().
8
9
Also update the expected qemu-iotests outputs to contain the new field.
10
11
Signed-off-by: Andrey Drobyshev <andrey.drobyshev@virtuozzo.com>
12
Message-ID: <20230907210226.953821-3-andrey.drobyshev@virtuozzo.com>
5
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
13
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
---
15
---
8
tests/unit/test-thread-pool.c | 2 +-
16
qapi/block-core.json | 6 +-
9
1 file changed, 1 insertion(+), 1 deletion(-)
17
qemu-img.c | 8 +-
18
tests/qemu-iotests/122.out | 84 +-
19
tests/qemu-iotests/146.out | 780 +++++++++---------
20
tests/qemu-iotests/154.out | 194 ++---
21
tests/qemu-iotests/179.out | 178 ++--
22
tests/qemu-iotests/209.out | 4 +-
23
tests/qemu-iotests/221.out | 16 +-
24
tests/qemu-iotests/223.out | 60 +-
25
tests/qemu-iotests/241.out | 10 +-
26
tests/qemu-iotests/244.out | 24 +-
27
tests/qemu-iotests/252.out | 10 +-
28
tests/qemu-iotests/253.out | 20 +-
29
tests/qemu-iotests/274.out | 48 +-
30
.../tests/nbd-qemu-allocation.out | 16 +-
31
tests/qemu-iotests/tests/qemu-img-bitmaps.out | 24 +-
32
16 files changed, 744 insertions(+), 738 deletions(-)
10
33
11
diff --git a/tests/unit/test-thread-pool.c b/tests/unit/test-thread-pool.c
34
diff --git a/qapi/block-core.json b/qapi/block-core.json
12
index XXXXXXX..XXXXXXX 100644
35
index XXXXXXX..XXXXXXX 100644
13
--- a/tests/unit/test-thread-pool.c
36
--- a/qapi/block-core.json
14
+++ b/tests/unit/test-thread-pool.c
37
+++ b/qapi/block-core.json
15
@@ -XXX,XX +XXX,XX @@ static void test_submit_aio(void)
38
@@ -XXX,XX +XXX,XX @@
16
g_assert_cmpint(data.ret, ==, 0);
39
#
17
}
40
# @zero: whether the virtual blocks read as zeroes
18
41
#
19
-static void co_test_cb(void *opaque)
42
+# @compressed: true if the data is stored compressed (since 8.2)
20
+static void coroutine_fn co_test_cb(void *opaque)
43
+#
21
{
44
# @depth: number of layers (0 = top image, 1 = top image's backing
22
WorkerTestData *data = opaque;
45
# file, ..., n - 1 = bottom image (where n is the number of images
46
# in the chain)) before reaching one for which the range is
47
@@ -XXX,XX +XXX,XX @@
48
##
49
{ 'struct': 'MapEntry',
50
'data': {'start': 'int', 'length': 'int', 'data': 'bool',
51
- 'zero': 'bool', 'depth': 'int', 'present': 'bool',
52
- '*offset': 'int', '*filename': 'str' } }
53
+ 'zero': 'bool', 'compressed': 'bool', 'depth': 'int',
54
+ 'present': 'bool', '*offset': 'int', '*filename': 'str' } }
55
56
##
57
# @BlockdevCacheInfo:
58
diff --git a/qemu-img.c b/qemu-img.c
59
index XXXXXXX..XXXXXXX 100644
60
--- a/qemu-img.c
61
+++ b/qemu-img.c
62
@@ -XXX,XX +XXX,XX @@ static int dump_map_entry(OutputFormat output_format, MapEntry *e,
63
case OFORMAT_JSON:
64
printf("{ \"start\": %"PRId64", \"length\": %"PRId64","
65
" \"depth\": %"PRId64", \"present\": %s, \"zero\": %s,"
66
- " \"data\": %s", e->start, e->length, e->depth,
67
+ " \"data\": %s, \"compressed\": %s",
68
+ e->start, e->length, e->depth,
69
e->present ? "true" : "false",
70
e->zero ? "true" : "false",
71
- e->data ? "true" : "false");
72
+ e->data ? "true" : "false",
73
+ e->compressed ? "true" : "false");
74
if (e->has_offset) {
75
printf(", \"offset\": %"PRId64"", e->offset);
76
}
77
@@ -XXX,XX +XXX,XX @@ static int get_block_status(BlockDriverState *bs, int64_t offset,
78
.length = bytes,
79
.data = !!(ret & BDRV_BLOCK_DATA),
80
.zero = !!(ret & BDRV_BLOCK_ZERO),
81
+ .compressed = !!(ret & BDRV_BLOCK_COMPRESSED),
82
.offset = map,
83
.has_offset = has_offset,
84
.depth = depth,
85
@@ -XXX,XX +XXX,XX @@ static inline bool entry_mergeable(const MapEntry *curr, const MapEntry *next)
86
}
87
if (curr->zero != next->zero ||
88
curr->data != next->data ||
89
+ curr->compressed != next->compressed ||
90
curr->depth != next->depth ||
91
curr->present != next->present ||
92
!curr->filename != !next->filename ||
93
diff --git a/tests/qemu-iotests/122.out b/tests/qemu-iotests/122.out
94
index XXXXXXX..XXXXXXX 100644
95
--- a/tests/qemu-iotests/122.out
96
+++ b/tests/qemu-iotests/122.out
97
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 4194304
98
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
99
read 65536/65536 bytes at offset 8388608
100
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
101
-[{ "start": 0, "length": 65536, "depth": 0, "present": true, "zero": false, "data": true},
102
-{ "start": 65536, "length": 4128768, "depth": 0, "present": false, "zero": true, "data": false},
103
-{ "start": 4194304, "length": 65536, "depth": 0, "present": true, "zero": false, "data": true},
104
-{ "start": 4259840, "length": 4128768, "depth": 0, "present": false, "zero": true, "data": false},
105
-{ "start": 8388608, "length": 65536, "depth": 0, "present": true, "zero": false, "data": true},
106
-{ "start": 8454144, "length": 4128768, "depth": 0, "present": false, "zero": true, "data": false}]
107
+[{ "start": 0, "length": 65536, "depth": 0, "present": true, "zero": false, "data": true, "compressed": true},
108
+{ "start": 65536, "length": 4128768, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false},
109
+{ "start": 4194304, "length": 65536, "depth": 0, "present": true, "zero": false, "data": true, "compressed": true},
110
+{ "start": 4259840, "length": 4128768, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false},
111
+{ "start": 8388608, "length": 65536, "depth": 0, "present": true, "zero": false, "data": true, "compressed": true},
112
+{ "start": 8454144, "length": 4128768, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}]
113
read 65536/65536 bytes at offset 0
114
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
115
read 65536/65536 bytes at offset 4194304
116
@@ -XXX,XX +XXX,XX @@ wrote 1024/1024 bytes at offset 1046528
117
1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
118
wrote 1024/1024 bytes at offset 0
119
1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
120
-[{ "start": 0, "length": 65536, "depth": 0, "present": true, "zero": false, "data": true},
121
-{ "start": 65536, "length": 65536, "depth": 0, "present": false, "zero": true, "data": false},
122
-{ "start": 131072, "length": 196608, "depth": 0, "present": true, "zero": false, "data": true},
123
-{ "start": 327680, "length": 655360, "depth": 0, "present": false, "zero": true, "data": false},
124
-{ "start": 983040, "length": 65536, "depth": 0, "present": true, "zero": false, "data": true},
125
-{ "start": 1048576, "length": 1046528, "depth": 0, "present": false, "zero": true, "data": false}]
126
+[{ "start": 0, "length": 65536, "depth": 0, "present": true, "zero": false, "data": true, "compressed": true},
127
+{ "start": 65536, "length": 65536, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false},
128
+{ "start": 131072, "length": 196608, "depth": 0, "present": true, "zero": false, "data": true, "compressed": true},
129
+{ "start": 327680, "length": 655360, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false},
130
+{ "start": 983040, "length": 65536, "depth": 0, "present": true, "zero": false, "data": true, "compressed": true},
131
+{ "start": 1048576, "length": 1046528, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}]
132
read 16384/16384 bytes at offset 0
133
16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
134
read 16384/16384 bytes at offset 16384
135
@@ -XXX,XX +XXX,XX @@ read 3145728/3145728 bytes at offset 0
136
3 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
137
read 63963136/63963136 bytes at offset 3145728
138
61 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
139
-[{ "start": 0, "length": 67108864, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}]
140
+[{ "start": 0, "length": 67108864, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}]
141
142
convert -c -S 0:
143
read 3145728/3145728 bytes at offset 0
144
3 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
145
read 63963136/63963136 bytes at offset 3145728
146
61 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
147
-[{ "start": 0, "length": 67108864, "depth": 0, "present": true, "zero": false, "data": true}]
148
+[{ "start": 0, "length": 67108864, "depth": 0, "present": true, "zero": false, "data": true, "compressed": true}]
149
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864
150
wrote 33554432/33554432 bytes at offset 0
151
32 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
152
@@ -XXX,XX +XXX,XX @@ read 30408704/30408704 bytes at offset 3145728
153
29 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
154
read 33554432/33554432 bytes at offset 33554432
155
32 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
156
-[{ "start": 0, "length": 67108864, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}]
157
+[{ "start": 0, "length": 67108864, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}]
158
159
convert -c -S 0 with source backing file:
160
read 3145728/3145728 bytes at offset 0
161
@@ -XXX,XX +XXX,XX @@ read 30408704/30408704 bytes at offset 3145728
162
29 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
163
read 33554432/33554432 bytes at offset 33554432
164
32 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
165
-[{ "start": 0, "length": 67108864, "depth": 0, "present": true, "zero": false, "data": true}]
166
+[{ "start": 0, "length": 67108864, "depth": 0, "present": true, "zero": false, "data": true, "compressed": true}]
167
168
convert -S 0 -B ...
169
read 3145728/3145728 bytes at offset 0
170
@@ -XXX,XX +XXX,XX @@ read 30408704/30408704 bytes at offset 3145728
171
29 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
172
read 33554432/33554432 bytes at offset 33554432
173
32 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
174
-[{ "start": 0, "length": 67108864, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}]
175
+[{ "start": 0, "length": 67108864, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}]
176
177
convert -c -S 0 -B ...
178
read 3145728/3145728 bytes at offset 0
179
@@ -XXX,XX +XXX,XX @@ read 30408704/30408704 bytes at offset 3145728
180
29 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
181
read 33554432/33554432 bytes at offset 33554432
182
32 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
183
-[{ "start": 0, "length": 67108864, "depth": 0, "present": true, "zero": false, "data": true}]
184
+[{ "start": 0, "length": 67108864, "depth": 0, "present": true, "zero": false, "data": true, "compressed": true}]
185
186
=== Non-zero -S ===
187
188
@@ -XXX,XX +XXX,XX @@ wrote 1024/1024 bytes at offset 66560
189
1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
190
191
convert -S 4k
192
-[{ "start": 0, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
193
-{ "start": 4096, "length": 4096, "depth": 0, "present": false, "zero": true, "data": false},
194
-{ "start": 8192, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
195
-{ "start": 12288, "length": 4096, "depth": 0, "present": false, "zero": true, "data": false},
196
-{ "start": 16384, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
197
-{ "start": 20480, "length": 67088384, "depth": 0, "present": false, "zero": true, "data": false}]
198
+[{ "start": 0, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
199
+{ "start": 4096, "length": 4096, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false},
200
+{ "start": 8192, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
201
+{ "start": 12288, "length": 4096, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false},
202
+{ "start": 16384, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
203
+{ "start": 20480, "length": 67088384, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}]
204
205
convert -c -S 4k
206
-[{ "start": 0, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true},
207
-{ "start": 1024, "length": 7168, "depth": 0, "present": false, "zero": true, "data": false},
208
-{ "start": 8192, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true},
209
-{ "start": 9216, "length": 8192, "depth": 0, "present": false, "zero": true, "data": false},
210
-{ "start": 17408, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true},
211
-{ "start": 18432, "length": 67090432, "depth": 0, "present": false, "zero": true, "data": false}]
212
+[{ "start": 0, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true, "compressed": true},
213
+{ "start": 1024, "length": 7168, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false},
214
+{ "start": 8192, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true, "compressed": true},
215
+{ "start": 9216, "length": 8192, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false},
216
+{ "start": 17408, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true, "compressed": true},
217
+{ "start": 18432, "length": 67090432, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}]
218
219
convert -S 8k
220
-[{ "start": 0, "length": 24576, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
221
-{ "start": 24576, "length": 67084288, "depth": 0, "present": false, "zero": true, "data": false}]
222
+[{ "start": 0, "length": 24576, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
223
+{ "start": 24576, "length": 67084288, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}]
224
225
convert -c -S 8k
226
-[{ "start": 0, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true},
227
-{ "start": 1024, "length": 7168, "depth": 0, "present": false, "zero": true, "data": false},
228
-{ "start": 8192, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true},
229
-{ "start": 9216, "length": 8192, "depth": 0, "present": false, "zero": true, "data": false},
230
-{ "start": 17408, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true},
231
-{ "start": 18432, "length": 67090432, "depth": 0, "present": false, "zero": true, "data": false}]
232
+[{ "start": 0, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true, "compressed": true},
233
+{ "start": 1024, "length": 7168, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false},
234
+{ "start": 8192, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true, "compressed": true},
235
+{ "start": 9216, "length": 8192, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false},
236
+{ "start": 17408, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true, "compressed": true},
237
+{ "start": 18432, "length": 67090432, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}]
238
239
=== -n to a non-zero image ===
240
241
@@ -XXX,XX +XXX,XX @@ Images are identical.
242
243
Formatting 'TEST_DIR/t.IMGFMT.orig', fmt=IMGFMT size=67108864
244
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
245
-[{ "start": 0, "length": 67108864, "depth": 0, "present": true, "zero": true, "data": false}]
246
+[{ "start": 0, "length": 67108864, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}]
247
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
248
-[{ "start": 0, "length": 67108864, "depth": 0, "present": false, "zero": true, "data": false}]
249
+[{ "start": 0, "length": 67108864, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}]
250
251
=== -n to an empty image with a backing file ===
252
253
Formatting 'TEST_DIR/t.IMGFMT.orig', fmt=IMGFMT size=67108864
254
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864
255
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT
256
-[{ "start": 0, "length": 67108864, "depth": 0, "present": true, "zero": true, "data": false}]
257
+[{ "start": 0, "length": 67108864, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}]
258
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT
259
-[{ "start": 0, "length": 67108864, "depth": 0, "present": true, "zero": false, "data": true, "offset": 327680}]
260
+[{ "start": 0, "length": 67108864, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": 327680}]
261
262
=== -n -B to an image without a backing file ===
263
264
diff --git a/tests/qemu-iotests/146.out b/tests/qemu-iotests/146.out
265
index XXXXXXX..XXXXXXX 100644
266
--- a/tests/qemu-iotests/146.out
267
+++ b/tests/qemu-iotests/146.out
268
@@ -XXX,XX +XXX,XX @@ QA output created by 146
269
270
=== Testing VPC Autodetect ===
271
272
-[{ "start": 0, "length": 136363130880, "depth": 0, "present": true, "zero": true, "data": false}]
273
+[{ "start": 0, "length": 136363130880, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}]
274
275
=== Testing VPC with current_size force ===
276
277
-[{ "start": 0, "length": 136365211648, "depth": 0, "present": true, "zero": true, "data": false}]
278
+[{ "start": 0, "length": 136365211648, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}]
279
280
=== Testing VPC with chs force ===
281
282
-[{ "start": 0, "length": 136363130880, "depth": 0, "present": true, "zero": true, "data": false}]
283
+[{ "start": 0, "length": 136363130880, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}]
284
285
=== Testing Hyper-V Autodetect ===
286
287
-[{ "start": 0, "length": 136365211648, "depth": 0, "present": true, "zero": true, "data": false}]
288
+[{ "start": 0, "length": 136365211648, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}]
289
290
=== Testing Hyper-V with current_size force ===
291
292
-[{ "start": 0, "length": 136365211648, "depth": 0, "present": true, "zero": true, "data": false}]
293
+[{ "start": 0, "length": 136365211648, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}]
294
295
=== Testing Hyper-V with chs force ===
296
297
-[{ "start": 0, "length": 136363130880, "depth": 0, "present": true, "zero": true, "data": false}]
298
+[{ "start": 0, "length": 136363130880, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}]
299
300
=== Testing d2v Autodetect ===
301
302
-[{ "start": 0, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
303
-{ "start": 2097152, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
304
-{ "start": 4194304, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
305
-{ "start": 6291456, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
306
-{ "start": 8388608, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
307
-{ "start": 10485760, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
308
-{ "start": 12582912, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
309
-{ "start": 14680064, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
310
-{ "start": 16777216, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
311
-{ "start": 18874368, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
312
-{ "start": 20971520, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
313
-{ "start": 23068672, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
314
-{ "start": 25165824, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
315
-{ "start": 27262976, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
316
-{ "start": 29360128, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
317
-{ "start": 31457280, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
318
-{ "start": 33554432, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
319
-{ "start": 35651584, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
320
-{ "start": 37748736, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
321
-{ "start": 39845888, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
322
-{ "start": 41943040, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
323
-{ "start": 44040192, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
324
-{ "start": 46137344, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
325
-{ "start": 48234496, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
326
-{ "start": 50331648, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
327
-{ "start": 52428800, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
328
-{ "start": 54525952, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
329
-{ "start": 56623104, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
330
-{ "start": 58720256, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
331
-{ "start": 60817408, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
332
-{ "start": 62914560, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
333
-{ "start": 65011712, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
334
-{ "start": 67108864, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
335
-{ "start": 69206016, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
336
-{ "start": 71303168, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
337
-{ "start": 73400320, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
338
-{ "start": 75497472, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
339
-{ "start": 77594624, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
340
-{ "start": 79691776, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
341
-{ "start": 81788928, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
342
-{ "start": 83886080, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
343
-{ "start": 85983232, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
344
-{ "start": 88080384, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
345
-{ "start": 90177536, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
346
-{ "start": 92274688, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
347
-{ "start": 94371840, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
348
-{ "start": 96468992, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
349
-{ "start": 98566144, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
350
-{ "start": 100663296, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
351
-{ "start": 102760448, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
352
-{ "start": 104857600, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
353
-{ "start": 106954752, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
354
-{ "start": 109051904, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
355
-{ "start": 111149056, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
356
-{ "start": 113246208, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
357
-{ "start": 115343360, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
358
-{ "start": 117440512, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
359
-{ "start": 119537664, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
360
-{ "start": 121634816, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
361
-{ "start": 123731968, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
362
-{ "start": 125829120, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
363
-{ "start": 127926272, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
364
-{ "start": 130023424, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
365
-{ "start": 132120576, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
366
-{ "start": 134217728, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
367
-{ "start": 136314880, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
368
-{ "start": 138412032, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
369
-{ "start": 140509184, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
370
-{ "start": 142606336, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
371
-{ "start": 144703488, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
372
-{ "start": 146800640, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
373
-{ "start": 148897792, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
374
-{ "start": 150994944, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
375
-{ "start": 153092096, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
376
-{ "start": 155189248, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
377
-{ "start": 157286400, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
378
-{ "start": 159383552, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
379
-{ "start": 161480704, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
380
-{ "start": 163577856, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
381
-{ "start": 165675008, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
382
-{ "start": 167772160, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
383
-{ "start": 169869312, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
384
-{ "start": 171966464, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
385
-{ "start": 174063616, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
386
-{ "start": 176160768, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
387
-{ "start": 178257920, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
388
-{ "start": 180355072, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
389
-{ "start": 182452224, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
390
-{ "start": 184549376, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
391
-{ "start": 186646528, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
392
-{ "start": 188743680, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
393
-{ "start": 190840832, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
394
-{ "start": 192937984, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
395
-{ "start": 195035136, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
396
-{ "start": 197132288, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
397
-{ "start": 199229440, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
398
-{ "start": 201326592, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
399
-{ "start": 203423744, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
400
-{ "start": 205520896, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
401
-{ "start": 207618048, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
402
-{ "start": 209715200, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
403
-{ "start": 211812352, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
404
-{ "start": 213909504, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
405
-{ "start": 216006656, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
406
-{ "start": 218103808, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
407
-{ "start": 220200960, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
408
-{ "start": 222298112, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
409
-{ "start": 224395264, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
410
-{ "start": 226492416, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
411
-{ "start": 228589568, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
412
-{ "start": 230686720, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
413
-{ "start": 232783872, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
414
-{ "start": 234881024, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
415
-{ "start": 236978176, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
416
-{ "start": 239075328, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
417
-{ "start": 241172480, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
418
-{ "start": 243269632, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
419
-{ "start": 245366784, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
420
-{ "start": 247463936, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
421
-{ "start": 249561088, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
422
-{ "start": 251658240, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
423
-{ "start": 253755392, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
424
-{ "start": 255852544, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
425
-{ "start": 257949696, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
426
-{ "start": 260046848, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
427
-{ "start": 262144000, "length": 1310720, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}]
428
+[{ "start": 0, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
429
+{ "start": 2097152, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
430
+{ "start": 4194304, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
431
+{ "start": 6291456, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
432
+{ "start": 8388608, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
433
+{ "start": 10485760, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
434
+{ "start": 12582912, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
435
+{ "start": 14680064, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
436
+{ "start": 16777216, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
437
+{ "start": 18874368, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
438
+{ "start": 20971520, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
439
+{ "start": 23068672, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
440
+{ "start": 25165824, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
441
+{ "start": 27262976, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
442
+{ "start": 29360128, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
443
+{ "start": 31457280, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
444
+{ "start": 33554432, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
445
+{ "start": 35651584, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
446
+{ "start": 37748736, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
447
+{ "start": 39845888, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
448
+{ "start": 41943040, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
449
+{ "start": 44040192, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
450
+{ "start": 46137344, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
451
+{ "start": 48234496, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
452
+{ "start": 50331648, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
453
+{ "start": 52428800, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
454
+{ "start": 54525952, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
455
+{ "start": 56623104, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
456
+{ "start": 58720256, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
457
+{ "start": 60817408, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
458
+{ "start": 62914560, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
459
+{ "start": 65011712, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
460
+{ "start": 67108864, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
461
+{ "start": 69206016, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
462
+{ "start": 71303168, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
463
+{ "start": 73400320, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
464
+{ "start": 75497472, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
465
+{ "start": 77594624, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
466
+{ "start": 79691776, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
467
+{ "start": 81788928, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
468
+{ "start": 83886080, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
469
+{ "start": 85983232, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
470
+{ "start": 88080384, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
471
+{ "start": 90177536, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
472
+{ "start": 92274688, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
473
+{ "start": 94371840, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
474
+{ "start": 96468992, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
475
+{ "start": 98566144, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
476
+{ "start": 100663296, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
477
+{ "start": 102760448, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
478
+{ "start": 104857600, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
479
+{ "start": 106954752, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
480
+{ "start": 109051904, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
481
+{ "start": 111149056, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
482
+{ "start": 113246208, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
483
+{ "start": 115343360, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
484
+{ "start": 117440512, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
485
+{ "start": 119537664, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
486
+{ "start": 121634816, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
487
+{ "start": 123731968, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
488
+{ "start": 125829120, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
489
+{ "start": 127926272, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
490
+{ "start": 130023424, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
491
+{ "start": 132120576, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
492
+{ "start": 134217728, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
493
+{ "start": 136314880, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
494
+{ "start": 138412032, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
495
+{ "start": 140509184, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
496
+{ "start": 142606336, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
497
+{ "start": 144703488, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
498
+{ "start": 146800640, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
499
+{ "start": 148897792, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
500
+{ "start": 150994944, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
501
+{ "start": 153092096, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
502
+{ "start": 155189248, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
503
+{ "start": 157286400, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
504
+{ "start": 159383552, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
505
+{ "start": 161480704, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
506
+{ "start": 163577856, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
507
+{ "start": 165675008, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
508
+{ "start": 167772160, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
509
+{ "start": 169869312, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
510
+{ "start": 171966464, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
511
+{ "start": 174063616, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
512
+{ "start": 176160768, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
513
+{ "start": 178257920, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
514
+{ "start": 180355072, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
515
+{ "start": 182452224, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
516
+{ "start": 184549376, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
517
+{ "start": 186646528, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
518
+{ "start": 188743680, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
519
+{ "start": 190840832, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
520
+{ "start": 192937984, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
521
+{ "start": 195035136, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
522
+{ "start": 197132288, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
523
+{ "start": 199229440, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
524
+{ "start": 201326592, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
525
+{ "start": 203423744, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
526
+{ "start": 205520896, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
527
+{ "start": 207618048, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
528
+{ "start": 209715200, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
529
+{ "start": 211812352, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
530
+{ "start": 213909504, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
531
+{ "start": 216006656, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
532
+{ "start": 218103808, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
533
+{ "start": 220200960, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
534
+{ "start": 222298112, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
535
+{ "start": 224395264, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
536
+{ "start": 226492416, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
537
+{ "start": 228589568, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
538
+{ "start": 230686720, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
539
+{ "start": 232783872, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
540
+{ "start": 234881024, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
541
+{ "start": 236978176, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
542
+{ "start": 239075328, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
543
+{ "start": 241172480, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
544
+{ "start": 243269632, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
545
+{ "start": 245366784, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
546
+{ "start": 247463936, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
547
+{ "start": 249561088, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
548
+{ "start": 251658240, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
549
+{ "start": 253755392, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
550
+{ "start": 255852544, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
551
+{ "start": 257949696, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
552
+{ "start": 260046848, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
553
+{ "start": 262144000, "length": 1310720, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}]
554
555
=== Testing d2v with current_size force ===
556
557
-[{ "start": 0, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
558
-{ "start": 2097152, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
559
-{ "start": 4194304, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
560
-{ "start": 6291456, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
561
-{ "start": 8388608, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
562
-{ "start": 10485760, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
563
-{ "start": 12582912, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
564
-{ "start": 14680064, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
565
-{ "start": 16777216, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
566
-{ "start": 18874368, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
567
-{ "start": 20971520, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
568
-{ "start": 23068672, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
569
-{ "start": 25165824, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
570
-{ "start": 27262976, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
571
-{ "start": 29360128, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
572
-{ "start": 31457280, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
573
-{ "start": 33554432, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
574
-{ "start": 35651584, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
575
-{ "start": 37748736, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
576
-{ "start": 39845888, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
577
-{ "start": 41943040, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
578
-{ "start": 44040192, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
579
-{ "start": 46137344, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
580
-{ "start": 48234496, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
581
-{ "start": 50331648, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
582
-{ "start": 52428800, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
583
-{ "start": 54525952, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
584
-{ "start": 56623104, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
585
-{ "start": 58720256, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
586
-{ "start": 60817408, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
587
-{ "start": 62914560, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
588
-{ "start": 65011712, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
589
-{ "start": 67108864, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
590
-{ "start": 69206016, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
591
-{ "start": 71303168, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
592
-{ "start": 73400320, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
593
-{ "start": 75497472, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
594
-{ "start": 77594624, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
595
-{ "start": 79691776, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
596
-{ "start": 81788928, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
597
-{ "start": 83886080, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
598
-{ "start": 85983232, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
599
-{ "start": 88080384, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
600
-{ "start": 90177536, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
601
-{ "start": 92274688, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
602
-{ "start": 94371840, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
603
-{ "start": 96468992, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
604
-{ "start": 98566144, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
605
-{ "start": 100663296, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
606
-{ "start": 102760448, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
607
-{ "start": 104857600, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
608
-{ "start": 106954752, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
609
-{ "start": 109051904, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
610
-{ "start": 111149056, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
611
-{ "start": 113246208, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
612
-{ "start": 115343360, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
613
-{ "start": 117440512, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
614
-{ "start": 119537664, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
615
-{ "start": 121634816, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
616
-{ "start": 123731968, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
617
-{ "start": 125829120, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
618
-{ "start": 127926272, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
619
-{ "start": 130023424, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
620
-{ "start": 132120576, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
621
-{ "start": 134217728, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
622
-{ "start": 136314880, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
623
-{ "start": 138412032, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
624
-{ "start": 140509184, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
625
-{ "start": 142606336, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
626
-{ "start": 144703488, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
627
-{ "start": 146800640, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
628
-{ "start": 148897792, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
629
-{ "start": 150994944, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
630
-{ "start": 153092096, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
631
-{ "start": 155189248, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
632
-{ "start": 157286400, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
633
-{ "start": 159383552, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
634
-{ "start": 161480704, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
635
-{ "start": 163577856, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
636
-{ "start": 165675008, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
637
-{ "start": 167772160, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
638
-{ "start": 169869312, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
639
-{ "start": 171966464, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
640
-{ "start": 174063616, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
641
-{ "start": 176160768, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
642
-{ "start": 178257920, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
643
-{ "start": 180355072, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
644
-{ "start": 182452224, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
645
-{ "start": 184549376, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
646
-{ "start": 186646528, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
647
-{ "start": 188743680, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
648
-{ "start": 190840832, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
649
-{ "start": 192937984, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
650
-{ "start": 195035136, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
651
-{ "start": 197132288, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
652
-{ "start": 199229440, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
653
-{ "start": 201326592, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
654
-{ "start": 203423744, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
655
-{ "start": 205520896, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
656
-{ "start": 207618048, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
657
-{ "start": 209715200, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
658
-{ "start": 211812352, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
659
-{ "start": 213909504, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
660
-{ "start": 216006656, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
661
-{ "start": 218103808, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
662
-{ "start": 220200960, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
663
-{ "start": 222298112, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
664
-{ "start": 224395264, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
665
-{ "start": 226492416, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
666
-{ "start": 228589568, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
667
-{ "start": 230686720, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
668
-{ "start": 232783872, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
669
-{ "start": 234881024, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
670
-{ "start": 236978176, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
671
-{ "start": 239075328, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
672
-{ "start": 241172480, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
673
-{ "start": 243269632, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
674
-{ "start": 245366784, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
675
-{ "start": 247463936, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
676
-{ "start": 249561088, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
677
-{ "start": 251658240, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
678
-{ "start": 253755392, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
679
-{ "start": 255852544, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
680
-{ "start": 257949696, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
681
-{ "start": 260046848, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
682
-{ "start": 262144000, "length": 1310720, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}]
683
+[{ "start": 0, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
684
+{ "start": 2097152, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
685
+{ "start": 4194304, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
686
+{ "start": 6291456, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
687
+{ "start": 8388608, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
688
+{ "start": 10485760, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
689
+{ "start": 12582912, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
690
+{ "start": 14680064, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
691
+{ "start": 16777216, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
692
+{ "start": 18874368, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
693
+{ "start": 20971520, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
694
+{ "start": 23068672, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
695
+{ "start": 25165824, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
696
+{ "start": 27262976, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
697
+{ "start": 29360128, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
698
+{ "start": 31457280, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
699
+{ "start": 33554432, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
700
+{ "start": 35651584, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
701
+{ "start": 37748736, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
702
+{ "start": 39845888, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
703
+{ "start": 41943040, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
704
+{ "start": 44040192, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
705
+{ "start": 46137344, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
706
+{ "start": 48234496, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
707
+{ "start": 50331648, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
708
+{ "start": 52428800, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
709
+{ "start": 54525952, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
710
+{ "start": 56623104, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
711
+{ "start": 58720256, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
712
+{ "start": 60817408, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
713
+{ "start": 62914560, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
714
+{ "start": 65011712, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
715
+{ "start": 67108864, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
716
+{ "start": 69206016, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
717
+{ "start": 71303168, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
718
+{ "start": 73400320, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
719
+{ "start": 75497472, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
720
+{ "start": 77594624, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
721
+{ "start": 79691776, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
722
+{ "start": 81788928, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
723
+{ "start": 83886080, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
724
+{ "start": 85983232, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
725
+{ "start": 88080384, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
726
+{ "start": 90177536, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
727
+{ "start": 92274688, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
728
+{ "start": 94371840, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
729
+{ "start": 96468992, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
730
+{ "start": 98566144, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
731
+{ "start": 100663296, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
732
+{ "start": 102760448, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
733
+{ "start": 104857600, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
734
+{ "start": 106954752, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
735
+{ "start": 109051904, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
736
+{ "start": 111149056, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
737
+{ "start": 113246208, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
738
+{ "start": 115343360, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
739
+{ "start": 117440512, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
740
+{ "start": 119537664, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
741
+{ "start": 121634816, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
742
+{ "start": 123731968, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
743
+{ "start": 125829120, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
744
+{ "start": 127926272, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
745
+{ "start": 130023424, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
746
+{ "start": 132120576, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
747
+{ "start": 134217728, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
748
+{ "start": 136314880, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
749
+{ "start": 138412032, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
750
+{ "start": 140509184, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
751
+{ "start": 142606336, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
752
+{ "start": 144703488, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
753
+{ "start": 146800640, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
754
+{ "start": 148897792, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
755
+{ "start": 150994944, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
756
+{ "start": 153092096, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
757
+{ "start": 155189248, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
758
+{ "start": 157286400, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
759
+{ "start": 159383552, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
760
+{ "start": 161480704, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
761
+{ "start": 163577856, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
762
+{ "start": 165675008, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
763
+{ "start": 167772160, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
764
+{ "start": 169869312, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
765
+{ "start": 171966464, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
766
+{ "start": 174063616, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
767
+{ "start": 176160768, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
768
+{ "start": 178257920, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
769
+{ "start": 180355072, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
770
+{ "start": 182452224, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
771
+{ "start": 184549376, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
772
+{ "start": 186646528, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
773
+{ "start": 188743680, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
774
+{ "start": 190840832, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
775
+{ "start": 192937984, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
776
+{ "start": 195035136, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
777
+{ "start": 197132288, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
778
+{ "start": 199229440, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
779
+{ "start": 201326592, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
780
+{ "start": 203423744, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
781
+{ "start": 205520896, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
782
+{ "start": 207618048, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
783
+{ "start": 209715200, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
784
+{ "start": 211812352, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
785
+{ "start": 213909504, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
786
+{ "start": 216006656, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
787
+{ "start": 218103808, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
788
+{ "start": 220200960, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
789
+{ "start": 222298112, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
790
+{ "start": 224395264, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
791
+{ "start": 226492416, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
792
+{ "start": 228589568, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
793
+{ "start": 230686720, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
794
+{ "start": 232783872, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
795
+{ "start": 234881024, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
796
+{ "start": 236978176, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
797
+{ "start": 239075328, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
798
+{ "start": 241172480, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
799
+{ "start": 243269632, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
800
+{ "start": 245366784, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
801
+{ "start": 247463936, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
802
+{ "start": 249561088, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
803
+{ "start": 251658240, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
804
+{ "start": 253755392, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
805
+{ "start": 255852544, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
806
+{ "start": 257949696, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
807
+{ "start": 260046848, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
808
+{ "start": 262144000, "length": 1310720, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}]
809
810
=== Testing d2v with chs force ===
811
812
-[{ "start": 0, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
813
-{ "start": 2097152, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
814
-{ "start": 4194304, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
815
-{ "start": 6291456, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
816
-{ "start": 8388608, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
817
-{ "start": 10485760, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
818
-{ "start": 12582912, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
819
-{ "start": 14680064, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
820
-{ "start": 16777216, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
821
-{ "start": 18874368, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
822
-{ "start": 20971520, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
823
-{ "start": 23068672, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
824
-{ "start": 25165824, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
825
-{ "start": 27262976, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
826
-{ "start": 29360128, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
827
-{ "start": 31457280, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
828
-{ "start": 33554432, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
829
-{ "start": 35651584, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
830
-{ "start": 37748736, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
831
-{ "start": 39845888, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
832
-{ "start": 41943040, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
833
-{ "start": 44040192, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
834
-{ "start": 46137344, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
835
-{ "start": 48234496, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
836
-{ "start": 50331648, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
837
-{ "start": 52428800, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
838
-{ "start": 54525952, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
839
-{ "start": 56623104, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
840
-{ "start": 58720256, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
841
-{ "start": 60817408, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
842
-{ "start": 62914560, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
843
-{ "start": 65011712, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
844
-{ "start": 67108864, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
845
-{ "start": 69206016, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
846
-{ "start": 71303168, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
847
-{ "start": 73400320, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
848
-{ "start": 75497472, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
849
-{ "start": 77594624, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
850
-{ "start": 79691776, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
851
-{ "start": 81788928, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
852
-{ "start": 83886080, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
853
-{ "start": 85983232, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
854
-{ "start": 88080384, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
855
-{ "start": 90177536, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
856
-{ "start": 92274688, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
857
-{ "start": 94371840, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
858
-{ "start": 96468992, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
859
-{ "start": 98566144, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
860
-{ "start": 100663296, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
861
-{ "start": 102760448, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
862
-{ "start": 104857600, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
863
-{ "start": 106954752, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
864
-{ "start": 109051904, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
865
-{ "start": 111149056, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
866
-{ "start": 113246208, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
867
-{ "start": 115343360, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
868
-{ "start": 117440512, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
869
-{ "start": 119537664, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
870
-{ "start": 121634816, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
871
-{ "start": 123731968, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
872
-{ "start": 125829120, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
873
-{ "start": 127926272, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
874
-{ "start": 130023424, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
875
-{ "start": 132120576, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
876
-{ "start": 134217728, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
877
-{ "start": 136314880, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
878
-{ "start": 138412032, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
879
-{ "start": 140509184, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
880
-{ "start": 142606336, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
881
-{ "start": 144703488, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
882
-{ "start": 146800640, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
883
-{ "start": 148897792, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
884
-{ "start": 150994944, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
885
-{ "start": 153092096, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
886
-{ "start": 155189248, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
887
-{ "start": 157286400, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
888
-{ "start": 159383552, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
889
-{ "start": 161480704, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
890
-{ "start": 163577856, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
891
-{ "start": 165675008, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
892
-{ "start": 167772160, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
893
-{ "start": 169869312, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
894
-{ "start": 171966464, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
895
-{ "start": 174063616, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
896
-{ "start": 176160768, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
897
-{ "start": 178257920, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
898
-{ "start": 180355072, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
899
-{ "start": 182452224, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
900
-{ "start": 184549376, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
901
-{ "start": 186646528, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
902
-{ "start": 188743680, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
903
-{ "start": 190840832, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
904
-{ "start": 192937984, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
905
-{ "start": 195035136, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
906
-{ "start": 197132288, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
907
-{ "start": 199229440, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
908
-{ "start": 201326592, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
909
-{ "start": 203423744, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
910
-{ "start": 205520896, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
911
-{ "start": 207618048, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
912
-{ "start": 209715200, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
913
-{ "start": 211812352, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
914
-{ "start": 213909504, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
915
-{ "start": 216006656, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
916
-{ "start": 218103808, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
917
-{ "start": 220200960, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
918
-{ "start": 222298112, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
919
-{ "start": 224395264, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
920
-{ "start": 226492416, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
921
-{ "start": 228589568, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
922
-{ "start": 230686720, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
923
-{ "start": 232783872, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
924
-{ "start": 234881024, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
925
-{ "start": 236978176, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
926
-{ "start": 239075328, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
927
-{ "start": 241172480, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
928
-{ "start": 243269632, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
929
-{ "start": 245366784, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
930
-{ "start": 247463936, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
931
-{ "start": 249561088, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
932
-{ "start": 251658240, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
933
-{ "start": 253755392, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
934
-{ "start": 255852544, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
935
-{ "start": 257949696, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
936
-{ "start": 260046848, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
937
-{ "start": 262144000, "length": 1310720, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}]
938
+[{ "start": 0, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
939
+{ "start": 2097152, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
940
+{ "start": 4194304, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
941
+{ "start": 6291456, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
942
+{ "start": 8388608, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
943
+{ "start": 10485760, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
944
+{ "start": 12582912, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
945
+{ "start": 14680064, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
946
+{ "start": 16777216, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
947
+{ "start": 18874368, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
948
+{ "start": 20971520, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
949
+{ "start": 23068672, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
950
+{ "start": 25165824, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
951
+{ "start": 27262976, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
952
+{ "start": 29360128, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
953
+{ "start": 31457280, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
954
+{ "start": 33554432, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
955
+{ "start": 35651584, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
956
+{ "start": 37748736, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
957
+{ "start": 39845888, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
958
+{ "start": 41943040, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
959
+{ "start": 44040192, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
960
+{ "start": 46137344, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
961
+{ "start": 48234496, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
962
+{ "start": 50331648, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
963
+{ "start": 52428800, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
964
+{ "start": 54525952, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
965
+{ "start": 56623104, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
966
+{ "start": 58720256, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
967
+{ "start": 60817408, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
968
+{ "start": 62914560, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
969
+{ "start": 65011712, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
970
+{ "start": 67108864, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
971
+{ "start": 69206016, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
972
+{ "start": 71303168, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
973
+{ "start": 73400320, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
974
+{ "start": 75497472, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
975
+{ "start": 77594624, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
976
+{ "start": 79691776, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
977
+{ "start": 81788928, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
978
+{ "start": 83886080, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
979
+{ "start": 85983232, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
980
+{ "start": 88080384, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
981
+{ "start": 90177536, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
982
+{ "start": 92274688, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
983
+{ "start": 94371840, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
984
+{ "start": 96468992, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
985
+{ "start": 98566144, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
986
+{ "start": 100663296, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
987
+{ "start": 102760448, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
988
+{ "start": 104857600, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
989
+{ "start": 106954752, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
990
+{ "start": 109051904, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
991
+{ "start": 111149056, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
992
+{ "start": 113246208, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
993
+{ "start": 115343360, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
994
+{ "start": 117440512, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
995
+{ "start": 119537664, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
996
+{ "start": 121634816, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
997
+{ "start": 123731968, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
998
+{ "start": 125829120, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
999
+{ "start": 127926272, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1000
+{ "start": 130023424, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1001
+{ "start": 132120576, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1002
+{ "start": 134217728, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1003
+{ "start": 136314880, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1004
+{ "start": 138412032, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1005
+{ "start": 140509184, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1006
+{ "start": 142606336, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1007
+{ "start": 144703488, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1008
+{ "start": 146800640, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1009
+{ "start": 148897792, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1010
+{ "start": 150994944, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1011
+{ "start": 153092096, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1012
+{ "start": 155189248, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1013
+{ "start": 157286400, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1014
+{ "start": 159383552, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1015
+{ "start": 161480704, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1016
+{ "start": 163577856, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1017
+{ "start": 165675008, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1018
+{ "start": 167772160, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1019
+{ "start": 169869312, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1020
+{ "start": 171966464, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1021
+{ "start": 174063616, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1022
+{ "start": 176160768, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1023
+{ "start": 178257920, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1024
+{ "start": 180355072, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1025
+{ "start": 182452224, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1026
+{ "start": 184549376, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1027
+{ "start": 186646528, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1028
+{ "start": 188743680, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1029
+{ "start": 190840832, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1030
+{ "start": 192937984, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1031
+{ "start": 195035136, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1032
+{ "start": 197132288, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1033
+{ "start": 199229440, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1034
+{ "start": 201326592, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1035
+{ "start": 203423744, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1036
+{ "start": 205520896, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1037
+{ "start": 207618048, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1038
+{ "start": 209715200, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1039
+{ "start": 211812352, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1040
+{ "start": 213909504, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1041
+{ "start": 216006656, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1042
+{ "start": 218103808, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1043
+{ "start": 220200960, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1044
+{ "start": 222298112, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1045
+{ "start": 224395264, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1046
+{ "start": 226492416, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1047
+{ "start": 228589568, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1048
+{ "start": 230686720, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1049
+{ "start": 232783872, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1050
+{ "start": 234881024, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1051
+{ "start": 236978176, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1052
+{ "start": 239075328, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1053
+{ "start": 241172480, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1054
+{ "start": 243269632, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1055
+{ "start": 245366784, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1056
+{ "start": 247463936, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1057
+{ "start": 249561088, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1058
+{ "start": 251658240, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1059
+{ "start": 253755392, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1060
+{ "start": 255852544, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1061
+{ "start": 257949696, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1062
+{ "start": 260046848, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1063
+{ "start": 262144000, "length": 1310720, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}]
1064
1065
=== Testing Image create, default ===
1066
1067
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/IMGFMT-create-test.IMGFMT', fmt=IMGFMT size=4294967296
1068
1069
=== Read created image, default opts ====
1070
1071
-[{ "start": 0, "length": 4295467008, "depth": 0, "present": true, "zero": true, "data": false}]
1072
+[{ "start": 0, "length": 4295467008, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}]
1073
1074
=== Read created image, force_size_calc=chs ====
1075
1076
-[{ "start": 0, "length": 4295467008, "depth": 0, "present": true, "zero": true, "data": false}]
1077
+[{ "start": 0, "length": 4295467008, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}]
1078
1079
=== Read created image, force_size_calc=current_size ====
1080
1081
-[{ "start": 0, "length": 4295467008, "depth": 0, "present": true, "zero": true, "data": false}]
1082
+[{ "start": 0, "length": 4295467008, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}]
1083
1084
=== Testing Image create, force_size ===
1085
1086
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/IMGFMT-create-test.IMGFMT', fmt=IMGFMT size=4294967296
1087
1088
=== Read created image, default opts ====
1089
1090
-[{ "start": 0, "length": 4294967296, "depth": 0, "present": true, "zero": true, "data": false}]
1091
+[{ "start": 0, "length": 4294967296, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}]
1092
1093
=== Read created image, force_size_calc=chs ====
1094
1095
-[{ "start": 0, "length": 4294967296, "depth": 0, "present": true, "zero": true, "data": false}]
1096
+[{ "start": 0, "length": 4294967296, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}]
1097
1098
=== Read created image, force_size_calc=current_size ====
1099
1100
-[{ "start": 0, "length": 4294967296, "depth": 0, "present": true, "zero": true, "data": false}]
1101
+[{ "start": 0, "length": 4294967296, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}]
1102
*** done
1103
diff --git a/tests/qemu-iotests/154.out b/tests/qemu-iotests/154.out
1104
index XXXXXXX..XXXXXXX 100644
1105
--- a/tests/qemu-iotests/154.out
1106
+++ b/tests/qemu-iotests/154.out
1107
@@ -XXX,XX +XXX,XX @@ wrote 2048/2048 bytes at offset 17408
1108
2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1109
wrote 2048/2048 bytes at offset 27648
1110
2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1111
-[{ "start": 0, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false},
1112
-{ "start": 4096, "length": 4096, "depth": 1, "present": false, "zero": true, "data": false},
1113
-{ "start": 8192, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false},
1114
-{ "start": 12288, "length": 4096, "depth": 1, "present": false, "zero": true, "data": false},
1115
-{ "start": 16384, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false},
1116
-{ "start": 20480, "length": 4096, "depth": 1, "present": false, "zero": true, "data": false},
1117
-{ "start": 24576, "length": 8192, "depth": 0, "present": true, "zero": true, "data": false},
1118
-{ "start": 32768, "length": 134184960, "depth": 1, "present": false, "zero": true, "data": false}]
1119
+[{ "start": 0, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false},
1120
+{ "start": 4096, "length": 4096, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false},
1121
+{ "start": 8192, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false},
1122
+{ "start": 12288, "length": 4096, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false},
1123
+{ "start": 16384, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false},
1124
+{ "start": 20480, "length": 4096, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false},
1125
+{ "start": 24576, "length": 8192, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false},
1126
+{ "start": 32768, "length": 134184960, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}]
1127
1128
== backing file contains non-zero data before write_zeroes ==
1129
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728
1130
@@ -XXX,XX +XXX,XX @@ read 1024/1024 bytes at offset 65536
1131
1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1132
read 2048/2048 bytes at offset 67584
1133
2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1134
-[{ "start": 0, "length": 32768, "depth": 1, "present": false, "zero": true, "data": false},
1135
-{ "start": 32768, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
1136
-{ "start": 36864, "length": 28672, "depth": 1, "present": false, "zero": true, "data": false},
1137
-{ "start": 65536, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
1138
-{ "start": 69632, "length": 134148096, "depth": 1, "present": false, "zero": true, "data": false}]
1139
+[{ "start": 0, "length": 32768, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false},
1140
+{ "start": 32768, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1141
+{ "start": 36864, "length": 28672, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false},
1142
+{ "start": 65536, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1143
+{ "start": 69632, "length": 134148096, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}]
1144
1145
== backing file contains non-zero data after write_zeroes ==
1146
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728
1147
@@ -XXX,XX +XXX,XX @@ read 1024/1024 bytes at offset 44032
1148
1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1149
read 3072/3072 bytes at offset 40960
1150
3 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1151
-[{ "start": 0, "length": 32768, "depth": 1, "present": false, "zero": true, "data": false},
1152
-{ "start": 32768, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
1153
-{ "start": 36864, "length": 4096, "depth": 1, "present": false, "zero": true, "data": false},
1154
-{ "start": 40960, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
1155
-{ "start": 45056, "length": 134172672, "depth": 1, "present": false, "zero": true, "data": false}]
1156
+[{ "start": 0, "length": 32768, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false},
1157
+{ "start": 32768, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1158
+{ "start": 36864, "length": 4096, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false},
1159
+{ "start": 40960, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1160
+{ "start": 45056, "length": 134172672, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}]
1161
1162
== write_zeroes covers non-zero data ==
1163
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728
1164
@@ -XXX,XX +XXX,XX @@ wrote 2048/2048 bytes at offset 29696
1165
2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1166
read 4096/4096 bytes at offset 28672
1167
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1168
-[{ "start": 0, "length": 4096, "depth": 1, "present": false, "zero": true, "data": false},
1169
-{ "start": 4096, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false},
1170
-{ "start": 8192, "length": 4096, "depth": 1, "present": false, "zero": true, "data": false},
1171
-{ "start": 12288, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false},
1172
-{ "start": 16384, "length": 4096, "depth": 1, "present": false, "zero": true, "data": false},
1173
-{ "start": 20480, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false},
1174
-{ "start": 24576, "length": 4096, "depth": 1, "present": false, "zero": true, "data": false},
1175
-{ "start": 28672, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false},
1176
-{ "start": 32768, "length": 134184960, "depth": 1, "present": false, "zero": true, "data": false}]
1177
+[{ "start": 0, "length": 4096, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false},
1178
+{ "start": 4096, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false},
1179
+{ "start": 8192, "length": 4096, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false},
1180
+{ "start": 12288, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false},
1181
+{ "start": 16384, "length": 4096, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false},
1182
+{ "start": 20480, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false},
1183
+{ "start": 24576, "length": 4096, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false},
1184
+{ "start": 28672, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false},
1185
+{ "start": 32768, "length": 134184960, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}]
1186
1187
== spanning two clusters, non-zero before request ==
1188
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728
1189
@@ -XXX,XX +XXX,XX @@ read 1024/1024 bytes at offset 67584
1190
1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1191
read 5120/5120 bytes at offset 68608
1192
5 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1193
-[{ "start": 0, "length": 32768, "depth": 1, "present": false, "zero": true, "data": false},
1194
-{ "start": 32768, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
1195
-{ "start": 36864, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false},
1196
-{ "start": 40960, "length": 8192, "depth": 1, "present": false, "zero": true, "data": false},
1197
-{ "start": 49152, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
1198
-{ "start": 53248, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false},
1199
-{ "start": 57344, "length": 8192, "depth": 1, "present": false, "zero": true, "data": false},
1200
-{ "start": 65536, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
1201
-{ "start": 69632, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false},
1202
-{ "start": 73728, "length": 134144000, "depth": 1, "present": false, "zero": true, "data": false}]
1203
+[{ "start": 0, "length": 32768, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false},
1204
+{ "start": 32768, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1205
+{ "start": 36864, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false},
1206
+{ "start": 40960, "length": 8192, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false},
1207
+{ "start": 49152, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1208
+{ "start": 53248, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false},
1209
+{ "start": 57344, "length": 8192, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false},
1210
+{ "start": 65536, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1211
+{ "start": 69632, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false},
1212
+{ "start": 73728, "length": 134144000, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}]
1213
1214
== spanning two clusters, non-zero after request ==
1215
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728
1216
@@ -XXX,XX +XXX,XX @@ read 7168/7168 bytes at offset 65536
1217
7 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1218
read 1024/1024 bytes at offset 72704
1219
1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1220
-[{ "start": 0, "length": 32768, "depth": 1, "present": false, "zero": true, "data": false},
1221
-{ "start": 32768, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false},
1222
-{ "start": 36864, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
1223
-{ "start": 40960, "length": 8192, "depth": 1, "present": false, "zero": true, "data": false},
1224
-{ "start": 49152, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false},
1225
-{ "start": 53248, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
1226
-{ "start": 57344, "length": 8192, "depth": 1, "present": false, "zero": true, "data": false},
1227
-{ "start": 65536, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false},
1228
-{ "start": 69632, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
1229
-{ "start": 73728, "length": 134144000, "depth": 1, "present": false, "zero": true, "data": false}]
1230
+[{ "start": 0, "length": 32768, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false},
1231
+{ "start": 32768, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false},
1232
+{ "start": 36864, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1233
+{ "start": 40960, "length": 8192, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false},
1234
+{ "start": 49152, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false},
1235
+{ "start": 53248, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1236
+{ "start": 57344, "length": 8192, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false},
1237
+{ "start": 65536, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false},
1238
+{ "start": 69632, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1239
+{ "start": 73728, "length": 134144000, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}]
1240
1241
== spanning two clusters, partially overwriting backing file ==
1242
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728
1243
@@ -XXX,XX +XXX,XX @@ read 1024/1024 bytes at offset 5120
1244
1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1245
read 2048/2048 bytes at offset 6144
1246
2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1247
-[{ "start": 0, "length": 8192, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
1248
-{ "start": 8192, "length": 134209536, "depth": 1, "present": false, "zero": true, "data": false}]
1249
+[{ "start": 0, "length": 8192, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1250
+{ "start": 8192, "length": 134209536, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}]
1251
1252
== spanning multiple clusters, non-zero in first cluster ==
1253
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728
1254
@@ -XXX,XX +XXX,XX @@ read 2048/2048 bytes at offset 65536
1255
2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1256
read 10240/10240 bytes at offset 67584
1257
10 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1258
-[{ "start": 0, "length": 65536, "depth": 1, "present": false, "zero": true, "data": false},
1259
-{ "start": 65536, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
1260
-{ "start": 69632, "length": 8192, "depth": 0, "present": true, "zero": true, "data": false},
1261
-{ "start": 77824, "length": 134139904, "depth": 1, "present": false, "zero": true, "data": false}]
1262
+[{ "start": 0, "length": 65536, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false},
1263
+{ "start": 65536, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1264
+{ "start": 69632, "length": 8192, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false},
1265
+{ "start": 77824, "length": 134139904, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}]
1266
1267
== spanning multiple clusters, non-zero in intermediate cluster ==
1268
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728
1269
@@ -XXX,XX +XXX,XX @@ wrote 7168/7168 bytes at offset 67584
1270
7 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1271
read 12288/12288 bytes at offset 65536
1272
12 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1273
-[{ "start": 0, "length": 65536, "depth": 1, "present": false, "zero": true, "data": false},
1274
-{ "start": 65536, "length": 12288, "depth": 0, "present": true, "zero": true, "data": false},
1275
-{ "start": 77824, "length": 134139904, "depth": 1, "present": false, "zero": true, "data": false}]
1276
+[{ "start": 0, "length": 65536, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false},
1277
+{ "start": 65536, "length": 12288, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false},
1278
+{ "start": 77824, "length": 134139904, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}]
1279
1280
== spanning multiple clusters, non-zero in final cluster ==
1281
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728
1282
@@ -XXX,XX +XXX,XX @@ read 10240/10240 bytes at offset 65536
1283
10 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1284
read 2048/2048 bytes at offset 75776
1285
2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1286
-[{ "start": 0, "length": 65536, "depth": 1, "present": false, "zero": true, "data": false},
1287
-{ "start": 65536, "length": 8192, "depth": 0, "present": true, "zero": true, "data": false},
1288
-{ "start": 73728, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
1289
-{ "start": 77824, "length": 134139904, "depth": 1, "present": false, "zero": true, "data": false}]
1290
+[{ "start": 0, "length": 65536, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false},
1291
+{ "start": 65536, "length": 8192, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false},
1292
+{ "start": 73728, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1293
+{ "start": 77824, "length": 134139904, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}]
1294
1295
== spanning multiple clusters, partially overwriting backing file ==
1296
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728
1297
@@ -XXX,XX +XXX,XX @@ read 2048/2048 bytes at offset 74752
1298
2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1299
read 1024/1024 bytes at offset 76800
1300
1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1301
-[{ "start": 0, "length": 65536, "depth": 1, "present": false, "zero": true, "data": false},
1302
-{ "start": 65536, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
1303
-{ "start": 69632, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false},
1304
-{ "start": 73728, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
1305
-{ "start": 77824, "length": 134139904, "depth": 1, "present": false, "zero": true, "data": false}]
1306
+[{ "start": 0, "length": 65536, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false},
1307
+{ "start": 65536, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1308
+{ "start": 69632, "length": 4096, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false},
1309
+{ "start": 73728, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1310
+{ "start": 77824, "length": 134139904, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}]
1311
1312
== unaligned image tail cluster, no allocation needed ==
1313
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776
1314
wrote 512/512 bytes at offset 134217728
1315
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1316
2048/2048 bytes allocated at offset 128 MiB
1317
-[{ "start": 0, "length": 134217728, "depth": 0, "present": false, "zero": true, "data": false},
1318
-{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false}]
1319
+[{ "start": 0, "length": 134217728, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false},
1320
+{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}]
1321
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776
1322
wrote 512/512 bytes at offset 134219264
1323
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1324
2048/2048 bytes allocated at offset 128 MiB
1325
-[{ "start": 0, "length": 134217728, "depth": 0, "present": false, "zero": true, "data": false},
1326
-{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false}]
1327
+[{ "start": 0, "length": 134217728, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false},
1328
+{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}]
1329
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776
1330
wrote 1024/1024 bytes at offset 134218240
1331
1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1332
2048/2048 bytes allocated at offset 128 MiB
1333
-[{ "start": 0, "length": 134217728, "depth": 0, "present": false, "zero": true, "data": false},
1334
-{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false}]
1335
+[{ "start": 0, "length": 134217728, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false},
1336
+{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}]
1337
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776
1338
wrote 2048/2048 bytes at offset 134217728
1339
2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1340
2048/2048 bytes allocated at offset 128 MiB
1341
-[{ "start": 0, "length": 134217728, "depth": 0, "present": false, "zero": true, "data": false},
1342
-{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false}]
1343
+[{ "start": 0, "length": 134217728, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false},
1344
+{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}]
1345
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134218752
1346
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT
1347
wrote 512/512 bytes at offset 134217728
1348
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1349
2048/2048 bytes allocated at offset 128 MiB
1350
-[{ "start": 0, "length": 134217728, "depth": 1, "present": false, "zero": true, "data": false},
1351
-{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false}]
1352
+[{ "start": 0, "length": 134217728, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false},
1353
+{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}]
1354
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT
1355
wrote 512/512 bytes at offset 134219264
1356
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1357
2048/2048 bytes allocated at offset 128 MiB
1358
-[{ "start": 0, "length": 134217728, "depth": 1, "present": false, "zero": true, "data": false},
1359
-{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false}]
1360
+[{ "start": 0, "length": 134217728, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false},
1361
+{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}]
1362
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT
1363
wrote 1024/1024 bytes at offset 134218240
1364
1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1365
2048/2048 bytes allocated at offset 128 MiB
1366
-[{ "start": 0, "length": 134217728, "depth": 1, "present": false, "zero": true, "data": false},
1367
-{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false}]
1368
+[{ "start": 0, "length": 134217728, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false},
1369
+{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}]
1370
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT
1371
wrote 2048/2048 bytes at offset 134217728
1372
2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1373
2048/2048 bytes allocated at offset 128 MiB
1374
-[{ "start": 0, "length": 134217728, "depth": 1, "present": false, "zero": true, "data": false},
1375
-{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false}]
1376
+[{ "start": 0, "length": 134217728, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false},
1377
+{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}]
1378
wrote 512/512 bytes at offset 134217728
1379
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1380
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT
1381
wrote 512/512 bytes at offset 134217728
1382
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1383
2048/2048 bytes allocated at offset 128 MiB
1384
-[{ "start": 0, "length": 134217728, "depth": 1, "present": false, "zero": true, "data": false},
1385
-{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false}]
1386
+[{ "start": 0, "length": 134217728, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false},
1387
+{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}]
1388
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT
1389
wrote 512/512 bytes at offset 134219264
1390
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1391
2048/2048 bytes allocated at offset 128 MiB
1392
-[{ "start": 0, "length": 134217728, "depth": 1, "present": false, "zero": true, "data": false},
1393
-{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false}]
1394
+[{ "start": 0, "length": 134217728, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false},
1395
+{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}]
1396
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT
1397
wrote 1024/1024 bytes at offset 134218240
1398
1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1399
2048/2048 bytes allocated at offset 128 MiB
1400
-[{ "start": 0, "length": 134217728, "depth": 1, "present": false, "zero": true, "data": false},
1401
-{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false}]
1402
+[{ "start": 0, "length": 134217728, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false},
1403
+{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}]
1404
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT
1405
wrote 2048/2048 bytes at offset 134217728
1406
2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1407
2048/2048 bytes allocated at offset 128 MiB
1408
-[{ "start": 0, "length": 134217728, "depth": 1, "present": false, "zero": true, "data": false},
1409
-{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false}]
1410
+[{ "start": 0, "length": 134217728, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false},
1411
+{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}]
1412
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134218752
1413
wrote 1024/1024 bytes at offset 134217728
1414
1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1415
@@ -XXX,XX +XXX,XX @@ read 512/512 bytes at offset 134217728
1416
read 512/512 bytes at offset 134218240
1417
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1418
1024/1024 bytes allocated at offset 128 MiB
1419
-[{ "start": 0, "length": 134217728, "depth": 0, "present": false, "zero": true, "data": false},
1420
-{ "start": 134217728, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}]
1421
+[{ "start": 0, "length": 134217728, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false},
1422
+{ "start": 134217728, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}]
1423
wrote 1024/1024 bytes at offset 134217728
1424
1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1425
1024/1024 bytes allocated at offset 128 MiB
1426
read 1024/1024 bytes at offset 134217728
1427
1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1428
-[{ "start": 0, "length": 134217728, "depth": 0, "present": false, "zero": true, "data": false},
1429
-{ "start": 134217728, "length": 1024, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET}]
1430
+[{ "start": 0, "length": 134217728, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false},
1431
+{ "start": 134217728, "length": 1024, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": OFFSET}]
1432
1433
== unaligned image tail cluster, allocation required ==
1434
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134218752
1435
@@ -XXX,XX +XXX,XX @@ read 512/512 bytes at offset 134217728
1436
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1437
read 1536/1536 bytes at offset 134218240
1438
1.500 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1439
-[{ "start": 0, "length": 134217728, "depth": 1, "present": false, "zero": true, "data": false},
1440
-{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}]
1441
+[{ "start": 0, "length": 134217728, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false},
1442
+{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}]
1443
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134218752
1444
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134219776 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT
1445
wrote 512/512 bytes at offset 134218240
1446
@@ -XXX,XX +XXX,XX @@ read 512/512 bytes at offset 134218240
1447
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1448
read 1024/1024 bytes at offset 134218752
1449
1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1450
-[{ "start": 0, "length": 134217728, "depth": 1, "present": false, "zero": true, "data": false},
1451
-{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}]
1452
+[{ "start": 0, "length": 134217728, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false},
1453
+{ "start": 134217728, "length": 2048, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}]
1454
*** done
1455
diff --git a/tests/qemu-iotests/179.out b/tests/qemu-iotests/179.out
1456
index XXXXXXX..XXXXXXX 100644
1457
--- a/tests/qemu-iotests/179.out
1458
+++ b/tests/qemu-iotests/179.out
1459
@@ -XXX,XX +XXX,XX @@ wrote 2097152/2097152 bytes at offset 6291456
1460
2 MiB (0x200000) bytes not allocated at offset 4 MiB (0x400000)
1461
2 MiB (0x200000) bytes allocated at offset 6 MiB (0x600000)
1462
56 MiB (0x3800000) bytes not allocated at offset 8 MiB (0x800000)
1463
-[{ "start": 0, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false},
1464
-{ "start": 2097152, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false},
1465
-{ "start": 4194304, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false},
1466
-{ "start": 6291456, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false},
1467
-{ "start": 8388608, "length": 58720256, "depth": 0, "present": false, "zero": true, "data": false}]
1468
+[{ "start": 0, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false},
1469
+{ "start": 2097152, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false},
1470
+{ "start": 4194304, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false},
1471
+{ "start": 6291456, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false},
1472
+{ "start": 8388608, "length": 58720256, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}]
1473
wrote 2097150/2097150 bytes at offset 10485761
1474
2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1475
wrote 2097150/2097150 bytes at offset 14680065
1476
@@ -XXX,XX +XXX,XX @@ wrote 2097150/2097150 bytes at offset 14680065
1477
2 MiB (0x200000) bytes not allocated at offset 12 MiB (0xc00000)
1478
2 MiB (0x200000) bytes allocated at offset 14 MiB (0xe00000)
1479
48 MiB (0x3000000) bytes not allocated at offset 16 MiB (0x1000000)
1480
-[{ "start": 0, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false},
1481
-{ "start": 2097152, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false},
1482
-{ "start": 4194304, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false},
1483
-{ "start": 6291456, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false},
1484
-{ "start": 8388608, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false},
1485
-{ "start": 10485760, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false},
1486
-{ "start": 12582912, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false},
1487
-{ "start": 14680064, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false},
1488
-{ "start": 16777216, "length": 50331648, "depth": 0, "present": false, "zero": true, "data": false}]
1489
+[{ "start": 0, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false},
1490
+{ "start": 2097152, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false},
1491
+{ "start": 4194304, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false},
1492
+{ "start": 6291456, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false},
1493
+{ "start": 8388608, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false},
1494
+{ "start": 10485760, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false},
1495
+{ "start": 12582912, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false},
1496
+{ "start": 14680064, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false},
1497
+{ "start": 16777216, "length": 50331648, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}]
1498
wrote 14680064/14680064 bytes at offset 18874368
1499
14 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1500
wrote 2097152/2097152 bytes at offset 20971520
1501
@@ -XXX,XX +XXX,XX @@ wrote 6291456/6291456 bytes at offset 25165824
1502
2 MiB (0x200000) bytes not allocated at offset 16 MiB (0x1000000)
1503
14 MiB (0xe00000) bytes allocated at offset 18 MiB (0x1200000)
1504
32 MiB (0x2000000) bytes not allocated at offset 32 MiB (0x2000000)
1505
-[{ "start": 0, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false},
1506
-{ "start": 2097152, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false},
1507
-{ "start": 4194304, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false},
1508
-{ "start": 6291456, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false},
1509
-{ "start": 8388608, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false},
1510
-{ "start": 10485760, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false},
1511
-{ "start": 12582912, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false},
1512
-{ "start": 14680064, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false},
1513
-{ "start": 16777216, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false},
1514
-{ "start": 18874368, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
1515
-{ "start": 20971520, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false},
1516
-{ "start": 23068672, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
1517
-{ "start": 25165824, "length": 6291456, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET},
1518
-{ "start": 31457280, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
1519
-{ "start": 33554432, "length": 33554432, "depth": 0, "present": false, "zero": true, "data": false}]
1520
+[{ "start": 0, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false},
1521
+{ "start": 2097152, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false},
1522
+{ "start": 4194304, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false},
1523
+{ "start": 6291456, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false},
1524
+{ "start": 8388608, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false},
1525
+{ "start": 10485760, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false},
1526
+{ "start": 12582912, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false},
1527
+{ "start": 14680064, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false},
1528
+{ "start": 16777216, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false},
1529
+{ "start": 18874368, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1530
+{ "start": 20971520, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false},
1531
+{ "start": 23068672, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1532
+{ "start": 25165824, "length": 6291456, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": OFFSET},
1533
+{ "start": 31457280, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1534
+{ "start": 33554432, "length": 33554432, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}]
1535
wrote 2097152/2097152 bytes at offset 27262976
1536
2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1537
wrote 2097152/2097152 bytes at offset 29360128
1538
@@ -XXX,XX +XXX,XX @@ wrote 2097152/2097152 bytes at offset 29360128
1539
2 MiB (0x200000) bytes not allocated at offset 16 MiB (0x1000000)
1540
14 MiB (0xe00000) bytes allocated at offset 18 MiB (0x1200000)
1541
32 MiB (0x2000000) bytes not allocated at offset 32 MiB (0x2000000)
1542
-[{ "start": 0, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false},
1543
-{ "start": 2097152, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false},
1544
-{ "start": 4194304, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false},
1545
-{ "start": 6291456, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false},
1546
-{ "start": 8388608, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false},
1547
-{ "start": 10485760, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false},
1548
-{ "start": 12582912, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false},
1549
-{ "start": 14680064, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false},
1550
-{ "start": 16777216, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false},
1551
-{ "start": 18874368, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
1552
-{ "start": 20971520, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false},
1553
-{ "start": 23068672, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
1554
-{ "start": 25165824, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET},
1555
-{ "start": 27262976, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false},
1556
-{ "start": 29360128, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET},
1557
-{ "start": 31457280, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
1558
-{ "start": 33554432, "length": 33554432, "depth": 0, "present": false, "zero": true, "data": false}]
1559
+[{ "start": 0, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false},
1560
+{ "start": 2097152, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false},
1561
+{ "start": 4194304, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false},
1562
+{ "start": 6291456, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false},
1563
+{ "start": 8388608, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false},
1564
+{ "start": 10485760, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false},
1565
+{ "start": 12582912, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false},
1566
+{ "start": 14680064, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false},
1567
+{ "start": 16777216, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false},
1568
+{ "start": 18874368, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1569
+{ "start": 20971520, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false},
1570
+{ "start": 23068672, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1571
+{ "start": 25165824, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": OFFSET},
1572
+{ "start": 27262976, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false},
1573
+{ "start": 29360128, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": OFFSET},
1574
+{ "start": 31457280, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1575
+{ "start": 33554432, "length": 33554432, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}]
1576
wrote 8388608/8388608 bytes at offset 33554432
1577
8 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1578
wrote 2097152/2097152 bytes at offset 35651584
1579
@@ -XXX,XX +XXX,XX @@ wrote 2097152/2097152 bytes at offset 37748736
1580
2 MiB (0x200000) bytes not allocated at offset 16 MiB (0x1000000)
1581
22 MiB (0x1600000) bytes allocated at offset 18 MiB (0x1200000)
1582
24 MiB (0x1800000) bytes not allocated at offset 40 MiB (0x2800000)
1583
-[{ "start": 0, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false},
1584
-{ "start": 2097152, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false},
1585
-{ "start": 4194304, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false},
1586
-{ "start": 6291456, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false},
1587
-{ "start": 8388608, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false},
1588
-{ "start": 10485760, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false},
1589
-{ "start": 12582912, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false},
1590
-{ "start": 14680064, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false},
1591
-{ "start": 16777216, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false},
1592
-{ "start": 18874368, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
1593
-{ "start": 20971520, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false},
1594
-{ "start": 23068672, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
1595
-{ "start": 25165824, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET},
1596
-{ "start": 27262976, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false},
1597
-{ "start": 29360128, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET},
1598
-{ "start": 31457280, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
1599
-{ "start": 33554432, "length": 8388608, "depth": 0, "present": true, "zero": true, "data": false},
1600
-{ "start": 41943040, "length": 25165824, "depth": 0, "present": false, "zero": true, "data": false}]
1601
+[{ "start": 0, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false},
1602
+{ "start": 2097152, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false},
1603
+{ "start": 4194304, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false},
1604
+{ "start": 6291456, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false},
1605
+{ "start": 8388608, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false},
1606
+{ "start": 10485760, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false},
1607
+{ "start": 12582912, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false},
1608
+{ "start": 14680064, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false},
1609
+{ "start": 16777216, "length": 2097152, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false},
1610
+{ "start": 18874368, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1611
+{ "start": 20971520, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false},
1612
+{ "start": 23068672, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1613
+{ "start": 25165824, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": OFFSET},
1614
+{ "start": 27262976, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false},
1615
+{ "start": 29360128, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": OFFSET},
1616
+{ "start": 31457280, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1617
+{ "start": 33554432, "length": 8388608, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false},
1618
+{ "start": 41943040, "length": 25165824, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}]
1619
wrote 8388608/8388608 bytes at offset 41943040
1620
8 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1621
wrote 8388608/8388608 bytes at offset 50331648
1622
@@ -XXX,XX +XXX,XX @@ wrote 2097152/2097152 bytes at offset 62914560
1623
4 MiB (0x400000) bytes not allocated at offset 54 MiB (0x3600000)
1624
4 MiB (0x400000) bytes allocated at offset 58 MiB (0x3a00000)
1625
2 MiB (0x200000) bytes not allocated at offset 62 MiB (0x3e00000)
1626
-[{ "start": 0, "length": 2097152, "depth": 1, "present": false, "zero": true, "data": false},
1627
-{ "start": 2097152, "length": 2097152, "depth": 1, "present": true, "zero": true, "data": false},
1628
-{ "start": 4194304, "length": 2097152, "depth": 1, "present": false, "zero": true, "data": false},
1629
-{ "start": 6291456, "length": 2097152, "depth": 1, "present": true, "zero": true, "data": false},
1630
-{ "start": 8388608, "length": 2097152, "depth": 1, "present": false, "zero": true, "data": false},
1631
-{ "start": 10485760, "length": 2097152, "depth": 1, "present": true, "zero": true, "data": false},
1632
-{ "start": 12582912, "length": 2097152, "depth": 1, "present": false, "zero": true, "data": false},
1633
-{ "start": 14680064, "length": 2097152, "depth": 1, "present": true, "zero": true, "data": false},
1634
-{ "start": 16777216, "length": 2097152, "depth": 1, "present": false, "zero": true, "data": false},
1635
-{ "start": 18874368, "length": 2097152, "depth": 1, "present": true, "zero": false, "data": true, "offset": OFFSET},
1636
-{ "start": 20971520, "length": 2097152, "depth": 1, "present": true, "zero": true, "data": false},
1637
-{ "start": 23068672, "length": 2097152, "depth": 1, "present": true, "zero": false, "data": true, "offset": OFFSET},
1638
-{ "start": 25165824, "length": 2097152, "depth": 1, "present": true, "zero": true, "data": false, "offset": OFFSET},
1639
-{ "start": 27262976, "length": 2097152, "depth": 1, "present": true, "zero": true, "data": false},
1640
-{ "start": 29360128, "length": 2097152, "depth": 1, "present": true, "zero": true, "data": false, "offset": OFFSET},
1641
-{ "start": 31457280, "length": 2097152, "depth": 1, "present": true, "zero": false, "data": true, "offset": OFFSET},
1642
-{ "start": 33554432, "length": 10485760, "depth": 1, "present": true, "zero": true, "data": false},
1643
-{ "start": 44040192, "length": 4194304, "depth": 0, "present": true, "zero": true, "data": false},
1644
-{ "start": 48234496, "length": 2097152, "depth": 1, "present": true, "zero": true, "data": false},
1645
-{ "start": 50331648, "length": 2097152, "depth": 1, "present": true, "zero": false, "data": true, "offset": OFFSET},
1646
-{ "start": 52428800, "length": 4194304, "depth": 0, "present": true, "zero": true, "data": false},
1647
-{ "start": 56623104, "length": 2097152, "depth": 1, "present": true, "zero": false, "data": true, "offset": OFFSET},
1648
-{ "start": 58720256, "length": 2097152, "depth": 1, "present": false, "zero": true, "data": false},
1649
-{ "start": 60817408, "length": 4194304, "depth": 0, "present": true, "zero": true, "data": false},
1650
-{ "start": 65011712, "length": 2097152, "depth": 1, "present": false, "zero": true, "data": false}]
1651
+[{ "start": 0, "length": 2097152, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false},
1652
+{ "start": 2097152, "length": 2097152, "depth": 1, "present": true, "zero": true, "data": false, "compressed": false},
1653
+{ "start": 4194304, "length": 2097152, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false},
1654
+{ "start": 6291456, "length": 2097152, "depth": 1, "present": true, "zero": true, "data": false, "compressed": false},
1655
+{ "start": 8388608, "length": 2097152, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false},
1656
+{ "start": 10485760, "length": 2097152, "depth": 1, "present": true, "zero": true, "data": false, "compressed": false},
1657
+{ "start": 12582912, "length": 2097152, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false},
1658
+{ "start": 14680064, "length": 2097152, "depth": 1, "present": true, "zero": true, "data": false, "compressed": false},
1659
+{ "start": 16777216, "length": 2097152, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false},
1660
+{ "start": 18874368, "length": 2097152, "depth": 1, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1661
+{ "start": 20971520, "length": 2097152, "depth": 1, "present": true, "zero": true, "data": false, "compressed": false},
1662
+{ "start": 23068672, "length": 2097152, "depth": 1, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1663
+{ "start": 25165824, "length": 2097152, "depth": 1, "present": true, "zero": true, "data": false, "compressed": false, "offset": OFFSET},
1664
+{ "start": 27262976, "length": 2097152, "depth": 1, "present": true, "zero": true, "data": false, "compressed": false},
1665
+{ "start": 29360128, "length": 2097152, "depth": 1, "present": true, "zero": true, "data": false, "compressed": false, "offset": OFFSET},
1666
+{ "start": 31457280, "length": 2097152, "depth": 1, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1667
+{ "start": 33554432, "length": 10485760, "depth": 1, "present": true, "zero": true, "data": false, "compressed": false},
1668
+{ "start": 44040192, "length": 4194304, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false},
1669
+{ "start": 48234496, "length": 2097152, "depth": 1, "present": true, "zero": true, "data": false, "compressed": false},
1670
+{ "start": 50331648, "length": 2097152, "depth": 1, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1671
+{ "start": 52428800, "length": 4194304, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false},
1672
+{ "start": 56623104, "length": 2097152, "depth": 1, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1673
+{ "start": 58720256, "length": 2097152, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false},
1674
+{ "start": 60817408, "length": 4194304, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false},
1675
+{ "start": 65011712, "length": 2097152, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}]
1676
No errors were found on the image.
1677
No errors were found on the image.
1678
1679
diff --git a/tests/qemu-iotests/209.out b/tests/qemu-iotests/209.out
1680
index XXXXXXX..XXXXXXX 100644
1681
--- a/tests/qemu-iotests/209.out
1682
+++ b/tests/qemu-iotests/209.out
1683
@@ -XXX,XX +XXX,XX @@
1684
-[{ "start": 0, "length": 524288, "depth": 0, "present": true, "zero": false, "data": true, "offset": 0},
1685
-{ "start": 524288, "length": 524288, "depth": 0, "present": true, "zero": true, "data": false, "offset": 524288}]
1686
+[{ "start": 0, "length": 524288, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": 0},
1687
+{ "start": 524288, "length": 524288, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": 524288}]
1688
1689
done.
1690
diff --git a/tests/qemu-iotests/221.out b/tests/qemu-iotests/221.out
1691
index XXXXXXX..XXXXXXX 100644
1692
--- a/tests/qemu-iotests/221.out
1693
+++ b/tests/qemu-iotests/221.out
1694
@@ -XXX,XX +XXX,XX @@ QA output created by 221
1695
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=65537
1696
discard 65537/65537 bytes at offset 0
1697
64.001 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1698
-[{ "start": 0, "length": 66048, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET}]
1699
-[{ "start": 0, "length": 66048, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET}]
1700
+[{ "start": 0, "length": 66048, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": OFFSET}]
1701
+[{ "start": 0, "length": 66048, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": OFFSET}]
1702
wrote 1/1 bytes at offset 65536
1703
1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1704
-[{ "start": 0, "length": 65536, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET},
1705
-{ "start": 65536, "length": 1, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
1706
-{ "start": 65537, "length": 511, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET}]
1707
-[{ "start": 0, "length": 65536, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET},
1708
-{ "start": 65536, "length": 1, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
1709
-{ "start": 65537, "length": 511, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET}]
1710
+[{ "start": 0, "length": 65536, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": OFFSET},
1711
+{ "start": 65536, "length": 1, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1712
+{ "start": 65537, "length": 511, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": OFFSET}]
1713
+[{ "start": 0, "length": 65536, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": OFFSET},
1714
+{ "start": 65536, "length": 1, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1715
+{ "start": 65537, "length": 511, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": OFFSET}]
1716
*** done
1717
diff --git a/tests/qemu-iotests/223.out b/tests/qemu-iotests/223.out
1718
index XXXXXXX..XXXXXXX 100644
1719
--- a/tests/qemu-iotests/223.out
1720
+++ b/tests/qemu-iotests/223.out
1721
@@ -XXX,XX +XXX,XX @@ read 1048576/1048576 bytes at offset 1048576
1722
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1723
read 2097152/2097152 bytes at offset 2097152
1724
2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1725
-[{ "start": 0, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
1726
-{ "start": 4096, "length": 1044480, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET},
1727
-{ "start": 1048576, "length": 3145728, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}]
1728
-[{ "start": 0, "length": 65536, "depth": 0, "present": false, "zero": false, "data": false},
1729
-{ "start": 65536, "length": 2031616, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
1730
-{ "start": 2097152, "length": 2097152, "depth": 0, "present": false, "zero": false, "data": false}]
1731
+[{ "start": 0, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1732
+{ "start": 4096, "length": 1044480, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": OFFSET},
1733
+{ "start": 1048576, "length": 3145728, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}]
1734
+[{ "start": 0, "length": 65536, "depth": 0, "present": false, "zero": false, "data": false, "compressed": false},
1735
+{ "start": 65536, "length": 2031616, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1736
+{ "start": 2097152, "length": 2097152, "depth": 0, "present": false, "zero": false, "data": false, "compressed": false}]
1737
1738
=== Contrast to small granularity dirty-bitmap ===
1739
1740
-[{ "start": 0, "length": 512, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
1741
-{ "start": 512, "length": 512, "depth": 0, "present": false, "zero": false, "data": false},
1742
-{ "start": 1024, "length": 2096128, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
1743
-{ "start": 2097152, "length": 2097152, "depth": 0, "present": false, "zero": false, "data": false}]
1744
+[{ "start": 0, "length": 512, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1745
+{ "start": 512, "length": 512, "depth": 0, "present": false, "zero": false, "data": false, "compressed": false},
1746
+{ "start": 1024, "length": 2096128, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1747
+{ "start": 2097152, "length": 2097152, "depth": 0, "present": false, "zero": false, "data": false, "compressed": false}]
1748
1749
=== Check bitmap taken from another node ===
1750
1751
-[{ "start": 0, "length": 4194304, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}]
1752
+[{ "start": 0, "length": 4194304, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}]
1753
1754
=== End qemu NBD server ===
1755
1756
@@ -XXX,XX +XXX,XX @@ read 1048576/1048576 bytes at offset 1048576
1757
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1758
read 2097152/2097152 bytes at offset 2097152
1759
2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1760
-[{ "start": 0, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
1761
-{ "start": 4096, "length": 1044480, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET},
1762
-{ "start": 1048576, "length": 3145728, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}]
1763
-[{ "start": 0, "length": 65536, "depth": 0, "present": false, "zero": false, "data": false},
1764
-{ "start": 65536, "length": 2031616, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
1765
-{ "start": 2097152, "length": 2097152, "depth": 0, "present": false, "zero": false, "data": false}]
1766
+[{ "start": 0, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1767
+{ "start": 4096, "length": 1044480, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": OFFSET},
1768
+{ "start": 1048576, "length": 3145728, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}]
1769
+[{ "start": 0, "length": 65536, "depth": 0, "present": false, "zero": false, "data": false, "compressed": false},
1770
+{ "start": 65536, "length": 2031616, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1771
+{ "start": 2097152, "length": 2097152, "depth": 0, "present": false, "zero": false, "data": false, "compressed": false}]
1772
1773
=== Contrast to small granularity dirty-bitmap ===
1774
1775
-[{ "start": 0, "length": 512, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
1776
-{ "start": 512, "length": 512, "depth": 0, "present": false, "zero": false, "data": false},
1777
-{ "start": 1024, "length": 2096128, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
1778
-{ "start": 2097152, "length": 2097152, "depth": 0, "present": false, "zero": false, "data": false}]
1779
+[{ "start": 0, "length": 512, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1780
+{ "start": 512, "length": 512, "depth": 0, "present": false, "zero": false, "data": false, "compressed": false},
1781
+{ "start": 1024, "length": 2096128, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1782
+{ "start": 2097152, "length": 2097152, "depth": 0, "present": false, "zero": false, "data": false, "compressed": false}]
1783
1784
=== Check bitmap taken from another node ===
1785
1786
-[{ "start": 0, "length": 4194304, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}]
1787
+[{ "start": 0, "length": 4194304, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}]
1788
1789
=== End qemu NBD server ===
1790
1791
@@ -XXX,XX +XXX,XX @@ read 2097152/2097152 bytes at offset 2097152
1792
1793
=== Use qemu-nbd as server ===
1794
1795
-[{ "start": 0, "length": 65536, "depth": 0, "present": false, "zero": false, "data": false},
1796
-{ "start": 65536, "length": 2031616, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
1797
-{ "start": 2097152, "length": 2097152, "depth": 0, "present": false, "zero": false, "data": false}]
1798
-[{ "start": 0, "length": 512, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
1799
-{ "start": 512, "length": 512, "depth": 0, "present": false, "zero": false, "data": false},
1800
-{ "start": 1024, "length": 11321, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}]
1801
-[{ "start": 12345, "length": 2084807, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
1802
-{ "start": 2097152, "length": 2097152, "depth": 0, "present": false, "zero": false, "data": false}]
1803
+[{ "start": 0, "length": 65536, "depth": 0, "present": false, "zero": false, "data": false, "compressed": false},
1804
+{ "start": 65536, "length": 2031616, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1805
+{ "start": 2097152, "length": 2097152, "depth": 0, "present": false, "zero": false, "data": false, "compressed": false}]
1806
+[{ "start": 0, "length": 512, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1807
+{ "start": 512, "length": 512, "depth": 0, "present": false, "zero": false, "data": false, "compressed": false},
1808
+{ "start": 1024, "length": 11321, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}]
1809
+[{ "start": 12345, "length": 2084807, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1810
+{ "start": 2097152, "length": 2097152, "depth": 0, "present": false, "zero": false, "data": false, "compressed": false}]
1811
*** done
1812
diff --git a/tests/qemu-iotests/241.out b/tests/qemu-iotests/241.out
1813
index XXXXXXX..XXXXXXX 100644
1814
--- a/tests/qemu-iotests/241.out
1815
+++ b/tests/qemu-iotests/241.out
1816
@@ -XXX,XX +XXX,XX @@ exports available: 1
1817
export: ''
1818
size: 1024
1819
min block: 1
1820
-[{ "start": 0, "length": 1000, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
1821
-{ "start": 1000, "length": 24, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET}]
1822
+[{ "start": 0, "length": 1000, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1823
+{ "start": 1000, "length": 24, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": OFFSET}]
1824
1 KiB (0x400) bytes allocated at offset 0 bytes (0x0)
1825
1826
=== Exporting unaligned raw image, forced server sector alignment ===
1827
@@ -XXX,XX +XXX,XX @@ exports available: 1
1828
export: ''
1829
size: 1024
1830
min block: 512
1831
-[{ "start": 0, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}]
1832
+[{ "start": 0, "length": 1024, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}]
1833
1 KiB (0x400) bytes allocated at offset 0 bytes (0x0)
1834
WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw.
1835
Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted.
1836
@@ -XXX,XX +XXX,XX @@ exports available: 1
1837
export: ''
1838
size: 1024
1839
min block: 1
1840
-[{ "start": 0, "length": 1000, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
1841
-{ "start": 1000, "length": 24, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET}]
1842
+[{ "start": 0, "length": 1000, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1843
+{ "start": 1000, "length": 24, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": OFFSET}]
1844
1 KiB (0x400) bytes allocated at offset 0 bytes (0x0)
1845
*** done
1846
diff --git a/tests/qemu-iotests/244.out b/tests/qemu-iotests/244.out
1847
index XXXXXXX..XXXXXXX 100644
1848
--- a/tests/qemu-iotests/244.out
1849
+++ b/tests/qemu-iotests/244.out
1850
@@ -XXX,XX +XXX,XX @@ wrote 3145728/3145728 bytes at offset 3145728
1851
3 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1852
No errors were found on the image.
1853
1854
-[{ "start": 0, "length": 1048576, "depth": 0, "present": false, "zero": true, "data": false},
1855
-{ "start": 1048576, "length": 1048576, "depth": 0, "present": true, "zero": false, "data": true, "offset": 1048576},
1856
-{ "start": 2097152, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false},
1857
-{ "start": 4194304, "length": 1048576, "depth": 0, "present": true, "zero": true, "data": false, "offset": 4194304},
1858
-{ "start": 5242880, "length": 1048576, "depth": 0, "present": true, "zero": true, "data": false},
1859
-{ "start": 6291456, "length": 60817408, "depth": 0, "present": false, "zero": true, "data": false}]
1860
+[{ "start": 0, "length": 1048576, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false},
1861
+{ "start": 1048576, "length": 1048576, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": 1048576},
1862
+{ "start": 2097152, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false},
1863
+{ "start": 4194304, "length": 1048576, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": 4194304},
1864
+{ "start": 5242880, "length": 1048576, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false},
1865
+{ "start": 6291456, "length": 60817408, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}]
1866
1867
read 1048576/1048576 bytes at offset 0
1868
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1869
@@ -XXX,XX +XXX,XX @@ wrote 3145728/3145728 bytes at offset 3145728
1870
3 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1871
No errors were found on the image.
1872
1873
-[{ "start": 0, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": 0},
1874
-{ "start": 2097152, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false},
1875
-{ "start": 4194304, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "offset": 4194304},
1876
-{ "start": 6291456, "length": 60817408, "depth": 0, "present": true, "zero": false, "data": true, "offset": 6291456}]
1877
+[{ "start": 0, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": 0},
1878
+{ "start": 2097152, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false},
1879
+{ "start": 4194304, "length": 2097152, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": 4194304},
1880
+{ "start": 6291456, "length": 60817408, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": 6291456}]
1881
1882
read 1048576/1048576 bytes at offset 0
1883
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1884
@@ -XXX,XX +XXX,XX @@ read 1048576/1048576 bytes at offset 0
1885
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1886
Offset Length Mapped to File
1887
0 0x100000 0 TEST_DIR/t.qcow2.data
1888
-[{ "start": 0, "length": 1048576, "depth": 0, "present": true, "zero": false, "data": true, "offset": 0},
1889
-{ "start": 1048576, "length": 66060288, "depth": 0, "present": false, "zero": true, "data": false}]
1890
+[{ "start": 0, "length": 1048576, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": 0},
1891
+{ "start": 1048576, "length": 66060288, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}]
1892
1893
=== Copy offloading ===
1894
1895
diff --git a/tests/qemu-iotests/252.out b/tests/qemu-iotests/252.out
1896
index XXXXXXX..XXXXXXX 100644
1897
--- a/tests/qemu-iotests/252.out
1898
+++ b/tests/qemu-iotests/252.out
1899
@@ -XXX,XX +XXX,XX @@ read 131072/131072 bytes at offset 131072
1900
read 131072/131072 bytes at offset 262144
1901
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1902
1903
-[{ "start": 0, "length": 262144, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
1904
-{ "start": 262144, "length": 131072, "depth": 0, "present": false, "zero": true, "data": false}]
1905
+[{ "start": 0, "length": 262144, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1906
+{ "start": 262144, "length": 131072, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}]
1907
1908
read 131072/131072 bytes at offset 0
1909
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1910
@@ -XXX,XX +XXX,XX @@ read 131072/131072 bytes at offset 131072
1911
read 131072/131072 bytes at offset 262144
1912
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1913
1914
-[{ "start": 0, "length": 262144, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
1915
-{ "start": 262144, "length": 65536, "depth": 0, "present": true, "zero": true, "data": false},
1916
-{ "start": 327680, "length": 65536, "depth": 1, "present": false, "zero": true, "data": false}]
1917
+[{ "start": 0, "length": 262144, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1918
+{ "start": 262144, "length": 65536, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false},
1919
+{ "start": 327680, "length": 65536, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}]
1920
*** done
1921
diff --git a/tests/qemu-iotests/253.out b/tests/qemu-iotests/253.out
1922
index XXXXXXX..XXXXXXX 100644
1923
--- a/tests/qemu-iotests/253.out
1924
+++ b/tests/qemu-iotests/253.out
1925
@@ -XXX,XX +XXX,XX @@ QA output created by 253
1926
=== Check mapping of unaligned raw image ===
1927
1928
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048575
1929
-[{ "start": 0, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
1930
-{ "start": 4096, "length": 1044480, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET}]
1931
-[{ "start": 0, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
1932
-{ "start": 4096, "length": 1044480, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET}]
1933
+[{ "start": 0, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1934
+{ "start": 4096, "length": 1044480, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": OFFSET}]
1935
+[{ "start": 0, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1936
+{ "start": 4096, "length": 1044480, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": OFFSET}]
1937
wrote 65535/65535 bytes at offset 983040
1938
63.999 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1939
-[{ "start": 0, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
1940
-{ "start": 4096, "length": 978944, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET},
1941
-{ "start": 983040, "length": 65536, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}]
1942
-[{ "start": 0, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
1943
-{ "start": 4096, "length": 978944, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET},
1944
-{ "start": 983040, "length": 65536, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}]
1945
+[{ "start": 0, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1946
+{ "start": 4096, "length": 978944, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": OFFSET},
1947
+{ "start": 983040, "length": 65536, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}]
1948
+[{ "start": 0, "length": 4096, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
1949
+{ "start": 4096, "length": 978944, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": OFFSET},
1950
+{ "start": 983040, "length": 65536, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}]
1951
*** done
1952
diff --git a/tests/qemu-iotests/274.out b/tests/qemu-iotests/274.out
1953
index XXXXXXX..XXXXXXX 100644
1954
--- a/tests/qemu-iotests/274.out
1955
+++ b/tests/qemu-iotests/274.out
1956
@@ -XXX,XX +XXX,XX @@ read 1048576/1048576 bytes at offset 1048576
1957
0/1048576 bytes allocated at offset 1 MiB
1958
1959
=== Checking map ===
1960
-[{ "start": 0, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": 327680}]
1961
+[{ "start": 0, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": 327680}]
1962
1963
Offset Length Mapped to File
1964
0 0x200000 0x50000 TEST_DIR/PID-base
1965
1966
-[{ "start": 0, "length": 1048576, "depth": 1, "present": true, "zero": false, "data": true, "offset": 327680}]
1967
+[{ "start": 0, "length": 1048576, "depth": 1, "present": true, "zero": false, "data": true, "compressed": false, "offset": 327680}]
1968
1969
Offset Length Mapped to File
1970
0 0x100000 0x50000 TEST_DIR/PID-base
1971
1972
-[{ "start": 0, "length": 1048576, "depth": 2, "present": true, "zero": false, "data": true, "offset": 327680},
1973
-{ "start": 1048576, "length": 1048576, "depth": 0, "present": false, "zero": true, "data": false}]
1974
+[{ "start": 0, "length": 1048576, "depth": 2, "present": true, "zero": false, "data": true, "compressed": false, "offset": 327680},
1975
+{ "start": 1048576, "length": 1048576, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}]
1976
1977
Offset Length Mapped to File
1978
0 0x100000 0x50000 TEST_DIR/PID-base
1979
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 5368709120
1980
1 GiB (0x40000000) bytes not allocated at offset 0 bytes (0x0)
1981
7 GiB (0x1c0000000) bytes allocated at offset 1 GiB (0x40000000)
1982
1983
-[{ "start": 0, "length": 1073741824, "depth": 1, "present": false, "zero": true, "data": false},
1984
-{ "start": 1073741824, "length": 7516192768, "depth": 0, "present": true, "zero": true, "data": false}]
1985
+[{ "start": 0, "length": 1073741824, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false},
1986
+{ "start": 1073741824, "length": 7516192768, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}]
1987
1988
=== preallocation=metadata ===
1989
wrote 65536/65536 bytes at offset 33285996544
1990
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 33285996544
1991
30 GiB (0x780000000) bytes not allocated at offset 0 bytes (0x0)
1992
3 GiB (0xc0000000) bytes allocated at offset 30 GiB (0x780000000)
1993
1994
-[{ "start": 0, "length": 32212254720, "depth": 1, "present": false, "zero": true, "data": false},
1995
-{ "start": 32212254720, "length": 536870912, "depth": 0, "present": true, "zero": true, "data": false, "offset": 327680},
1996
-{ "start": 32749125632, "length": 536870912, "depth": 0, "present": true, "zero": true, "data": false, "offset": 537264128},
1997
-{ "start": 33285996544, "length": 536870912, "depth": 0, "present": true, "zero": true, "data": false, "offset": 1074200576},
1998
-{ "start": 33822867456, "length": 536870912, "depth": 0, "present": true, "zero": true, "data": false, "offset": 1611137024},
1999
-{ "start": 34359738368, "length": 536870912, "depth": 0, "present": true, "zero": true, "data": false, "offset": 2148139008},
2000
-{ "start": 34896609280, "length": 536870912, "depth": 0, "present": true, "zero": true, "data": false, "offset": 2685075456}]
2001
+[{ "start": 0, "length": 32212254720, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false},
2002
+{ "start": 32212254720, "length": 536870912, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": 327680},
2003
+{ "start": 32749125632, "length": 536870912, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": 537264128},
2004
+{ "start": 33285996544, "length": 536870912, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": 1074200576},
2005
+{ "start": 33822867456, "length": 536870912, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": 1611137024},
2006
+{ "start": 34359738368, "length": 536870912, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": 2148139008},
2007
+{ "start": 34896609280, "length": 536870912, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": 2685075456}]
2008
2009
=== preallocation=falloc ===
2010
wrote 65536/65536 bytes at offset 9437184
2011
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 9437184
2012
5 MiB (0x500000) bytes not allocated at offset 0 bytes (0x0)
2013
10 MiB (0xa00000) bytes allocated at offset 5 MiB (0x500000)
2014
2015
-[{ "start": 0, "length": 5242880, "depth": 1, "present": false, "zero": true, "data": false},
2016
-{ "start": 5242880, "length": 10485760, "depth": 0, "present": true, "zero": false, "data": true, "offset": 327680}]
2017
+[{ "start": 0, "length": 5242880, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false},
2018
+{ "start": 5242880, "length": 10485760, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": 327680}]
2019
2020
=== preallocation=full ===
2021
wrote 65536/65536 bytes at offset 11534336
2022
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 11534336
2023
8 MiB (0x800000) bytes not allocated at offset 0 bytes (0x0)
2024
4 MiB (0x400000) bytes allocated at offset 8 MiB (0x800000)
2025
2026
-[{ "start": 0, "length": 8388608, "depth": 1, "present": false, "zero": true, "data": false},
2027
-{ "start": 8388608, "length": 4194304, "depth": 0, "present": true, "zero": false, "data": true, "offset": 327680}]
2028
+[{ "start": 0, "length": 8388608, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false},
2029
+{ "start": 8388608, "length": 4194304, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": 327680}]
2030
2031
=== preallocation=off ===
2032
wrote 65536/65536 bytes at offset 259072
2033
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 259072
2034
192 KiB (0x30000) bytes not allocated at offset 0 bytes (0x0)
2035
320 KiB (0x50000) bytes allocated at offset 192 KiB (0x30000)
2036
2037
-[{ "start": 0, "length": 196608, "depth": 1, "present": false, "zero": true, "data": false},
2038
-{ "start": 196608, "length": 65536, "depth": 0, "present": true, "zero": false, "data": true, "offset": 327680},
2039
-{ "start": 262144, "length": 262144, "depth": 0, "present": true, "zero": true, "data": false}]
2040
+[{ "start": 0, "length": 196608, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false},
2041
+{ "start": 196608, "length": 65536, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": 327680},
2042
+{ "start": 262144, "length": 262144, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}]
2043
2044
=== preallocation=off ===
2045
wrote 65536/65536 bytes at offset 344064
2046
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 344064
2047
256 KiB (0x40000) bytes not allocated at offset 0 bytes (0x0)
2048
256 KiB (0x40000) bytes allocated at offset 256 KiB (0x40000)
2049
2050
-[{ "start": 0, "length": 262144, "depth": 1, "present": false, "zero": true, "data": false},
2051
-{ "start": 262144, "length": 262144, "depth": 0, "present": true, "zero": true, "data": false}]
2052
+[{ "start": 0, "length": 262144, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false},
2053
+{ "start": 262144, "length": 262144, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}]
2054
2055
=== preallocation=off ===
2056
wrote 65536/65536 bytes at offset 446464
2057
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 446464
2058
256 KiB (0x40000) bytes not allocated at offset 0 bytes (0x0)
2059
244 KiB (0x3d000) bytes allocated at offset 256 KiB (0x40000)
2060
2061
-[{ "start": 0, "length": 262144, "depth": 1, "present": false, "zero": true, "data": false},
2062
-{ "start": 262144, "length": 249856, "depth": 0, "present": true, "zero": true, "data": false}]
2063
+[{ "start": 0, "length": 262144, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false},
2064
+{ "start": 262144, "length": 249856, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}]
2065
2066
diff --git a/tests/qemu-iotests/tests/nbd-qemu-allocation.out b/tests/qemu-iotests/tests/nbd-qemu-allocation.out
2067
index XXXXXXX..XXXXXXX 100644
2068
--- a/tests/qemu-iotests/tests/nbd-qemu-allocation.out
2069
+++ b/tests/qemu-iotests/tests/nbd-qemu-allocation.out
2070
@@ -XXX,XX +XXX,XX @@ wrote 2097152/2097152 bytes at offset 1048576
2071
2072
=== Check allocation over NBD ===
2073
2074
-[{ "start": 0, "length": 1048576, "depth": 1, "present": true, "zero": false, "data": true, "offset": 327680},
2075
-{ "start": 1048576, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": 327680},
2076
-{ "start": 3145728, "length": 1048576, "depth": 1, "present": false, "zero": true, "data": false}]
2077
+[{ "start": 0, "length": 1048576, "depth": 1, "present": true, "zero": false, "data": true, "compressed": false, "offset": 327680},
2078
+{ "start": 1048576, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": 327680},
2079
+{ "start": 3145728, "length": 1048576, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}]
2080
exports available: 1
2081
export: ''
2082
size: 4194304
2083
@@ -XXX,XX +XXX,XX @@ exports available: 1
2084
available meta contexts: 2
2085
base:allocation
2086
qemu:allocation-depth
2087
-[{ "start": 0, "length": 3145728, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
2088
-{ "start": 3145728, "length": 1048576, "depth": 0, "present": true, "zero": true, "data": false, "offset": OFFSET}]
2089
-[{ "start": 0, "length": 1048576, "depth": 0, "present": true, "zero": true, "data": true, "offset": OFFSET},
2090
-{ "start": 1048576, "length": 2097152, "depth": 0, "present": false, "zero": false, "data": false},
2091
-{ "start": 3145728, "length": 1048576, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}]
2092
+[{ "start": 0, "length": 3145728, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
2093
+{ "start": 3145728, "length": 1048576, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false, "offset": OFFSET}]
2094
+[{ "start": 0, "length": 1048576, "depth": 0, "present": true, "zero": true, "data": true, "compressed": false, "offset": OFFSET},
2095
+{ "start": 1048576, "length": 2097152, "depth": 0, "present": false, "zero": false, "data": false, "compressed": false},
2096
+{ "start": 3145728, "length": 1048576, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}]
2097
*** done
2098
diff --git a/tests/qemu-iotests/tests/qemu-img-bitmaps.out b/tests/qemu-iotests/tests/qemu-img-bitmaps.out
2099
index XXXXXXX..XXXXXXX 100644
2100
--- a/tests/qemu-iotests/tests/qemu-img-bitmaps.out
2101
+++ b/tests/qemu-iotests/tests/qemu-img-bitmaps.out
2102
@@ -XXX,XX +XXX,XX @@ Format specific information:
2103
2104
=== Check bitmap contents ===
2105
2106
-[{ "start": 0, "length": 3145728, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
2107
-{ "start": 3145728, "length": 1048576, "depth": 0, "present": false, "zero": false, "data": false},
2108
-{ "start": 4194304, "length": 6291456, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}]
2109
-[{ "start": 0, "length": 1048576, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
2110
-{ "start": 1048576, "length": 1048576, "depth": 0, "present": false, "zero": false, "data": false},
2111
-{ "start": 2097152, "length": 8388608, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}]
2112
-[{ "start": 0, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
2113
-{ "start": 2097152, "length": 1048576, "depth": 0, "present": false, "zero": false, "data": false},
2114
-{ "start": 3145728, "length": 7340032, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}]
2115
-[{ "start": 0, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET},
2116
-{ "start": 2097152, "length": 1048576, "depth": 0, "present": false, "zero": false, "data": false},
2117
-{ "start": 3145728, "length": 7340032, "depth": 0, "present": true, "zero": false, "data": true, "offset": OFFSET}]
2118
+[{ "start": 0, "length": 3145728, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
2119
+{ "start": 3145728, "length": 1048576, "depth": 0, "present": false, "zero": false, "data": false, "compressed": false},
2120
+{ "start": 4194304, "length": 6291456, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}]
2121
+[{ "start": 0, "length": 1048576, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
2122
+{ "start": 1048576, "length": 1048576, "depth": 0, "present": false, "zero": false, "data": false, "compressed": false},
2123
+{ "start": 2097152, "length": 8388608, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}]
2124
+[{ "start": 0, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
2125
+{ "start": 2097152, "length": 1048576, "depth": 0, "present": false, "zero": false, "data": false, "compressed": false},
2126
+{ "start": 3145728, "length": 7340032, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}]
2127
+[{ "start": 0, "length": 2097152, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET},
2128
+{ "start": 2097152, "length": 1048576, "depth": 0, "present": false, "zero": false, "data": false, "compressed": false},
2129
+{ "start": 3145728, "length": 7340032, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}]
2130
2131
=== Check handling of inconsistent bitmap ===
23
2132
24
--
2133
--
25
2.40.0
2134
2.41.0
diff view generated by jsdifflib
1
From: Stefan Hajnoczi <stefanha@redhat.com>
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
2
3
The main loop thread increments/decrements BlockBackend->quiesce_counter
3
The synchronous bdrv_aio_cancel() function needs the acb's AioContext so
4
when drained sections begin/end. The counter is read in the I/O code
4
it can call aio_poll() to wait for cancellation.
5
path. Therefore this field is used to communicate between threads
5
6
without a lock.
6
It turns out that all users run under the BQL in the main AioContext, so
7
7
this callback is not needed.
8
Acquire/release are not necessary because the BlockBackend->in_flight
8
9
counter already uses sequentially consistent accesses and running I/O
9
Remove the callback, mark bdrv_aio_cancel() GLOBAL_STATE_CODE just like
10
requests hold that counter when blk_wait_while_drained() is called.
10
its blk_aio_cancel() caller, and poll the main loop AioContext.
11
qatomic_read() can be used.
11
12
12
The purpose of this cleanup is to identify bdrv_aio_cancel() as an API
13
Use qatomic_fetch_inc()/qatomic_fetch_dec() for modifications even
13
that does not work with the multi-queue block layer.
14
though sequentially consistent atomic accesses are not strictly required
15
here. They are, however, nicer to read than multiple calls to
16
qatomic_read() and qatomic_set(). Since beginning and ending drain is
17
not a hot path the extra cost doesn't matter.
18
14
19
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
15
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
20
Message-Id: <20230307210427.269214-2-stefanha@redhat.com>
16
Message-ID: <20230912231037.826804-2-stefanha@redhat.com>
21
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
22
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
17
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
18
Reviewed-by: Eric Blake <eblake@redhat.com>
19
Reviewed-by: Klaus Jensen <k.jensen@samsung.com>
23
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
20
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
24
---
21
---
25
block/block-backend.c | 14 +++++++-------
22
include/block/aio.h | 1 -
26
1 file changed, 7 insertions(+), 7 deletions(-)
23
include/block/block-global-state.h | 2 ++
27
24
include/block/block-io.h | 1 -
25
block/block-backend.c | 17 -----------------
26
block/io.c | 23 ++++++++---------------
27
hw/nvme/ctrl.c | 7 -------
28
softmmu/dma-helpers.c | 8 --------
29
util/thread-pool.c | 8 --------
30
8 files changed, 10 insertions(+), 57 deletions(-)
31
32
diff --git a/include/block/aio.h b/include/block/aio.h
33
index XXXXXXX..XXXXXXX 100644
34
--- a/include/block/aio.h
35
+++ b/include/block/aio.h
36
@@ -XXX,XX +XXX,XX @@ typedef void BlockCompletionFunc(void *opaque, int ret);
37
38
typedef struct AIOCBInfo {
39
void (*cancel_async)(BlockAIOCB *acb);
40
- AioContext *(*get_aio_context)(BlockAIOCB *acb);
41
size_t aiocb_size;
42
} AIOCBInfo;
43
44
diff --git a/include/block/block-global-state.h b/include/block/block-global-state.h
45
index XXXXXXX..XXXXXXX 100644
46
--- a/include/block/block-global-state.h
47
+++ b/include/block/block-global-state.h
48
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin_nopoll(void);
49
void bdrv_drain_all_end(void);
50
void bdrv_drain_all(void);
51
52
+void bdrv_aio_cancel(BlockAIOCB *acb);
53
+
54
int bdrv_has_zero_init_1(BlockDriverState *bs);
55
int bdrv_has_zero_init(BlockDriverState *bs);
56
BlockDriverState *bdrv_find_node(const char *node_name);
57
diff --git a/include/block/block-io.h b/include/block/block-io.h
58
index XXXXXXX..XXXXXXX 100644
59
--- a/include/block/block-io.h
60
+++ b/include/block/block-io.h
61
@@ -XXX,XX +XXX,XX @@ bdrv_co_delete_file_noerr(BlockDriverState *bs);
62
63
64
/* async block I/O */
65
-void bdrv_aio_cancel(BlockAIOCB *acb);
66
void bdrv_aio_cancel_async(BlockAIOCB *acb);
67
68
/* sg packet commands */
28
diff --git a/block/block-backend.c b/block/block-backend.c
69
diff --git a/block/block-backend.c b/block/block-backend.c
29
index XXXXXXX..XXXXXXX 100644
70
index XXXXXXX..XXXXXXX 100644
30
--- a/block/block-backend.c
71
--- a/block/block-backend.c
31
+++ b/block/block-backend.c
72
+++ b/block/block-backend.c
32
@@ -XXX,XX +XXX,XX @@ struct BlockBackend {
73
@@ -XXX,XX +XXX,XX @@
33
NotifierList remove_bs_notifiers, insert_bs_notifiers;
74
34
QLIST_HEAD(, BlockBackendAioNotifier) aio_notifiers;
75
#define NOT_DONE 0x7fffffff /* used while emulated sync operation in progress */
35
76
36
- int quiesce_counter;
77
-static AioContext *blk_aiocb_get_aio_context(BlockAIOCB *acb);
37
+ int quiesce_counter; /* atomic: written under BQL, read by other threads */
78
-
38
CoQueue queued_requests;
79
typedef struct BlockBackendAioNotifier {
39
bool disable_request_queuing;
80
void (*attached_aio_context)(AioContext *new_context, void *opaque);
40
81
void (*detach_aio_context)(void *opaque);
41
@@ -XXX,XX +XXX,XX @@ void blk_set_dev_ops(BlockBackend *blk, const BlockDevOps *ops,
82
@@ -XXX,XX +XXX,XX @@ typedef struct BlockBackendAIOCB {
42
blk->dev_opaque = opaque;
83
} BlockBackendAIOCB;
43
84
44
/* Are we currently quiesced? Should we enforce this right now? */
85
static const AIOCBInfo block_backend_aiocb_info = {
45
- if (blk->quiesce_counter && ops && ops->drained_begin) {
86
- .get_aio_context = blk_aiocb_get_aio_context,
46
+ if (qatomic_read(&blk->quiesce_counter) && ops && ops->drained_begin) {
87
.aiocb_size = sizeof(BlockBackendAIOCB),
47
ops->drained_begin(opaque);
88
};
89
90
@@ -XXX,XX +XXX,XX @@ typedef struct BlkAioEmAIOCB {
91
bool has_returned;
92
} BlkAioEmAIOCB;
93
94
-static AioContext *blk_aio_em_aiocb_get_aio_context(BlockAIOCB *acb_)
95
-{
96
- BlkAioEmAIOCB *acb = container_of(acb_, BlkAioEmAIOCB, common);
97
-
98
- return blk_get_aio_context(acb->rwco.blk);
99
-}
100
-
101
static const AIOCBInfo blk_aio_em_aiocb_info = {
102
.aiocb_size = sizeof(BlkAioEmAIOCB),
103
- .get_aio_context = blk_aio_em_aiocb_get_aio_context,
104
};
105
106
static void blk_aio_complete(BlkAioEmAIOCB *acb)
107
@@ -XXX,XX +XXX,XX @@ AioContext *blk_get_aio_context(BlockBackend *blk)
108
return blk->ctx;
109
}
110
111
-static AioContext *blk_aiocb_get_aio_context(BlockAIOCB *acb)
112
-{
113
- BlockBackendAIOCB *blk_acb = DO_UPCAST(BlockBackendAIOCB, common, acb);
114
- return blk_get_aio_context(blk_acb->blk);
115
-}
116
-
117
int blk_set_aio_context(BlockBackend *blk, AioContext *new_context,
118
Error **errp)
119
{
120
diff --git a/block/io.c b/block/io.c
121
index XXXXXXX..XXXXXXX 100644
122
--- a/block/io.c
123
+++ b/block/io.c
124
@@ -XXX,XX +XXX,XX @@ int bdrv_load_vmstate(BlockDriverState *bs, uint8_t *buf,
125
/**************************************************************/
126
/* async I/Os */
127
128
+/**
129
+ * Synchronously cancels an acb. Must be called with the BQL held and the acb
130
+ * must be processed with the BQL held too (IOThreads are not allowed).
131
+ *
132
+ * Use bdrv_aio_cancel_async() instead when possible.
133
+ */
134
void bdrv_aio_cancel(BlockAIOCB *acb)
135
{
136
- IO_CODE();
137
+ GLOBAL_STATE_CODE();
138
qemu_aio_ref(acb);
139
bdrv_aio_cancel_async(acb);
140
- while (acb->refcnt > 1) {
141
- if (acb->aiocb_info->get_aio_context) {
142
- aio_poll(acb->aiocb_info->get_aio_context(acb), true);
143
- } else if (acb->bs) {
144
- /* qemu_aio_ref and qemu_aio_unref are not thread-safe, so
145
- * assert that we're not using an I/O thread. Thread-safe
146
- * code should use bdrv_aio_cancel_async exclusively.
147
- */
148
- assert(bdrv_get_aio_context(acb->bs) == qemu_get_aio_context());
149
- aio_poll(bdrv_get_aio_context(acb->bs), true);
150
- } else {
151
- abort();
152
- }
153
- }
154
+ AIO_WAIT_WHILE_UNLOCKED(NULL, acb->refcnt > 1);
155
qemu_aio_unref(acb);
156
}
157
158
diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c
159
index XXXXXXX..XXXXXXX 100644
160
--- a/hw/nvme/ctrl.c
161
+++ b/hw/nvme/ctrl.c
162
@@ -XXX,XX +XXX,XX @@ static inline bool nvme_is_write(NvmeRequest *req)
163
rw->opcode == NVME_CMD_WRITE_ZEROES;
164
}
165
166
-static AioContext *nvme_get_aio_context(BlockAIOCB *acb)
167
-{
168
- return qemu_get_aio_context();
169
-}
170
-
171
static void nvme_misc_cb(void *opaque, int ret)
172
{
173
NvmeRequest *req = opaque;
174
@@ -XXX,XX +XXX,XX @@ static void nvme_flush_cancel(BlockAIOCB *acb)
175
static const AIOCBInfo nvme_flush_aiocb_info = {
176
.aiocb_size = sizeof(NvmeFlushAIOCB),
177
.cancel_async = nvme_flush_cancel,
178
- .get_aio_context = nvme_get_aio_context,
179
};
180
181
static void nvme_do_flush(NvmeFlushAIOCB *iocb);
182
@@ -XXX,XX +XXX,XX @@ static void nvme_format_cancel(BlockAIOCB *aiocb)
183
static const AIOCBInfo nvme_format_aiocb_info = {
184
.aiocb_size = sizeof(NvmeFormatAIOCB),
185
.cancel_async = nvme_format_cancel,
186
- .get_aio_context = nvme_get_aio_context,
187
};
188
189
static void nvme_format_set(NvmeNamespace *ns, uint8_t lbaf, uint8_t mset,
190
diff --git a/softmmu/dma-helpers.c b/softmmu/dma-helpers.c
191
index XXXXXXX..XXXXXXX 100644
192
--- a/softmmu/dma-helpers.c
193
+++ b/softmmu/dma-helpers.c
194
@@ -XXX,XX +XXX,XX @@ static void dma_aio_cancel(BlockAIOCB *acb)
48
}
195
}
49
}
196
}
50
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn blk_wait_while_drained(BlockBackend *blk)
197
51
{
198
-static AioContext *dma_get_aio_context(BlockAIOCB *acb)
52
assert(blk->in_flight > 0);
199
-{
53
200
- DMAAIOCB *dbs = container_of(acb, DMAAIOCB, common);
54
- if (blk->quiesce_counter && !blk->disable_request_queuing) {
201
-
55
+ if (qatomic_read(&blk->quiesce_counter) && !blk->disable_request_queuing) {
202
- return dbs->ctx;
56
blk_dec_in_flight(blk);
203
-}
57
qemu_co_queue_wait(&blk->queued_requests, NULL);
204
-
58
blk_inc_in_flight(blk);
205
static const AIOCBInfo dma_aiocb_info = {
59
@@ -XXX,XX +XXX,XX @@ static void blk_root_drained_begin(BdrvChild *child)
206
.aiocb_size = sizeof(DMAAIOCB),
60
BlockBackend *blk = child->opaque;
207
.cancel_async = dma_aio_cancel,
61
ThrottleGroupMember *tgm = &blk->public.throttle_group_member;
208
- .get_aio_context = dma_get_aio_context,
62
209
};
63
- if (++blk->quiesce_counter == 1) {
210
64
+ if (qatomic_fetch_inc(&blk->quiesce_counter) == 0) {
211
BlockAIOCB *dma_blk_io(AioContext *ctx,
65
if (blk->dev_ops && blk->dev_ops->drained_begin) {
212
diff --git a/util/thread-pool.c b/util/thread-pool.c
66
blk->dev_ops->drained_begin(blk->dev_opaque);
213
index XXXXXXX..XXXXXXX 100644
67
}
214
--- a/util/thread-pool.c
68
@@ -XXX,XX +XXX,XX @@ static bool blk_root_drained_poll(BdrvChild *child)
215
+++ b/util/thread-pool.c
69
{
216
@@ -XXX,XX +XXX,XX @@ static void thread_pool_cancel(BlockAIOCB *acb)
70
BlockBackend *blk = child->opaque;
217
71
bool busy = false;
218
}
72
- assert(blk->quiesce_counter);
219
73
+ assert(qatomic_read(&blk->quiesce_counter));
220
-static AioContext *thread_pool_get_aio_context(BlockAIOCB *acb)
74
221
-{
75
if (blk->dev_ops && blk->dev_ops->drained_poll) {
222
- ThreadPoolElement *elem = (ThreadPoolElement *)acb;
76
busy = blk->dev_ops->drained_poll(blk->dev_opaque);
223
- ThreadPool *pool = elem->pool;
77
@@ -XXX,XX +XXX,XX @@ static bool blk_root_drained_poll(BdrvChild *child)
224
- return pool->ctx;
78
static void blk_root_drained_end(BdrvChild *child)
225
-}
79
{
226
-
80
BlockBackend *blk = child->opaque;
227
static const AIOCBInfo thread_pool_aiocb_info = {
81
- assert(blk->quiesce_counter);
228
.aiocb_size = sizeof(ThreadPoolElement),
82
+ assert(qatomic_read(&blk->quiesce_counter));
229
.cancel_async = thread_pool_cancel,
83
230
- .get_aio_context = thread_pool_get_aio_context,
84
assert(blk->public.throttle_group_member.io_limits_disabled);
231
};
85
qatomic_dec(&blk->public.throttle_group_member.io_limits_disabled);
232
86
233
BlockAIOCB *thread_pool_submit_aio(ThreadPoolFunc *func, void *arg,
87
- if (--blk->quiesce_counter == 0) {
88
+ if (qatomic_fetch_dec(&blk->quiesce_counter) == 1) {
89
if (blk->dev_ops && blk->dev_ops->drained_end) {
90
blk->dev_ops->drained_end(blk->dev_opaque);
91
}
92
--
234
--
93
2.40.0
235
2.41.0
94
95
diff view generated by jsdifflib
1
From: Stefan Hajnoczi <stefanha@redhat.com>
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
2
3
This field is accessed by multiple threads without a lock. Use explicit
3
This patch fixes a race condition in test-bdrv-drain that is difficult
4
qatomic_read()/qatomic_set() calls. There is no need for acquire/release
4
to reproduce. test-bdrv-drain sometimes fails without an error message
5
because blk_set_disable_request_queuing() doesn't provide any
5
on the block pull request sent by Kevin Wolf on Sep 4, 2023. I was able
6
guarantees (it helps that it's used at BlockBackend creation time and
6
to reproduce it locally and found that "block-backend: process I/O in
7
not when there is I/O in flight).
7
the current AioContext" (in this patch series) is the first commit where
8
it reproduces.
9
10
I do not know why "block-backend: process I/O in the current AioContext"
11
exposes this bug. It might be related to the fact that the test's preadv
12
request runs in the main thread instead of IOThread a after my commit.
13
That might simply change the timing of the test.
14
15
Now on to the race condition in test-bdrv-drain. The main thread
16
schedules a BH in IOThread a and then drains the BDS:
17
18
aio_bh_schedule_oneshot(ctx_a, test_iothread_main_thread_bh, &data);
19
20
/* The request is running on the IOThread a. Draining its block device
21
* will make sure that it has completed as far as the BDS is concerned,
22
* but the drain in this thread can continue immediately after
23
* bdrv_dec_in_flight() and aio_ret might be assigned only slightly
24
* later. */
25
do_drain_begin(drain_type, bs);
26
27
If the BH completes before do_drain_begin() then there is nothing to
28
worry about.
29
30
If the BH invokes bdrv_flush() before do_drain_begin(), then
31
do_drain_begin() waits for it to complete.
32
33
The problematic case is when do_drain_begin() runs before the BH enters
34
bdrv_flush(). Then do_drain_begin() misses the BH and the drain
35
mechanism has failed in quiescing I/O.
36
37
Fix this by incrementing the in_flight counter so that do_drain_begin()
38
waits for test_iothread_main_thread_bh().
8
39
9
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
40
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
10
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
41
Message-ID: <20230912231037.826804-3-stefanha@redhat.com>
11
Message-Id: <20230307210427.269214-3-stefanha@redhat.com>
42
Reviewed-by: Eric Blake <eblake@redhat.com>
12
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
13
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
43
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
44
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
---
45
---
16
block/block-backend.c | 7 ++++---
46
tests/unit/test-bdrv-drain.c | 8 ++++++++
17
1 file changed, 4 insertions(+), 3 deletions(-)
47
1 file changed, 8 insertions(+)
18
48
19
diff --git a/block/block-backend.c b/block/block-backend.c
49
diff --git a/tests/unit/test-bdrv-drain.c b/tests/unit/test-bdrv-drain.c
20
index XXXXXXX..XXXXXXX 100644
50
index XXXXXXX..XXXXXXX 100644
21
--- a/block/block-backend.c
51
--- a/tests/unit/test-bdrv-drain.c
22
+++ b/block/block-backend.c
52
+++ b/tests/unit/test-bdrv-drain.c
23
@@ -XXX,XX +XXX,XX @@ struct BlockBackend {
53
@@ -XXX,XX +XXX,XX @@ static void test_iothread_main_thread_bh(void *opaque)
24
54
* executed during drain, otherwise this would deadlock. */
25
int quiesce_counter; /* atomic: written under BQL, read by other threads */
55
aio_context_acquire(bdrv_get_aio_context(data->bs));
26
CoQueue queued_requests;
56
bdrv_flush(data->bs);
27
- bool disable_request_queuing;
57
+ bdrv_dec_in_flight(data->bs); /* incremented by test_iothread_common() */
28
+ bool disable_request_queuing; /* atomic */
58
aio_context_release(bdrv_get_aio_context(data->bs));
29
30
VMChangeStateEntry *vmsh;
31
bool force_allow_inactivate;
32
@@ -XXX,XX +XXX,XX @@ void blk_set_allow_aio_context_change(BlockBackend *blk, bool allow)
33
void blk_set_disable_request_queuing(BlockBackend *blk, bool disable)
34
{
35
IO_CODE();
36
- blk->disable_request_queuing = disable;
37
+ qatomic_set(&blk->disable_request_queuing, disable);
38
}
59
}
39
60
40
static int coroutine_fn GRAPH_RDLOCK
61
@@ -XXX,XX +XXX,XX @@ static void test_iothread_common(enum drain_type drain_type, int drain_thread)
41
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn blk_wait_while_drained(BlockBackend *blk)
62
aio_context_acquire(ctx_a);
42
{
63
}
43
assert(blk->in_flight > 0);
64
44
65
+ /*
45
- if (qatomic_read(&blk->quiesce_counter) && !blk->disable_request_queuing) {
66
+ * Increment in_flight so that do_drain_begin() waits for
46
+ if (qatomic_read(&blk->quiesce_counter) &&
67
+ * test_iothread_main_thread_bh(). This prevents the race between
47
+ !qatomic_read(&blk->disable_request_queuing)) {
68
+ * test_iothread_main_thread_bh() in IOThread a and do_drain_begin() in
48
blk_dec_in_flight(blk);
69
+ * this thread. test_iothread_main_thread_bh() decrements in_flight.
49
qemu_co_queue_wait(&blk->queued_requests, NULL);
70
+ */
50
blk_inc_in_flight(blk);
71
+ bdrv_inc_in_flight(bs);
72
aio_bh_schedule_oneshot(ctx_a, test_iothread_main_thread_bh, &data);
73
74
/* The request is running on the IOThread a. Draining its block device
51
--
75
--
52
2.40.0
76
2.41.0
53
54
diff view generated by jsdifflib
1
From: Stefan Hajnoczi <stefanha@redhat.com>
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
2
3
There is no need for the AioContext lock in bdrv_drain_all() because
3
Switch blk_aio_*() APIs over to multi-queue by using
4
nothing in AIO_WAIT_WHILE() needs the lock and the condition is atomic.
4
qemu_get_current_aio_context() instead of blk_get_aio_context(). This
5
change will allow devices to process I/O in multiple IOThreads in the
6
future.
5
7
6
AIO_WAIT_WHILE_UNLOCKED() has no use for the AioContext parameter other
8
I audited existing blk_aio_*() callers:
7
than performing a check that is nowadays already done by the
9
- migration/block.c: blk_mig_lock() protects the data accessed by the
8
GLOBAL_STATE_CODE()/IO_CODE() macros. Set the ctx argument to NULL here
10
completion callback.
9
to help us keep track of all converted callers. Eventually all callers
11
- The remaining emulated devices and exports run with
10
will have been converted and then the argument can be dropped entirely.
12
qemu_get_aio_context() == blk_get_aio_context().
11
13
14
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
15
Message-ID: <20230912231037.826804-4-stefanha@redhat.com>
12
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
16
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
13
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
17
Reviewed-by: Eric Blake <eblake@redhat.com>
14
Message-Id: <20230309190855.414275-2-stefanha@redhat.com>
15
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
16
Reviewed-by: Wilfred Mallawa <wilfred.mallawa@wdc.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
18
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
18
---
19
---
19
block/block-backend.c | 8 +-------
20
block/block-backend.c | 6 +++---
20
1 file changed, 1 insertion(+), 7 deletions(-)
21
1 file changed, 3 insertions(+), 3 deletions(-)
21
22
22
diff --git a/block/block-backend.c b/block/block-backend.c
23
diff --git a/block/block-backend.c b/block/block-backend.c
23
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
24
--- a/block/block-backend.c
25
--- a/block/block-backend.c
25
+++ b/block/block-backend.c
26
+++ b/block/block-backend.c
26
@@ -XXX,XX +XXX,XX @@ void blk_drain_all(void)
27
@@ -XXX,XX +XXX,XX @@ BlockAIOCB *blk_abort_aio_request(BlockBackend *blk,
27
bdrv_drain_all_begin();
28
acb->blk = blk;
28
29
acb->ret = ret;
29
while ((blk = blk_all_next(blk)) != NULL) {
30
30
- AioContext *ctx = blk_get_aio_context(blk);
31
- replay_bh_schedule_oneshot_event(blk_get_aio_context(blk),
31
-
32
+ replay_bh_schedule_oneshot_event(qemu_get_current_aio_context(),
32
- aio_context_acquire(ctx);
33
error_callback_bh, acb);
33
-
34
return &acb->common;
34
/* We may have -ENOMEDIUM completions in flight */
35
}
35
- AIO_WAIT_WHILE(ctx, qatomic_read(&blk->in_flight) > 0);
36
@@ -XXX,XX +XXX,XX @@ static BlockAIOCB *blk_aio_prwv(BlockBackend *blk, int64_t offset,
36
-
37
acb->has_returned = false;
37
- aio_context_release(ctx);
38
38
+ AIO_WAIT_WHILE_UNLOCKED(NULL, qatomic_read(&blk->in_flight) > 0);
39
co = qemu_coroutine_create(co_entry, acb);
40
- aio_co_enter(blk_get_aio_context(blk), co);
41
+ aio_co_enter(qemu_get_current_aio_context(), co);
42
43
acb->has_returned = true;
44
if (acb->rwco.ret != NOT_DONE) {
45
- replay_bh_schedule_oneshot_event(blk_get_aio_context(blk),
46
+ replay_bh_schedule_oneshot_event(qemu_get_current_aio_context(),
47
blk_aio_complete_bh, acb);
39
}
48
}
40
49
41
bdrv_drain_all_end();
42
--
50
--
43
2.40.0
51
2.41.0
diff view generated by jsdifflib
1
From: Stefan Hajnoczi <stefanha@redhat.com>
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
2
3
The CoQueue API offers thread-safety via the lock argument that
3
Process zoned requests in the current thread's AioContext instead of in
4
qemu_co_queue_wait() and qemu_co_enter_next() take. BlockBackend
4
the BlockBackend's AioContext.
5
currently does not make use of the lock argument. This means that
6
multiple threads submitting I/O requests can corrupt the CoQueue's
7
QSIMPLEQ.
8
5
9
Add a QemuMutex and pass it to CoQueue APIs so that the queue is
6
There is no need to use the BlockBackend's AioContext thanks to CoMutex
10
protected. While we're at it, also assert that the queue is empty when
7
bs->wps->colock, which protects zone metadata.
11
the BlockBackend is deleted.
12
8
13
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
9
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
14
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
10
Message-ID: <20230912231037.826804-5-stefanha@redhat.com>
15
Message-Id: <20230307210427.269214-4-stefanha@redhat.com>
16
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
11
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
12
Reviewed-by: Eric Blake <eblake@redhat.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
18
---
14
---
19
block/block-backend.c | 18 ++++++++++++++++--
15
block/block-backend.c | 12 ++++++------
20
1 file changed, 16 insertions(+), 2 deletions(-)
16
1 file changed, 6 insertions(+), 6 deletions(-)
21
17
22
diff --git a/block/block-backend.c b/block/block-backend.c
18
diff --git a/block/block-backend.c b/block/block-backend.c
23
index XXXXXXX..XXXXXXX 100644
19
index XXXXXXX..XXXXXXX 100644
24
--- a/block/block-backend.c
20
--- a/block/block-backend.c
25
+++ b/block/block-backend.c
21
+++ b/block/block-backend.c
26
@@ -XXX,XX +XXX,XX @@ struct BlockBackend {
22
@@ -XXX,XX +XXX,XX @@ BlockAIOCB *blk_aio_zone_report(BlockBackend *blk, int64_t offset,
27
QLIST_HEAD(, BlockBackendAioNotifier) aio_notifiers;
23
acb->has_returned = false;
28
24
29
int quiesce_counter; /* atomic: written under BQL, read by other threads */
25
co = qemu_coroutine_create(blk_aio_zone_report_entry, acb);
30
+ QemuMutex queued_requests_lock; /* protects queued_requests */
26
- aio_co_enter(blk_get_aio_context(blk), co);
31
CoQueue queued_requests;
27
+ aio_co_enter(qemu_get_current_aio_context(), co);
32
bool disable_request_queuing; /* atomic */
28
33
29
acb->has_returned = true;
34
@@ -XXX,XX +XXX,XX @@ BlockBackend *blk_new(AioContext *ctx, uint64_t perm, uint64_t shared_perm)
30
if (acb->rwco.ret != NOT_DONE) {
35
31
- replay_bh_schedule_oneshot_event(blk_get_aio_context(blk),
36
block_acct_init(&blk->stats);
32
+ replay_bh_schedule_oneshot_event(qemu_get_current_aio_context(),
37
33
blk_aio_complete_bh, acb);
38
+ qemu_mutex_init(&blk->queued_requests_lock);
39
qemu_co_queue_init(&blk->queued_requests);
40
notifier_list_init(&blk->remove_bs_notifiers);
41
notifier_list_init(&blk->insert_bs_notifiers);
42
@@ -XXX,XX +XXX,XX @@ static void blk_delete(BlockBackend *blk)
43
assert(QLIST_EMPTY(&blk->remove_bs_notifiers.notifiers));
44
assert(QLIST_EMPTY(&blk->insert_bs_notifiers.notifiers));
45
assert(QLIST_EMPTY(&blk->aio_notifiers));
46
+ assert(qemu_co_queue_empty(&blk->queued_requests));
47
+ qemu_mutex_destroy(&blk->queued_requests_lock);
48
QTAILQ_REMOVE(&block_backends, blk, link);
49
drive_info_del(blk->legacy_dinfo);
50
block_acct_cleanup(&blk->stats);
51
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn blk_wait_while_drained(BlockBackend *blk)
52
53
if (qatomic_read(&blk->quiesce_counter) &&
54
!qatomic_read(&blk->disable_request_queuing)) {
55
+ /*
56
+ * Take lock before decrementing in flight counter so main loop thread
57
+ * waits for us to enqueue ourselves before it can leave the drained
58
+ * section.
59
+ */
60
+ qemu_mutex_lock(&blk->queued_requests_lock);
61
blk_dec_in_flight(blk);
62
- qemu_co_queue_wait(&blk->queued_requests, NULL);
63
+ qemu_co_queue_wait(&blk->queued_requests, &blk->queued_requests_lock);
64
blk_inc_in_flight(blk);
65
+ qemu_mutex_unlock(&blk->queued_requests_lock);
66
}
34
}
67
}
35
68
36
@@ -XXX,XX +XXX,XX @@ BlockAIOCB *blk_aio_zone_mgmt(BlockBackend *blk, BlockZoneOp op,
69
@@ -XXX,XX +XXX,XX @@ static void blk_root_drained_end(BdrvChild *child)
37
acb->has_returned = false;
70
if (blk->dev_ops && blk->dev_ops->drained_end) {
38
71
blk->dev_ops->drained_end(blk->dev_opaque);
39
co = qemu_coroutine_create(blk_aio_zone_mgmt_entry, acb);
72
}
40
- aio_co_enter(blk_get_aio_context(blk), co);
73
- while (qemu_co_enter_next(&blk->queued_requests, NULL)) {
41
+ aio_co_enter(qemu_get_current_aio_context(), co);
74
+ qemu_mutex_lock(&blk->queued_requests_lock);
42
75
+ while (qemu_co_enter_next(&blk->queued_requests,
43
acb->has_returned = true;
76
+ &blk->queued_requests_lock)) {
44
if (acb->rwco.ret != NOT_DONE) {
77
/* Resume all queued requests */
45
- replay_bh_schedule_oneshot_event(blk_get_aio_context(blk),
78
}
46
+ replay_bh_schedule_oneshot_event(qemu_get_current_aio_context(),
79
+ qemu_mutex_unlock(&blk->queued_requests_lock);
47
blk_aio_complete_bh, acb);
80
}
48
}
81
}
49
50
@@ -XXX,XX +XXX,XX @@ BlockAIOCB *blk_aio_zone_append(BlockBackend *blk, int64_t *offset,
51
acb->has_returned = false;
52
53
co = qemu_coroutine_create(blk_aio_zone_append_entry, acb);
54
- aio_co_enter(blk_get_aio_context(blk), co);
55
+ aio_co_enter(qemu_get_current_aio_context(), co);
56
acb->has_returned = true;
57
if (acb->rwco.ret != NOT_DONE) {
58
- replay_bh_schedule_oneshot_event(blk_get_aio_context(blk),
59
+ replay_bh_schedule_oneshot_event(qemu_get_current_aio_context(),
60
blk_aio_complete_bh, acb);
61
}
82
62
83
--
63
--
84
2.40.0
64
2.41.0
diff view generated by jsdifflib
1
From: Stefan Hajnoczi <stefanha@redhat.com>
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
2
3
Since the AioContext argument was already NULL, AIO_WAIT_WHILE() was
3
Use qemu_get_current_aio_context() in mixed wrappers and coroutine
4
never going to unlock the AioContext. Therefore it is possible to
4
wrappers so that code runs in the caller's AioContext instead of moving
5
replace AIO_WAIT_WHILE() with AIO_WAIT_WHILE_UNLOCKED().
5
to the BlockDriverState's AioContext. This change is necessary for the
6
multi-queue block layer where any thread can call into the block layer.
6
7
7
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
8
Most wrappers are IO_CODE where it's safe to use the current AioContext
8
Tested-by: Philippe Mathieu-Daudé <philmd@linaro.org>
9
nowadays. BlockDrivers and the core block layer use their own locks and
10
no longer depend on the AioContext lock for thread-safety.
11
12
The bdrv_create() wrapper invokes GLOBAL_STATE code. Using the current
13
AioContext is safe because this code is only called with the BQL held
14
from the main loop thread.
15
16
The output of qemu-iotests 051 is sensitive to event loop activity.
17
Update the output because the monitor BH runs at a different time,
18
causing prompts to be printed differently in the output.
19
20
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
21
Message-ID: <20230912231037.826804-6-stefanha@redhat.com>
9
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
22
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
23
Reviewed-by: Eric Blake <eblake@redhat.com>
11
Message-Id: <20230309190855.414275-5-stefanha@redhat.com>
12
Reviewed-by: Wilfred Mallawa <wilfred.mallawa@wdc.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
24
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
---
25
---
15
block/io.c | 2 +-
26
scripts/block-coroutine-wrapper.py | 6 ++----
16
1 file changed, 1 insertion(+), 1 deletion(-)
27
1 file changed, 2 insertions(+), 4 deletions(-)
17
28
18
diff --git a/block/io.c b/block/io.c
29
diff --git a/scripts/block-coroutine-wrapper.py b/scripts/block-coroutine-wrapper.py
19
index XXXXXXX..XXXXXXX 100644
30
index XXXXXXX..XXXXXXX 100644
20
--- a/block/io.c
31
--- a/scripts/block-coroutine-wrapper.py
21
+++ b/block/io.c
32
+++ b/scripts/block-coroutine-wrapper.py
22
@@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_begin(void)
33
@@ -XXX,XX +XXX,XX @@ def __init__(self, wrapper_type: str, return_type: str, name: str,
23
bdrv_drain_all_begin_nopoll();
34
raise ValueError(f"no_co function can't be rdlock: {self.name}")
24
35
self.target_name = f'{subsystem}_{subname}'
25
/* Now poll the in-flight requests */
36
26
- AIO_WAIT_WHILE(NULL, bdrv_drain_all_poll());
37
- self.ctx = self.gen_ctx()
27
+ AIO_WAIT_WHILE_UNLOCKED(NULL, bdrv_drain_all_poll());
38
-
28
39
self.get_result = 's->ret = '
29
while ((bs = bdrv_next_all_states(bs))) {
40
self.ret = 'return s.ret;'
30
bdrv_drain_assert_idle(bs);
41
self.co_ret = 'return '
42
@@ -XXX,XX +XXX,XX @@ def create_mixed_wrapper(func: FuncDecl) -> str:
43
{func.co_ret}{name}({ func.gen_list('{name}') });
44
}} else {{
45
{struct_name} s = {{
46
- .poll_state.ctx = {func.ctx},
47
+ .poll_state.ctx = qemu_get_current_aio_context(),
48
.poll_state.in_progress = true,
49
50
{ func.gen_block(' .{name} = {name},') }
51
@@ -XXX,XX +XXX,XX @@ def create_co_wrapper(func: FuncDecl) -> str:
52
{func.return_type} {func.name}({ func.gen_list('{decl}') })
53
{{
54
{struct_name} s = {{
55
- .poll_state.ctx = {func.ctx},
56
+ .poll_state.ctx = qemu_get_current_aio_context(),
57
.poll_state.in_progress = true,
58
59
{ func.gen_block(' .{name} = {name},') }
31
--
60
--
32
2.40.0
61
2.41.0
33
34
diff view generated by jsdifflib