1
The following changes since commit 79b677d658d3d35e1e776826ac4abb28cdce69b8:
1
The following changes since commit d922088eb4ba6bc31a99f17b32cf75e59dd306cd:
2
2
3
Merge tag 'net-pull-request' of https://github.com/jasowang/qemu into staging (2023-02-21 11:28:31 +0000)
3
Merge tag 'ui-pull-request' of https://gitlab.com/marcandre.lureau/qemu into staging (2025-02-03 13:42:02 -0500)
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 0f385a2420d2c3f8ae7ed65fbe2712027664059e:
9
for you to fetch changes up to fc4e394b2887e15d5f83994e4fc7b26c895c627a:
10
10
11
block/rbd: Add support for layered encryption (2023-02-23 19:49:35 +0100)
11
block: remove unused BLOCK_OP_TYPE_DATAPLANE (2025-02-06 14:51:10 +0100)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Block layer patches
14
Block layer patches
15
15
16
- Lock the graph, part 2 (BlockDriver callbacks)
16
- Managing inactive nodes (enables QSD migration with shared storage)
17
- virtio-scsi: fix SCSIDevice hot unplug with IOThread
17
- Fix swapped values for BLOCK_IO_ERROR 'device' and 'qom-path'
18
- rbd: Add support for layered encryption
18
- vpc: Read images exported from Azure correctly
19
- scripts/qemu-gdb: Support coroutine dumps in coredumps
20
- Minor cleanups
19
21
20
----------------------------------------------------------------
22
----------------------------------------------------------------
21
Emanuele Giuseppe Esposito (5):
23
Fabiano Rosas (1):
22
block/qed: add missing graph rdlock in qed_need_check_timer_entry
24
block: Fix leak in send_qmp_error_event
23
block: Mark bdrv_co_flush() and callers GRAPH_RDLOCK
24
block: Mark bdrv_co_pdiscard() and callers GRAPH_RDLOCK
25
block: Mark bdrv_co_copy_range() GRAPH_RDLOCK
26
block: Mark bdrv_co_is_inserted() and callers GRAPH_RDLOCK
27
25
28
Kevin Wolf (18):
26
Kevin Wolf (16):
29
block: Make bdrv_can_set_read_only() static
27
block: Add 'active' field to BlockDeviceInfo
30
mirror: Fix access of uninitialised fields during start
28
block: Allow inactivating already inactive nodes
31
block: Mark bdrv_co_truncate() and callers GRAPH_RDLOCK
29
block: Inactivate external snapshot overlays when necessary
32
block: Mark bdrv_co_block_status() and callers GRAPH_RDLOCK
30
migration/block-active: Remove global active flag
33
block: Mark bdrv_co_ioctl() and callers GRAPH_RDLOCK
31
block: Don't attach inactive child to active node
34
block: Mark bdrv_co_pwrite_zeroes() and callers GRAPH_RDLOCK
32
block: Fix crash on block_resize on inactive node
35
block: Mark read/write in block/io.c GRAPH_RDLOCK
33
block: Add option to create inactive nodes
36
block: Mark public read/write functions GRAPH_RDLOCK
34
block: Add blockdev-set-active QMP command
37
block: Mark bdrv_co_pwrite_sync() and callers GRAPH_RDLOCK
35
block: Support inactive nodes in blk_insert_bs()
38
block: Mark bdrv_co_do_pwrite_zeroes() GRAPH_RDLOCK
36
block/export: Don't ignore image activation error in blk_exp_add()
39
block: Mark preadv_snapshot/snapshot_block_status GRAPH_RDLOCK
37
block: Drain nodes before inactivating them
40
block: Mark bdrv_co_create() and callers GRAPH_RDLOCK
38
block/export: Add option to allow export of inactive nodes
41
block: Mark bdrv_co_io_(un)plug() and callers GRAPH_RDLOCK
39
nbd/server: Support inactive nodes
42
block: Mark bdrv_co_eject/lock_medium() and callers GRAPH_RDLOCK
40
iotests: Add filter_qtest()
43
block: Mark bdrv_(un)register_buf() GRAPH_RDLOCK
41
iotests: Add qsd-migrate case
44
block: Mark bdrv_co_delete_file() and callers GRAPH_RDLOCK
42
iotests: Add (NBD-based) tests for inactive nodes
45
block: Mark bdrv_*_dirty_bitmap() and callers GRAPH_RDLOCK
46
block: Mark bdrv_co_refresh_total_sectors() and callers GRAPH_RDLOCK
47
43
48
Or Ozeri (3):
44
Peter Krempa (1):
49
block/rbd: Remove redundant stack variable passphrase_len
45
block-backend: Fix argument order when calling 'qapi_event_send_block_io_error()'
50
block/rbd: Add luks-any encryption opening option
51
block/rbd: Add support for layered encryption
52
46
53
Stefan Hajnoczi (3):
47
Peter Xu (3):
54
scsi: protect req->aiocb with AioContext lock
48
scripts/qemu-gdb: Always do full stack dump for python errors
55
dma-helpers: prevent dma_blk_cb() vs dma_aio_cancel() race
49
scripts/qemu-gdb: Simplify fs_base fetching for coroutines
56
virtio-scsi: reset SCSI devices from main loop thread
50
scripts/qemu-gdb: Support coroutine dumps in coredumps
57
51
58
qapi/block-core.json | 27 +++++-
52
Philippe Mathieu-Daudé (1):
59
block/coroutines.h | 2 +-
53
block: Improve blk_get_attached_dev_id() docstring
60
block/qcow2.h | 27 ++++--
54
61
block/qed.h | 45 +++++----
55
Stefan Hajnoczi (1):
62
include/block/block-copy.h | 6 +-
56
block: remove unused BLOCK_OP_TYPE_DATAPLANE
63
include/block/block-global-state.h | 14 +--
57
64
include/block/block-io.h | 110 ++++++++++++----------
58
Vitaly Kuznetsov (2):
65
include/block/block_int-common.h | 173 ++++++++++++++++++----------------
59
vpc: Split off vpc_ignore_current_size() helper
66
include/block/block_int-io.h | 53 ++++++-----
60
vpc: Read images exported from Azure correctly
67
include/block/dirty-bitmap.h | 12 +--
61
68
include/hw/virtio/virtio-scsi.h | 11 ++-
62
qapi/block-core.json | 44 +++-
69
include/sysemu/block-backend-io.h | 7 +-
63
qapi/block-export.json | 10 +-
70
block.c | 12 ++-
64
include/block/block-common.h | 2 +-
71
block/backup.c | 3 +
65
include/block/block-global-state.h | 6 +
72
block/blkdebug.c | 19 ++--
66
include/block/export.h | 3 +
73
block/blklogwrites.c | 35 ++++---
67
include/system/block-backend-io.h | 7 +
74
block/blkreplay.c | 24 +++--
68
migration/migration.h | 3 -
75
block/blkverify.c | 5 +-
69
block.c | 64 +++++-
76
block/block-backend.c | 39 +++++---
70
block/block-backend.c | 32 ++-
77
block/block-copy.c | 32 ++++---
71
block/export/export.c | 29 ++-
78
block/bochs.c | 2 +-
72
block/monitor/block-hmp-cmds.c | 5 +-
79
block/commit.c | 5 +-
73
block/qapi.c | 1 +
80
block/copy-before-write.c | 33 ++++---
74
block/replication.c | 1 -
81
block/copy-on-read.c | 44 +++++----
75
block/vpc.c | 65 +++---
82
block/create.c | 9 +-
76
blockdev.c | 48 ++++
83
block/crypto.c | 16 ++--
77
blockjob.c | 2 -
84
block/dirty-bitmap.c | 2 +
78
hw/block/virtio-blk.c | 9 -
85
block/file-posix.c | 27 +++---
79
hw/scsi/virtio-scsi.c | 3 -
86
block/file-win32.c | 7 +-
80
migration/block-active.c | 46 ----
87
block/filter-compress.c | 36 ++++---
81
migration/migration.c | 8 -
88
block/io.c | 108 +++++++++++++--------
82
nbd/server.c | 17 ++
89
block/iscsi.c | 28 +++---
83
scripts/qemu-gdb.py | 2 +
90
block/mirror.c | 59 ++++++++----
84
scripts/qemugdb/coroutine.py | 102 ++++++---
91
block/parallels.c | 33 +++----
85
tests/qemu-iotests/iotests.py | 8 +
92
block/preallocate.c | 38 ++++----
86
tests/qemu-iotests/041 | 4 +-
93
block/qcow.c | 46 +++++----
87
tests/qemu-iotests/165 | 4 +-
94
block/qcow2-cluster.c | 17 ++--
88
tests/qemu-iotests/184.out | 2 +
95
block/qcow2.c | 136 +++++++++++++++------------
89
tests/qemu-iotests/191.out | 16 ++
96
block/qed-check.c | 3 +-
90
tests/qemu-iotests/273.out | 5 +
97
block/qed-table.c | 10 +-
91
tests/qemu-iotests/tests/copy-before-write | 3 +-
98
block/qed.c | 101 ++++++++++----------
92
tests/qemu-iotests/tests/inactive-node-nbd | 303 +++++++++++++++++++++++++
99
block/quorum.c | 62 +++++++-----
93
tests/qemu-iotests/tests/inactive-node-nbd.out | 239 +++++++++++++++++++
100
block/raw-format.c | 76 ++++++++-------
94
tests/qemu-iotests/tests/migrate-bitmaps-test | 7 +-
101
block/rbd.c | 188 ++++++++++++++++++++++++++++++++++---
95
tests/qemu-iotests/tests/qsd-migrate | 140 ++++++++++++
102
block/replication.c | 18 ++--
96
tests/qemu-iotests/tests/qsd-migrate.out | 59 +++++
103
block/snapshot-access.c | 8 +-
97
35 files changed, 1133 insertions(+), 166 deletions(-)
104
block/stream.c | 40 ++++----
98
create mode 100755 tests/qemu-iotests/tests/inactive-node-nbd
105
block/throttle.c | 36 ++++---
99
create mode 100644 tests/qemu-iotests/tests/inactive-node-nbd.out
106
block/vdi.c | 11 +--
100
create mode 100755 tests/qemu-iotests/tests/qsd-migrate
107
block/vhdx.c | 18 ++--
101
create mode 100644 tests/qemu-iotests/tests/qsd-migrate.out
108
block/vmdk.c | 132 ++++++++++++--------------
102
109
block/vpc.c | 11 +--
103
110
hw/scsi/scsi-disk.c | 23 +++--
111
hw/scsi/scsi-generic.c | 11 ++-
112
hw/scsi/virtio-scsi.c | 169 ++++++++++++++++++++++++++-------
113
qemu-img.c | 8 +-
114
softmmu/dma-helpers.c | 12 ++-
115
tests/unit/test-bdrv-drain.c | 20 ++--
116
tests/unit/test-block-iothread.c | 3 +-
117
59 files changed, 1355 insertions(+), 907 deletions(-)
diff view generated by jsdifflib
1
This adds GRAPH_RDLOCK annotations to declare that callers of
1
From: Vitaly Kuznetsov <vkuznets@redhat.com>
2
bdrv_co_pread*/pwrite*() need to hold a reader lock for the graph.
3
2
4
For some places, we know that they will hold the lock, but we don't have
3
In preparation to making changes to the logic deciding whether CHS or
5
the GRAPH_RDLOCK annotations yet. In this case, add assume_graph_lock()
4
'current_size' need to be used in determining the image size, split off
6
with a FIXME comment. These places will be removed once everything is
5
vpc_ignore_current_size() helper.
7
properly annotated.
8
6
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
No functional change intended.
10
Message-Id: <20230203152202.49054-12-kwolf@redhat.com>
8
11
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
9
Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
10
Message-ID: <20241212134504.1983757-2-vkuznets@redhat.com>
11
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
12
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
---
14
---
14
block/qcow2.h | 9 ++---
15
block/vpc.c | 67 +++++++++++++++++++++++++++++------------------------
15
block/qed.h | 18 +++++-----
16
1 file changed, 37 insertions(+), 30 deletions(-)
16
include/block/block_int-io.h | 14 ++++----
17
block/blkdebug.c | 4 +--
18
block/blklogwrites.c | 7 ++--
19
block/blkreplay.c | 10 +++---
20
block/block-backend.c | 2 ++
21
block/bochs.c | 2 +-
22
block/commit.c | 5 +--
23
block/copy-before-write.c | 16 ++++-----
24
block/copy-on-read.c | 26 ++++++---------
25
block/crypto.c | 4 +--
26
block/filter-compress.c | 19 +++++------
27
block/io.c | 7 ++--
28
block/mirror.c | 18 +++++-----
29
block/parallels.c | 8 +++--
30
block/preallocate.c | 18 +++++-----
31
block/qcow.c | 8 ++---
32
block/qcow2-cluster.c | 7 ++--
33
block/qcow2.c | 53 +++++++++++++++--------------
34
block/qed-table.c | 4 +--
35
block/qed.c | 31 +++++++++--------
36
block/quorum.c | 29 ++++++++++------
37
block/raw-format.c | 12 +++----
38
block/replication.c | 15 ++++-----
39
block/throttle.c | 21 +++++-------
40
block/vdi.c | 4 +--
41
block/vhdx.c | 11 +++---
42
block/vmdk.c | 65 +++++++++++++++---------------------
43
block/vpc.c | 4 +--
44
tests/unit/test-bdrv-drain.c | 20 ++++++-----
45
31 files changed, 233 insertions(+), 238 deletions(-)
46
17
47
diff --git a/block/qcow2.h b/block/qcow2.h
48
index XXXXXXX..XXXXXXX 100644
49
--- a/block/qcow2.h
50
+++ b/block/qcow2.h
51
@@ -XXX,XX +XXX,XX @@ int qcow2_validate_table(BlockDriverState *bs, uint64_t offset,
52
Error **errp);
53
54
/* qcow2-refcount.c functions */
55
-int coroutine_fn qcow2_refcount_init(BlockDriverState *bs);
56
+int coroutine_fn GRAPH_RDLOCK qcow2_refcount_init(BlockDriverState *bs);
57
void qcow2_refcount_close(BlockDriverState *bs);
58
59
int qcow2_get_refcount(BlockDriverState *bs, int64_t cluster_index,
60
@@ -XXX,XX +XXX,XX @@ void qcow2_free_snapshots(BlockDriverState *bs);
61
int qcow2_read_snapshots(BlockDriverState *bs, Error **errp);
62
int qcow2_write_snapshots(BlockDriverState *bs);
63
64
-int coroutine_fn qcow2_check_read_snapshot_table(BlockDriverState *bs,
65
- BdrvCheckResult *result,
66
- BdrvCheckMode fix);
67
+int coroutine_fn GRAPH_RDLOCK
68
+qcow2_check_read_snapshot_table(BlockDriverState *bs, BdrvCheckResult *result,
69
+ BdrvCheckMode fix);
70
+
71
int coroutine_fn qcow2_check_fix_snapshot_table(BlockDriverState *bs,
72
BdrvCheckResult *result,
73
BdrvCheckMode fix);
74
diff --git a/block/qed.h b/block/qed.h
75
index XXXXXXX..XXXXXXX 100644
76
--- a/block/qed.h
77
+++ b/block/qed.h
78
@@ -XXX,XX +XXX,XX @@ void qed_commit_l2_cache_entry(L2TableCache *l2_cache, CachedL2Table *l2_table);
79
/**
80
* Table I/O functions
81
*/
82
-int coroutine_fn qed_read_l1_table_sync(BDRVQEDState *s);
83
+int coroutine_fn GRAPH_RDLOCK qed_read_l1_table_sync(BDRVQEDState *s);
84
85
int coroutine_fn GRAPH_RDLOCK
86
qed_write_l1_table(BDRVQEDState *s, unsigned int index, unsigned int n);
87
@@ -XXX,XX +XXX,XX @@ qed_write_l1_table(BDRVQEDState *s, unsigned int index, unsigned int n);
88
int coroutine_fn GRAPH_RDLOCK
89
qed_write_l1_table_sync(BDRVQEDState *s, unsigned int index, unsigned int n);
90
91
-int coroutine_fn qed_read_l2_table_sync(BDRVQEDState *s, QEDRequest *request,
92
- uint64_t offset);
93
-int coroutine_fn qed_read_l2_table(BDRVQEDState *s, QEDRequest *request,
94
- uint64_t offset);
95
+int coroutine_fn GRAPH_RDLOCK
96
+qed_read_l2_table_sync(BDRVQEDState *s, QEDRequest *request, uint64_t offset);
97
+
98
+int coroutine_fn GRAPH_RDLOCK
99
+qed_read_l2_table(BDRVQEDState *s, QEDRequest *request, uint64_t offset);
100
101
int coroutine_fn GRAPH_RDLOCK
102
qed_write_l2_table(BDRVQEDState *s, QEDRequest *request, unsigned int index,
103
@@ -XXX,XX +XXX,XX @@ qed_write_l2_table_sync(BDRVQEDState *s, QEDRequest *request,
104
/**
105
* Cluster functions
106
*/
107
-int coroutine_fn qed_find_cluster(BDRVQEDState *s, QEDRequest *request,
108
- uint64_t pos, size_t *len,
109
- uint64_t *img_offset);
110
+int coroutine_fn GRAPH_RDLOCK
111
+qed_find_cluster(BDRVQEDState *s, QEDRequest *request, uint64_t pos,
112
+ size_t *len, uint64_t *img_offset);
113
114
/**
115
* Consistency check
116
@@ -XXX,XX +XXX,XX @@ int coroutine_fn qed_find_cluster(BDRVQEDState *s, QEDRequest *request,
117
int coroutine_fn GRAPH_RDLOCK
118
qed_check(BDRVQEDState *s, BdrvCheckResult *result, bool fix);
119
120
-
121
QEDTable *qed_alloc_table(BDRVQEDState *s);
122
123
/**
124
diff --git a/include/block/block_int-io.h b/include/block/block_int-io.h
125
index XXXXXXX..XXXXXXX 100644
126
--- a/include/block/block_int-io.h
127
+++ b/include/block/block_int-io.h
128
@@ -XXX,XX +XXX,XX @@ int coroutine_fn GRAPH_RDLOCK bdrv_co_pdiscard_snapshot(BlockDriverState *bs,
129
int64_t offset, int64_t bytes);
130
131
132
-int coroutine_fn bdrv_co_preadv(BdrvChild *child,
133
+int coroutine_fn GRAPH_RDLOCK bdrv_co_preadv(BdrvChild *child,
134
int64_t offset, int64_t bytes, QEMUIOVector *qiov,
135
BdrvRequestFlags flags);
136
-int coroutine_fn bdrv_co_preadv_part(BdrvChild *child,
137
+int coroutine_fn GRAPH_RDLOCK bdrv_co_preadv_part(BdrvChild *child,
138
int64_t offset, int64_t bytes,
139
QEMUIOVector *qiov, size_t qiov_offset, BdrvRequestFlags flags);
140
-int coroutine_fn bdrv_co_pwritev(BdrvChild *child,
141
+int coroutine_fn GRAPH_RDLOCK bdrv_co_pwritev(BdrvChild *child,
142
int64_t offset, int64_t bytes, QEMUIOVector *qiov,
143
BdrvRequestFlags flags);
144
-int coroutine_fn bdrv_co_pwritev_part(BdrvChild *child,
145
+int coroutine_fn GRAPH_RDLOCK bdrv_co_pwritev_part(BdrvChild *child,
146
int64_t offset, int64_t bytes,
147
QEMUIOVector *qiov, size_t qiov_offset, BdrvRequestFlags flags);
148
149
-static inline int coroutine_fn bdrv_co_pread(BdrvChild *child,
150
+static inline int coroutine_fn GRAPH_RDLOCK bdrv_co_pread(BdrvChild *child,
151
int64_t offset, int64_t bytes, void *buf, BdrvRequestFlags flags)
152
{
153
QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes);
154
IO_CODE();
155
+ assert_bdrv_graph_readable();
156
157
return bdrv_co_preadv(child, offset, bytes, &qiov, flags);
158
}
159
160
-static inline int coroutine_fn bdrv_co_pwrite(BdrvChild *child,
161
+static inline int coroutine_fn GRAPH_RDLOCK bdrv_co_pwrite(BdrvChild *child,
162
int64_t offset, int64_t bytes, const void *buf, BdrvRequestFlags flags)
163
{
164
QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes);
165
IO_CODE();
166
+ assert_bdrv_graph_readable();
167
168
return bdrv_co_pwritev(child, offset, bytes, &qiov, flags);
169
}
170
diff --git a/block/blkdebug.c b/block/blkdebug.c
171
index XXXXXXX..XXXXXXX 100644
172
--- a/block/blkdebug.c
173
+++ b/block/blkdebug.c
174
@@ -XXX,XX +XXX,XX @@ static int rule_check(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
175
return -error;
176
}
177
178
-static int coroutine_fn
179
+static int coroutine_fn GRAPH_RDLOCK
180
blkdebug_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
181
QEMUIOVector *qiov, BdrvRequestFlags flags)
182
{
183
@@ -XXX,XX +XXX,XX @@ blkdebug_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
184
return bdrv_co_preadv(bs->file, offset, bytes, qiov, flags);
185
}
186
187
-static int coroutine_fn
188
+static int coroutine_fn GRAPH_RDLOCK
189
blkdebug_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes,
190
QEMUIOVector *qiov, BdrvRequestFlags flags)
191
{
192
diff --git a/block/blklogwrites.c b/block/blklogwrites.c
193
index XXXXXXX..XXXXXXX 100644
194
--- a/block/blklogwrites.c
195
+++ b/block/blklogwrites.c
196
@@ -XXX,XX +XXX,XX @@ static void blk_log_writes_refresh_limits(BlockDriverState *bs, Error **errp)
197
bs->bl.request_alignment = s->sectorsize;
198
}
199
200
-static int coroutine_fn
201
+static int coroutine_fn GRAPH_RDLOCK
202
blk_log_writes_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
203
QEMUIOVector *qiov, BdrvRequestFlags flags)
204
{
205
@@ -XXX,XX +XXX,XX @@ blk_log_writes_co_log(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
206
return fr.file_ret;
207
}
208
209
-static int coroutine_fn
210
+static int coroutine_fn GRAPH_RDLOCK
211
blk_log_writes_co_do_file_pwritev(BlkLogWritesFileReq *fr)
212
{
213
return bdrv_co_pwritev(fr->bs->file, fr->offset, fr->bytes,
214
@@ -XXX,XX +XXX,XX @@ blk_log_writes_co_do_file_pdiscard(BlkLogWritesFileReq *fr)
215
return bdrv_co_pdiscard(fr->bs->file, fr->offset, fr->bytes);
216
}
217
218
-static int coroutine_fn
219
+static int coroutine_fn GRAPH_RDLOCK
220
blk_log_writes_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes,
221
QEMUIOVector *qiov, BdrvRequestFlags flags)
222
{
223
- assume_graph_lock(); /* FIXME */
224
return blk_log_writes_co_log(bs, offset, bytes, qiov, flags,
225
blk_log_writes_co_do_file_pwritev, 0, false);
226
}
227
diff --git a/block/blkreplay.c b/block/blkreplay.c
228
index XXXXXXX..XXXXXXX 100644
229
--- a/block/blkreplay.c
230
+++ b/block/blkreplay.c
231
@@ -XXX,XX +XXX,XX @@ static void block_request_create(uint64_t reqid, BlockDriverState *bs,
232
replay_block_event(req->bh, reqid);
233
}
234
235
-static int coroutine_fn blkreplay_co_preadv(BlockDriverState *bs,
236
- int64_t offset, int64_t bytes, QEMUIOVector *qiov, BdrvRequestFlags flags)
237
+static int coroutine_fn GRAPH_RDLOCK
238
+blkreplay_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
239
+ QEMUIOVector *qiov, BdrvRequestFlags flags)
240
{
241
uint64_t reqid = blkreplay_next_id();
242
int ret = bdrv_co_preadv(bs->file, offset, bytes, qiov, flags);
243
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn blkreplay_co_preadv(BlockDriverState *bs,
244
return ret;
245
}
246
247
-static int coroutine_fn blkreplay_co_pwritev(BlockDriverState *bs,
248
- int64_t offset, int64_t bytes, QEMUIOVector *qiov, BdrvRequestFlags flags)
249
+static int coroutine_fn GRAPH_RDLOCK
250
+blkreplay_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes,
251
+ QEMUIOVector *qiov, BdrvRequestFlags flags)
252
{
253
uint64_t reqid = blkreplay_next_id();
254
int ret = bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags);
255
diff --git a/block/block-backend.c b/block/block-backend.c
256
index XXXXXXX..XXXXXXX 100644
257
--- a/block/block-backend.c
258
+++ b/block/block-backend.c
259
@@ -XXX,XX +XXX,XX @@ blk_co_do_preadv_part(BlockBackend *blk, int64_t offset, int64_t bytes,
260
IO_CODE();
261
262
blk_wait_while_drained(blk);
263
+ GRAPH_RDLOCK_GUARD();
264
265
/* Call blk_bs() only after waiting, the graph may have changed */
266
bs = blk_bs(blk);
267
@@ -XXX,XX +XXX,XX @@ blk_co_do_pwritev_part(BlockBackend *blk, int64_t offset, int64_t bytes,
268
IO_CODE();
269
270
blk_wait_while_drained(blk);
271
+ GRAPH_RDLOCK_GUARD();
272
273
/* Call blk_bs() only after waiting, the graph may have changed */
274
bs = blk_bs(blk);
275
diff --git a/block/bochs.c b/block/bochs.c
276
index XXXXXXX..XXXXXXX 100644
277
--- a/block/bochs.c
278
+++ b/block/bochs.c
279
@@ -XXX,XX +XXX,XX @@ static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num)
280
return bitmap_offset + (512 * (s->bitmap_blocks + extent_offset));
281
}
282
283
-static int coroutine_fn
284
+static int coroutine_fn GRAPH_RDLOCK
285
bochs_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
286
QEMUIOVector *qiov, BdrvRequestFlags flags)
287
{
288
diff --git a/block/commit.c b/block/commit.c
289
index XXXXXXX..XXXXXXX 100644
290
--- a/block/commit.c
291
+++ b/block/commit.c
292
@@ -XXX,XX +XXX,XX @@ static const BlockJobDriver commit_job_driver = {
293
},
294
};
295
296
-static int coroutine_fn bdrv_commit_top_preadv(BlockDriverState *bs,
297
- int64_t offset, int64_t bytes, QEMUIOVector *qiov, BdrvRequestFlags flags)
298
+static int coroutine_fn GRAPH_RDLOCK
299
+bdrv_commit_top_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
300
+ QEMUIOVector *qiov, BdrvRequestFlags flags)
301
{
302
return bdrv_co_preadv(bs->backing, offset, bytes, qiov, flags);
303
}
304
diff --git a/block/copy-before-write.c b/block/copy-before-write.c
305
index XXXXXXX..XXXXXXX 100644
306
--- a/block/copy-before-write.c
307
+++ b/block/copy-before-write.c
308
@@ -XXX,XX +XXX,XX @@ typedef struct BDRVCopyBeforeWriteState {
309
int snapshot_error;
310
} BDRVCopyBeforeWriteState;
311
312
-static coroutine_fn int cbw_co_preadv(
313
- BlockDriverState *bs, int64_t offset, int64_t bytes,
314
- QEMUIOVector *qiov, BdrvRequestFlags flags)
315
+static int coroutine_fn GRAPH_RDLOCK
316
+cbw_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
317
+ QEMUIOVector *qiov, BdrvRequestFlags flags)
318
{
319
return bdrv_co_preadv(bs->file, offset, bytes, qiov, flags);
320
}
321
@@ -XXX,XX +XXX,XX @@ cbw_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int64_t bytes,
322
return bdrv_co_pwrite_zeroes(bs->file, offset, bytes, flags);
323
}
324
325
-static coroutine_fn int cbw_co_pwritev(BlockDriverState *bs,
326
- int64_t offset,
327
- int64_t bytes,
328
- QEMUIOVector *qiov,
329
- BdrvRequestFlags flags)
330
+static coroutine_fn GRAPH_RDLOCK
331
+int cbw_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes,
332
+ QEMUIOVector *qiov, BdrvRequestFlags flags)
333
{
334
int ret = cbw_do_copy_before_write(bs, offset, bytes, flags);
335
if (ret < 0) {
336
@@ -XXX,XX +XXX,XX @@ cbw_co_preadv_snapshot(BlockDriverState *bs, int64_t offset, int64_t bytes,
337
BdrvChild *file;
338
int ret;
339
340
+ assume_graph_lock(); /* FIXME */
341
+
342
/* TODO: upgrade to async loop using AioTask */
343
while (bytes) {
344
int64_t cur_bytes;
345
diff --git a/block/copy-on-read.c b/block/copy-on-read.c
346
index XXXXXXX..XXXXXXX 100644
347
--- a/block/copy-on-read.c
348
+++ b/block/copy-on-read.c
349
@@ -XXX,XX +XXX,XX @@ static int64_t coroutine_fn cor_co_getlength(BlockDriverState *bs)
350
}
351
352
353
-static int coroutine_fn cor_co_preadv_part(BlockDriverState *bs,
354
- int64_t offset, int64_t bytes,
355
- QEMUIOVector *qiov,
356
- size_t qiov_offset,
357
- BdrvRequestFlags flags)
358
+static int coroutine_fn GRAPH_RDLOCK
359
+cor_co_preadv_part(BlockDriverState *bs, int64_t offset, int64_t bytes,
360
+ QEMUIOVector *qiov, size_t qiov_offset,
361
+ BdrvRequestFlags flags)
362
{
363
int64_t n;
364
int local_flags;
365
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn cor_co_preadv_part(BlockDriverState *bs,
366
}
367
368
369
-static int coroutine_fn cor_co_pwritev_part(BlockDriverState *bs,
370
- int64_t offset,
371
- int64_t bytes,
372
- QEMUIOVector *qiov,
373
- size_t qiov_offset,
374
- BdrvRequestFlags flags)
375
+static int coroutine_fn GRAPH_RDLOCK
376
+cor_co_pwritev_part(BlockDriverState *bs, int64_t offset, int64_t bytes,
377
+ QEMUIOVector *qiov, size_t qiov_offset,
378
+ BdrvRequestFlags flags)
379
{
380
return bdrv_co_pwritev_part(bs->file, offset, bytes, qiov, qiov_offset,
381
flags);
382
@@ -XXX,XX +XXX,XX @@ cor_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes)
383
}
384
385
386
-static int coroutine_fn cor_co_pwritev_compressed(BlockDriverState *bs,
387
- int64_t offset,
388
- int64_t bytes,
389
- QEMUIOVector *qiov)
390
+static int coroutine_fn GRAPH_RDLOCK
391
+cor_co_pwritev_compressed(BlockDriverState *bs, int64_t offset, int64_t bytes,
392
+ QEMUIOVector *qiov)
393
{
394
return bdrv_co_pwritev(bs->file, offset, bytes, qiov,
395
BDRV_REQ_WRITE_COMPRESSED);
396
diff --git a/block/crypto.c b/block/crypto.c
397
index XXXXXXX..XXXXXXX 100644
398
--- a/block/crypto.c
399
+++ b/block/crypto.c
400
@@ -XXX,XX +XXX,XX @@ static int block_crypto_reopen_prepare(BDRVReopenState *state,
401
*/
402
#define BLOCK_CRYPTO_MAX_IO_SIZE (1024 * 1024)
403
404
-static coroutine_fn int
405
+static int coroutine_fn GRAPH_RDLOCK
406
block_crypto_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
407
QEMUIOVector *qiov, BdrvRequestFlags flags)
408
{
409
@@ -XXX,XX +XXX,XX @@ block_crypto_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
410
}
411
412
413
-static coroutine_fn int
414
+static int coroutine_fn GRAPH_RDLOCK
415
block_crypto_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes,
416
QEMUIOVector *qiov, BdrvRequestFlags flags)
417
{
418
diff --git a/block/filter-compress.c b/block/filter-compress.c
419
index XXXXXXX..XXXXXXX 100644
420
--- a/block/filter-compress.c
421
+++ b/block/filter-compress.c
422
@@ -XXX,XX +XXX,XX @@ static int64_t coroutine_fn compress_co_getlength(BlockDriverState *bs)
423
}
424
425
426
-static int coroutine_fn compress_co_preadv_part(BlockDriverState *bs,
427
- int64_t offset, int64_t bytes,
428
- QEMUIOVector *qiov,
429
- size_t qiov_offset,
430
- BdrvRequestFlags flags)
431
+static int coroutine_fn GRAPH_RDLOCK
432
+compress_co_preadv_part(BlockDriverState *bs, int64_t offset, int64_t bytes,
433
+ QEMUIOVector *qiov, size_t qiov_offset,
434
+ BdrvRequestFlags flags)
435
{
436
return bdrv_co_preadv_part(bs->file, offset, bytes, qiov, qiov_offset,
437
flags);
438
}
439
440
441
-static int coroutine_fn compress_co_pwritev_part(BlockDriverState *bs,
442
- int64_t offset,
443
- int64_t bytes,
444
- QEMUIOVector *qiov,
445
- size_t qiov_offset,
446
- BdrvRequestFlags flags)
447
+static int coroutine_fn GRAPH_RDLOCK
448
+compress_co_pwritev_part(BlockDriverState *bs, int64_t offset, int64_t bytes,
449
+ QEMUIOVector *qiov, size_t qiov_offset,
450
+ BdrvRequestFlags flags)
451
{
452
return bdrv_co_pwritev_part(bs->file, offset, bytes, qiov, qiov_offset,
453
flags | BDRV_REQ_WRITE_COMPRESSED);
454
diff --git a/block/io.c b/block/io.c
455
index XXXXXXX..XXXXXXX 100644
456
--- a/block/io.c
457
+++ b/block/io.c
458
@@ -XXX,XX +XXX,XX @@ bdrv_driver_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
459
unsigned int nb_sectors;
460
QEMUIOVector local_qiov;
461
int ret;
462
+ assert_bdrv_graph_readable();
463
464
bdrv_check_qiov_request(offset, bytes, qiov, qiov_offset, &error_abort);
465
assert(!(flags & ~bs->supported_read_flags));
466
@@ -XXX,XX +XXX,XX @@ bdrv_driver_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes,
467
unsigned int nb_sectors;
468
QEMUIOVector local_qiov;
469
int ret;
470
+ assert_bdrv_graph_readable();
471
472
bdrv_check_qiov_request(offset, bytes, qiov, qiov_offset, &error_abort);
473
474
@@ -XXX,XX +XXX,XX @@ bdrv_driver_pwritev_compressed(BlockDriverState *bs, int64_t offset,
475
BlockDriver *drv = bs->drv;
476
QEMUIOVector local_qiov;
477
int ret;
478
+ assert_bdrv_graph_readable();
479
480
bdrv_check_qiov_request(offset, bytes, qiov, qiov_offset, &error_abort);
481
482
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_preadv_part(BdrvChild *child,
483
int ret;
484
IO_CODE();
485
486
- assume_graph_lock(); /* FIXME */
487
-
488
trace_bdrv_co_preadv_part(bs, offset, bytes, flags);
489
490
if (!bdrv_co_is_inserted(bs)) {
491
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_pwritev_part(BdrvChild *child,
492
bool padded = false;
493
IO_CODE();
494
495
- assume_graph_lock(); /* FIXME */
496
-
497
trace_bdrv_co_pwritev_part(child->bs, offset, bytes, flags);
498
499
if (!bdrv_co_is_inserted(bs)) {
500
diff --git a/block/mirror.c b/block/mirror.c
501
index XXXXXXX..XXXXXXX 100644
502
--- a/block/mirror.c
503
+++ b/block/mirror.c
504
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn mirror_co_read(void *opaque)
505
op->is_in_flight = true;
506
trace_mirror_one_iteration(s, op->offset, op->bytes);
507
508
- ret = bdrv_co_preadv(s->mirror_top_bs->backing, op->offset, op->bytes,
509
- &op->qiov, 0);
510
+ WITH_GRAPH_RDLOCK_GUARD() {
511
+ ret = bdrv_co_preadv(s->mirror_top_bs->backing, op->offset, op->bytes,
512
+ &op->qiov, 0);
513
+ }
514
mirror_read_complete(op, ret);
515
}
516
517
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn active_write_settle(MirrorOp *op)
518
g_free(op);
519
}
520
521
-static int coroutine_fn bdrv_mirror_top_preadv(BlockDriverState *bs,
522
- int64_t offset, int64_t bytes, QEMUIOVector *qiov, BdrvRequestFlags flags)
523
+static int coroutine_fn GRAPH_RDLOCK
524
+bdrv_mirror_top_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
525
+ QEMUIOVector *qiov, BdrvRequestFlags flags)
526
{
527
return bdrv_co_preadv(bs->backing, offset, bytes, qiov, flags);
528
}
529
@@ -XXX,XX +XXX,XX @@ out:
530
return ret;
531
}
532
533
-static int coroutine_fn bdrv_mirror_top_pwritev(BlockDriverState *bs,
534
- int64_t offset, int64_t bytes, QEMUIOVector *qiov, BdrvRequestFlags flags)
535
+static int coroutine_fn GRAPH_RDLOCK
536
+bdrv_mirror_top_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes,
537
+ QEMUIOVector *qiov, BdrvRequestFlags flags)
538
{
539
MirrorBDSOpaque *s = bs->opaque;
540
QEMUIOVector bounce_qiov;
541
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_mirror_top_pwritev(BlockDriverState *bs,
542
int ret = 0;
543
bool copy_to_target = false;
544
545
- assume_graph_lock(); /* FIXME */
546
-
547
if (s->job) {
548
copy_to_target = s->job->ret >= 0 &&
549
!job_is_cancelled(&s->job->common.job) &&
550
diff --git a/block/parallels.c b/block/parallels.c
551
index XXXXXXX..XXXXXXX 100644
552
--- a/block/parallels.c
553
+++ b/block/parallels.c
554
@@ -XXX,XX +XXX,XX @@ allocate_clusters(BlockDriverState *bs, int64_t sector_num,
555
}
556
557
558
-static coroutine_fn int parallels_co_flush_to_os(BlockDriverState *bs)
559
+static int coroutine_fn GRAPH_RDLOCK
560
+parallels_co_flush_to_os(BlockDriverState *bs)
561
{
562
BDRVParallelsState *s = bs->opaque;
563
unsigned long size = DIV_ROUND_UP(s->header_size, s->bat_dirty_block);
564
@@ -XXX,XX +XXX,XX @@ parallels_co_writev(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
565
return ret;
566
}
567
568
-static coroutine_fn int parallels_co_readv(BlockDriverState *bs,
569
- int64_t sector_num, int nb_sectors, QEMUIOVector *qiov)
570
+static int coroutine_fn GRAPH_RDLOCK
571
+parallels_co_readv(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
572
+ QEMUIOVector *qiov)
573
{
574
BDRVParallelsState *s = bs->opaque;
575
uint64_t bytes_done = 0;
576
diff --git a/block/preallocate.c b/block/preallocate.c
577
index XXXXXXX..XXXXXXX 100644
578
--- a/block/preallocate.c
579
+++ b/block/preallocate.c
580
@@ -XXX,XX +XXX,XX @@ static void preallocate_reopen_abort(BDRVReopenState *state)
581
state->opaque = NULL;
582
}
583
584
-static coroutine_fn int preallocate_co_preadv_part(
585
- BlockDriverState *bs, int64_t offset, int64_t bytes,
586
- QEMUIOVector *qiov, size_t qiov_offset, BdrvRequestFlags flags)
587
+static int coroutine_fn GRAPH_RDLOCK
588
+preallocate_co_preadv_part(BlockDriverState *bs, int64_t offset, int64_t bytes,
589
+ QEMUIOVector *qiov, size_t qiov_offset,
590
+ BdrvRequestFlags flags)
591
{
592
return bdrv_co_preadv_part(bs->file, offset, bytes, qiov, qiov_offset,
593
flags);
594
@@ -XXX,XX +XXX,XX @@ preallocate_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset,
595
return bdrv_co_pwrite_zeroes(bs->file, offset, bytes, flags);
596
}
597
598
-static coroutine_fn int preallocate_co_pwritev_part(BlockDriverState *bs,
599
- int64_t offset,
600
- int64_t bytes,
601
- QEMUIOVector *qiov,
602
- size_t qiov_offset,
603
- BdrvRequestFlags flags)
604
+static int coroutine_fn GRAPH_RDLOCK
605
+preallocate_co_pwritev_part(BlockDriverState *bs, int64_t offset, int64_t bytes,
606
+ QEMUIOVector *qiov, size_t qiov_offset,
607
+ BdrvRequestFlags flags)
608
{
609
- assume_graph_lock(); /* FIXME */
610
handle_write(bs, offset, bytes, false);
611
612
return bdrv_co_pwritev_part(bs->file, offset, bytes, qiov, qiov_offset,
613
diff --git a/block/qcow.c b/block/qcow.c
614
index XXXXXXX..XXXXXXX 100644
615
--- a/block/qcow.c
616
+++ b/block/qcow.c
617
@@ -XXX,XX +XXX,XX @@ typedef struct BDRVQcowState {
618
619
static QemuOptsList qcow_create_opts;
620
621
-static int coroutine_fn decompress_cluster(BlockDriverState *bs,
622
- uint64_t cluster_offset);
623
+static int coroutine_fn GRAPH_RDLOCK
624
+decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset);
625
626
static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename)
627
{
628
@@ -XXX,XX +XXX,XX @@ static int decompress_buffer(uint8_t *out_buf, int out_buf_size,
629
return 0;
630
}
631
632
-static int coroutine_fn decompress_cluster(BlockDriverState *bs,
633
- uint64_t cluster_offset)
634
+static int coroutine_fn GRAPH_RDLOCK
635
+decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset)
636
{
637
BDRVQcowState *s = bs->opaque;
638
int ret, csize;
639
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
640
index XXXXXXX..XXXXXXX 100644
641
--- a/block/qcow2-cluster.c
642
+++ b/block/qcow2-cluster.c
643
@@ -XXX,XX +XXX,XX @@ do_perform_cow_read(BlockDriverState *bs, uint64_t src_cluster_offset,
644
return 0;
645
}
646
647
-static int coroutine_fn do_perform_cow_write(BlockDriverState *bs,
648
- uint64_t cluster_offset,
649
- unsigned offset_in_cluster,
650
- QEMUIOVector *qiov)
651
+static int coroutine_fn GRAPH_RDLOCK
652
+do_perform_cow_write(BlockDriverState *bs, uint64_t cluster_offset,
653
+ unsigned offset_in_cluster, QEMUIOVector *qiov)
654
{
655
BDRVQcow2State *s = bs->opaque;
656
int ret;
657
diff --git a/block/qcow2.c b/block/qcow2.c
658
index XXXXXXX..XXXXXXX 100644
659
--- a/block/qcow2.c
660
+++ b/block/qcow2.c
661
@@ -XXX,XX +XXX,XX @@ static void qcow2_add_check_result(BdrvCheckResult *out,
662
}
663
}
664
665
-static int coroutine_fn qcow2_co_check_locked(BlockDriverState *bs,
666
- BdrvCheckResult *result,
667
- BdrvCheckMode fix)
668
+static int coroutine_fn GRAPH_RDLOCK
669
+qcow2_co_check_locked(BlockDriverState *bs, BdrvCheckResult *result,
670
+ BdrvCheckMode fix)
671
{
672
BdrvCheckResult snapshot_res = {};
673
BdrvCheckResult refcount_res = {};
674
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_check_locked(BlockDriverState *bs,
675
return ret;
676
}
677
678
-static int coroutine_fn qcow2_co_check(BlockDriverState *bs,
679
- BdrvCheckResult *result,
680
- BdrvCheckMode fix)
681
+static int coroutine_fn GRAPH_RDLOCK
682
+qcow2_co_check(BlockDriverState *bs, BdrvCheckResult *result,
683
+ BdrvCheckMode fix)
684
{
685
BDRVQcow2State *s = bs->opaque;
686
int ret;
687
@@ -XXX,XX +XXX,XX @@ static int validate_compression_type(BDRVQcow2State *s, Error **errp)
688
}
689
690
/* Called with s->lock held. */
691
-static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
692
- int flags, bool open_data_file,
693
- Error **errp)
694
+static int coroutine_fn GRAPH_RDLOCK
695
+qcow2_do_open(BlockDriverState *bs, QDict *options, int flags,
696
+ bool open_data_file, Error **errp)
697
{
698
ERRP_GUARD();
699
BDRVQcow2State *s = bs->opaque;
700
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn qcow2_open_entry(void *opaque)
701
QCow2OpenCo *qoc = opaque;
702
BDRVQcow2State *s = qoc->bs->opaque;
703
704
+ assume_graph_lock(); /* FIXME */
705
+
706
qemu_co_mutex_lock(&s->lock);
707
qoc->ret = qcow2_do_open(qoc->bs, qoc->options, qoc->flags, true,
708
qoc->errp);
709
@@ -XXX,XX +XXX,XX @@ out:
710
return ret;
711
}
712
713
-static coroutine_fn int
714
+static int coroutine_fn GRAPH_RDLOCK
715
qcow2_co_preadv_encrypted(BlockDriverState *bs,
716
uint64_t host_offset,
717
uint64_t offset,
718
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_add_task(BlockDriverState *bs,
719
return 0;
720
}
721
722
-static coroutine_fn int qcow2_co_preadv_task(BlockDriverState *bs,
723
- QCow2SubclusterType subc_type,
724
- uint64_t host_offset,
725
- uint64_t offset, uint64_t bytes,
726
- QEMUIOVector *qiov,
727
- size_t qiov_offset)
728
+static int coroutine_fn GRAPH_RDLOCK
729
+qcow2_co_preadv_task(BlockDriverState *bs, QCow2SubclusterType subc_type,
730
+ uint64_t host_offset, uint64_t offset, uint64_t bytes,
731
+ QEMUIOVector *qiov, size_t qiov_offset)
732
{
733
BDRVQcow2State *s = bs->opaque;
734
735
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_preadv_task(BlockDriverState *bs,
736
g_assert_not_reached();
737
}
738
739
-static coroutine_fn int qcow2_co_preadv_task_entry(AioTask *task)
740
+/*
741
+ * This function can count as GRAPH_RDLOCK because qcow2_co_preadv_part() holds
742
+ * the graph lock and keeps it until this coroutine has terminated.
743
+ */
744
+static int coroutine_fn GRAPH_RDLOCK qcow2_co_preadv_task_entry(AioTask *task)
745
{
746
Qcow2AioTask *t = container_of(task, Qcow2AioTask, task);
747
748
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_preadv_task_entry(AioTask *task)
749
t->qiov, t->qiov_offset);
750
}
751
752
-static coroutine_fn int qcow2_co_preadv_part(BlockDriverState *bs,
753
- int64_t offset, int64_t bytes,
754
- QEMUIOVector *qiov,
755
- size_t qiov_offset,
756
- BdrvRequestFlags flags)
757
+static int coroutine_fn GRAPH_RDLOCK
758
+qcow2_co_preadv_part(BlockDriverState *bs, int64_t offset, int64_t bytes,
759
+ QEMUIOVector *qiov, size_t qiov_offset,
760
+ BdrvRequestFlags flags)
761
{
762
BDRVQcow2State *s = bs->opaque;
763
int ret = 0;
764
@@ -XXX,XX +XXX,XX @@ static void qcow2_close(BlockDriverState *bs)
765
qcow2_do_close(bs, true);
766
}
767
768
-static void coroutine_fn qcow2_co_invalidate_cache(BlockDriverState *bs,
769
- Error **errp)
770
+static void coroutine_fn GRAPH_RDLOCK
771
+qcow2_co_invalidate_cache(BlockDriverState *bs, Error **errp)
772
{
773
ERRP_GUARD();
774
BDRVQcow2State *s = bs->opaque;
775
@@ -XXX,XX +XXX,XX @@ qcow2_co_pwritev_compressed_part(BlockDriverState *bs,
776
return ret;
777
}
778
779
-static int coroutine_fn
780
+static int coroutine_fn GRAPH_RDLOCK
781
qcow2_co_preadv_compressed(BlockDriverState *bs,
782
uint64_t l2_entry,
783
uint64_t offset,
784
diff --git a/block/qed-table.c b/block/qed-table.c
785
index XXXXXXX..XXXXXXX 100644
786
--- a/block/qed-table.c
787
+++ b/block/qed-table.c
788
@@ -XXX,XX +XXX,XX @@
789
#include "qemu/memalign.h"
790
791
/* Called with table_lock held. */
792
-static int coroutine_fn qed_read_table(BDRVQEDState *s, uint64_t offset,
793
- QEDTable *table)
794
+static int coroutine_fn GRAPH_RDLOCK
795
+qed_read_table(BDRVQEDState *s, uint64_t offset, QEDTable *table)
796
{
797
unsigned int bytes = s->header.cluster_size * s->header.table_size;
798
799
diff --git a/block/qed.c b/block/qed.c
800
index XXXXXXX..XXXXXXX 100644
801
--- a/block/qed.c
802
+++ b/block/qed.c
803
@@ -XXX,XX +XXX,XX @@ int qed_write_header_sync(BDRVQEDState *s)
804
*
805
* No new allocating reqs can start while this function runs.
806
*/
807
-static int coroutine_fn qed_write_header(BDRVQEDState *s)
808
+static int coroutine_fn GRAPH_RDLOCK qed_write_header(BDRVQEDState *s)
809
{
810
/* We must write full sectors for O_DIRECT but cannot necessarily generate
811
* the data following the header if an unrecognized compat feature is
812
@@ -XXX,XX +XXX,XX @@ fail:
813
return ret;
814
}
815
816
-static int coroutine_fn bdrv_qed_co_block_status(BlockDriverState *bs,
817
- bool want_zero,
818
- int64_t pos, int64_t bytes,
819
- int64_t *pnum, int64_t *map,
820
- BlockDriverState **file)
821
+static int coroutine_fn GRAPH_RDLOCK
822
+bdrv_qed_co_block_status(BlockDriverState *bs, bool want_zero, int64_t pos,
823
+ int64_t bytes, int64_t *pnum, int64_t *map,
824
+ BlockDriverState **file)
825
{
826
BDRVQEDState *s = bs->opaque;
827
size_t len = MIN(bytes, SIZE_MAX);
828
@@ -XXX,XX +XXX,XX @@ static BDRVQEDState *acb_to_s(QEDAIOCB *acb)
829
* This function reads qiov->size bytes starting at pos from the backing file.
830
* If there is no backing file then zeroes are read.
831
*/
832
-static int coroutine_fn qed_read_backing_file(BDRVQEDState *s, uint64_t pos,
833
- QEMUIOVector *qiov)
834
+static int coroutine_fn GRAPH_RDLOCK
835
+qed_read_backing_file(BDRVQEDState *s, uint64_t pos, QEMUIOVector *qiov)
836
{
837
if (s->bs->backing) {
838
BLKDBG_EVENT(s->bs->file, BLKDBG_READ_BACKING_AIO);
839
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qed_read_backing_file(BDRVQEDState *s, uint64_t pos,
840
* @len: Number of bytes
841
* @offset: Byte offset in image file
842
*/
843
-static int coroutine_fn qed_copy_from_backing_file(BDRVQEDState *s,
844
- uint64_t pos, uint64_t len,
845
- uint64_t offset)
846
+static int coroutine_fn GRAPH_RDLOCK
847
+qed_copy_from_backing_file(BDRVQEDState *s, uint64_t pos, uint64_t len,
848
+ uint64_t offset)
849
{
850
QEMUIOVector qiov;
851
int ret;
852
@@ -XXX,XX +XXX,XX @@ qed_aio_write_l2_update(QEDAIOCB *acb, uint64_t offset)
853
*
854
* Called with table_lock *not* held.
855
*/
856
-static int coroutine_fn qed_aio_write_main(QEDAIOCB *acb)
857
+static int coroutine_fn GRAPH_RDLOCK qed_aio_write_main(QEDAIOCB *acb)
858
{
859
BDRVQEDState *s = acb_to_s(acb);
860
uint64_t offset = acb->cur_cluster +
861
@@ -XXX,XX +XXX,XX @@ qed_aio_write_alloc(QEDAIOCB *acb, size_t len)
862
*
863
* Called with table_lock held.
864
*/
865
-static int coroutine_fn qed_aio_write_inplace(QEDAIOCB *acb, uint64_t offset,
866
- size_t len)
867
+static int coroutine_fn GRAPH_RDLOCK
868
+qed_aio_write_inplace(QEDAIOCB *acb, uint64_t offset, size_t len)
869
{
870
BDRVQEDState *s = acb_to_s(acb);
871
int r;
872
@@ -XXX,XX +XXX,XX @@ qed_aio_write_data(void *opaque, int ret, uint64_t offset, size_t len)
873
*
874
* Called with table_lock held.
875
*/
876
-static int coroutine_fn qed_aio_read_data(void *opaque, int ret,
877
- uint64_t offset, size_t len)
878
+static int coroutine_fn GRAPH_RDLOCK
879
+qed_aio_read_data(void *opaque, int ret, uint64_t offset, size_t len)
880
{
881
QEDAIOCB *acb = opaque;
882
BDRVQEDState *s = acb_to_s(acb);
883
diff --git a/block/quorum.c b/block/quorum.c
884
index XXXXXXX..XXXXXXX 100644
885
--- a/block/quorum.c
886
+++ b/block/quorum.c
887
@@ -XXX,XX +XXX,XX @@ static void quorum_report_bad_versions(BDRVQuorumState *s,
888
}
889
}
890
891
-static void coroutine_fn quorum_rewrite_entry(void *opaque)
892
+/*
893
+ * This function can count as GRAPH_RDLOCK because read_quorum_children() holds
894
+ * the graph lock and keeps it until this coroutine has terminated.
895
+ */
896
+static void coroutine_fn GRAPH_RDLOCK quorum_rewrite_entry(void *opaque)
897
{
898
QuorumCo *co = opaque;
899
QuorumAIOCB *acb = co->acb;
900
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn quorum_rewrite_entry(void *opaque)
901
}
902
}
903
904
-static bool quorum_rewrite_bad_versions(QuorumAIOCB *acb,
905
- QuorumVoteValue *value)
906
+static bool coroutine_fn GRAPH_RDLOCK
907
+quorum_rewrite_bad_versions(QuorumAIOCB *acb, QuorumVoteValue *value)
908
{
909
QuorumVoteVersion *version;
910
QuorumVoteItem *item;
911
@@ -XXX,XX +XXX,XX @@ static int quorum_vote_error(QuorumAIOCB *acb)
912
return ret;
913
}
914
915
-static void quorum_vote(QuorumAIOCB *acb)
916
+static void coroutine_fn GRAPH_RDLOCK quorum_vote(QuorumAIOCB *acb)
917
{
918
bool quorum = true;
919
int i, j, ret;
920
@@ -XXX,XX +XXX,XX @@ free_exit:
921
quorum_free_vote_list(&acb->votes);
922
}
923
924
-static void coroutine_fn read_quorum_children_entry(void *opaque)
925
+/*
926
+ * This function can count as GRAPH_RDLOCK because read_quorum_children() holds
927
+ * the graph lock and keeps it until this coroutine has terminated.
928
+ */
929
+static void coroutine_fn GRAPH_RDLOCK read_quorum_children_entry(void *opaque)
930
{
931
QuorumCo *co = opaque;
932
QuorumAIOCB *acb = co->acb;
933
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn read_quorum_children_entry(void *opaque)
934
}
935
}
936
937
-static int coroutine_fn read_quorum_children(QuorumAIOCB *acb)
938
+static int coroutine_fn GRAPH_RDLOCK read_quorum_children(QuorumAIOCB *acb)
939
{
940
BDRVQuorumState *s = acb->bs->opaque;
941
int i;
942
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn read_quorum_children(QuorumAIOCB *acb)
943
return acb->vote_ret;
944
}
945
946
-static int coroutine_fn read_fifo_child(QuorumAIOCB *acb)
947
+static int coroutine_fn GRAPH_RDLOCK read_fifo_child(QuorumAIOCB *acb)
948
{
949
BDRVQuorumState *s = acb->bs->opaque;
950
int n, ret;
951
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn read_fifo_child(QuorumAIOCB *acb)
952
return ret;
953
}
954
955
-static int coroutine_fn quorum_co_preadv(BlockDriverState *bs,
956
- int64_t offset, int64_t bytes,
957
- QEMUIOVector *qiov,
958
- BdrvRequestFlags flags)
959
+static int coroutine_fn GRAPH_RDLOCK
960
+quorum_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
961
+ QEMUIOVector *qiov, BdrvRequestFlags flags)
962
{
963
BDRVQuorumState *s = bs->opaque;
964
QuorumAIOCB *acb = quorum_aio_get(bs, qiov, offset, bytes, flags);
965
diff --git a/block/raw-format.c b/block/raw-format.c
966
index XXXXXXX..XXXXXXX 100644
967
--- a/block/raw-format.c
968
+++ b/block/raw-format.c
969
@@ -XXX,XX +XXX,XX @@ static inline int raw_adjust_offset(BlockDriverState *bs, int64_t *offset,
970
return 0;
971
}
972
973
-static int coroutine_fn raw_co_preadv(BlockDriverState *bs, int64_t offset,
974
- int64_t bytes, QEMUIOVector *qiov,
975
- BdrvRequestFlags flags)
976
+static int coroutine_fn GRAPH_RDLOCK
977
+raw_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
978
+ QEMUIOVector *qiov, BdrvRequestFlags flags)
979
{
980
int ret;
981
982
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_preadv(BlockDriverState *bs, int64_t offset,
983
return bdrv_co_preadv(bs->file, offset, bytes, qiov, flags);
984
}
985
986
-static int coroutine_fn raw_co_pwritev(BlockDriverState *bs, int64_t offset,
987
- int64_t bytes, QEMUIOVector *qiov,
988
- BdrvRequestFlags flags)
989
+static int coroutine_fn GRAPH_RDLOCK
990
+raw_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes,
991
+ QEMUIOVector *qiov, BdrvRequestFlags flags)
992
{
993
void *buf = NULL;
994
BlockDriver *drv;
995
diff --git a/block/replication.c b/block/replication.c
996
index XXXXXXX..XXXXXXX 100644
997
--- a/block/replication.c
998
+++ b/block/replication.c
999
@@ -XXX,XX +XXX,XX @@ static int replication_return_value(BDRVReplicationState *s, int ret)
1000
return ret;
1001
}
1002
1003
-static coroutine_fn int replication_co_readv(BlockDriverState *bs,
1004
- int64_t sector_num,
1005
- int remaining_sectors,
1006
- QEMUIOVector *qiov)
1007
+static int coroutine_fn GRAPH_RDLOCK
1008
+replication_co_readv(BlockDriverState *bs, int64_t sector_num,
1009
+ int remaining_sectors, QEMUIOVector *qiov)
1010
{
1011
BDRVReplicationState *s = bs->opaque;
1012
int ret;
1013
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int replication_co_readv(BlockDriverState *bs,
1014
return replication_return_value(s, ret);
1015
}
1016
1017
-static coroutine_fn int replication_co_writev(BlockDriverState *bs,
1018
- int64_t sector_num,
1019
- int remaining_sectors,
1020
- QEMUIOVector *qiov,
1021
- int flags)
1022
+static int coroutine_fn GRAPH_RDLOCK
1023
+replication_co_writev(BlockDriverState *bs, int64_t sector_num,
1024
+ int remaining_sectors, QEMUIOVector *qiov, int flags)
1025
{
1026
BDRVReplicationState *s = bs->opaque;
1027
QEMUIOVector hd_qiov;
1028
diff --git a/block/throttle.c b/block/throttle.c
1029
index XXXXXXX..XXXXXXX 100644
1030
--- a/block/throttle.c
1031
+++ b/block/throttle.c
1032
@@ -XXX,XX +XXX,XX @@ static int64_t coroutine_fn throttle_co_getlength(BlockDriverState *bs)
1033
return bdrv_co_getlength(bs->file->bs);
1034
}
1035
1036
-static int coroutine_fn throttle_co_preadv(BlockDriverState *bs,
1037
- int64_t offset, int64_t bytes,
1038
- QEMUIOVector *qiov,
1039
- BdrvRequestFlags flags)
1040
+static int coroutine_fn GRAPH_RDLOCK
1041
+throttle_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
1042
+ QEMUIOVector *qiov, BdrvRequestFlags flags)
1043
{
1044
1045
ThrottleGroupMember *tgm = bs->opaque;
1046
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn throttle_co_preadv(BlockDriverState *bs,
1047
return bdrv_co_preadv(bs->file, offset, bytes, qiov, flags);
1048
}
1049
1050
-static int coroutine_fn throttle_co_pwritev(BlockDriverState *bs,
1051
- int64_t offset, int64_t bytes,
1052
- QEMUIOVector *qiov,
1053
- BdrvRequestFlags flags)
1054
+static int coroutine_fn GRAPH_RDLOCK
1055
+throttle_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes,
1056
+ QEMUIOVector *qiov, BdrvRequestFlags flags)
1057
{
1058
ThrottleGroupMember *tgm = bs->opaque;
1059
throttle_group_co_io_limits_intercept(tgm, bytes, true);
1060
@@ -XXX,XX +XXX,XX @@ throttle_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes)
1061
return bdrv_co_pdiscard(bs->file, offset, bytes);
1062
}
1063
1064
-static int coroutine_fn throttle_co_pwritev_compressed(BlockDriverState *bs,
1065
- int64_t offset,
1066
- int64_t bytes,
1067
- QEMUIOVector *qiov)
1068
+static int coroutine_fn GRAPH_RDLOCK
1069
+throttle_co_pwritev_compressed(BlockDriverState *bs, int64_t offset,
1070
+ int64_t bytes, QEMUIOVector *qiov)
1071
{
1072
return throttle_co_pwritev(bs, offset, bytes, qiov,
1073
BDRV_REQ_WRITE_COMPRESSED);
1074
diff --git a/block/vdi.c b/block/vdi.c
1075
index XXXXXXX..XXXXXXX 100644
1076
--- a/block/vdi.c
1077
+++ b/block/vdi.c
1078
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vdi_co_block_status(BlockDriverState *bs,
1079
(s->header.image_type == VDI_TYPE_STATIC ? BDRV_BLOCK_RECURSE : 0);
1080
}
1081
1082
-static int coroutine_fn
1083
+static int coroutine_fn GRAPH_RDLOCK
1084
vdi_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
1085
QEMUIOVector *qiov, BdrvRequestFlags flags)
1086
{
1087
@@ -XXX,XX +XXX,XX @@ vdi_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
1088
return ret;
1089
}
1090
1091
-static int coroutine_fn
1092
+static int coroutine_fn GRAPH_RDLOCK
1093
vdi_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes,
1094
QEMUIOVector *qiov, BdrvRequestFlags flags)
1095
{
1096
diff --git a/block/vhdx.c b/block/vhdx.c
1097
index XXXXXXX..XXXXXXX 100644
1098
--- a/block/vhdx.c
1099
+++ b/block/vhdx.c
1100
@@ -XXX,XX +XXX,XX @@ vhdx_co_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
1101
}
1102
1103
1104
-static coroutine_fn int vhdx_co_readv(BlockDriverState *bs, int64_t sector_num,
1105
- int nb_sectors, QEMUIOVector *qiov)
1106
+static int coroutine_fn GRAPH_RDLOCK
1107
+vhdx_co_readv(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
1108
+ QEMUIOVector *qiov)
1109
{
1110
BDRVVHDXState *s = bs->opaque;
1111
int ret = 0;
1112
@@ -XXX,XX +XXX,XX @@ int vhdx_user_visible_write(BlockDriverState *bs, BDRVVHDXState *s)
1113
return ret;
1114
}
1115
1116
-static coroutine_fn int vhdx_co_writev(BlockDriverState *bs, int64_t sector_num,
1117
- int nb_sectors, QEMUIOVector *qiov,
1118
- int flags)
1119
+static int coroutine_fn GRAPH_RDLOCK
1120
+vhdx_co_writev(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
1121
+ QEMUIOVector *qiov, int flags)
1122
{
1123
int ret = -ENOTSUP;
1124
BDRVVHDXState *s = bs->opaque;
1125
diff --git a/block/vmdk.c b/block/vmdk.c
1126
index XXXXXXX..XXXXXXX 100644
1127
--- a/block/vmdk.c
1128
+++ b/block/vmdk.c
1129
@@ -XXX,XX +XXX,XX @@ static void vmdk_refresh_limits(BlockDriverState *bs, Error **errp)
1130
* [@skip_start_sector, @skip_end_sector) is not copied or written, and leave
1131
* it for call to write user data in the request.
1132
*/
1133
-static int coroutine_fn get_whole_cluster(BlockDriverState *bs,
1134
- VmdkExtent *extent,
1135
- uint64_t cluster_offset,
1136
- uint64_t offset,
1137
- uint64_t skip_start_bytes,
1138
- uint64_t skip_end_bytes,
1139
- bool zeroed)
1140
+static int coroutine_fn GRAPH_RDLOCK
1141
+get_whole_cluster(BlockDriverState *bs, VmdkExtent *extent,
1142
+ uint64_t cluster_offset, uint64_t offset,
1143
+ uint64_t skip_start_bytes, uint64_t skip_end_bytes,
1144
+ bool zeroed)
1145
{
1146
int ret = VMDK_OK;
1147
int64_t cluster_bytes;
1148
@@ -XXX,XX +XXX,XX @@ vmdk_L2update(VmdkExtent *extent, VmdkMetaData *m_data, uint32_t offset)
1149
* VMDK_UNALLOC if cluster is not mapped and @allocate is false.
1150
* VMDK_ERROR if failed.
1151
*/
1152
-static int coroutine_fn get_cluster_offset(BlockDriverState *bs,
1153
- VmdkExtent *extent,
1154
- VmdkMetaData *m_data,
1155
- uint64_t offset,
1156
- bool allocate,
1157
- uint64_t *cluster_offset,
1158
- uint64_t skip_start_bytes,
1159
- uint64_t skip_end_bytes)
1160
+static int coroutine_fn GRAPH_RDLOCK
1161
+get_cluster_offset(BlockDriverState *bs, VmdkExtent *extent,
1162
+ VmdkMetaData *m_data, uint64_t offset, bool allocate,
1163
+ uint64_t *cluster_offset, uint64_t skip_start_bytes,
1164
+ uint64_t skip_end_bytes)
1165
{
1166
unsigned int l1_index, l2_offset, l2_index;
1167
int min_index, i, j;
1168
@@ -XXX,XX +XXX,XX @@ static inline uint64_t vmdk_find_offset_in_cluster(VmdkExtent *extent,
1169
return extent_relative_offset % cluster_size;
1170
}
1171
1172
-static int coroutine_fn vmdk_co_block_status(BlockDriverState *bs,
1173
- bool want_zero,
1174
- int64_t offset, int64_t bytes,
1175
- int64_t *pnum, int64_t *map,
1176
- BlockDriverState **file)
1177
+static int coroutine_fn GRAPH_RDLOCK
1178
+vmdk_co_block_status(BlockDriverState *bs, bool want_zero,
1179
+ int64_t offset, int64_t bytes, int64_t *pnum,
1180
+ int64_t *map, BlockDriverState **file)
1181
{
1182
BDRVVmdkState *s = bs->opaque;
1183
int64_t index_in_cluster, n, ret;
1184
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vmdk_co_block_status(BlockDriverState *bs,
1185
return ret;
1186
}
1187
1188
-static int coroutine_fn
1189
+static int coroutine_fn GRAPH_RDLOCK
1190
vmdk_write_extent(VmdkExtent *extent, int64_t cluster_offset,
1191
int64_t offset_in_cluster, QEMUIOVector *qiov,
1192
uint64_t qiov_offset, uint64_t n_bytes,
1193
@@ -XXX,XX +XXX,XX @@ vmdk_write_extent(VmdkExtent *extent, int64_t cluster_offset,
1194
return ret;
1195
}
1196
1197
-static int coroutine_fn
1198
+static int coroutine_fn GRAPH_RDLOCK
1199
vmdk_read_extent(VmdkExtent *extent, int64_t cluster_offset,
1200
- int64_t offset_in_cluster, QEMUIOVector *qiov,
1201
- int bytes)
1202
+ int64_t offset_in_cluster, QEMUIOVector *qiov, int bytes)
1203
{
1204
int ret;
1205
int cluster_bytes, buf_bytes;
1206
@@ -XXX,XX +XXX,XX @@ vmdk_read_extent(VmdkExtent *extent, int64_t cluster_offset,
1207
return ret;
1208
}
1209
1210
-static int coroutine_fn
1211
+static int coroutine_fn GRAPH_RDLOCK
1212
vmdk_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
1213
QEMUIOVector *qiov, BdrvRequestFlags flags)
1214
{
1215
@@ -XXX,XX +XXX,XX @@ fail:
1216
*
1217
* Returns: error code with 0 for success.
1218
*/
1219
-static int coroutine_fn vmdk_pwritev(BlockDriverState *bs, uint64_t offset,
1220
- uint64_t bytes, QEMUIOVector *qiov,
1221
- bool zeroed, bool zero_dry_run)
1222
+static int coroutine_fn GRAPH_RDLOCK
1223
+vmdk_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
1224
+ QEMUIOVector *qiov, bool zeroed, bool zero_dry_run)
1225
{
1226
BDRVVmdkState *s = bs->opaque;
1227
VmdkExtent *extent = NULL;
1228
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vmdk_pwritev(BlockDriverState *bs, uint64_t offset,
1229
uint64_t bytes_done = 0;
1230
VmdkMetaData m_data;
1231
1232
- assume_graph_lock(); /* FIXME */
1233
-
1234
if (DIV_ROUND_UP(offset, BDRV_SECTOR_SIZE) > bs->total_sectors) {
1235
error_report("Wrong offset: offset=0x%" PRIx64
1236
" total_sectors=0x%" PRIx64,
1237
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vmdk_pwritev(BlockDriverState *bs, uint64_t offset,
1238
return 0;
1239
}
1240
1241
-static int coroutine_fn
1242
+static int coroutine_fn GRAPH_RDLOCK
1243
vmdk_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes,
1244
QEMUIOVector *qiov, BdrvRequestFlags flags)
1245
{
1246
@@ -XXX,XX +XXX,XX @@ vmdk_co_pwritev_compressed(BlockDriverState *bs, int64_t offset, int64_t bytes,
1247
return vmdk_co_pwritev(bs, offset, bytes, qiov, 0);
1248
}
1249
1250
-static int coroutine_fn vmdk_co_pwrite_zeroes(BlockDriverState *bs,
1251
- int64_t offset,
1252
- int64_t bytes,
1253
- BdrvRequestFlags flags)
1254
+static int coroutine_fn GRAPH_RDLOCK
1255
+vmdk_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int64_t bytes,
1256
+ BdrvRequestFlags flags)
1257
{
1258
int ret;
1259
BDRVVmdkState *s = bs->opaque;
1260
@@ -XXX,XX +XXX,XX @@ static VmdkExtentInfo *vmdk_get_extent_info(VmdkExtent *extent)
1261
return info;
1262
}
1263
1264
-static int coroutine_fn vmdk_co_check(BlockDriverState *bs,
1265
- BdrvCheckResult *result,
1266
- BdrvCheckMode fix)
1267
+static int coroutine_fn GRAPH_RDLOCK
1268
+vmdk_co_check(BlockDriverState *bs, BdrvCheckResult *result, BdrvCheckMode fix)
1269
{
1270
BDRVVmdkState *s = bs->opaque;
1271
VmdkExtent *extent = NULL;
1272
diff --git a/block/vpc.c b/block/vpc.c
18
diff --git a/block/vpc.c b/block/vpc.c
1273
index XXXXXXX..XXXXXXX 100644
19
index XXXXXXX..XXXXXXX 100644
1274
--- a/block/vpc.c
20
--- a/block/vpc.c
1275
+++ b/block/vpc.c
21
+++ b/block/vpc.c
1276
@@ -XXX,XX +XXX,XX @@ vpc_co_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
22
@@ -XXX,XX +XXX,XX @@ static void vpc_parse_options(BlockDriverState *bs, QemuOpts *opts,
1277
return 0;
1278
}
1279
1280
-static int coroutine_fn
1281
+static int coroutine_fn GRAPH_RDLOCK
1282
vpc_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
1283
QEMUIOVector *qiov, BdrvRequestFlags flags)
1284
{
1285
@@ -XXX,XX +XXX,XX @@ fail:
1286
return ret;
1287
}
1288
1289
-static int coroutine_fn
1290
+static int coroutine_fn GRAPH_RDLOCK
1291
vpc_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes,
1292
QEMUIOVector *qiov, BdrvRequestFlags flags)
1293
{
1294
diff --git a/tests/unit/test-bdrv-drain.c b/tests/unit/test-bdrv-drain.c
1295
index XXXXXXX..XXXXXXX 100644
1296
--- a/tests/unit/test-bdrv-drain.c
1297
+++ b/tests/unit/test-bdrv-drain.c
1298
@@ -XXX,XX +XXX,XX @@ static void bdrv_test_top_close(BlockDriverState *bs)
1299
}
23
}
1300
}
24
}
1301
25
1302
-static int coroutine_fn bdrv_test_top_co_preadv(BlockDriverState *bs,
26
+/*
1303
- int64_t offset, int64_t bytes,
27
+ * Microsoft Virtual PC and Microsoft Hyper-V produce and read
1304
- QEMUIOVector *qiov,
28
+ * VHD image sizes differently. VPC will rely on CHS geometry,
1305
- BdrvRequestFlags flags)
29
+ * while Hyper-V and disk2vhd use the size specified in the footer.
1306
+static int coroutine_fn GRAPH_RDLOCK
30
+ *
1307
+bdrv_test_top_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
31
+ * We use a couple of approaches to try and determine the correct method:
1308
+ QEMUIOVector *qiov, BdrvRequestFlags flags)
32
+ * look at the Creator App field, and look for images that have CHS
33
+ * geometry that is the maximum value.
34
+ *
35
+ * If the CHS geometry is the maximum CHS geometry, then we assume that
36
+ * the size is the footer->current_size to avoid truncation. Otherwise,
37
+ * we follow the table based on footer->creator_app:
38
+ *
39
+ * Known creator apps:
40
+ * 'vpc ' : CHS Virtual PC (uses disk geometry)
41
+ * 'qemu' : CHS QEMU (uses disk geometry)
42
+ * 'qem2' : current_size QEMU (uses current_size)
43
+ * 'win ' : current_size Hyper-V
44
+ * 'd2v ' : current_size Disk2vhd
45
+ * 'tap\0' : current_size XenServer
46
+ * 'CTXS' : current_size XenConverter
47
+ *
48
+ * The user can override the table values via drive options, however
49
+ * even with an override we will still use current_size for images
50
+ * that have CHS geometry of the maximum size.
51
+ */
52
+static bool vpc_ignore_current_size(VHDFooter *footer)
53
+{
54
+ return !!strncmp(footer->creator_app, "win ", 4) &&
55
+ !!strncmp(footer->creator_app, "qem2", 4) &&
56
+ !!strncmp(footer->creator_app, "d2v ", 4) &&
57
+ !!strncmp(footer->creator_app, "CTXS", 4) &&
58
+ !!memcmp(footer->creator_app, "tap", 4));
59
+}
60
+
61
static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
62
Error **errp)
1309
{
63
{
1310
BDRVTestTopState *tts = bs->opaque;
64
@@ -XXX,XX +XXX,XX @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
1311
return bdrv_co_preadv(tts->wait_child, offset, bytes, qiov, flags);
65
bs->total_sectors = (int64_t)
1312
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn test_co_delete_by_drain(void *opaque)
66
be16_to_cpu(footer->cyls) * footer->heads * footer->secs_per_cyl;
1313
void *buffer = g_malloc(65536);
67
1314
QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buffer, 65536);
68
- /* Microsoft Virtual PC and Microsoft Hyper-V produce and read
1315
69
- * VHD image sizes differently. VPC will rely on CHS geometry,
1316
+ GRAPH_RDLOCK_GUARD();
70
- * while Hyper-V and disk2vhd use the size specified in the footer.
1317
+
71
- *
1318
/* Pretend some internal write operation from parent to child.
72
- * We use a couple of approaches to try and determine the correct method:
1319
* Important: We have to read from the child, not from the parent!
73
- * look at the Creator App field, and look for images that have CHS
1320
* Draining works by first propagating it all up the tree to the
74
- * geometry that is the maximum value.
1321
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_test_close(BlockDriverState *bs)
75
- *
1322
* Otherwise:
76
- * If the CHS geometry is the maximum CHS geometry, then we assume that
1323
* Set .has_read to true and return success.
77
- * the size is the footer->current_size to avoid truncation. Otherwise,
1324
*/
78
- * we follow the table based on footer->creator_app:
1325
-static int coroutine_fn bdrv_replace_test_co_preadv(BlockDriverState *bs,
79
- *
1326
- int64_t offset,
80
- * Known creator apps:
1327
- int64_t bytes,
81
- * 'vpc ' : CHS Virtual PC (uses disk geometry)
1328
- QEMUIOVector *qiov,
82
- * 'qemu' : CHS QEMU (uses disk geometry)
1329
- BdrvRequestFlags flags)
83
- * 'qem2' : current_size QEMU (uses current_size)
1330
+static int coroutine_fn GRAPH_RDLOCK
84
- * 'win ' : current_size Hyper-V
1331
+bdrv_replace_test_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
85
- * 'd2v ' : current_size Disk2vhd
1332
+ QEMUIOVector *qiov, BdrvRequestFlags flags)
86
- * 'tap\0' : current_size XenServer
1333
{
87
- * 'CTXS' : current_size XenConverter
1334
BDRVReplaceTestState *s = bs->opaque;
88
- *
1335
89
- * The user can override the table values via drive options, however
1336
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_replace_test_read_entry(void *opaque)
90
- * even with an override we will still use current_size for images
1337
int ret;
91
- * that have CHS geometry of the maximum size.
1338
92
- */
1339
/* Queue a read request post-drain */
93
- use_chs = (!!strncmp(footer->creator_app, "win ", 4) &&
1340
+ bdrv_graph_co_rdlock();
94
- !!strncmp(footer->creator_app, "qem2", 4) &&
1341
ret = bdrv_replace_test_co_preadv(bs, 0, 1, &qiov, 0);
95
- !!strncmp(footer->creator_app, "d2v ", 4) &&
1342
+ bdrv_graph_co_rdunlock();
96
- !!strncmp(footer->creator_app, "CTXS", 4) &&
1343
+
97
- !!memcmp(footer->creator_app, "tap", 4)) || s->force_use_chs;
1344
g_assert(ret >= 0);
98
+ /* Use CHS or current_size to determine the image size. */
1345
bdrv_dec_in_flight(bs);
99
+ use_chs = vpc_ignore_current_size(footer) || s->force_use_chs;
1346
}
100
101
if (!use_chs || bs->total_sectors == VHD_MAX_GEOMETRY || s->force_use_sz) {
102
bs->total_sectors = be64_to_cpu(footer->current_size) /
1347
--
103
--
1348
2.39.2
104
2.48.1
105
106
diff view generated by jsdifflib
1
From: Stefan Hajnoczi <stefanha@redhat.com>
1
From: Vitaly Kuznetsov <vkuznets@redhat.com>
2
2
3
dma_blk_cb() only takes the AioContext lock around ->io_func(). That
3
It was found that 'qemu-nbd' is not able to work with some disk images
4
means the rest of dma_blk_cb() is not protected. In particular, the
4
exported from Azure. Looking at the 512b footer (which contains VPC
5
DMAAIOCB field accesses happen outside the lock.
5
metadata):
6
6
7
There is a race when the main loop thread holds the AioContext lock and
7
00000000 63 6f 6e 65 63 74 69 78 00 00 00 02 00 01 00 00 |conectix........|
8
invokes scsi_device_purge_requests() -> bdrv_aio_cancel() ->
8
00000010 ff ff ff ff ff ff ff ff 2e c7 9b 96 77 61 00 00 |............wa..|
9
dma_aio_cancel() while an IOThread executes dma_blk_cb(). The dbs->acb
9
00000020 00 07 00 00 57 69 32 6b 00 00 00 01 40 00 00 00 |....Wi2k....@...|
10
field determines how cancellation proceeds. If dma_aio_cancel() sees
10
00000030 00 00 00 01 40 00 00 00 28 a2 10 3f 00 00 00 02 |....@...(..?....|
11
dbs->acb == NULL while dma_blk_cb() is still running, the request can be
11
00000040 ff ff e7 47 8c 54 df 94 bd 35 71 4c 94 5f e5 44 |...G.T...5qL._.D|
12
completed twice (-ECANCELED and the actual return value).
12
00000050 44 53 92 1a 00 00 00 00 00 00 00 00 00 00 00 00 |DS..............|
13
00000060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
13
14
14
The following assertion can occur with virtio-scsi when an IOThread is
15
we can see that Azure uses a different 'Creator application' --
15
used:
16
'wa\0\0' (offset 0x1c, likely reads as 'Windows Azure') and QEMU uses this
17
field to determine how it can get image size. Apparently, Azure uses 'new'
18
method, just like Hyper-V.
16
19
17
../hw/scsi/scsi-disk.c:368: scsi_dma_complete: Assertion `r->req.aiocb != NULL' failed.
20
Overall, it seems that only VPC and old QEMUs need to be ignored as all new
21
creator apps seem to have reliable current_size. Invert the logic and make
22
'current_size' method the default to avoid adding every new creator app to
23
the list.
18
24
19
Fix the race by holding the AioContext across dma_blk_cb(). Now
25
Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
20
dma_aio_cancel() under the AioContext lock will not see
26
Message-ID: <20241212134504.1983757-3-vkuznets@redhat.com>
21
inconsistent/intermediate states.
27
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
22
23
Cc: Paolo Bonzini <pbonzini@redhat.com>
24
Reviewed-by: Eric Blake <eblake@redhat.com>
25
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
26
Message-Id: <20230221212218.1378734-3-stefanha@redhat.com>
27
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
28
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
28
---
29
---
29
hw/scsi/scsi-disk.c | 4 +---
30
block/vpc.c | 8 +++-----
30
softmmu/dma-helpers.c | 12 +++++++-----
31
1 file changed, 3 insertions(+), 5 deletions(-)
31
2 files changed, 8 insertions(+), 8 deletions(-)
32
32
33
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
33
diff --git a/block/vpc.c b/block/vpc.c
34
index XXXXXXX..XXXXXXX 100644
34
index XXXXXXX..XXXXXXX 100644
35
--- a/hw/scsi/scsi-disk.c
35
--- a/block/vpc.c
36
+++ b/hw/scsi/scsi-disk.c
36
+++ b/block/vpc.c
37
@@ -XXX,XX +XXX,XX @@ done:
37
@@ -XXX,XX +XXX,XX @@ static void vpc_parse_options(BlockDriverState *bs, QemuOpts *opts,
38
scsi_req_unref(&r->req);
38
* 'd2v ' : current_size Disk2vhd
39
* 'tap\0' : current_size XenServer
40
* 'CTXS' : current_size XenConverter
41
+ * 'wa\0\0': current_size Azure
42
*
43
* The user can override the table values via drive options, however
44
* even with an override we will still use current_size for images
45
@@ -XXX,XX +XXX,XX @@ static void vpc_parse_options(BlockDriverState *bs, QemuOpts *opts,
46
*/
47
static bool vpc_ignore_current_size(VHDFooter *footer)
48
{
49
- return !!strncmp(footer->creator_app, "win ", 4) &&
50
- !!strncmp(footer->creator_app, "qem2", 4) &&
51
- !!strncmp(footer->creator_app, "d2v ", 4) &&
52
- !!strncmp(footer->creator_app, "CTXS", 4) &&
53
- !!memcmp(footer->creator_app, "tap", 4));
54
+ return !strncmp(footer->creator_app, "vpc ", 4) ||
55
+ !strncmp(footer->creator_app, "qemu", 4);
39
}
56
}
40
57
41
+/* Called with AioContext lock held */
58
static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
42
static void scsi_dma_complete(void *opaque, int ret)
43
{
44
SCSIDiskReq *r = (SCSIDiskReq *)opaque;
45
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
46
47
- aio_context_acquire(blk_get_aio_context(s->qdev.conf.blk));
48
-
49
assert(r->req.aiocb != NULL);
50
r->req.aiocb = NULL;
51
52
@@ -XXX,XX +XXX,XX @@ static void scsi_dma_complete(void *opaque, int ret)
53
block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct);
54
}
55
scsi_dma_complete_noio(r, ret);
56
- aio_context_release(blk_get_aio_context(s->qdev.conf.blk));
57
}
58
59
static void scsi_read_complete_noio(SCSIDiskReq *r, int ret)
60
diff --git a/softmmu/dma-helpers.c b/softmmu/dma-helpers.c
61
index XXXXXXX..XXXXXXX 100644
62
--- a/softmmu/dma-helpers.c
63
+++ b/softmmu/dma-helpers.c
64
@@ -XXX,XX +XXX,XX @@ static void dma_complete(DMAAIOCB *dbs, int ret)
65
static void dma_blk_cb(void *opaque, int ret)
66
{
67
DMAAIOCB *dbs = (DMAAIOCB *)opaque;
68
+ AioContext *ctx = dbs->ctx;
69
dma_addr_t cur_addr, cur_len;
70
void *mem;
71
72
trace_dma_blk_cb(dbs, ret);
73
74
+ aio_context_acquire(ctx);
75
dbs->acb = NULL;
76
dbs->offset += dbs->iov.size;
77
78
if (dbs->sg_cur_index == dbs->sg->nsg || ret < 0) {
79
dma_complete(dbs, ret);
80
- return;
81
+ goto out;
82
}
83
dma_blk_unmap(dbs);
84
85
@@ -XXX,XX +XXX,XX @@ static void dma_blk_cb(void *opaque, int ret)
86
87
if (dbs->iov.size == 0) {
88
trace_dma_map_wait(dbs);
89
- dbs->bh = aio_bh_new(dbs->ctx, reschedule_dma, dbs);
90
+ dbs->bh = aio_bh_new(ctx, reschedule_dma, dbs);
91
cpu_register_map_client(dbs->bh);
92
- return;
93
+ goto out;
94
}
95
96
if (!QEMU_IS_ALIGNED(dbs->iov.size, dbs->align)) {
97
@@ -XXX,XX +XXX,XX @@ static void dma_blk_cb(void *opaque, int ret)
98
QEMU_ALIGN_DOWN(dbs->iov.size, dbs->align));
99
}
100
101
- aio_context_acquire(dbs->ctx);
102
dbs->acb = dbs->io_func(dbs->offset, &dbs->iov,
103
dma_blk_cb, dbs, dbs->io_func_opaque);
104
- aio_context_release(dbs->ctx);
105
assert(dbs->acb);
106
+out:
107
+ aio_context_release(ctx);
108
}
109
110
static void dma_aio_cancel(BlockAIOCB *acb)
111
--
59
--
112
2.39.2
60
2.48.1
diff view generated by jsdifflib
1
From: Emanuele Giuseppe Esposito <eesposit@redhat.com>
1
From: Philippe Mathieu-Daudé <philmd@linaro.org>
2
2
3
This adds GRAPH_RDLOCK annotations to declare that callers of
3
Expose the method docstring in the header, and mention
4
bdrv_co_pdiscard() need to hold a reader lock for the graph.
4
returned value must be free'd by caller.
5
5
6
For some places, we know that they will hold the lock, but we don't have
6
Reported-by: Fabiano Rosas <farosas@suse.de>
7
the GRAPH_RDLOCK annotations yet. In this case, add assume_graph_lock()
7
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
8
with a FIXME comment. These places will be removed once everything is
8
Message-ID: <20241111170333.43833-2-philmd@linaro.org>
9
properly annotated.
10
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Message-Id: <20230203152202.49054-9-kwolf@redhat.com>
13
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
---
10
---
16
include/block/block-io.h | 5 +++--
11
include/system/block-backend-io.h | 7 +++++++
17
include/block/block_int-common.h | 15 +++++++++------
12
block/block-backend.c | 12 ++++++++----
18
include/block/block_int-io.h | 2 +-
13
2 files changed, 15 insertions(+), 4 deletions(-)
19
block/blkdebug.c | 4 ++--
20
block/blklogwrites.c | 5 ++---
21
block/blkreplay.c | 4 ++--
22
block/block-backend.c | 1 +
23
block/copy-before-write.c | 8 ++++----
24
block/copy-on-read.c | 4 ++--
25
block/filter-compress.c | 4 ++--
26
block/io.c | 2 ++
27
block/mirror.c | 14 +++++++++-----
28
block/preallocate.c | 4 ++--
29
block/raw-format.c | 4 ++--
30
block/snapshot-access.c | 4 ++--
31
block/throttle.c | 4 ++--
32
16 files changed, 47 insertions(+), 37 deletions(-)
33
14
34
diff --git a/include/block/block-io.h b/include/block/block-io.h
15
diff --git a/include/system/block-backend-io.h b/include/system/block-backend-io.h
35
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
36
--- a/include/block/block-io.h
17
--- a/include/system/block-backend-io.h
37
+++ b/include/block/block-io.h
18
+++ b/include/system/block-backend-io.h
38
@@ -XXX,XX +XXX,XX @@ bdrv_co_ioctl(BlockDriverState *bs, int req, void *buf);
19
@@ -XXX,XX +XXX,XX @@ void blk_set_allow_aio_context_change(BlockBackend *blk, bool allow);
39
/* Ensure contents are flushed to disk. */
20
void blk_set_disable_request_queuing(BlockBackend *blk, bool disable);
40
int coroutine_fn GRAPH_RDLOCK bdrv_co_flush(BlockDriverState *bs);
21
bool blk_iostatus_is_enabled(const BlockBackend *blk);
41
22
42
-int coroutine_fn bdrv_co_pdiscard(BdrvChild *child, int64_t offset,
23
+/*
43
- int64_t bytes);
24
+ * Return the qdev ID, or if no ID is assigned the QOM path,
44
+int coroutine_fn GRAPH_RDLOCK bdrv_co_pdiscard(BdrvChild *child, int64_t offset,
25
+ * of the block device attached to the BlockBackend.
45
+ int64_t bytes);
26
+ *
46
+
27
+ * The caller is responsible for releasing the value returned
47
bool bdrv_can_write_zeroes_with_unmap(BlockDriverState *bs);
28
+ * with g_free() after use.
48
int bdrv_block_status(BlockDriverState *bs, int64_t offset,
29
+ */
49
int64_t bytes, int64_t *pnum, int64_t *map,
30
char *blk_get_attached_dev_id(BlockBackend *blk);
50
diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
31
51
index XXXXXXX..XXXXXXX 100644
32
BlockAIOCB *blk_aio_pwrite_zeroes(BlockBackend *blk, int64_t offset,
52
--- a/include/block/block_int-common.h
53
+++ b/include/block/block_int-common.h
54
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
55
BdrvRequestFlags flags, BlockCompletionFunc *cb, void *opaque);
56
BlockAIOCB * GRAPH_RDLOCK_PTR (*bdrv_aio_flush)(
57
BlockDriverState *bs, BlockCompletionFunc *cb, void *opaque);
58
- BlockAIOCB *(*bdrv_aio_pdiscard)(BlockDriverState *bs,
59
- int64_t offset, int bytes,
60
+
61
+ BlockAIOCB * GRAPH_RDLOCK_PTR (*bdrv_aio_pdiscard)(
62
+ BlockDriverState *bs, int64_t offset, int bytes,
63
BlockCompletionFunc *cb, void *opaque);
64
65
int coroutine_fn (*bdrv_co_readv)(BlockDriverState *bs,
66
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
67
*/
68
int coroutine_fn (*bdrv_co_pwrite_zeroes)(BlockDriverState *bs,
69
int64_t offset, int64_t bytes, BdrvRequestFlags flags);
70
- int coroutine_fn (*bdrv_co_pdiscard)(BlockDriverState *bs,
71
- int64_t offset, int64_t bytes);
72
+
73
+ int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_pdiscard)(
74
+ BlockDriverState *bs, int64_t offset, int64_t bytes);
75
76
/*
77
* Map [offset, offset + nbytes) range onto a child of @bs to copy from,
78
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
79
int coroutine_fn (*bdrv_co_snapshot_block_status)(BlockDriverState *bs,
80
bool want_zero, int64_t offset, int64_t bytes, int64_t *pnum,
81
int64_t *map, BlockDriverState **file);
82
- int coroutine_fn (*bdrv_co_pdiscard_snapshot)(BlockDriverState *bs,
83
- int64_t offset, int64_t bytes);
84
+
85
+ int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_pdiscard_snapshot)(
86
+ BlockDriverState *bs, int64_t offset, int64_t bytes);
87
88
/*
89
* Invalidate any cached meta-data.
90
diff --git a/include/block/block_int-io.h b/include/block/block_int-io.h
91
index XXXXXXX..XXXXXXX 100644
92
--- a/include/block/block_int-io.h
93
+++ b/include/block/block_int-io.h
94
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_preadv_snapshot(BdrvChild *child,
95
int coroutine_fn bdrv_co_snapshot_block_status(BlockDriverState *bs,
96
bool want_zero, int64_t offset, int64_t bytes, int64_t *pnum,
97
int64_t *map, BlockDriverState **file);
98
-int coroutine_fn bdrv_co_pdiscard_snapshot(BlockDriverState *bs,
99
+int coroutine_fn GRAPH_RDLOCK bdrv_co_pdiscard_snapshot(BlockDriverState *bs,
100
int64_t offset, int64_t bytes);
101
102
103
diff --git a/block/blkdebug.c b/block/blkdebug.c
104
index XXXXXXX..XXXXXXX 100644
105
--- a/block/blkdebug.c
106
+++ b/block/blkdebug.c
107
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn blkdebug_co_pwrite_zeroes(BlockDriverState *bs,
108
return bdrv_co_pwrite_zeroes(bs->file, offset, bytes, flags);
109
}
110
111
-static int coroutine_fn blkdebug_co_pdiscard(BlockDriverState *bs,
112
- int64_t offset, int64_t bytes)
113
+static int coroutine_fn GRAPH_RDLOCK
114
+blkdebug_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes)
115
{
116
uint32_t align = bs->bl.pdiscard_alignment;
117
int err;
118
diff --git a/block/blklogwrites.c b/block/blklogwrites.c
119
index XXXXXXX..XXXXXXX 100644
120
--- a/block/blklogwrites.c
121
+++ b/block/blklogwrites.c
122
@@ -XXX,XX +XXX,XX @@ blk_log_writes_co_do_file_flush(BlkLogWritesFileReq *fr)
123
return bdrv_co_flush(fr->bs->file->bs);
124
}
125
126
-static int coroutine_fn
127
+static int coroutine_fn GRAPH_RDLOCK
128
blk_log_writes_co_do_file_pdiscard(BlkLogWritesFileReq *fr)
129
{
130
return bdrv_co_pdiscard(fr->bs->file, fr->offset, fr->bytes);
131
@@ -XXX,XX +XXX,XX @@ blk_log_writes_co_flush_to_disk(BlockDriverState *bs)
132
LOG_FLUSH_FLAG, false);
133
}
134
135
-static int coroutine_fn
136
+static int coroutine_fn GRAPH_RDLOCK
137
blk_log_writes_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes)
138
{
139
- assume_graph_lock(); /* FIXME */
140
return blk_log_writes_co_log(bs, offset, bytes, NULL, 0,
141
blk_log_writes_co_do_file_pdiscard,
142
LOG_DISCARD_FLAG, false);
143
diff --git a/block/blkreplay.c b/block/blkreplay.c
144
index XXXXXXX..XXXXXXX 100644
145
--- a/block/blkreplay.c
146
+++ b/block/blkreplay.c
147
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn blkreplay_co_pwrite_zeroes(BlockDriverState *bs,
148
return ret;
149
}
150
151
-static int coroutine_fn blkreplay_co_pdiscard(BlockDriverState *bs,
152
- int64_t offset, int64_t bytes)
153
+static int coroutine_fn GRAPH_RDLOCK
154
+blkreplay_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes)
155
{
156
uint64_t reqid = blkreplay_next_id();
157
int ret = bdrv_co_pdiscard(bs->file, offset, bytes);
158
diff --git a/block/block-backend.c b/block/block-backend.c
33
diff --git a/block/block-backend.c b/block/block-backend.c
159
index XXXXXXX..XXXXXXX 100644
34
index XXXXXXX..XXXXXXX 100644
160
--- a/block/block-backend.c
35
--- a/block/block-backend.c
161
+++ b/block/block-backend.c
36
+++ b/block/block-backend.c
162
@@ -XXX,XX +XXX,XX @@ blk_co_do_pdiscard(BlockBackend *blk, int64_t offset, int64_t bytes)
37
@@ -XXX,XX +XXX,XX @@ DeviceState *blk_get_attached_dev(BlockBackend *blk)
163
IO_CODE();
38
return blk->dev;
164
165
blk_wait_while_drained(blk);
166
+ GRAPH_RDLOCK_GUARD();
167
168
ret = blk_check_byte_request(blk, offset, bytes);
169
if (ret < 0) {
170
diff --git a/block/copy-before-write.c b/block/copy-before-write.c
171
index XXXXXXX..XXXXXXX 100644
172
--- a/block/copy-before-write.c
173
+++ b/block/copy-before-write.c
174
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int cbw_do_copy_before_write(BlockDriverState *bs,
175
return 0;
176
}
39
}
177
40
178
-static int coroutine_fn cbw_co_pdiscard(BlockDriverState *bs,
41
+/*
179
- int64_t offset, int64_t bytes)
42
+ * The caller is responsible for releasing the value returned
180
+static int coroutine_fn GRAPH_RDLOCK
43
+ * with g_free() after use.
181
+cbw_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes)
44
+ */
45
static char *blk_get_attached_dev_id_or_path(BlockBackend *blk, bool want_id)
182
{
46
{
183
int ret = cbw_do_copy_before_write(bs, offset, bytes, 0);
47
DeviceState *dev = blk->dev;
184
if (ret < 0) {
48
@@ -XXX,XX +XXX,XX @@ static char *blk_get_attached_dev_id_or_path(BlockBackend *blk, bool want_id)
185
@@ -XXX,XX +XXX,XX @@ cbw_co_snapshot_block_status(BlockDriverState *bs,
49
return object_get_canonical_path(OBJECT(dev)) ?: g_strdup("");
186
return ret;
187
}
50
}
188
51
189
-static int coroutine_fn cbw_co_pdiscard_snapshot(BlockDriverState *bs,
52
-/*
190
- int64_t offset, int64_t bytes)
53
- * Return the qdev ID, or if no ID is assigned the QOM path, of the block
191
+static int coroutine_fn GRAPH_RDLOCK
54
- * device attached to the BlockBackend.
192
+cbw_co_pdiscard_snapshot(BlockDriverState *bs, int64_t offset, int64_t bytes)
55
- */
56
char *blk_get_attached_dev_id(BlockBackend *blk)
193
{
57
{
194
BDRVCopyBeforeWriteState *s = bs->opaque;
58
return blk_get_attached_dev_id_or_path(blk, true);
195
196
diff --git a/block/copy-on-read.c b/block/copy-on-read.c
197
index XXXXXXX..XXXXXXX 100644
198
--- a/block/copy-on-read.c
199
+++ b/block/copy-on-read.c
200
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn cor_co_pwrite_zeroes(BlockDriverState *bs,
201
}
59
}
202
60
203
61
+/*
204
-static int coroutine_fn cor_co_pdiscard(BlockDriverState *bs,
62
+ * The caller is responsible for releasing the value returned
205
- int64_t offset, int64_t bytes)
63
+ * with g_free() after use.
206
+static int coroutine_fn GRAPH_RDLOCK
64
+ */
207
+cor_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes)
65
static char *blk_get_attached_dev_path(BlockBackend *blk)
208
{
66
{
209
return bdrv_co_pdiscard(bs->file, offset, bytes);
67
return blk_get_attached_dev_id_or_path(blk, false);
210
}
211
diff --git a/block/filter-compress.c b/block/filter-compress.c
212
index XXXXXXX..XXXXXXX 100644
213
--- a/block/filter-compress.c
214
+++ b/block/filter-compress.c
215
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn compress_co_pwrite_zeroes(BlockDriverState *bs,
216
}
217
218
219
-static int coroutine_fn compress_co_pdiscard(BlockDriverState *bs,
220
- int64_t offset, int64_t bytes)
221
+static int coroutine_fn GRAPH_RDLOCK
222
+compress_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes)
223
{
224
return bdrv_co_pdiscard(bs->file, offset, bytes);
225
}
226
diff --git a/block/io.c b/block/io.c
227
index XXXXXXX..XXXXXXX 100644
228
--- a/block/io.c
229
+++ b/block/io.c
230
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_pdiscard(BdrvChild *child, int64_t offset,
231
int head, tail, align;
232
BlockDriverState *bs = child->bs;
233
IO_CODE();
234
+ assert_bdrv_graph_readable();
235
236
if (!bs || !bs->drv || !bdrv_co_is_inserted(bs)) {
237
return -ENOMEDIUM;
238
@@ -XXX,XX +XXX,XX @@ bdrv_co_pdiscard_snapshot(BlockDriverState *bs, int64_t offset, int64_t bytes)
239
BlockDriver *drv = bs->drv;
240
int ret;
241
IO_CODE();
242
+ assert_bdrv_graph_readable();
243
244
if (!drv) {
245
return -ENOMEDIUM;
246
diff --git a/block/mirror.c b/block/mirror.c
247
index XXXXXXX..XXXXXXX 100644
248
--- a/block/mirror.c
249
+++ b/block/mirror.c
250
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_mirror_top_preadv(BlockDriverState *bs,
251
return bdrv_co_preadv(bs->backing, offset, bytes, qiov, flags);
252
}
253
254
-static int coroutine_fn bdrv_mirror_top_do_write(BlockDriverState *bs,
255
- MirrorMethod method, uint64_t offset, uint64_t bytes, QEMUIOVector *qiov,
256
- int flags)
257
+static int coroutine_fn GRAPH_RDLOCK
258
+bdrv_mirror_top_do_write(BlockDriverState *bs, MirrorMethod method,
259
+ uint64_t offset, uint64_t bytes, QEMUIOVector *qiov,
260
+ int flags)
261
{
262
MirrorOp *op = NULL;
263
MirrorBDSOpaque *s = bs->opaque;
264
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_mirror_top_pwritev(BlockDriverState *bs,
265
int ret = 0;
266
bool copy_to_target = false;
267
268
+ assume_graph_lock(); /* FIXME */
269
+
270
if (s->job) {
271
copy_to_target = s->job->ret >= 0 &&
272
!job_is_cancelled(&s->job->common.job) &&
273
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn GRAPH_RDLOCK bdrv_mirror_top_flush(BlockDriverState *bs)
274
static int coroutine_fn bdrv_mirror_top_pwrite_zeroes(BlockDriverState *bs,
275
int64_t offset, int64_t bytes, BdrvRequestFlags flags)
276
{
277
+ assume_graph_lock(); /* FIXME */
278
return bdrv_mirror_top_do_write(bs, MIRROR_METHOD_ZERO, offset, bytes, NULL,
279
flags);
280
}
281
282
-static int coroutine_fn bdrv_mirror_top_pdiscard(BlockDriverState *bs,
283
- int64_t offset, int64_t bytes)
284
+static int coroutine_fn GRAPH_RDLOCK
285
+bdrv_mirror_top_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes)
286
{
287
return bdrv_mirror_top_do_write(bs, MIRROR_METHOD_DISCARD, offset, bytes,
288
NULL, 0);
289
diff --git a/block/preallocate.c b/block/preallocate.c
290
index XXXXXXX..XXXXXXX 100644
291
--- a/block/preallocate.c
292
+++ b/block/preallocate.c
293
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int preallocate_co_preadv_part(
294
flags);
295
}
296
297
-static int coroutine_fn preallocate_co_pdiscard(BlockDriverState *bs,
298
- int64_t offset, int64_t bytes)
299
+static int coroutine_fn GRAPH_RDLOCK
300
+preallocate_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes)
301
{
302
return bdrv_co_pdiscard(bs->file, offset, bytes);
303
}
304
diff --git a/block/raw-format.c b/block/raw-format.c
305
index XXXXXXX..XXXXXXX 100644
306
--- a/block/raw-format.c
307
+++ b/block/raw-format.c
308
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_pwrite_zeroes(BlockDriverState *bs,
309
return bdrv_co_pwrite_zeroes(bs->file, offset, bytes, flags);
310
}
311
312
-static int coroutine_fn raw_co_pdiscard(BlockDriverState *bs,
313
- int64_t offset, int64_t bytes)
314
+static int coroutine_fn GRAPH_RDLOCK
315
+raw_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes)
316
{
317
int ret;
318
319
diff --git a/block/snapshot-access.c b/block/snapshot-access.c
320
index XXXXXXX..XXXXXXX 100644
321
--- a/block/snapshot-access.c
322
+++ b/block/snapshot-access.c
323
@@ -XXX,XX +XXX,XX @@ snapshot_access_co_block_status(BlockDriverState *bs,
324
bytes, pnum, map, file);
325
}
326
327
-static int coroutine_fn snapshot_access_co_pdiscard(BlockDriverState *bs,
328
- int64_t offset, int64_t bytes)
329
+static int coroutine_fn GRAPH_RDLOCK
330
+snapshot_access_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes)
331
{
332
return bdrv_co_pdiscard_snapshot(bs->file->bs, offset, bytes);
333
}
334
diff --git a/block/throttle.c b/block/throttle.c
335
index XXXXXXX..XXXXXXX 100644
336
--- a/block/throttle.c
337
+++ b/block/throttle.c
338
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn throttle_co_pwrite_zeroes(BlockDriverState *bs,
339
return bdrv_co_pwrite_zeroes(bs->file, offset, bytes, flags);
340
}
341
342
-static int coroutine_fn throttle_co_pdiscard(BlockDriverState *bs,
343
- int64_t offset, int64_t bytes)
344
+static int coroutine_fn GRAPH_RDLOCK
345
+throttle_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes)
346
{
347
ThrottleGroupMember *tgm = bs->opaque;
348
throttle_group_co_io_limits_intercept(tgm, bytes, true);
349
--
68
--
350
2.39.2
69
2.48.1
70
71
diff view generated by jsdifflib
1
This adds GRAPH_RDLOCK annotations to declare that callers of
1
From: Fabiano Rosas <farosas@suse.de>
2
bdrv_co_eject() and bdrv_co_lock_medium() need to hold a reader lock for
3
the graph.
4
2
5
Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
3
ASAN detected a leak when running the ahci-test
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
/ahci/io/dma/lba28/retry:
7
Message-Id: <20230203152202.49054-20-kwolf@redhat.com>
5
8
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
6
Direct leak of 35 byte(s) in 1 object(s) allocated from:
7
#0 in malloc
8
#1 in __vasprintf_internal
9
#2 in vasprintf
10
#3 in g_vasprintf
11
#4 in g_strdup_vprintf
12
#5 in g_strdup_printf
13
#6 in object_get_canonical_path ../qom/object.c:2096:19
14
#7 in blk_get_attached_dev_id_or_path ../block/block-backend.c:1033:12
15
#8 in blk_get_attached_dev_path ../block/block-backend.c:1047:12
16
#9 in send_qmp_error_event ../block/block-backend.c:2140:36
17
#10 in blk_error_action ../block/block-backend.c:2172:9
18
#11 in ide_handle_rw_error ../hw/ide/core.c:875:5
19
#12 in ide_dma_cb ../hw/ide/core.c:894:13
20
#13 in dma_complete ../system/dma-helpers.c:107:9
21
#14 in dma_blk_cb ../system/dma-helpers.c:129:9
22
#15 in blk_aio_complete ../block/block-backend.c:1552:9
23
#16 in blk_aio_write_entry ../block/block-backend.c:1619:5
24
#17 in coroutine_trampoline ../util/coroutine-ucontext.c:175:9
25
26
Plug the leak by freeing the device path string.
27
28
Signed-off-by: Fabiano Rosas <farosas@suse.de>
29
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
30
Message-ID: <20241111145214.8261-1-farosas@suse.de>
31
[PMD: Use g_autofree]
32
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
33
Message-ID: <20241111170333.43833-3-philmd@linaro.org>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
34
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
35
---
11
include/block/block-io.h | 7 +++++--
36
block/block-backend.c | 4 ++--
12
include/block/block_int-common.h | 6 ++++--
37
1 file changed, 2 insertions(+), 2 deletions(-)
13
block.c | 2 ++
14
block/block-backend.c | 2 ++
15
block/copy-on-read.c | 6 ++++--
16
block/filter-compress.c | 4 ++--
17
block/raw-format.c | 6 ++++--
18
7 files changed, 23 insertions(+), 10 deletions(-)
19
38
20
diff --git a/include/block/block-io.h b/include/block/block-io.h
21
index XXXXXXX..XXXXXXX 100644
22
--- a/include/block/block-io.h
23
+++ b/include/block/block-io.h
24
@@ -XXX,XX +XXX,XX @@ int bdrv_get_flags(BlockDriverState *bs);
25
bool coroutine_fn GRAPH_RDLOCK bdrv_co_is_inserted(BlockDriverState *bs);
26
bool co_wrapper_bdrv_rdlock bdrv_is_inserted(BlockDriverState *bs);
27
28
-void coroutine_fn bdrv_co_lock_medium(BlockDriverState *bs, bool locked);
29
-void coroutine_fn bdrv_co_eject(BlockDriverState *bs, bool eject_flag);
30
+void coroutine_fn GRAPH_RDLOCK
31
+bdrv_co_lock_medium(BlockDriverState *bs, bool locked);
32
+
33
+void coroutine_fn GRAPH_RDLOCK
34
+bdrv_co_eject(BlockDriverState *bs, bool eject_flag);
35
36
const char *bdrv_get_format_name(BlockDriverState *bs);
37
38
diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
39
index XXXXXXX..XXXXXXX 100644
40
--- a/include/block/block_int-common.h
41
+++ b/include/block/block_int-common.h
42
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
43
/* removable device specific */
44
bool coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_is_inserted)(
45
BlockDriverState *bs);
46
- void coroutine_fn (*bdrv_co_eject)(BlockDriverState *bs, bool eject_flag);
47
- void coroutine_fn (*bdrv_co_lock_medium)(BlockDriverState *bs, bool locked);
48
+ void coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_eject)(
49
+ BlockDriverState *bs, bool eject_flag);
50
+ void coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_lock_medium)(
51
+ BlockDriverState *bs, bool locked);
52
53
/* to control generic scsi devices */
54
BlockAIOCB *coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_aio_ioctl)(
55
diff --git a/block.c b/block.c
56
index XXXXXXX..XXXXXXX 100644
57
--- a/block.c
58
+++ b/block.c
59
@@ -XXX,XX +XXX,XX @@ void coroutine_fn bdrv_co_eject(BlockDriverState *bs, bool eject_flag)
60
{
61
BlockDriver *drv = bs->drv;
62
IO_CODE();
63
+ assert_bdrv_graph_readable();
64
65
if (drv && drv->bdrv_co_eject) {
66
drv->bdrv_co_eject(bs, eject_flag);
67
@@ -XXX,XX +XXX,XX @@ void coroutine_fn bdrv_co_lock_medium(BlockDriverState *bs, bool locked)
68
{
69
BlockDriver *drv = bs->drv;
70
IO_CODE();
71
+ assert_bdrv_graph_readable();
72
trace_bdrv_lock_medium(bs, locked);
73
74
if (drv && drv->bdrv_co_lock_medium) {
75
diff --git a/block/block-backend.c b/block/block-backend.c
39
diff --git a/block/block-backend.c b/block/block-backend.c
76
index XXXXXXX..XXXXXXX 100644
40
index XXXXXXX..XXXXXXX 100644
77
--- a/block/block-backend.c
41
--- a/block/block-backend.c
78
+++ b/block/block-backend.c
42
+++ b/block/block-backend.c
79
@@ -XXX,XX +XXX,XX @@ void coroutine_fn blk_co_lock_medium(BlockBackend *blk, bool locked)
43
@@ -XXX,XX +XXX,XX @@ static void send_qmp_error_event(BlockBackend *blk,
80
{
44
{
45
IoOperationType optype;
81
BlockDriverState *bs = blk_bs(blk);
46
BlockDriverState *bs = blk_bs(blk);
82
IO_CODE();
47
+ g_autofree char *path = blk_get_attached_dev_path(blk);
83
+ GRAPH_RDLOCK_GUARD();
48
84
49
optype = is_read ? IO_OPERATION_TYPE_READ : IO_OPERATION_TYPE_WRITE;
85
if (bs) {
50
- qapi_event_send_block_io_error(blk_name(blk),
86
bdrv_co_lock_medium(bs, locked);
51
- blk_get_attached_dev_path(blk),
87
@@ -XXX,XX +XXX,XX @@ void coroutine_fn blk_co_eject(BlockBackend *blk, bool eject_flag)
52
+ qapi_event_send_block_io_error(blk_name(blk), path,
88
BlockDriverState *bs = blk_bs(blk);
53
bs ? bdrv_get_node_name(bs) : NULL, optype,
89
char *id;
54
action, blk_iostatus_is_enabled(blk),
90
IO_CODE();
55
error == ENOSPC, strerror(error));
91
+ GRAPH_RDLOCK_GUARD();
92
93
if (bs) {
94
bdrv_co_eject(bs, eject_flag);
95
diff --git a/block/copy-on-read.c b/block/copy-on-read.c
96
index XXXXXXX..XXXXXXX 100644
97
--- a/block/copy-on-read.c
98
+++ b/block/copy-on-read.c
99
@@ -XXX,XX +XXX,XX @@ cor_co_pwritev_compressed(BlockDriverState *bs, int64_t offset, int64_t bytes,
100
}
101
102
103
-static void coroutine_fn cor_co_eject(BlockDriverState *bs, bool eject_flag)
104
+static void coroutine_fn GRAPH_RDLOCK
105
+cor_co_eject(BlockDriverState *bs, bool eject_flag)
106
{
107
bdrv_co_eject(bs->file->bs, eject_flag);
108
}
109
110
111
-static void coroutine_fn cor_co_lock_medium(BlockDriverState *bs, bool locked)
112
+static void coroutine_fn GRAPH_RDLOCK
113
+cor_co_lock_medium(BlockDriverState *bs, bool locked)
114
{
115
bdrv_co_lock_medium(bs->file->bs, locked);
116
}
117
diff --git a/block/filter-compress.c b/block/filter-compress.c
118
index XXXXXXX..XXXXXXX 100644
119
--- a/block/filter-compress.c
120
+++ b/block/filter-compress.c
121
@@ -XXX,XX +XXX,XX @@ static void compress_refresh_limits(BlockDriverState *bs, Error **errp)
122
}
123
124
125
-static void coroutine_fn
126
+static void coroutine_fn GRAPH_RDLOCK
127
compress_co_eject(BlockDriverState *bs, bool eject_flag)
128
{
129
bdrv_co_eject(bs->file->bs, eject_flag);
130
}
131
132
133
-static void coroutine_fn
134
+static void coroutine_fn GRAPH_RDLOCK
135
compress_co_lock_medium(BlockDriverState *bs, bool locked)
136
{
137
bdrv_co_lock_medium(bs->file->bs, locked);
138
diff --git a/block/raw-format.c b/block/raw-format.c
139
index XXXXXXX..XXXXXXX 100644
140
--- a/block/raw-format.c
141
+++ b/block/raw-format.c
142
@@ -XXX,XX +XXX,XX @@ raw_co_truncate(BlockDriverState *bs, int64_t offset, bool exact,
143
return bdrv_co_truncate(bs->file, offset, exact, prealloc, flags, errp);
144
}
145
146
-static void coroutine_fn raw_co_eject(BlockDriverState *bs, bool eject_flag)
147
+static void coroutine_fn GRAPH_RDLOCK
148
+raw_co_eject(BlockDriverState *bs, bool eject_flag)
149
{
150
bdrv_co_eject(bs->file->bs, eject_flag);
151
}
152
153
-static void coroutine_fn raw_co_lock_medium(BlockDriverState *bs, bool locked)
154
+static void coroutine_fn GRAPH_RDLOCK
155
+raw_co_lock_medium(BlockDriverState *bs, bool locked)
156
{
157
bdrv_co_lock_medium(bs->file->bs, locked);
158
}
159
--
56
--
160
2.39.2
57
2.48.1
58
59
diff view generated by jsdifflib
1
From: Stefan Hajnoczi <stefanha@redhat.com>
1
From: Peter Xu <peterx@redhat.com>
2
2
3
If requests are being processed in the IOThread when a SCSIDevice is
3
It's easier for either debugging plugin errors, or issue reports.
4
unplugged, scsi_device_purge_requests() -> scsi_req_cancel_async() races
5
with I/O completion callbacks. Both threads load and store req->aiocb.
6
This can lead to assert(r->req.aiocb == NULL) failures and undefined
7
behavior.
8
4
9
Protect r->req.aiocb with the AioContext lock to prevent the race.
5
Signed-off-by: Peter Xu <peterx@redhat.com>
10
6
Message-ID: <20241212204801.1420528-2-peterx@redhat.com>
11
Reviewed-by: Eric Blake <eblake@redhat.com>
12
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
7
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
13
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
14
Message-Id: <20230221212218.1378734-2-stefanha@redhat.com>
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
---
9
---
17
hw/scsi/scsi-disk.c | 23 ++++++++++++++++-------
10
scripts/qemu-gdb.py | 2 ++
18
hw/scsi/scsi-generic.c | 11 ++++++-----
11
1 file changed, 2 insertions(+)
19
2 files changed, 22 insertions(+), 12 deletions(-)
20
12
21
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
13
diff --git a/scripts/qemu-gdb.py b/scripts/qemu-gdb.py
22
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
23
--- a/hw/scsi/scsi-disk.c
15
--- a/scripts/qemu-gdb.py
24
+++ b/hw/scsi/scsi-disk.c
16
+++ b/scripts/qemu-gdb.py
25
@@ -XXX,XX +XXX,XX @@ static void scsi_aio_complete(void *opaque, int ret)
17
@@ -XXX,XX +XXX,XX @@ def __init__(self):
26
SCSIDiskReq *r = (SCSIDiskReq *)opaque;
18
# Default to silently passing through SIGUSR1, because QEMU sends it
27
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
19
# to itself a lot.
28
20
gdb.execute('handle SIGUSR1 pass noprint nostop')
29
+ aio_context_acquire(blk_get_aio_context(s->qdev.conf.blk));
21
+# Always print full stack for python errors, easier to debug and report issues
30
+
22
+gdb.execute('set python print-stack full')
31
assert(r->req.aiocb != NULL);
32
r->req.aiocb = NULL;
33
- aio_context_acquire(blk_get_aio_context(s->qdev.conf.blk));
34
+
35
if (scsi_disk_req_check_error(r, ret, true)) {
36
goto done;
37
}
38
@@ -XXX,XX +XXX,XX @@ static void scsi_dma_complete(void *opaque, int ret)
39
SCSIDiskReq *r = (SCSIDiskReq *)opaque;
40
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
41
42
+ aio_context_acquire(blk_get_aio_context(s->qdev.conf.blk));
43
+
44
assert(r->req.aiocb != NULL);
45
r->req.aiocb = NULL;
46
47
- aio_context_acquire(blk_get_aio_context(s->qdev.conf.blk));
48
if (ret < 0) {
49
block_acct_failed(blk_get_stats(s->qdev.conf.blk), &r->acct);
50
} else {
51
@@ -XXX,XX +XXX,XX @@ static void scsi_read_complete(void *opaque, int ret)
52
SCSIDiskReq *r = (SCSIDiskReq *)opaque;
53
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
54
55
+ aio_context_acquire(blk_get_aio_context(s->qdev.conf.blk));
56
+
57
assert(r->req.aiocb != NULL);
58
r->req.aiocb = NULL;
59
60
- aio_context_acquire(blk_get_aio_context(s->qdev.conf.blk));
61
if (ret < 0) {
62
block_acct_failed(blk_get_stats(s->qdev.conf.blk), &r->acct);
63
} else {
64
@@ -XXX,XX +XXX,XX @@ static void scsi_do_read_cb(void *opaque, int ret)
65
SCSIDiskReq *r = (SCSIDiskReq *)opaque;
66
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
67
68
+ aio_context_acquire(blk_get_aio_context(s->qdev.conf.blk));
69
+
70
assert (r->req.aiocb != NULL);
71
r->req.aiocb = NULL;
72
73
- aio_context_acquire(blk_get_aio_context(s->qdev.conf.blk));
74
if (ret < 0) {
75
block_acct_failed(blk_get_stats(s->qdev.conf.blk), &r->acct);
76
} else {
77
@@ -XXX,XX +XXX,XX @@ static void scsi_write_complete(void * opaque, int ret)
78
SCSIDiskReq *r = (SCSIDiskReq *)opaque;
79
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
80
81
+ aio_context_acquire(blk_get_aio_context(s->qdev.conf.blk));
82
+
83
assert (r->req.aiocb != NULL);
84
r->req.aiocb = NULL;
85
86
- aio_context_acquire(blk_get_aio_context(s->qdev.conf.blk));
87
if (ret < 0) {
88
block_acct_failed(blk_get_stats(s->qdev.conf.blk), &r->acct);
89
} else {
90
@@ -XXX,XX +XXX,XX @@ static void scsi_unmap_complete(void *opaque, int ret)
91
SCSIDiskReq *r = data->r;
92
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
93
94
+ aio_context_acquire(blk_get_aio_context(s->qdev.conf.blk));
95
+
96
assert(r->req.aiocb != NULL);
97
r->req.aiocb = NULL;
98
99
- aio_context_acquire(blk_get_aio_context(s->qdev.conf.blk));
100
if (scsi_disk_req_check_error(r, ret, true)) {
101
scsi_req_unref(&r->req);
102
g_free(data);
103
@@ -XXX,XX +XXX,XX @@ static void scsi_write_same_complete(void *opaque, int ret)
104
SCSIDiskReq *r = data->r;
105
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
106
107
+ aio_context_acquire(blk_get_aio_context(s->qdev.conf.blk));
108
+
109
assert(r->req.aiocb != NULL);
110
r->req.aiocb = NULL;
111
- aio_context_acquire(blk_get_aio_context(s->qdev.conf.blk));
112
+
113
if (scsi_disk_req_check_error(r, ret, true)) {
114
goto done;
115
}
116
diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c
117
index XXXXXXX..XXXXXXX 100644
118
--- a/hw/scsi/scsi-generic.c
119
+++ b/hw/scsi/scsi-generic.c
120
@@ -XXX,XX +XXX,XX @@ static void scsi_command_complete(void *opaque, int ret)
121
SCSIGenericReq *r = (SCSIGenericReq *)opaque;
122
SCSIDevice *s = r->req.dev;
123
124
+ aio_context_acquire(blk_get_aio_context(s->conf.blk));
125
+
126
assert(r->req.aiocb != NULL);
127
r->req.aiocb = NULL;
128
129
- aio_context_acquire(blk_get_aio_context(s->conf.blk));
130
scsi_command_complete_noio(r, ret);
131
aio_context_release(blk_get_aio_context(s->conf.blk));
132
}
133
@@ -XXX,XX +XXX,XX @@ static void scsi_read_complete(void * opaque, int ret)
134
SCSIDevice *s = r->req.dev;
135
int len;
136
137
+ aio_context_acquire(blk_get_aio_context(s->conf.blk));
138
+
139
assert(r->req.aiocb != NULL);
140
r->req.aiocb = NULL;
141
142
- aio_context_acquire(blk_get_aio_context(s->conf.blk));
143
-
144
if (ret || r->req.io_canceled) {
145
scsi_command_complete_noio(r, ret);
146
goto done;
147
@@ -XXX,XX +XXX,XX @@ static void scsi_write_complete(void * opaque, int ret)
148
149
trace_scsi_generic_write_complete(ret);
150
151
+ aio_context_acquire(blk_get_aio_context(s->conf.blk));
152
+
153
assert(r->req.aiocb != NULL);
154
r->req.aiocb = NULL;
155
156
- aio_context_acquire(blk_get_aio_context(s->conf.blk));
157
-
158
if (ret || r->req.io_canceled) {
159
scsi_command_complete_noio(r, ret);
160
goto done;
161
--
23
--
162
2.39.2
24
2.48.1
diff view generated by jsdifflib
1
This adds GRAPH_RDLOCK annotations to declare that callers of
1
From: Peter Xu <peterx@redhat.com>
2
bdrv_*_dirty_bitmap() need to hold a reader lock for the graph.
3
2
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
3
There're a bunch of code trying to fetch fs_base in different ways. IIUC
5
Message-Id: <20230203152202.49054-23-kwolf@redhat.com>
4
the simplest way instead is "$fs_base". It also has the benefit that it'll
6
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
5
work for both live gdb session or coredumps.
6
7
Signed-off-by: Peter Xu <peterx@redhat.com>
8
Message-ID: <20241212204801.1420528-3-peterx@redhat.com>
9
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
---
11
---
9
include/block/block-io.h | 14 ++++++--------
12
scripts/qemugdb/coroutine.py | 23 ++---------------------
10
include/block/block_int-common.h | 6 ++++--
13
1 file changed, 2 insertions(+), 21 deletions(-)
11
include/block/dirty-bitmap.h | 12 ++++++------
12
block/dirty-bitmap.c | 2 ++
13
4 files changed, 18 insertions(+), 16 deletions(-)
14
14
15
diff --git a/include/block/block-io.h b/include/block/block-io.h
15
diff --git a/scripts/qemugdb/coroutine.py b/scripts/qemugdb/coroutine.py
16
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
17
--- a/include/block/block-io.h
17
--- a/scripts/qemugdb/coroutine.py
18
+++ b/include/block/block-io.h
18
+++ b/scripts/qemugdb/coroutine.py
19
@@ -XXX,XX +XXX,XX @@ AioContext *child_of_bds_get_parent_aio_context(BdrvChild *c);
19
@@ -XXX,XX +XXX,XX @@
20
void coroutine_fn GRAPH_RDLOCK bdrv_co_io_plug(BlockDriverState *bs);
20
21
void coroutine_fn GRAPH_RDLOCK bdrv_co_io_unplug(BlockDriverState *bs);
21
VOID_PTR = gdb.lookup_type('void').pointer()
22
22
23
-bool coroutine_fn bdrv_co_can_store_new_dirty_bitmap(BlockDriverState *bs,
23
-def get_fs_base():
24
- const char *name,
24
- '''Fetch %fs base value using arch_prctl(ARCH_GET_FS). This is
25
- uint32_t granularity,
25
- pthread_self().'''
26
- Error **errp);
26
- # %rsp - 120 is scratch space according to the SystemV ABI
27
-bool co_wrapper bdrv_can_store_new_dirty_bitmap(BlockDriverState *bs,
27
- old = gdb.parse_and_eval('*(uint64_t*)($rsp - 120)')
28
- const char *name,
28
- gdb.execute('call (int)arch_prctl(0x1003, $rsp - 120)', False, True)
29
- uint32_t granularity,
29
- fs_base = gdb.parse_and_eval('*(uint64_t*)($rsp - 120)')
30
- Error **errp);
30
- gdb.execute('set *(uint64_t*)($rsp - 120) = %s' % old, False, True)
31
+bool coroutine_fn GRAPH_RDLOCK
31
- return fs_base
32
+bdrv_co_can_store_new_dirty_bitmap(BlockDriverState *bs, const char *name,
32
-
33
+ uint32_t granularity, Error **errp);
33
def pthread_self():
34
+bool co_wrapper_bdrv_rdlock
34
- '''Fetch pthread_self() from the glibc start_thread function.'''
35
+bdrv_can_store_new_dirty_bitmap(BlockDriverState *bs, const char *name,
35
- f = gdb.newest_frame()
36
+ uint32_t granularity, Error **errp);
36
- while f.name() != 'start_thread':
37
37
- f = f.older()
38
/**
38
- if f is None:
39
*
39
- return get_fs_base()
40
diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
40
-
41
index XXXXXXX..XXXXXXX 100644
41
- try:
42
--- a/include/block/block_int-common.h
42
- return f.read_var("arg")
43
+++ b/include/block/block_int-common.h
43
- except ValueError:
44
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
44
- return get_fs_base()
45
void (*bdrv_drain_end)(BlockDriverState *bs);
45
+ '''Fetch the base address of TLS.'''
46
46
+ return gdb.parse_and_eval("$fs_base")
47
bool (*bdrv_supports_persistent_dirty_bitmap)(BlockDriverState *bs);
47
48
- bool coroutine_fn (*bdrv_co_can_store_new_dirty_bitmap)(
48
def get_glibc_pointer_guard():
49
+
49
'''Fetch glibc pointer guard value'''
50
+ bool coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_can_store_new_dirty_bitmap)(
51
BlockDriverState *bs, const char *name, uint32_t granularity,
52
Error **errp);
53
- int coroutine_fn (*bdrv_co_remove_persistent_dirty_bitmap)(
54
+
55
+ int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_remove_persistent_dirty_bitmap)(
56
BlockDriverState *bs, const char *name, Error **errp);
57
};
58
59
diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h
60
index XXXXXXX..XXXXXXX 100644
61
--- a/include/block/dirty-bitmap.h
62
+++ b/include/block/dirty-bitmap.h
63
@@ -XXX,XX +XXX,XX @@ int bdrv_dirty_bitmap_check(const BdrvDirtyBitmap *bitmap, uint32_t flags,
64
void bdrv_release_dirty_bitmap(BdrvDirtyBitmap *bitmap);
65
void bdrv_release_named_dirty_bitmaps(BlockDriverState *bs);
66
67
-int coroutine_fn bdrv_co_remove_persistent_dirty_bitmap(BlockDriverState *bs,
68
- const char *name,
69
- Error **errp);
70
-int co_wrapper bdrv_remove_persistent_dirty_bitmap(BlockDriverState *bs,
71
- const char *name,
72
- Error **errp);
73
+int coroutine_fn GRAPH_RDLOCK
74
+bdrv_co_remove_persistent_dirty_bitmap(BlockDriverState *bs, const char *name,
75
+ Error **errp);
76
+int co_wrapper_bdrv_rdlock
77
+bdrv_remove_persistent_dirty_bitmap(BlockDriverState *bs, const char *name,
78
+ Error **errp);
79
80
void bdrv_disable_dirty_bitmap(BdrvDirtyBitmap *bitmap);
81
void bdrv_enable_dirty_bitmap(BdrvDirtyBitmap *bitmap);
82
diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
83
index XXXXXXX..XXXXXXX 100644
84
--- a/block/dirty-bitmap.c
85
+++ b/block/dirty-bitmap.c
86
@@ -XXX,XX +XXX,XX @@ int coroutine_fn
87
bdrv_co_remove_persistent_dirty_bitmap(BlockDriverState *bs, const char *name,
88
Error **errp)
89
{
90
+ assert_bdrv_graph_readable();
91
if (bs->drv && bs->drv->bdrv_co_remove_persistent_dirty_bitmap) {
92
return bs->drv->bdrv_co_remove_persistent_dirty_bitmap(bs, name, errp);
93
}
94
@@ -XXX,XX +XXX,XX @@ bdrv_co_can_store_new_dirty_bitmap(BlockDriverState *bs, const char *name,
95
uint32_t granularity, Error **errp)
96
{
97
BlockDriver *drv = bs->drv;
98
+ assert_bdrv_graph_readable();
99
100
if (!drv) {
101
error_setg_errno(errp, ENOMEDIUM,
102
--
50
--
103
2.39.2
51
2.48.1
diff view generated by jsdifflib
1
From: Or Ozeri <oro@il.ibm.com>
1
From: Peter Xu <peterx@redhat.com>
2
2
3
Signed-off-by: Or Ozeri <oro@il.ibm.com>
3
Dumping coroutines don't yet work with coredumps. Let's make it work.
4
Message-Id: <20230129113120.722708-2-oro@oro.sl.cloud9.ibm.com>
4
5
Reviewed-by: Ilya Dryomov <idryomov@gmail.com>
5
We still kept most of the old code because they can be either more
6
flexible, or prettier. Only add the fallbacks when they stop working.
7
8
Currently the raw unwind is pretty ugly, but it works, like this:
9
10
(gdb) qemu bt
11
#0 process_incoming_migration_co (opaque=0x0) at ../migration/migration.c:788
12
#1 0x000055ae6c0dc4d9 in coroutine_trampoline (i0=-1711718576, i1=21934) at ../util/coroutine-ucontext.c:175
13
#2 0x00007f9f59d72f40 in ??? () at /lib64/libc.so.6
14
#3 0x00007ffd549214a0 in ??? ()
15
#4 0x0000000000000000 in ??? ()
16
Coroutine at 0x7f9f4c57c748:
17
#0 0x55ae6c0dc9a8 in qemu_coroutine_switch<+120> () at ../util/coroutine-ucontext.c:321
18
#1 0x55ae6c0da2f8 in qemu_aio_coroutine_enter<+356> () at ../util/qemu-coroutine.c:293
19
#2 0x55ae6c0da3f1 in qemu_coroutine_enter<+34> () at ../util/qemu-coroutine.c:316
20
#3 0x55ae6baf775e in migration_incoming_process<+43> () at ../migration/migration.c:876
21
#4 0x55ae6baf7ab4 in migration_ioc_process_incoming<+490> () at ../migration/migration.c:1008
22
#5 0x55ae6bae9ae7 in migration_channel_process_incoming<+145> () at ../migration/channel.c:45
23
#6 0x55ae6bb18e35 in socket_accept_incoming_migration<+118> () at ../migration/socket.c:132
24
#7 0x55ae6be939ef in qio_net_listener_channel_func<+131> () at ../io/net-listener.c:54
25
#8 0x55ae6be8ce1a in qio_channel_fd_source_dispatch<+78> () at ../io/channel-watch.c:84
26
#9 0x7f9f5b26728c in g_main_context_dispatch_unlocked.lto_priv<+315> ()
27
#10 0x7f9f5b267555 in g_main_context_dispatch<+36> ()
28
#11 0x55ae6c0d91a7 in glib_pollfds_poll<+90> () at ../util/main-loop.c:287
29
#12 0x55ae6c0d9235 in os_host_main_loop_wait<+128> () at ../util/main-loop.c:310
30
#13 0x55ae6c0d9364 in main_loop_wait<+203> () at ../util/main-loop.c:589
31
#14 0x55ae6bac212a in qemu_main_loop<+41> () at ../system/runstate.c:835
32
#15 0x55ae6bfdf522 in qemu_default_main<+19> () at ../system/main.c:37
33
#16 0x55ae6bfdf55f in main<+40> () at ../system/main.c:48
34
#17 0x7f9f59d42248 in __libc_start_call_main<+119> ()
35
#18 0x7f9f59d4230b in __libc_start_main_impl<+138> ()
36
37
Signed-off-by: Peter Xu <peterx@redhat.com>
38
Message-ID: <20241212204801.1420528-4-peterx@redhat.com>
6
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
39
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
40
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
---
41
---
9
block/rbd.c | 16 ++++++----------
42
scripts/qemugdb/coroutine.py | 79 +++++++++++++++++++++++++++++++++---
10
1 file changed, 6 insertions(+), 10 deletions(-)
43
1 file changed, 73 insertions(+), 6 deletions(-)
11
44
12
diff --git a/block/rbd.c b/block/rbd.c
45
diff --git a/scripts/qemugdb/coroutine.py b/scripts/qemugdb/coroutine.py
13
index XXXXXXX..XXXXXXX 100644
46
index XXXXXXX..XXXXXXX 100644
14
--- a/block/rbd.c
47
--- a/scripts/qemugdb/coroutine.py
15
+++ b/block/rbd.c
48
+++ b/scripts/qemugdb/coroutine.py
16
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_encryption_format(rbd_image_t image,
49
@@ -XXX,XX +XXX,XX @@ def get_jmpbuf_regs(jmpbuf):
17
{
50
'r15': jmpbuf[JB_R15],
18
int r = 0;
51
'rip': glibc_ptr_demangle(jmpbuf[JB_PC], pointer_guard) }
19
g_autofree char *passphrase = NULL;
52
20
- size_t passphrase_len;
53
-def bt_jmpbuf(jmpbuf):
21
rbd_encryption_format_t format;
54
- '''Backtrace a jmpbuf'''
22
rbd_encryption_options_t opts;
55
- regs = get_jmpbuf_regs(jmpbuf)
23
rbd_encryption_luks1_format_options_t luks_opts;
56
+def symbol_lookup(addr):
24
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_encryption_format(rbd_image_t image,
57
+ # Example: "__clone3 + 44 in section .text of /lib64/libc.so.6"
25
opts_size = sizeof(luks_opts);
58
+ result = gdb.execute(f"info symbol {hex(addr)}", to_string=True).strip()
26
r = qemu_rbd_convert_luks_create_options(
59
+ try:
27
qapi_RbdEncryptionCreateOptionsLUKS_base(&encrypt->u.luks),
60
+ if "+" in result:
28
- &luks_opts.alg, &passphrase, &passphrase_len, errp);
61
+ (func, result) = result.split(" + ")
29
+ &luks_opts.alg, &passphrase, &luks_opts.passphrase_size,
62
+ (offset, result) = result.split(" in ")
30
+ errp);
63
+ else:
31
if (r < 0) {
64
+ offset = "0"
32
return r;
65
+ (func, result) = result.split(" in ")
33
}
66
+ func_str = f"{func}<+{offset}> ()"
34
luks_opts.passphrase = passphrase;
67
+ except:
35
- luks_opts.passphrase_size = passphrase_len;
68
+ return f"??? ({result})"
36
break;
69
+
37
}
70
+ # Example: Line 321 of "../util/coroutine-ucontext.c" starts at address
38
case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS2: {
71
+ # 0x55cf3894d993 <qemu_coroutine_switch+99> and ends at 0x55cf3894d9ab
39
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_encryption_format(rbd_image_t image,
72
+ # <qemu_coroutine_switch+123>.
40
r = qemu_rbd_convert_luks_create_options(
73
+ result = gdb.execute(f"info line *{hex(addr)}", to_string=True).strip()
41
qapi_RbdEncryptionCreateOptionsLUKS2_base(
74
+ if not result.startswith("Line "):
42
&encrypt->u.luks2),
75
+ return func_str
43
- &luks2_opts.alg, &passphrase, &passphrase_len, errp);
76
+ result = result[5:]
44
+ &luks2_opts.alg, &passphrase, &luks2_opts.passphrase_size,
77
+
45
+ errp);
78
+ try:
46
if (r < 0) {
79
+ result = result.split(" starts ")[0]
47
return r;
80
+ (line, path) = result.split(" of ")
48
}
81
+ path = path.replace("\"", "")
49
luks2_opts.passphrase = passphrase;
82
+ except:
50
- luks2_opts.passphrase_size = passphrase_len;
83
+ return func_str
51
break;
84
+
52
}
85
+ return f"{func_str} at {path}:{line}"
53
default: {
86
+
54
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_encryption_load(rbd_image_t image,
87
+def dump_backtrace(regs):
55
{
88
+ '''
56
int r = 0;
89
+ Backtrace dump with raw registers, mimic GDB command 'bt'.
57
g_autofree char *passphrase = NULL;
90
+ '''
58
- size_t passphrase_len;
91
+ # Here only rbp and rip that matter..
59
rbd_encryption_luks1_format_options_t luks_opts;
92
+ rbp = regs['rbp']
60
rbd_encryption_luks2_format_options_t luks2_opts;
93
+ rip = regs['rip']
61
rbd_encryption_format_t format;
94
+ i = 0
62
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_encryption_load(rbd_image_t image,
95
+
63
opts_size = sizeof(luks_opts);
96
+ while rbp:
64
r = qemu_rbd_convert_luks_options(
97
+ # For all return addresses on stack, we want to look up symbol/line
65
qapi_RbdEncryptionOptionsLUKS_base(&encrypt->u.luks),
98
+ # on the CALL command, because the return address is the next
66
- &passphrase, &passphrase_len, errp);
99
+ # instruction instead of the CALL. Here -1 would work for any
67
+ &passphrase, &luks_opts.passphrase_size, errp);
100
+ # sized CALL instruction.
68
if (r < 0) {
101
+ print(f"#{i} {hex(rip)} in {symbol_lookup(rip if i == 0 else rip-1)}")
69
return r;
102
+ rip = gdb.parse_and_eval(f"*(uint64_t *)(uint64_t)({hex(rbp)} + 8)")
70
}
103
+ rbp = gdb.parse_and_eval(f"*(uint64_t *)(uint64_t)({hex(rbp)})")
71
luks_opts.passphrase = passphrase;
104
+ i += 1
72
- luks_opts.passphrase_size = passphrase_len;
105
+
73
break;
106
+def dump_backtrace_live(regs):
74
}
107
+ '''
75
case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS2: {
108
+ Backtrace dump with gdb's 'bt' command, only usable in a live session.
76
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_encryption_load(rbd_image_t image,
109
+ '''
77
opts_size = sizeof(luks2_opts);
110
old = dict()
78
r = qemu_rbd_convert_luks_options(
111
79
qapi_RbdEncryptionOptionsLUKS2_base(&encrypt->u.luks2),
112
# remember current stack frame and select the topmost
80
- &passphrase, &passphrase_len, errp);
113
@@ -XXX,XX +XXX,XX @@ def bt_jmpbuf(jmpbuf):
81
+ &passphrase, &luks2_opts.passphrase_size, errp);
114
82
if (r < 0) {
115
selected_frame.select()
83
return r;
116
84
}
117
+def bt_jmpbuf(jmpbuf):
85
luks2_opts.passphrase = passphrase;
118
+ '''Backtrace a jmpbuf'''
86
- luks2_opts.passphrase_size = passphrase_len;
119
+ regs = get_jmpbuf_regs(jmpbuf)
87
break;
120
+ try:
88
}
121
+ # This reuses gdb's "bt" command, which can be slightly prettier
89
default: {
122
+ # but only works with live sessions.
123
+ dump_backtrace_live(regs)
124
+ except:
125
+ # If above doesn't work, fallback to poor man's unwind
126
+ dump_backtrace(regs)
127
+
128
def co_cast(co):
129
return co.cast(gdb.lookup_type('CoroutineUContext').pointer())
130
131
@@ -XXX,XX +XXX,XX @@ def invoke(self, arg, from_tty):
132
133
gdb.execute("bt")
134
135
- if gdb.parse_and_eval("qemu_in_coroutine()") == False:
136
- return
137
+ try:
138
+ # This only works with a live session
139
+ co_ptr = gdb.parse_and_eval("qemu_coroutine_self()")
140
+ except:
141
+ # Fallback to use hard-coded ucontext vars if it's coredump
142
+ co_ptr = gdb.parse_and_eval("co_tls_current")
143
144
- co_ptr = gdb.parse_and_eval("qemu_coroutine_self()")
145
+ if co_ptr == False:
146
+ return
147
148
while True:
149
co = co_cast(co_ptr)
90
--
150
--
91
2.39.2
151
2.48.1
diff view generated by jsdifflib
1
From: Emanuele Giuseppe Esposito <eesposit@redhat.com>
1
From: Peter Krempa <pkrempa@redhat.com>
2
2
3
This adds GRAPH_RDLOCK annotations to declare that callers of
3
Commit 7452162adec25c10 introduced 'qom-path' argument to BLOCK_IO_ERROR
4
bdrv_co_copy_range() need to hold a reader lock for the graph.
4
event but when the event is instantiated in 'send_qmp_error_event()' the
5
arguments for 'device' and 'qom_path' in
6
qapi_event_send_block_io_error() were reversed :
5
7
6
Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
8
Generated code for sending event:
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
8
Message-Id: <20230203152202.49054-15-kwolf@redhat.com>
10
void qapi_event_send_block_io_error(const char *qom_path,
9
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
11
const char *device,
12
const char *node_name,
13
IoOperationType operation,
14
[...]
15
16
Call inside send_qmp_error_event():
17
18
qapi_event_send_block_io_error(blk_name(blk),
19
blk_get_attached_dev_path(blk),
20
bs ? bdrv_get_node_name(bs) : NULL, optype,
21
[...]
22
23
This results into reporting the QOM path as the device alias and vice
24
versa which in turn breaks libvirt, which expects the device alias being
25
either a valid alias or empty (which would make libvirt do the lookup by
26
node-name instead).
27
28
Cc: qemu-stable@nongnu.org
29
Fixes: 7452162adec2 ("qapi: add qom-path to BLOCK_IO_ERROR event")
30
Signed-off-by: Peter Krempa <pkrempa@redhat.com>
31
Message-ID: <09728d784888b38d7a8f09ee5e9e9c542c875e1e.1737973614.git.pkrempa@redhat.com>
32
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
33
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
34
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
35
---
12
include/block/block-io.h | 9 +++++----
36
block/block-backend.c | 2 +-
13
include/block/block_int-common.h | 24 ++++++++----------------
37
1 file changed, 1 insertion(+), 1 deletion(-)
14
include/block/block_int-io.h | 20 ++++++++++----------
15
block/block-backend.c | 2 ++
16
block/file-posix.c | 16 +++++++---------
17
block/io.c | 7 +++++--
18
block/iscsi.c | 28 ++++++++++++----------------
19
block/qcow2.c | 5 ++---
20
block/raw-format.c | 28 ++++++++++++----------------
21
qemu-img.c | 4 +++-
22
10 files changed, 66 insertions(+), 77 deletions(-)
23
38
24
diff --git a/include/block/block-io.h b/include/block/block-io.h
25
index XXXXXXX..XXXXXXX 100644
26
--- a/include/block/block-io.h
27
+++ b/include/block/block-io.h
28
@@ -XXX,XX +XXX,XX @@ bool co_wrapper bdrv_can_store_new_dirty_bitmap(BlockDriverState *bs,
29
*
30
* Returns: 0 if succeeded; negative error code if failed.
31
**/
32
-int coroutine_fn bdrv_co_copy_range(BdrvChild *src, int64_t src_offset,
33
- BdrvChild *dst, int64_t dst_offset,
34
- int64_t bytes, BdrvRequestFlags read_flags,
35
- BdrvRequestFlags write_flags);
36
+int coroutine_fn GRAPH_RDLOCK
37
+bdrv_co_copy_range(BdrvChild *src, int64_t src_offset,
38
+ BdrvChild *dst, int64_t dst_offset,
39
+ int64_t bytes, BdrvRequestFlags read_flags,
40
+ BdrvRequestFlags write_flags);
41
42
/*
43
* "I/O or GS" API functions. These functions can run without
44
diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
45
index XXXXXXX..XXXXXXX 100644
46
--- a/include/block/block_int-common.h
47
+++ b/include/block/block_int-common.h
48
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
49
* See the comment of bdrv_co_copy_range for the parameter and return value
50
* semantics.
51
*/
52
- int coroutine_fn (*bdrv_co_copy_range_from)(BlockDriverState *bs,
53
- BdrvChild *src,
54
- int64_t offset,
55
- BdrvChild *dst,
56
- int64_t dst_offset,
57
- int64_t bytes,
58
- BdrvRequestFlags read_flags,
59
- BdrvRequestFlags write_flags);
60
+ int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_copy_range_from)(
61
+ BlockDriverState *bs, BdrvChild *src, int64_t offset,
62
+ BdrvChild *dst, int64_t dst_offset, int64_t bytes,
63
+ BdrvRequestFlags read_flags, BdrvRequestFlags write_flags);
64
65
/*
66
* Map [offset, offset + nbytes) range onto a child of bs to copy data to,
67
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
68
* See the comment of bdrv_co_copy_range for the parameter and return value
69
* semantics.
70
*/
71
- int coroutine_fn (*bdrv_co_copy_range_to)(BlockDriverState *bs,
72
- BdrvChild *src,
73
- int64_t src_offset,
74
- BdrvChild *dst,
75
- int64_t dst_offset,
76
- int64_t bytes,
77
- BdrvRequestFlags read_flags,
78
- BdrvRequestFlags write_flags);
79
+ int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_copy_range_to)(
80
+ BlockDriverState *bs, BdrvChild *src, int64_t src_offset,
81
+ BdrvChild *dst, int64_t dst_offset, int64_t bytes,
82
+ BdrvRequestFlags read_flags, BdrvRequestFlags write_flags);
83
84
/*
85
* Building block for bdrv_block_status[_above] and
86
diff --git a/include/block/block_int-io.h b/include/block/block_int-io.h
87
index XXXXXXX..XXXXXXX 100644
88
--- a/include/block/block_int-io.h
89
+++ b/include/block/block_int-io.h
90
@@ -XXX,XX +XXX,XX @@ void bdrv_dirty_bitmap_merge_internal(BdrvDirtyBitmap *dest,
91
void bdrv_inc_in_flight(BlockDriverState *bs);
92
void bdrv_dec_in_flight(BlockDriverState *bs);
93
94
-int coroutine_fn bdrv_co_copy_range_from(BdrvChild *src, int64_t src_offset,
95
- BdrvChild *dst, int64_t dst_offset,
96
- int64_t bytes,
97
- BdrvRequestFlags read_flags,
98
- BdrvRequestFlags write_flags);
99
-int coroutine_fn bdrv_co_copy_range_to(BdrvChild *src, int64_t src_offset,
100
- BdrvChild *dst, int64_t dst_offset,
101
- int64_t bytes,
102
- BdrvRequestFlags read_flags,
103
- BdrvRequestFlags write_flags);
104
+int coroutine_fn GRAPH_RDLOCK
105
+bdrv_co_copy_range_from(BdrvChild *src, int64_t src_offset,
106
+ BdrvChild *dst, int64_t dst_offset,
107
+ int64_t bytes, BdrvRequestFlags read_flags,
108
+ BdrvRequestFlags write_flags);
109
+int coroutine_fn GRAPH_RDLOCK
110
+bdrv_co_copy_range_to(BdrvChild *src, int64_t src_offset,
111
+ BdrvChild *dst, int64_t dst_offset,
112
+ int64_t bytes, BdrvRequestFlags read_flags,
113
+ BdrvRequestFlags write_flags);
114
115
int coroutine_fn bdrv_co_refresh_total_sectors(BlockDriverState *bs,
116
int64_t hint);
117
diff --git a/block/block-backend.c b/block/block-backend.c
39
diff --git a/block/block-backend.c b/block/block-backend.c
118
index XXXXXXX..XXXXXXX 100644
40
index XXXXXXX..XXXXXXX 100644
119
--- a/block/block-backend.c
41
--- a/block/block-backend.c
120
+++ b/block/block-backend.c
42
+++ b/block/block-backend.c
121
@@ -XXX,XX +XXX,XX @@ int coroutine_fn blk_co_copy_range(BlockBackend *blk_in, int64_t off_in,
43
@@ -XXX,XX +XXX,XX @@ static void send_qmp_error_event(BlockBackend *blk,
122
if (r) {
44
g_autofree char *path = blk_get_attached_dev_path(blk);
123
return r;
45
124
}
46
optype = is_read ? IO_OPERATION_TYPE_READ : IO_OPERATION_TYPE_WRITE;
125
+
47
- qapi_event_send_block_io_error(blk_name(blk), path,
126
+ GRAPH_RDLOCK_GUARD();
48
+ qapi_event_send_block_io_error(path, blk_name(blk),
127
return bdrv_co_copy_range(blk_in->root, off_in,
49
bs ? bdrv_get_node_name(bs) : NULL, optype,
128
blk_out->root, off_out,
50
action, blk_iostatus_is_enabled(blk),
129
bytes, read_flags, write_flags);
51
error == ENOSPC, strerror(error));
130
diff --git a/block/file-posix.c b/block/file-posix.c
131
index XXXXXXX..XXXXXXX 100644
132
--- a/block/file-posix.c
133
+++ b/block/file-posix.c
134
@@ -XXX,XX +XXX,XX @@ static void raw_abort_perm_update(BlockDriverState *bs)
135
raw_handle_perm_lock(bs, RAW_PL_ABORT, 0, 0, NULL);
136
}
137
138
-static int coroutine_fn raw_co_copy_range_from(
139
+static int coroutine_fn GRAPH_RDLOCK raw_co_copy_range_from(
140
BlockDriverState *bs, BdrvChild *src, int64_t src_offset,
141
BdrvChild *dst, int64_t dst_offset, int64_t bytes,
142
BdrvRequestFlags read_flags, BdrvRequestFlags write_flags)
143
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_copy_range_from(
144
read_flags, write_flags);
145
}
146
147
-static int coroutine_fn raw_co_copy_range_to(BlockDriverState *bs,
148
- BdrvChild *src,
149
- int64_t src_offset,
150
- BdrvChild *dst,
151
- int64_t dst_offset,
152
- int64_t bytes,
153
- BdrvRequestFlags read_flags,
154
- BdrvRequestFlags write_flags)
155
+static int coroutine_fn GRAPH_RDLOCK
156
+raw_co_copy_range_to(BlockDriverState *bs,
157
+ BdrvChild *src, int64_t src_offset,
158
+ BdrvChild *dst, int64_t dst_offset,
159
+ int64_t bytes, BdrvRequestFlags read_flags,
160
+ BdrvRequestFlags write_flags)
161
{
162
RawPosixAIOData acb;
163
BDRVRawState *s = bs->opaque;
164
diff --git a/block/io.c b/block/io.c
165
index XXXXXXX..XXXXXXX 100644
166
--- a/block/io.c
167
+++ b/block/io.c
168
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn GRAPH_RDLOCK bdrv_co_copy_range_internal(
169
{
170
BdrvTrackedRequest req;
171
int ret;
172
+ assert_bdrv_graph_readable();
173
174
/* TODO We can support BDRV_REQ_NO_FALLBACK here */
175
assert(!(read_flags & BDRV_REQ_NO_FALLBACK));
176
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_copy_range_from(BdrvChild *src, int64_t src_offset,
177
BdrvRequestFlags write_flags)
178
{
179
IO_CODE();
180
- assume_graph_lock(); /* FIXME */
181
+ assert_bdrv_graph_readable();
182
trace_bdrv_co_copy_range_from(src, src_offset, dst, dst_offset, bytes,
183
read_flags, write_flags);
184
return bdrv_co_copy_range_internal(src, src_offset, dst, dst_offset,
185
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_copy_range_to(BdrvChild *src, int64_t src_offset,
186
BdrvRequestFlags write_flags)
187
{
188
IO_CODE();
189
- assume_graph_lock(); /* FIXME */
190
+ assert_bdrv_graph_readable();
191
trace_bdrv_co_copy_range_to(src, src_offset, dst, dst_offset, bytes,
192
read_flags, write_flags);
193
return bdrv_co_copy_range_internal(src, src_offset, dst, dst_offset,
194
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_copy_range(BdrvChild *src, int64_t src_offset,
195
BdrvRequestFlags write_flags)
196
{
197
IO_CODE();
198
+ assert_bdrv_graph_readable();
199
+
200
return bdrv_co_copy_range_from(src, src_offset,
201
dst, dst_offset,
202
bytes, read_flags, write_flags);
203
diff --git a/block/iscsi.c b/block/iscsi.c
204
index XXXXXXX..XXXXXXX 100644
205
--- a/block/iscsi.c
206
+++ b/block/iscsi.c
207
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn iscsi_co_invalidate_cache(BlockDriverState *bs,
208
iscsi_allocmap_invalidate(iscsilun);
209
}
210
211
-static int coroutine_fn iscsi_co_copy_range_from(BlockDriverState *bs,
212
- BdrvChild *src,
213
- int64_t src_offset,
214
- BdrvChild *dst,
215
- int64_t dst_offset,
216
- int64_t bytes,
217
- BdrvRequestFlags read_flags,
218
- BdrvRequestFlags write_flags)
219
+static int coroutine_fn GRAPH_RDLOCK
220
+iscsi_co_copy_range_from(BlockDriverState *bs,
221
+ BdrvChild *src, int64_t src_offset,
222
+ BdrvChild *dst, int64_t dst_offset,
223
+ int64_t bytes, BdrvRequestFlags read_flags,
224
+ BdrvRequestFlags write_flags)
225
{
226
return bdrv_co_copy_range_to(src, src_offset, dst, dst_offset, bytes,
227
read_flags, write_flags);
228
@@ -XXX,XX +XXX,XX @@ static void iscsi_xcopy_data(struct iscsi_data *data,
229
src_lba, dst_lba);
230
}
231
232
-static int coroutine_fn iscsi_co_copy_range_to(BlockDriverState *bs,
233
- BdrvChild *src,
234
- int64_t src_offset,
235
- BdrvChild *dst,
236
- int64_t dst_offset,
237
- int64_t bytes,
238
- BdrvRequestFlags read_flags,
239
- BdrvRequestFlags write_flags)
240
+static int coroutine_fn GRAPH_RDLOCK
241
+iscsi_co_copy_range_to(BlockDriverState *bs,
242
+ BdrvChild *src, int64_t src_offset,
243
+ BdrvChild *dst, int64_t dst_offset,
244
+ int64_t bytes, BdrvRequestFlags read_flags,
245
+ BdrvRequestFlags write_flags)
246
{
247
IscsiLun *dst_lun = dst->bs->opaque;
248
IscsiLun *src_lun;
249
diff --git a/block/qcow2.c b/block/qcow2.c
250
index XXXXXXX..XXXXXXX 100644
251
--- a/block/qcow2.c
252
+++ b/block/qcow2.c
253
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pdiscard(BlockDriverState *bs,
254
return ret;
255
}
256
257
-static int coroutine_fn
258
+static int coroutine_fn GRAPH_RDLOCK
259
qcow2_co_copy_range_from(BlockDriverState *bs,
260
BdrvChild *src, int64_t src_offset,
261
BdrvChild *dst, int64_t dst_offset,
262
@@ -XXX,XX +XXX,XX @@ out:
263
return ret;
264
}
265
266
-static int coroutine_fn
267
+static int coroutine_fn GRAPH_RDLOCK
268
qcow2_co_copy_range_to(BlockDriverState *bs,
269
BdrvChild *src, int64_t src_offset,
270
BdrvChild *dst, int64_t dst_offset,
271
@@ -XXX,XX +XXX,XX @@ qcow2_co_copy_range_to(BlockDriverState *bs,
272
uint64_t host_offset;
273
QCowL2Meta *l2meta = NULL;
274
275
- assume_graph_lock(); /* FIXME */
276
assert(!bs->encrypted);
277
278
qemu_co_mutex_lock(&s->lock);
279
diff --git a/block/raw-format.c b/block/raw-format.c
280
index XXXXXXX..XXXXXXX 100644
281
--- a/block/raw-format.c
282
+++ b/block/raw-format.c
283
@@ -XXX,XX +XXX,XX @@ static int raw_probe_geometry(BlockDriverState *bs, HDGeometry *geo)
284
return bdrv_probe_geometry(bs->file->bs, geo);
285
}
286
287
-static int coroutine_fn raw_co_copy_range_from(BlockDriverState *bs,
288
- BdrvChild *src,
289
- int64_t src_offset,
290
- BdrvChild *dst,
291
- int64_t dst_offset,
292
- int64_t bytes,
293
- BdrvRequestFlags read_flags,
294
- BdrvRequestFlags write_flags)
295
+static int coroutine_fn GRAPH_RDLOCK
296
+raw_co_copy_range_from(BlockDriverState *bs,
297
+ BdrvChild *src, int64_t src_offset,
298
+ BdrvChild *dst, int64_t dst_offset,
299
+ int64_t bytes, BdrvRequestFlags read_flags,
300
+ BdrvRequestFlags write_flags)
301
{
302
int ret;
303
304
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_copy_range_from(BlockDriverState *bs,
305
bytes, read_flags, write_flags);
306
}
307
308
-static int coroutine_fn raw_co_copy_range_to(BlockDriverState *bs,
309
- BdrvChild *src,
310
- int64_t src_offset,
311
- BdrvChild *dst,
312
- int64_t dst_offset,
313
- int64_t bytes,
314
- BdrvRequestFlags read_flags,
315
- BdrvRequestFlags write_flags)
316
+static int coroutine_fn GRAPH_RDLOCK
317
+raw_co_copy_range_to(BlockDriverState *bs,
318
+ BdrvChild *src, int64_t src_offset,
319
+ BdrvChild *dst, int64_t dst_offset,
320
+ int64_t bytes, BdrvRequestFlags read_flags,
321
+ BdrvRequestFlags write_flags)
322
{
323
int ret;
324
325
diff --git a/qemu-img.c b/qemu-img.c
326
index XXXXXXX..XXXXXXX 100644
327
--- a/qemu-img.c
328
+++ b/qemu-img.c
329
@@ -XXX,XX +XXX,XX @@ retry:
330
331
if (s->ret == -EINPROGRESS) {
332
if (copy_range) {
333
- ret = convert_co_copy_range(s, sector_num, n);
334
+ WITH_GRAPH_RDLOCK_GUARD() {
335
+ ret = convert_co_copy_range(s, sector_num, n);
336
+ }
337
if (ret) {
338
s->copy_range = false;
339
goto retry;
340
--
52
--
341
2.39.2
53
2.48.1
54
55
diff view generated by jsdifflib
1
This adds GRAPH_RDLOCK annotations to declare that callers of
1
This allows querying from QMP (and also HMP) whether an image is
2
bdrv_co_create() need to hold a reader lock for the graph.
2
currently active or inactive (in the sense of BDRV_O_INACTIVE).
3
3
4
Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Message-Id: <20230203152202.49054-17-kwolf@redhat.com>
5
Acked-by: Fabiano Rosas <farosas@suse.de>
7
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
8
Message-ID: <20250204211407.381505-2-kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
10
---
10
include/block/block-global-state.h | 14 ++++---
11
qapi/block-core.json | 6 +++++-
11
include/block/block_int-common.h | 11 +++---
12
include/block/block-global-state.h | 3 +++
12
block.c | 1 +
13
block.c | 4 ++++
13
block/create.c | 9 ++++-
14
block/monitor/block-hmp-cmds.c | 5 +++--
14
block/crypto.c | 7 ++--
15
block/qapi.c | 1 +
15
block/file-posix.c | 7 ++--
16
tests/qemu-iotests/184.out | 2 ++
16
block/file-win32.c | 7 ++--
17
tests/qemu-iotests/191.out | 16 ++++++++++++++++
17
block/parallels.c | 7 ++--
18
tests/qemu-iotests/273.out | 5 +++++
18
block/qcow.c | 6 +--
19
8 files changed, 39 insertions(+), 3 deletions(-)
19
block/qcow2.c | 7 ++--
20
block/qed.c | 7 ++--
21
block/raw-format.c | 7 ++--
22
block/vdi.c | 7 ++--
23
block/vhdx.c | 7 ++--
24
block/vmdk.c | 63 ++++++++++++++----------------
25
block/vpc.c | 7 ++--
26
16 files changed, 84 insertions(+), 90 deletions(-)
27
20
21
diff --git a/qapi/block-core.json b/qapi/block-core.json
22
index XXXXXXX..XXXXXXX 100644
23
--- a/qapi/block-core.json
24
+++ b/qapi/block-core.json
25
@@ -XXX,XX +XXX,XX @@
26
# @backing_file_depth: number of files in the backing file chain
27
# (since: 1.2)
28
#
29
+# @active: true if the backend is active; typical cases for inactive backends
30
+# are on the migration source instance after migration completes and on the
31
+# destination before it completes. (since: 10.0)
32
+#
33
# @encrypted: true if the backing device is encrypted
34
#
35
# @detect_zeroes: detect and optimize zero writes (Since 2.1)
36
@@ -XXX,XX +XXX,XX @@
37
{ 'struct': 'BlockDeviceInfo',
38
'data': { 'file': 'str', '*node-name': 'str', 'ro': 'bool', 'drv': 'str',
39
'*backing_file': 'str', 'backing_file_depth': 'int',
40
- 'encrypted': 'bool',
41
+ 'active': 'bool', 'encrypted': 'bool',
42
'detect_zeroes': 'BlockdevDetectZeroesOptions',
43
'bps': 'int', 'bps_rd': 'int', 'bps_wr': 'int',
44
'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int',
28
diff --git a/include/block/block-global-state.h b/include/block/block-global-state.h
45
diff --git a/include/block/block-global-state.h b/include/block/block-global-state.h
29
index XXXXXXX..XXXXXXX 100644
46
index XXXXXXX..XXXXXXX 100644
30
--- a/include/block/block-global-state.h
47
--- a/include/block/block-global-state.h
31
+++ b/include/block/block-global-state.h
48
+++ b/include/block/block-global-state.h
32
@@ -XXX,XX +XXX,XX @@ BlockDriver *bdrv_find_protocol(const char *filename,
49
@@ -XXX,XX +XXX,XX @@ BlockDriverState * GRAPH_RDLOCK
33
Error **errp);
50
check_to_replace_node(BlockDriverState *parent_bs, const char *node_name,
34
BlockDriver *bdrv_find_format(const char *format_name);
51
Error **errp);
35
52
36
-int coroutine_fn bdrv_co_create(BlockDriver *drv, const char *filename,
37
- QemuOpts *opts, Error **errp);
38
-int co_wrapper bdrv_create(BlockDriver *drv, const char *filename,
39
- QemuOpts *opts, Error **errp);
40
+int coroutine_fn GRAPH_RDLOCK
41
+bdrv_co_create(BlockDriver *drv, const char *filename, QemuOpts *opts,
42
+ Error **errp);
43
44
-int coroutine_fn bdrv_co_create_file(const char *filename, QemuOpts *opts,
45
- Error **errp);
46
+int co_wrapper_bdrv_rdlock bdrv_create(BlockDriver *drv, const char *filename,
47
+ QemuOpts *opts, Error **errp);
48
+
53
+
49
+int coroutine_fn GRAPH_RDLOCK
54
+bool GRAPH_RDLOCK bdrv_is_inactive(BlockDriverState *bs);
50
+bdrv_co_create_file(const char *filename, QemuOpts *opts, Error **errp);
51
52
BlockDriverState *bdrv_new(void);
53
int bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top,
54
diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
55
index XXXXXXX..XXXXXXX 100644
56
--- a/include/block/block_int-common.h
57
+++ b/include/block/block_int-common.h
58
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
59
Error **errp);
60
void (*bdrv_close)(BlockDriverState *bs);
61
62
- int coroutine_fn (*bdrv_co_create)(BlockdevCreateOptions *opts,
63
- Error **errp);
64
- int coroutine_fn (*bdrv_co_create_opts)(BlockDriver *drv,
65
- const char *filename,
66
- QemuOpts *opts,
67
- Error **errp);
68
+ int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_create)(
69
+ BlockdevCreateOptions *opts, Error **errp);
70
+
55
+
71
+ int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_create_opts)(
56
int no_coroutine_fn GRAPH_RDLOCK
72
+ BlockDriver *drv, const char *filename, QemuOpts *opts, Error **errp);
57
bdrv_activate(BlockDriverState *bs, Error **errp);
73
58
74
int (*bdrv_amend_options)(BlockDriverState *bs,
75
QemuOpts *opts,
76
diff --git a/block.c b/block.c
59
diff --git a/block.c b/block.c
77
index XXXXXXX..XXXXXXX 100644
60
index XXXXXXX..XXXXXXX 100644
78
--- a/block.c
61
--- a/block.c
79
+++ b/block.c
62
+++ b/block.c
80
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_create(BlockDriver *drv, const char *filename,
63
@@ -XXX,XX +XXX,XX @@ void bdrv_init_with_whitelist(void)
81
int ret;
64
bdrv_init();
82
GLOBAL_STATE_CODE();
65
}
83
ERRP_GUARD();
66
84
+ assert_bdrv_graph_readable();
67
+bool bdrv_is_inactive(BlockDriverState *bs) {
85
68
+ return bs->open_flags & BDRV_O_INACTIVE;
86
if (!drv->bdrv_co_create_opts) {
87
error_setg(errp, "Driver '%s' does not support image creation",
88
diff --git a/block/create.c b/block/create.c
89
index XXXXXXX..XXXXXXX 100644
90
--- a/block/create.c
91
+++ b/block/create.c
92
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn blockdev_create_run(Job *job, Error **errp)
93
int ret;
94
95
GLOBAL_STATE_CODE();
96
+ GRAPH_RDLOCK_GUARD();
97
98
job_progress_set_remaining(&s->common, 1);
99
ret = s->drv->bdrv_co_create(s->opts, errp);
100
@@ -XXX,XX +XXX,XX @@ static const JobDriver blockdev_create_job_driver = {
101
.run = blockdev_create_run,
102
};
103
104
+/* Checking whether the function is present doesn't require the graph lock */
105
+static inline bool TSA_NO_TSA has_bdrv_co_create(BlockDriver *drv)
106
+{
107
+ return drv->bdrv_co_create;
108
+}
69
+}
109
+
70
+
110
void qmp_blockdev_create(const char *job_id, BlockdevCreateOptions *options,
71
int bdrv_activate(BlockDriverState *bs, Error **errp)
111
Error **errp)
112
{
72
{
113
@@ -XXX,XX +XXX,XX @@ void qmp_blockdev_create(const char *job_id, BlockdevCreateOptions *options,
73
BdrvChild *child, *parent;
74
diff --git a/block/monitor/block-hmp-cmds.c b/block/monitor/block-hmp-cmds.c
75
index XXXXXXX..XXXXXXX 100644
76
--- a/block/monitor/block-hmp-cmds.c
77
+++ b/block/monitor/block-hmp-cmds.c
78
@@ -XXX,XX +XXX,XX @@ static void print_block_info(Monitor *mon, BlockInfo *info,
114
}
79
}
115
80
116
/* Error out if the driver doesn't support .bdrv_co_create */
81
if (inserted) {
117
- if (!drv->bdrv_co_create) {
82
- monitor_printf(mon, ": %s (%s%s%s)\n",
118
+ if (!has_bdrv_co_create(drv)) {
83
+ monitor_printf(mon, ": %s (%s%s%s%s)\n",
119
error_setg(errp, "Driver does not support blockdev-create");
84
inserted->file,
120
return;
85
inserted->drv,
86
inserted->ro ? ", read-only" : "",
87
- inserted->encrypted ? ", encrypted" : "");
88
+ inserted->encrypted ? ", encrypted" : "",
89
+ inserted->active ? "" : ", inactive");
90
} else {
91
monitor_printf(mon, ": [not inserted]\n");
121
}
92
}
122
diff --git a/block/crypto.c b/block/crypto.c
93
diff --git a/block/qapi.c b/block/qapi.c
123
index XXXXXXX..XXXXXXX 100644
94
index XXXXXXX..XXXXXXX 100644
124
--- a/block/crypto.c
95
--- a/block/qapi.c
125
+++ b/block/crypto.c
96
+++ b/block/qapi.c
126
@@ -XXX,XX +XXX,XX @@ fail:
97
@@ -XXX,XX +XXX,XX @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk,
127
return ret;
98
info->file = g_strdup(bs->filename);
128
}
99
info->ro = bdrv_is_read_only(bs);
129
100
info->drv = g_strdup(bs->drv->format_name);
130
-static int coroutine_fn block_crypto_co_create_opts_luks(BlockDriver *drv,
101
+ info->active = !bdrv_is_inactive(bs);
131
- const char *filename,
102
info->encrypted = bs->encrypted;
132
- QemuOpts *opts,
103
133
- Error **errp)
104
info->cache = g_new(BlockdevCacheInfo, 1);
134
+static int coroutine_fn GRAPH_RDLOCK
105
diff --git a/tests/qemu-iotests/184.out b/tests/qemu-iotests/184.out
135
+block_crypto_co_create_opts_luks(BlockDriver *drv, const char *filename,
106
index XXXXXXX..XXXXXXX 100644
136
+ QemuOpts *opts, Error **errp)
107
--- a/tests/qemu-iotests/184.out
137
{
108
+++ b/tests/qemu-iotests/184.out
138
QCryptoBlockCreateOptions *create_opts = NULL;
109
@@ -XXX,XX +XXX,XX @@ Testing:
139
BlockDriverState *bs = NULL;
110
{
140
diff --git a/block/file-posix.c b/block/file-posix.c
111
"iops_rd": 0,
141
index XXXXXXX..XXXXXXX 100644
112
"detect_zeroes": "off",
142
--- a/block/file-posix.c
113
+ "active": true,
143
+++ b/block/file-posix.c
114
"image": {
144
@@ -XXX,XX +XXX,XX @@ out:
115
"backing-image": {
145
return result;
116
"virtual-size": 1073741824,
146
}
117
@@ -XXX,XX +XXX,XX @@ Testing:
147
118
{
148
-static int coroutine_fn raw_co_create_opts(BlockDriver *drv,
119
"iops_rd": 0,
149
- const char *filename,
120
"detect_zeroes": "off",
150
- QemuOpts *opts,
121
+ "active": true,
151
- Error **errp)
122
"image": {
152
+static int coroutine_fn GRAPH_RDLOCK
123
"virtual-size": 1073741824,
153
+raw_co_create_opts(BlockDriver *drv, const char *filename,
124
"filename": "null-co://",
154
+ QemuOpts *opts, Error **errp)
125
diff --git a/tests/qemu-iotests/191.out b/tests/qemu-iotests/191.out
155
{
126
index XXXXXXX..XXXXXXX 100644
156
BlockdevCreateOptions options;
127
--- a/tests/qemu-iotests/191.out
157
int64_t total_size = 0;
128
+++ b/tests/qemu-iotests/191.out
158
diff --git a/block/file-win32.c b/block/file-win32.c
129
@@ -XXX,XX +XXX,XX @@ wrote 65536/65536 bytes at offset 1048576
159
index XXXXXXX..XXXXXXX 100644
130
{
160
--- a/block/file-win32.c
131
"iops_rd": 0,
161
+++ b/block/file-win32.c
132
"detect_zeroes": "off",
162
@@ -XXX,XX +XXX,XX @@ static int raw_co_create(BlockdevCreateOptions *options, Error **errp)
133
+ "active": true,
163
return 0;
134
"image": {
164
}
135
"backing-image": {
165
136
"virtual-size": 67108864,
166
-static int coroutine_fn raw_co_create_opts(BlockDriver *drv,
137
@@ -XXX,XX +XXX,XX @@ wrote 65536/65536 bytes at offset 1048576
167
- const char *filename,
138
{
168
- QemuOpts *opts,
139
"iops_rd": 0,
169
- Error **errp)
140
"detect_zeroes": "off",
170
+static int coroutine_fn GRAPH_RDLOCK
141
+ "active": true,
171
+raw_co_create_opts(BlockDriver *drv, const char *filename,
142
"image": {
172
+ QemuOpts *opts, Error **errp)
143
"virtual-size": 197120,
173
{
144
"filename": "TEST_DIR/t.IMGFMT.ovl2",
174
BlockdevCreateOptions options;
145
@@ -XXX,XX +XXX,XX @@ wrote 65536/65536 bytes at offset 1048576
175
int64_t total_size = 0;
146
{
176
diff --git a/block/parallels.c b/block/parallels.c
147
"iops_rd": 0,
177
index XXXXXXX..XXXXXXX 100644
148
"detect_zeroes": "off",
178
--- a/block/parallels.c
149
+ "active": true,
179
+++ b/block/parallels.c
150
"image": {
180
@@ -XXX,XX +XXX,XX @@ exit:
151
"backing-image": {
181
goto out;
152
"virtual-size": 67108864,
182
}
153
@@ -XXX,XX +XXX,XX @@ wrote 65536/65536 bytes at offset 1048576
183
154
{
184
-static int coroutine_fn parallels_co_create_opts(BlockDriver *drv,
155
"iops_rd": 0,
185
- const char *filename,
156
"detect_zeroes": "off",
186
- QemuOpts *opts,
157
+ "active": true,
187
- Error **errp)
158
"image": {
188
+static int coroutine_fn GRAPH_RDLOCK
159
"virtual-size": 197120,
189
+parallels_co_create_opts(BlockDriver *drv, const char *filename,
160
"filename": "TEST_DIR/t.IMGFMT",
190
+ QemuOpts *opts, Error **errp)
161
@@ -XXX,XX +XXX,XX @@ wrote 65536/65536 bytes at offset 1048576
191
{
162
{
192
BlockdevCreateOptions *create_options = NULL;
163
"iops_rd": 0,
193
BlockDriverState *bs = NULL;
164
"detect_zeroes": "off",
194
diff --git a/block/qcow.c b/block/qcow.c
165
+ "active": true,
195
index XXXXXXX..XXXXXXX 100644
166
"image": {
196
--- a/block/qcow.c
167
"backing-image": {
197
+++ b/block/qcow.c
168
"virtual-size": 67108864,
198
@@ -XXX,XX +XXX,XX @@ exit:
169
@@ -XXX,XX +XXX,XX @@ wrote 65536/65536 bytes at offset 1048576
199
return ret;
170
{
200
}
171
"iops_rd": 0,
201
172
"detect_zeroes": "off",
202
-static int coroutine_fn qcow_co_create_opts(BlockDriver *drv,
173
+ "active": true,
203
- const char *filename,
174
"image": {
204
- QemuOpts *opts, Error **errp)
175
"virtual-size": 393216,
205
+static int coroutine_fn GRAPH_RDLOCK
176
"filename": "TEST_DIR/t.IMGFMT.mid",
206
+qcow_co_create_opts(BlockDriver *drv, const char *filename,
177
@@ -XXX,XX +XXX,XX @@ wrote 65536/65536 bytes at offset 1048576
207
+ QemuOpts *opts, Error **errp)
178
{
208
{
179
"iops_rd": 0,
209
BlockdevCreateOptions *create_options = NULL;
180
"detect_zeroes": "off",
210
BlockDriverState *bs = NULL;
181
+ "active": true,
211
diff --git a/block/qcow2.c b/block/qcow2.c
182
"image": {
212
index XXXXXXX..XXXXXXX 100644
183
"virtual-size": 67108864,
213
--- a/block/qcow2.c
184
"filename": "TEST_DIR/t.IMGFMT.base",
214
+++ b/block/qcow2.c
185
@@ -XXX,XX +XXX,XX @@ wrote 65536/65536 bytes at offset 1048576
215
@@ -XXX,XX +XXX,XX @@ out:
186
{
216
return ret;
187
"iops_rd": 0,
217
}
188
"detect_zeroes": "off",
218
189
+ "active": true,
219
-static int coroutine_fn qcow2_co_create_opts(BlockDriver *drv,
190
"image": {
220
- const char *filename,
191
"virtual-size": 393216,
221
- QemuOpts *opts,
192
"filename": "TEST_DIR/t.IMGFMT.base",
222
- Error **errp)
193
@@ -XXX,XX +XXX,XX @@ wrote 65536/65536 bytes at offset 1048576
223
+static int coroutine_fn GRAPH_RDLOCK
194
{
224
+qcow2_co_create_opts(BlockDriver *drv, const char *filename, QemuOpts *opts,
195
"iops_rd": 0,
225
+ Error **errp)
196
"detect_zeroes": "off",
226
{
197
+ "active": true,
227
BlockdevCreateOptions *create_options = NULL;
198
"image": {
228
QDict *qdict;
199
"backing-image": {
229
diff --git a/block/qed.c b/block/qed.c
200
"virtual-size": 67108864,
230
index XXXXXXX..XXXXXXX 100644
201
@@ -XXX,XX +XXX,XX @@ wrote 65536/65536 bytes at offset 1048576
231
--- a/block/qed.c
202
{
232
+++ b/block/qed.c
203
"iops_rd": 0,
233
@@ -XXX,XX +XXX,XX @@ out:
204
"detect_zeroes": "off",
234
return ret;
205
+ "active": true,
235
}
206
"image": {
236
207
"virtual-size": 197120,
237
-static int coroutine_fn bdrv_qed_co_create_opts(BlockDriver *drv,
208
"filename": "TEST_DIR/t.IMGFMT.ovl2",
238
- const char *filename,
209
@@ -XXX,XX +XXX,XX @@ wrote 65536/65536 bytes at offset 1048576
239
- QemuOpts *opts,
210
{
240
- Error **errp)
211
"iops_rd": 0,
241
+static int coroutine_fn GRAPH_RDLOCK
212
"detect_zeroes": "off",
242
+bdrv_qed_co_create_opts(BlockDriver *drv, const char *filename,
213
+ "active": true,
243
+ QemuOpts *opts, Error **errp)
214
"image": {
244
{
215
"backing-image": {
245
BlockdevCreateOptions *create_options = NULL;
216
"backing-image": {
246
QDict *qdict;
217
@@ -XXX,XX +XXX,XX @@ wrote 65536/65536 bytes at offset 1048576
247
diff --git a/block/raw-format.c b/block/raw-format.c
218
{
248
index XXXXXXX..XXXXXXX 100644
219
"iops_rd": 0,
249
--- a/block/raw-format.c
220
"detect_zeroes": "off",
250
+++ b/block/raw-format.c
221
+ "active": true,
251
@@ -XXX,XX +XXX,XX @@ static int raw_has_zero_init(BlockDriverState *bs)
222
"image": {
252
return bdrv_has_zero_init(bs->file->bs);
223
"virtual-size": 197120,
253
}
224
"filename": "TEST_DIR/t.IMGFMT.ovl3",
254
225
@@ -XXX,XX +XXX,XX @@ wrote 65536/65536 bytes at offset 1048576
255
-static int coroutine_fn raw_co_create_opts(BlockDriver *drv,
226
{
256
- const char *filename,
227
"iops_rd": 0,
257
- QemuOpts *opts,
228
"detect_zeroes": "off",
258
- Error **errp)
229
+ "active": true,
259
+static int coroutine_fn GRAPH_RDLOCK
230
"image": {
260
+raw_co_create_opts(BlockDriver *drv, const char *filename,
231
"virtual-size": 67108864,
261
+ QemuOpts *opts, Error **errp)
232
"filename": "TEST_DIR/t.IMGFMT.base",
262
{
233
@@ -XXX,XX +XXX,XX @@ wrote 65536/65536 bytes at offset 1048576
263
return bdrv_co_create_file(filename, opts, errp);
234
{
264
}
235
"iops_rd": 0,
265
diff --git a/block/vdi.c b/block/vdi.c
236
"detect_zeroes": "off",
266
index XXXXXXX..XXXXXXX 100644
237
+ "active": true,
267
--- a/block/vdi.c
238
"image": {
268
+++ b/block/vdi.c
239
"virtual-size": 393216,
269
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vdi_co_create(BlockdevCreateOptions *create_options,
240
"filename": "TEST_DIR/t.IMGFMT.base",
270
return vdi_co_do_create(create_options, DEFAULT_CLUSTER_SIZE, errp);
241
@@ -XXX,XX +XXX,XX @@ wrote 65536/65536 bytes at offset 1048576
271
}
242
{
272
243
"iops_rd": 0,
273
-static int coroutine_fn vdi_co_create_opts(BlockDriver *drv,
244
"detect_zeroes": "off",
274
- const char *filename,
245
+ "active": true,
275
- QemuOpts *opts,
246
"image": {
276
- Error **errp)
247
"backing-image": {
277
+static int coroutine_fn GRAPH_RDLOCK
248
"virtual-size": 67108864,
278
+vdi_co_create_opts(BlockDriver *drv, const char *filename,
249
@@ -XXX,XX +XXX,XX @@ wrote 65536/65536 bytes at offset 1048576
279
+ QemuOpts *opts, Error **errp)
250
{
280
{
251
"iops_rd": 0,
281
QDict *qdict = NULL;
252
"detect_zeroes": "off",
282
BlockdevCreateOptions *create_options = NULL;
253
+ "active": true,
283
diff --git a/block/vhdx.c b/block/vhdx.c
254
"image": {
284
index XXXXXXX..XXXXXXX 100644
255
"virtual-size": 197120,
285
--- a/block/vhdx.c
256
"filename": "TEST_DIR/t.IMGFMT",
286
+++ b/block/vhdx.c
257
diff --git a/tests/qemu-iotests/273.out b/tests/qemu-iotests/273.out
287
@@ -XXX,XX +XXX,XX @@ delete_and_exit:
258
index XXXXXXX..XXXXXXX 100644
288
return ret;
259
--- a/tests/qemu-iotests/273.out
289
}
260
+++ b/tests/qemu-iotests/273.out
290
261
@@ -XXX,XX +XXX,XX @@ Testing: -blockdev file,node-name=base,filename=TEST_DIR/t.IMGFMT.base -blockdev
291
-static int coroutine_fn vhdx_co_create_opts(BlockDriver *drv,
262
{
292
- const char *filename,
263
"iops_rd": 0,
293
- QemuOpts *opts,
264
"detect_zeroes": "off",
294
- Error **errp)
265
+ "active": true,
295
+static int coroutine_fn GRAPH_RDLOCK
266
"image": {
296
+vhdx_co_create_opts(BlockDriver *drv, const char *filename,
267
"backing-image": {
297
+ QemuOpts *opts, Error **errp)
268
"backing-image": {
298
{
269
@@ -XXX,XX +XXX,XX @@ Testing: -blockdev file,node-name=base,filename=TEST_DIR/t.IMGFMT.base -blockdev
299
BlockdevCreateOptions *create_options = NULL;
270
{
300
QDict *qdict;
271
"iops_rd": 0,
301
diff --git a/block/vmdk.c b/block/vmdk.c
272
"detect_zeroes": "off",
302
index XXXXXXX..XXXXXXX 100644
273
+ "active": true,
303
--- a/block/vmdk.c
274
"image": {
304
+++ b/block/vmdk.c
275
"virtual-size": 197120,
305
@@ -XXX,XX +XXX,XX @@ exit:
276
"filename": "TEST_DIR/t.IMGFMT",
306
return ret;
277
@@ -XXX,XX +XXX,XX @@ Testing: -blockdev file,node-name=base,filename=TEST_DIR/t.IMGFMT.base -blockdev
307
}
278
{
308
279
"iops_rd": 0,
309
-static int coroutine_fn vmdk_create_extent(const char *filename,
280
"detect_zeroes": "off",
310
- int64_t filesize, bool flat,
281
+ "active": true,
311
- bool compress, bool zeroed_grain,
282
"image": {
312
- BlockBackend **pbb,
283
"backing-image": {
313
- QemuOpts *opts, Error **errp)
284
"virtual-size": 197120,
314
+static int coroutine_fn GRAPH_RDLOCK
285
@@ -XXX,XX +XXX,XX @@ Testing: -blockdev file,node-name=base,filename=TEST_DIR/t.IMGFMT.base -blockdev
315
+vmdk_create_extent(const char *filename, int64_t filesize, bool flat,
286
{
316
+ bool compress, bool zeroed_grain, BlockBackend **pbb,
287
"iops_rd": 0,
317
+ QemuOpts *opts, Error **errp)
288
"detect_zeroes": "off",
318
{
289
+ "active": true,
319
int ret;
290
"image": {
320
BlockBackend *blk = NULL;
291
"virtual-size": 197120,
321
@@ -XXX,XX +XXX,XX @@ static int filename_decompose(const char *filename, char *path, char *prefix,
292
"filename": "TEST_DIR/t.IMGFMT.mid",
322
* non-split format.
293
@@ -XXX,XX +XXX,XX @@ Testing: -blockdev file,node-name=base,filename=TEST_DIR/t.IMGFMT.base -blockdev
323
* idx >= 1: get the n-th extent if in a split subformat
294
{
324
*/
295
"iops_rd": 0,
325
-typedef BlockBackend * coroutine_fn (*vmdk_create_extent_fn)(int64_t size,
296
"detect_zeroes": "off",
326
- int idx,
297
+ "active": true,
327
- bool flat,
298
"image": {
328
- bool split,
299
"virtual-size": 197120,
329
- bool compress,
300
"filename": "TEST_DIR/t.IMGFMT.base",
330
- bool zeroed_grain,
331
- void *opaque,
332
- Error **errp);
333
+typedef BlockBackend * coroutine_fn /* GRAPH_RDLOCK */
334
+ (*vmdk_create_extent_fn)(int64_t size, int idx, bool flat, bool split,
335
+ bool compress, bool zeroed_grain, void *opaque,
336
+ Error **errp);
337
338
static void vmdk_desc_add_extent(GString *desc,
339
const char *extent_line_fmt,
340
@@ -XXX,XX +XXX,XX @@ static void vmdk_desc_add_extent(GString *desc,
341
g_free(basename);
342
}
343
344
-static int coroutine_fn vmdk_co_do_create(int64_t size,
345
- BlockdevVmdkSubformat subformat,
346
- BlockdevVmdkAdapterType adapter_type,
347
- const char *backing_file,
348
- const char *hw_version,
349
- const char *toolsversion,
350
- bool compat6,
351
- bool zeroed_grain,
352
- vmdk_create_extent_fn extent_fn,
353
- void *opaque,
354
- Error **errp)
355
+static int coroutine_fn GRAPH_RDLOCK
356
+vmdk_co_do_create(int64_t size,
357
+ BlockdevVmdkSubformat subformat,
358
+ BlockdevVmdkAdapterType adapter_type,
359
+ const char *backing_file,
360
+ const char *hw_version,
361
+ const char *toolsversion,
362
+ bool compat6,
363
+ bool zeroed_grain,
364
+ vmdk_create_extent_fn extent_fn,
365
+ void *opaque,
366
+ Error **errp)
367
{
368
int extent_idx;
369
BlockBackend *blk = NULL;
370
@@ -XXX,XX +XXX,XX @@ typedef struct {
371
QemuOpts *opts;
372
} VMDKCreateOptsData;
373
374
-static BlockBackend * coroutine_fn vmdk_co_create_opts_cb(int64_t size, int idx,
375
- bool flat, bool split, bool compress,
376
- bool zeroed_grain, void *opaque,
377
- Error **errp)
378
+static BlockBackend * coroutine_fn GRAPH_RDLOCK
379
+vmdk_co_create_opts_cb(int64_t size, int idx, bool flat, bool split,
380
+ bool compress, bool zeroed_grain, void *opaque,
381
+ Error **errp)
382
{
383
BlockBackend *blk = NULL;
384
BlockDriverState *bs = NULL;
385
@@ -XXX,XX +XXX,XX @@ exit:
386
return blk;
387
}
388
389
-static int coroutine_fn vmdk_co_create_opts(BlockDriver *drv,
390
- const char *filename,
391
- QemuOpts *opts,
392
- Error **errp)
393
+static int coroutine_fn GRAPH_RDLOCK
394
+vmdk_co_create_opts(BlockDriver *drv, const char *filename,
395
+ QemuOpts *opts, Error **errp)
396
{
397
Error *local_err = NULL;
398
char *desc = NULL;
399
@@ -XXX,XX +XXX,XX @@ static BlockBackend * coroutine_fn vmdk_co_create_cb(int64_t size, int idx,
400
return blk;
401
}
402
403
-static int coroutine_fn vmdk_co_create(BlockdevCreateOptions *create_options,
404
- Error **errp)
405
+static int coroutine_fn GRAPH_RDLOCK
406
+vmdk_co_create(BlockdevCreateOptions *create_options, Error **errp)
407
{
408
BlockdevCreateOptionsVmdk *opts;
409
410
diff --git a/block/vpc.c b/block/vpc.c
411
index XXXXXXX..XXXXXXX 100644
412
--- a/block/vpc.c
413
+++ b/block/vpc.c
414
@@ -XXX,XX +XXX,XX @@ out:
415
return ret;
416
}
417
418
-static int coroutine_fn vpc_co_create_opts(BlockDriver *drv,
419
- const char *filename,
420
- QemuOpts *opts,
421
- Error **errp)
422
+static int coroutine_fn GRAPH_RDLOCK
423
+vpc_co_create_opts(BlockDriver *drv, const char *filename,
424
+ QemuOpts *opts, Error **errp)
425
{
426
BlockdevCreateOptions *create_options = NULL;
427
QDict *qdict;
428
--
301
--
429
2.39.2
302
2.48.1
diff view generated by jsdifflib
1
This adds GRAPH_RDLOCK annotations to declare that callers of
1
What we wanted to catch with the assertion is cases where the recursion
2
bdrv_co_refresh_total_sectors() need to hold a reader lock for the
2
finds that a child was inactive before its parent. This should never
3
graph.
3
happen. But if the user tries to inactivate an image that is already
4
inactive, that's harmless and we don't want to fail the assertion.
4
5
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Message-Id: <20230203152202.49054-24-kwolf@redhat.com>
7
Acked-by: Fabiano Rosas <farosas@suse.de>
7
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
8
Reviewed-by: Eric Blake <eblake@redhat.com>
9
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
10
Message-ID: <20250204211407.381505-3-kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
12
---
10
include/block/block-io.h | 8 ++++----
13
block.c | 16 ++++++++++++----
11
include/block/block_int-common.h | 4 +++-
14
1 file changed, 12 insertions(+), 4 deletions(-)
12
include/block/block_int-io.h | 7 ++++---
13
block.c | 3 +++
14
block/blkdebug.c | 3 ++-
15
block/blklogwrites.c | 3 ++-
16
block/blkreplay.c | 3 ++-
17
block/blkverify.c | 3 ++-
18
block/copy-on-read.c | 2 +-
19
block/crypto.c | 3 ++-
20
block/filter-compress.c | 3 ++-
21
block/mirror.c | 3 +++
22
block/preallocate.c | 3 ++-
23
block/quorum.c | 3 ++-
24
block/raw-format.c | 3 ++-
25
block/replication.c | 3 ++-
26
block/stream.c | 8 +++++---
27
block/throttle.c | 3 ++-
28
18 files changed, 45 insertions(+), 23 deletions(-)
29
15
30
diff --git a/include/block/block-io.h b/include/block/block-io.h
31
index XXXXXXX..XXXXXXX 100644
32
--- a/include/block/block-io.h
33
+++ b/include/block/block-io.h
34
@@ -XXX,XX +XXX,XX @@ int coroutine_fn GRAPH_RDLOCK
35
bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
36
PreallocMode prealloc, BdrvRequestFlags flags, Error **errp);
37
38
-int64_t coroutine_fn bdrv_co_nb_sectors(BlockDriverState *bs);
39
-int64_t co_wrapper_mixed bdrv_nb_sectors(BlockDriverState *bs);
40
+int64_t coroutine_fn GRAPH_RDLOCK bdrv_co_nb_sectors(BlockDriverState *bs);
41
+int64_t co_wrapper_mixed_bdrv_rdlock bdrv_nb_sectors(BlockDriverState *bs);
42
43
-int64_t coroutine_fn bdrv_co_getlength(BlockDriverState *bs);
44
-int64_t co_wrapper_mixed bdrv_getlength(BlockDriverState *bs);
45
+int64_t coroutine_fn GRAPH_RDLOCK bdrv_co_getlength(BlockDriverState *bs);
46
+int64_t co_wrapper_mixed_bdrv_rdlock bdrv_getlength(BlockDriverState *bs);
47
48
int64_t coroutine_fn bdrv_co_get_allocated_file_size(BlockDriverState *bs);
49
int64_t co_wrapper bdrv_get_allocated_file_size(BlockDriverState *bs);
50
diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
51
index XXXXXXX..XXXXXXX 100644
52
--- a/include/block/block_int-common.h
53
+++ b/include/block/block_int-common.h
54
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
55
BlockDriverState *bs, int64_t offset, bool exact,
56
PreallocMode prealloc, BdrvRequestFlags flags, Error **errp);
57
58
- int64_t coroutine_fn (*bdrv_co_getlength)(BlockDriverState *bs);
59
+ int64_t coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_getlength)(
60
+ BlockDriverState *bs);
61
+
62
int64_t coroutine_fn (*bdrv_co_get_allocated_file_size)(
63
BlockDriverState *bs);
64
65
diff --git a/include/block/block_int-io.h b/include/block/block_int-io.h
66
index XXXXXXX..XXXXXXX 100644
67
--- a/include/block/block_int-io.h
68
+++ b/include/block/block_int-io.h
69
@@ -XXX,XX +XXX,XX @@ bdrv_co_copy_range_to(BdrvChild *src, int64_t src_offset,
70
int64_t bytes, BdrvRequestFlags read_flags,
71
BdrvRequestFlags write_flags);
72
73
-int coroutine_fn bdrv_co_refresh_total_sectors(BlockDriverState *bs,
74
- int64_t hint);
75
-int co_wrapper_mixed
76
+int coroutine_fn GRAPH_RDLOCK
77
+bdrv_co_refresh_total_sectors(BlockDriverState *bs, int64_t hint);
78
+
79
+int co_wrapper_mixed_bdrv_rdlock
80
bdrv_refresh_total_sectors(BlockDriverState *bs, int64_t hint);
81
82
BdrvChild *bdrv_cow_child(BlockDriverState *bs);
83
diff --git a/block.c b/block.c
16
diff --git a/block.c b/block.c
84
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
85
--- a/block.c
18
--- a/block.c
86
+++ b/block.c
19
+++ b/block.c
87
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_refresh_total_sectors(BlockDriverState *bs,
20
@@ -XXX,XX +XXX,XX @@ bdrv_has_bds_parent(BlockDriverState *bs, bool only_active)
88
{
89
BlockDriver *drv = bs->drv;
90
IO_CODE();
91
+ assert_bdrv_graph_readable();
92
93
if (!drv) {
94
return -ENOMEDIUM;
95
@@ -XXX,XX +XXX,XX @@ int64_t coroutine_fn bdrv_co_nb_sectors(BlockDriverState *bs)
96
{
97
BlockDriver *drv = bs->drv;
98
IO_CODE();
99
+ assert_bdrv_graph_readable();
100
101
if (!drv)
102
return -ENOMEDIUM;
103
@@ -XXX,XX +XXX,XX @@ int64_t coroutine_fn bdrv_co_getlength(BlockDriverState *bs)
104
{
105
int64_t ret;
106
IO_CODE();
107
+ assert_bdrv_graph_readable();
108
109
ret = bdrv_co_nb_sectors(bs);
110
if (ret < 0) {
111
diff --git a/block/blkdebug.c b/block/blkdebug.c
112
index XXXXXXX..XXXXXXX 100644
113
--- a/block/blkdebug.c
114
+++ b/block/blkdebug.c
115
@@ -XXX,XX +XXX,XX @@ static bool blkdebug_debug_is_suspended(BlockDriverState *bs, const char *tag)
116
return false;
21
return false;
117
}
22
}
118
23
119
-static int64_t coroutine_fn blkdebug_co_getlength(BlockDriverState *bs)
24
-static int GRAPH_RDLOCK bdrv_inactivate_recurse(BlockDriverState *bs)
120
+static int64_t coroutine_fn GRAPH_RDLOCK
25
+static int GRAPH_RDLOCK
121
+blkdebug_co_getlength(BlockDriverState *bs)
26
+bdrv_inactivate_recurse(BlockDriverState *bs, bool top_level)
122
{
27
{
123
return bdrv_co_getlength(bs->file->bs);
28
BdrvChild *child, *parent;
124
}
29
int ret;
125
diff --git a/block/blklogwrites.c b/block/blklogwrites.c
30
@@ -XXX,XX +XXX,XX @@ static int GRAPH_RDLOCK bdrv_inactivate_recurse(BlockDriverState *bs)
126
index XXXXXXX..XXXXXXX 100644
127
--- a/block/blklogwrites.c
128
+++ b/block/blklogwrites.c
129
@@ -XXX,XX +XXX,XX @@ static void blk_log_writes_close(BlockDriverState *bs)
130
s->log_file = NULL;
131
}
132
133
-static int64_t coroutine_fn blk_log_writes_co_getlength(BlockDriverState *bs)
134
+static int64_t coroutine_fn GRAPH_RDLOCK
135
+blk_log_writes_co_getlength(BlockDriverState *bs)
136
{
137
return bdrv_co_getlength(bs->file->bs);
138
}
139
diff --git a/block/blkreplay.c b/block/blkreplay.c
140
index XXXXXXX..XXXXXXX 100644
141
--- a/block/blkreplay.c
142
+++ b/block/blkreplay.c
143
@@ -XXX,XX +XXX,XX @@ fail:
144
return ret;
145
}
146
147
-static int64_t coroutine_fn blkreplay_co_getlength(BlockDriverState *bs)
148
+static int64_t coroutine_fn GRAPH_RDLOCK
149
+blkreplay_co_getlength(BlockDriverState *bs)
150
{
151
return bdrv_co_getlength(bs->file->bs);
152
}
153
diff --git a/block/blkverify.c b/block/blkverify.c
154
index XXXXXXX..XXXXXXX 100644
155
--- a/block/blkverify.c
156
+++ b/block/blkverify.c
157
@@ -XXX,XX +XXX,XX @@ static void blkverify_close(BlockDriverState *bs)
158
s->test_file = NULL;
159
}
160
161
-static int64_t coroutine_fn blkverify_co_getlength(BlockDriverState *bs)
162
+static int64_t coroutine_fn GRAPH_RDLOCK
163
+blkverify_co_getlength(BlockDriverState *bs)
164
{
165
BDRVBlkverifyState *s = bs->opaque;
166
167
diff --git a/block/copy-on-read.c b/block/copy-on-read.c
168
index XXXXXXX..XXXXXXX 100644
169
--- a/block/copy-on-read.c
170
+++ b/block/copy-on-read.c
171
@@ -XXX,XX +XXX,XX @@ static void cor_child_perm(BlockDriverState *bs, BdrvChild *c,
172
}
173
174
175
-static int64_t coroutine_fn cor_co_getlength(BlockDriverState *bs)
176
+static int64_t coroutine_fn GRAPH_RDLOCK cor_co_getlength(BlockDriverState *bs)
177
{
178
return bdrv_co_getlength(bs->file->bs);
179
}
180
diff --git a/block/crypto.c b/block/crypto.c
181
index XXXXXXX..XXXXXXX 100644
182
--- a/block/crypto.c
183
+++ b/block/crypto.c
184
@@ -XXX,XX +XXX,XX @@ static void block_crypto_refresh_limits(BlockDriverState *bs, Error **errp)
185
}
186
187
188
-static int64_t coroutine_fn block_crypto_co_getlength(BlockDriverState *bs)
189
+static int64_t coroutine_fn GRAPH_RDLOCK
190
+block_crypto_co_getlength(BlockDriverState *bs)
191
{
192
BlockCrypto *crypto = bs->opaque;
193
int64_t len = bdrv_co_getlength(bs->file->bs);
194
diff --git a/block/filter-compress.c b/block/filter-compress.c
195
index XXXXXXX..XXXXXXX 100644
196
--- a/block/filter-compress.c
197
+++ b/block/filter-compress.c
198
@@ -XXX,XX +XXX,XX @@ static int compress_open(BlockDriverState *bs, QDict *options, int flags,
199
}
200
201
202
-static int64_t coroutine_fn compress_co_getlength(BlockDriverState *bs)
203
+static int64_t coroutine_fn GRAPH_RDLOCK
204
+compress_co_getlength(BlockDriverState *bs)
205
{
206
return bdrv_co_getlength(bs->file->bs);
207
}
208
diff --git a/block/mirror.c b/block/mirror.c
209
index XXXXXXX..XXXXXXX 100644
210
--- a/block/mirror.c
211
+++ b/block/mirror.c
212
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn mirror_run(Job *job, Error **errp)
213
goto immediate_exit;
214
}
215
216
+ bdrv_graph_co_rdlock();
217
s->bdev_length = bdrv_co_getlength(bs);
218
+ bdrv_graph_co_rdunlock();
219
+
220
if (s->bdev_length < 0) {
221
ret = s->bdev_length;
222
goto immediate_exit;
223
diff --git a/block/preallocate.c b/block/preallocate.c
224
index XXXXXXX..XXXXXXX 100644
225
--- a/block/preallocate.c
226
+++ b/block/preallocate.c
227
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn GRAPH_RDLOCK preallocate_co_flush(BlockDriverState *bs)
228
return bdrv_co_flush(bs->file->bs);
229
}
230
231
-static int64_t coroutine_fn preallocate_co_getlength(BlockDriverState *bs)
232
+static int64_t coroutine_fn GRAPH_RDLOCK
233
+preallocate_co_getlength(BlockDriverState *bs)
234
{
235
int64_t ret;
236
BDRVPreallocateState *s = bs->opaque;
237
diff --git a/block/quorum.c b/block/quorum.c
238
index XXXXXXX..XXXXXXX 100644
239
--- a/block/quorum.c
240
+++ b/block/quorum.c
241
@@ -XXX,XX +XXX,XX @@ quorum_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int64_t bytes,
242
flags | BDRV_REQ_ZERO_WRITE);
243
}
244
245
-static int64_t coroutine_fn quorum_co_getlength(BlockDriverState *bs)
246
+static int64_t coroutine_fn GRAPH_RDLOCK
247
+quorum_co_getlength(BlockDriverState *bs)
248
{
249
BDRVQuorumState *s = bs->opaque;
250
int64_t result;
251
diff --git a/block/raw-format.c b/block/raw-format.c
252
index XXXXXXX..XXXXXXX 100644
253
--- a/block/raw-format.c
254
+++ b/block/raw-format.c
255
@@ -XXX,XX +XXX,XX @@ raw_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes)
256
return bdrv_co_pdiscard(bs->file, offset, bytes);
257
}
258
259
-static int64_t coroutine_fn raw_co_getlength(BlockDriverState *bs)
260
+static int64_t coroutine_fn GRAPH_RDLOCK
261
+raw_co_getlength(BlockDriverState *bs)
262
{
263
int64_t len;
264
BDRVRawState *s = bs->opaque;
265
diff --git a/block/replication.c b/block/replication.c
266
index XXXXXXX..XXXXXXX 100644
267
--- a/block/replication.c
268
+++ b/block/replication.c
269
@@ -XXX,XX +XXX,XX @@ static void replication_child_perm(BlockDriverState *bs, BdrvChild *c,
270
return;
271
}
272
273
-static int64_t coroutine_fn replication_co_getlength(BlockDriverState *bs)
274
+static int64_t coroutine_fn GRAPH_RDLOCK
275
+replication_co_getlength(BlockDriverState *bs)
276
{
277
return bdrv_co_getlength(bs->file->bs);
278
}
279
diff --git a/block/stream.c b/block/stream.c
280
index XXXXXXX..XXXXXXX 100644
281
--- a/block/stream.c
282
+++ b/block/stream.c
283
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn stream_run(Job *job, Error **errp)
284
return 0;
31
return 0;
285
}
32
}
286
33
287
- len = bdrv_getlength(s->target_bs);
34
- assert(!(bs->open_flags & BDRV_O_INACTIVE));
288
- if (len < 0) {
35
+ /*
289
- return len;
36
+ * Inactivating an already inactive node on user request is harmless, but if
290
+ WITH_GRAPH_RDLOCK_GUARD() {
37
+ * a child is already inactive before its parent, that's bad.
291
+ len = bdrv_co_getlength(s->target_bs);
38
+ */
292
+ if (len < 0) {
39
+ if (bs->open_flags & BDRV_O_INACTIVE) {
293
+ return len;
40
+ assert(top_level);
294
+ }
41
+ return 0;
295
}
42
+ }
296
job_progress_set_remaining(&s->common.job, len);
43
297
44
/* Inactivate this node */
298
diff --git a/block/throttle.c b/block/throttle.c
45
if (bs->drv->bdrv_inactivate) {
299
index XXXXXXX..XXXXXXX 100644
46
@@ -XXX,XX +XXX,XX @@ static int GRAPH_RDLOCK bdrv_inactivate_recurse(BlockDriverState *bs)
300
--- a/block/throttle.c
47
301
+++ b/block/throttle.c
48
/* Recursively inactivate children */
302
@@ -XXX,XX +XXX,XX @@ static void throttle_close(BlockDriverState *bs)
49
QLIST_FOREACH(child, &bs->children, next) {
303
}
50
- ret = bdrv_inactivate_recurse(child->bs);
304
51
+ ret = bdrv_inactivate_recurse(child->bs, false);
305
52
if (ret < 0) {
306
-static int64_t coroutine_fn throttle_co_getlength(BlockDriverState *bs)
53
return ret;
307
+static int64_t coroutine_fn GRAPH_RDLOCK
54
}
308
+throttle_co_getlength(BlockDriverState *bs)
55
@@ -XXX,XX +XXX,XX @@ int bdrv_inactivate_all(void)
309
{
56
if (bdrv_has_bds_parent(bs, false)) {
310
return bdrv_co_getlength(bs->file->bs);
57
continue;
311
}
58
}
59
- ret = bdrv_inactivate_recurse(bs);
60
+ ret = bdrv_inactivate_recurse(bs, true);
61
if (ret < 0) {
62
bdrv_next_cleanup(&it);
63
break;
312
--
64
--
313
2.39.2
65
2.48.1
diff view generated by jsdifflib
1
bdrv_mirror_top_pwritev() accesses the job object when active mirroring
1
Putting an active block node on top of an inactive one is strictly
2
is enabled. It disables this code during early initialisation while
2
speaking an invalid configuration and the next patch will turn it into a
3
s->job isn't set yet.
3
hard error.
4
4
5
However, s->job is still set way too early when the job object isn't
5
However, taking a snapshot while disk images are inactive after
6
fully initialised. For example, &s->ops_in_flight isn't initialised yet
6
completing migration has an important use case: After migrating to a
7
and the in_flight bitmap doesn't exist yet. This causes crashes when a
7
file, taking an external snapshot is what is needed to take a full VM
8
write request comes in too early.
8
snapshot.
9
9
10
Move the assignment of s->job to when the mirror job is actually fully
10
In order for this to keep working after the later patches, change
11
initialised to make sure that the mirror_top driver doesn't access it
11
creating a snapshot such that it automatically inactivates an overlay
12
too early.
12
that is added on top of an already inactive node.
13
13
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
Message-Id: <20230203152202.49054-3-kwolf@redhat.com>
15
Acked-by: Fabiano Rosas <farosas@suse.de>
16
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
16
Reviewed-by: Eric Blake <eblake@redhat.com>
17
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
17
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
18
Message-ID: <20250204211407.381505-4-kwolf@redhat.com>
18
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
19
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
19
---
20
---
20
block/mirror.c | 8 +++++++-
21
blockdev.c | 16 ++++++++++++++++
21
1 file changed, 7 insertions(+), 1 deletion(-)
22
1 file changed, 16 insertions(+)
22
23
23
diff --git a/block/mirror.c b/block/mirror.c
24
diff --git a/blockdev.c b/blockdev.c
24
index XXXXXXX..XXXXXXX 100644
25
index XXXXXXX..XXXXXXX 100644
25
--- a/block/mirror.c
26
--- a/blockdev.c
26
+++ b/block/mirror.c
27
+++ b/blockdev.c
27
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn mirror_run(Job *job, Error **errp)
28
@@ -XXX,XX +XXX,XX @@ static void external_snapshot_action(TransactionAction *action,
28
{
29
return;
29
MirrorBlockJob *s = container_of(job, MirrorBlockJob, common.job);
30
BlockDriverState *bs = s->mirror_top_bs->backing->bs;
31
+ MirrorBDSOpaque *mirror_top_opaque = s->mirror_top_bs->opaque;
32
BlockDriverState *target_bs = blk_bs(s->target);
33
bool need_drain = true;
34
BlockDeviceIoStatus iostatus;
35
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn mirror_run(Job *job, Error **errp)
36
}
37
}
30
}
38
31
39
+ /*
32
+ /*
40
+ * Only now the job is fully initialised and mirror_top_bs should start
33
+ * Older QEMU versions have allowed adding an active parent node to an
41
+ * accessing it.
34
+ * inactive child node. This is unsafe in the general case, but there is an
35
+ * important use case, which is taking a VM snapshot with migration to file
36
+ * and then adding an external snapshot while the VM is still stopped and
37
+ * images are inactive. Requiring the user to explicitly create the overlay
38
+ * as inactive would break compatibility, so just do it automatically here
39
+ * to keep this working.
42
+ */
40
+ */
43
+ mirror_top_opaque->job = s;
41
+ if (bdrv_is_inactive(state->old_bs) && !bdrv_is_inactive(state->new_bs)) {
42
+ ret = bdrv_inactivate(state->new_bs, errp);
43
+ if (ret < 0) {
44
+ return;
45
+ }
46
+ }
44
+
47
+
45
assert(!s->dbi);
48
ret = bdrv_append(state->new_bs, state->old_bs, errp);
46
s->dbi = bdrv_dirty_iter_new(s->dirty_bitmap);
49
if (ret < 0) {
47
for (;;) {
50
return;
48
@@ -XXX,XX +XXX,XX @@ static BlockJob *mirror_start_job(
49
if (!s) {
50
goto fail;
51
}
52
- bs_opaque->job = s;
53
54
/* The block job now has a reference to this node */
55
bdrv_unref(mirror_top_bs);
56
--
51
--
57
2.39.2
52
2.48.1
diff view generated by jsdifflib
1
This adds GRAPH_RDLOCK annotations to declare that callers of
1
Block devices have an individual active state, a single global flag
2
bdrv_driver_*() need to hold a reader lock for the graph. It doesn't add
2
can't cover this correctly. This becomes more important as we allow
3
the annotation to public functions yet.
3
users to manually manage which nodes are active or inactive.
4
4
5
For some places, we know that they will hold the lock, but we don't have
5
Now that it's allowed to call bdrv_inactivate_all() even when some
6
the GRAPH_RDLOCK annotations yet. In this case, add assume_graph_lock()
6
nodes are already inactive, we can remove the flag and just
7
with a FIXME comment. These places will be removed once everything is
7
unconditionally call bdrv_inactivate_all() and, more importantly,
8
properly annotated.
8
bdrv_activate_all() before we make use of the nodes.
9
9
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Message-Id: <20230203152202.49054-11-kwolf@redhat.com>
11
Acked-by: Fabiano Rosas <farosas@suse.de>
12
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
12
Reviewed-by: Eric Blake <eblake@redhat.com>
13
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
14
Message-ID: <20250204211407.381505-5-kwolf@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
---
16
---
15
block/qcow2.h | 5 ++-
17
migration/migration.h | 3 ---
16
include/block/block_int-common.h | 40 ++++++++++---------
18
migration/block-active.c | 46 ----------------------------------------
17
block/io.c | 66 +++++++++++++++-----------------
19
migration/migration.c | 8 -------
18
block/parallels.c | 8 ++--
20
3 files changed, 57 deletions(-)
19
block/qcow.c | 20 ++++------
20
block/qcow2-cluster.c | 10 ++---
21
block/qcow2.c | 37 ++++++++++--------
22
block/qed.c | 14 +++----
23
block/quorum.c | 8 ++--
24
block/vmdk.c | 4 +-
25
10 files changed, 101 insertions(+), 111 deletions(-)
26
21
27
diff --git a/block/qcow2.h b/block/qcow2.h
22
diff --git a/migration/migration.h b/migration/migration.h
28
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
29
--- a/block/qcow2.h
24
--- a/migration/migration.h
30
+++ b/block/qcow2.h
25
+++ b/migration/migration.h
31
@@ -XXX,XX +XXX,XX @@ int coroutine_fn qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
26
@@ -XXX,XX +XXX,XX @@ void migration_bitmap_sync_precopy(bool last_stage);
32
void qcow2_parse_compressed_l2_entry(BlockDriverState *bs, uint64_t l2_entry,
27
void dirty_bitmap_mig_init(void);
33
uint64_t *coffset, int *csize);
28
bool should_send_vmdesc(void);
34
29
35
-int coroutine_fn qcow2_alloc_cluster_link_l2(BlockDriverState *bs,
30
-/* migration/block-active.c */
36
- QCowL2Meta *m);
31
-void migration_block_active_setup(bool active);
37
+int coroutine_fn GRAPH_RDLOCK
32
-
38
+qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m);
33
#endif
39
+
34
diff --git a/migration/block-active.c b/migration/block-active.c
40
void qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m);
41
int qcow2_cluster_discard(BlockDriverState *bs, uint64_t offset,
42
uint64_t bytes, enum qcow2_discard_type type,
43
diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
44
index XXXXXXX..XXXXXXX 100644
35
index XXXXXXX..XXXXXXX 100644
45
--- a/include/block/block_int-common.h
36
--- a/migration/block-active.c
46
+++ b/include/block/block_int-common.h
37
+++ b/migration/block-active.c
47
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
38
@@ -XXX,XX +XXX,XX @@
48
Error **errp);
39
#include "qemu/error-report.h"
49
40
#include "trace.h"
50
/* aio */
41
51
- BlockAIOCB *(*bdrv_aio_preadv)(BlockDriverState *bs,
42
-/*
52
+ BlockAIOCB * GRAPH_RDLOCK_PTR (*bdrv_aio_preadv)(BlockDriverState *bs,
43
- * Migration-only cache to remember the block layer activation status.
53
int64_t offset, int64_t bytes, QEMUIOVector *qiov,
44
- * Protected by BQL.
54
BdrvRequestFlags flags, BlockCompletionFunc *cb, void *opaque);
45
- *
55
- BlockAIOCB *(*bdrv_aio_pwritev)(BlockDriverState *bs,
46
- * We need this because..
56
+
47
- *
57
+ BlockAIOCB * GRAPH_RDLOCK_PTR (*bdrv_aio_pwritev)(BlockDriverState *bs,
48
- * - Migration can fail after block devices are invalidated (during
58
int64_t offset, int64_t bytes, QEMUIOVector *qiov,
49
- * switchover phase). When that happens, we need to be able to recover
59
BdrvRequestFlags flags, BlockCompletionFunc *cb, void *opaque);
50
- * the block drive status by re-activating them.
60
+
51
- *
61
BlockAIOCB * GRAPH_RDLOCK_PTR (*bdrv_aio_flush)(
52
- * - Currently bdrv_inactivate_all() is not safe to be invoked on top of
62
BlockDriverState *bs, BlockCompletionFunc *cb, void *opaque);
53
- * invalidated drives (even if bdrv_activate_all() is actually safe to be
63
54
- * called any time!). It means remembering this could help migration to
64
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
55
- * make sure it won't invalidate twice in a row, crashing QEMU. It can
65
BlockDriverState *bs, int64_t offset, int bytes,
56
- * happen when we migrate a PAUSED VM from host1 to host2, then migrate
66
BlockCompletionFunc *cb, void *opaque);
57
- * again to host3 without starting it. TODO: a cleaner solution is to
67
58
- * allow safe invoke of bdrv_inactivate_all() at anytime, like
68
- int coroutine_fn (*bdrv_co_readv)(BlockDriverState *bs,
59
- * bdrv_activate_all().
69
+ int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_readv)(BlockDriverState *bs,
60
- *
70
int64_t sector_num, int nb_sectors, QEMUIOVector *qiov);
61
- * For freshly started QEMU, the flag is initialized to TRUE reflecting the
71
62
- * scenario where QEMU owns block device ownerships.
72
/**
63
- *
73
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
64
- * For incoming QEMU taking a migration stream, the flag is initialized to
74
*
65
- * FALSE reflecting that the incoming side doesn't own the block devices,
75
* The buffer in @qiov may point directly to guest memory.
66
- * not until switchover happens.
76
*/
67
- */
77
- int coroutine_fn (*bdrv_co_preadv)(BlockDriverState *bs,
68
-static bool migration_block_active;
78
+ int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_preadv)(BlockDriverState *bs,
69
-
79
int64_t offset, int64_t bytes, QEMUIOVector *qiov,
70
-/* Setup the disk activation status */
80
BdrvRequestFlags flags);
71
-void migration_block_active_setup(bool active)
81
72
-{
82
- int coroutine_fn (*bdrv_co_preadv_part)(BlockDriverState *bs,
73
- migration_block_active = active;
83
- int64_t offset, int64_t bytes,
74
-}
84
+ int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_preadv_part)(
75
-
85
+ BlockDriverState *bs, int64_t offset, int64_t bytes,
76
bool migration_block_activate(Error **errp)
86
QEMUIOVector *qiov, size_t qiov_offset,
87
BdrvRequestFlags flags);
88
89
- int coroutine_fn (*bdrv_co_writev)(BlockDriverState *bs,
90
+ int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_writev)(BlockDriverState *bs,
91
int64_t sector_num, int nb_sectors, QEMUIOVector *qiov,
92
int flags);
93
/**
94
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
95
*
96
* The buffer in @qiov may point directly to guest memory.
97
*/
98
- int coroutine_fn (*bdrv_co_pwritev)(BlockDriverState *bs,
99
- int64_t offset, int64_t bytes, QEMUIOVector *qiov,
100
- BdrvRequestFlags flags);
101
- int coroutine_fn (*bdrv_co_pwritev_part)(BlockDriverState *bs,
102
- int64_t offset, int64_t bytes, QEMUIOVector *qiov, size_t qiov_offset,
103
+ int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_pwritev)(
104
+ BlockDriverState *bs, int64_t offset, int64_t bytes, QEMUIOVector *qiov,
105
BdrvRequestFlags flags);
106
+ int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_pwritev_part)(
107
+ BlockDriverState *bs, int64_t offset, int64_t bytes, QEMUIOVector *qiov,
108
+ size_t qiov_offset, BdrvRequestFlags flags);
109
110
/*
111
* Efficiently zero a region of the disk image. Typically an image format
112
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
113
BlockMeasureInfo *(*bdrv_measure)(QemuOpts *opts, BlockDriverState *in_bs,
114
Error **errp);
115
116
- int coroutine_fn (*bdrv_co_pwritev_compressed)(BlockDriverState *bs,
117
- int64_t offset, int64_t bytes, QEMUIOVector *qiov);
118
- int coroutine_fn (*bdrv_co_pwritev_compressed_part)(BlockDriverState *bs,
119
- int64_t offset, int64_t bytes, QEMUIOVector *qiov,
120
- size_t qiov_offset);
121
+ int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_pwritev_compressed)(
122
+ BlockDriverState *bs, int64_t offset, int64_t bytes,
123
+ QEMUIOVector *qiov);
124
+
125
+ int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_pwritev_compressed_part)(
126
+ BlockDriverState *bs, int64_t offset, int64_t bytes,
127
+ QEMUIOVector *qiov, size_t qiov_offset);
128
129
int coroutine_fn (*bdrv_co_get_info)(BlockDriverState *bs,
130
BlockDriverInfo *bdi);
131
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
132
BlockDriverState *bs, const char *name, Error **errp);
133
};
134
135
-static inline bool block_driver_can_compress(BlockDriver *drv)
136
+static inline bool TSA_NO_TSA block_driver_can_compress(BlockDriver *drv)
137
{
77
{
138
return drv->bdrv_co_pwritev_compressed ||
78
ERRP_GUARD();
139
drv->bdrv_co_pwritev_compressed_part;
79
140
diff --git a/block/io.c b/block/io.c
80
assert(bql_locked());
141
index XXXXXXX..XXXXXXX 100644
81
142
--- a/block/io.c
82
- if (migration_block_active) {
143
+++ b/block/io.c
83
- trace_migration_block_activation("active-skipped");
144
@@ -XXX,XX +XXX,XX @@ void bdrv_refresh_limits(BlockDriverState *bs, Transaction *tran, Error **errp)
84
- return true;
145
bool have_limits;
85
- }
146
147
GLOBAL_STATE_CODE();
148
+ assume_graph_lock(); /* FIXME */
149
150
if (tran) {
151
BdrvRefreshLimitsState *s = g_new(BdrvRefreshLimitsState, 1);
152
@@ -XXX,XX +XXX,XX @@ static void bdrv_co_io_em_complete(void *opaque, int ret)
153
aio_co_wake(co->coroutine);
154
}
155
156
-static int coroutine_fn bdrv_driver_preadv(BlockDriverState *bs,
157
- int64_t offset, int64_t bytes,
158
- QEMUIOVector *qiov,
159
- size_t qiov_offset, int flags)
160
+static int coroutine_fn GRAPH_RDLOCK
161
+bdrv_driver_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
162
+ QEMUIOVector *qiov, size_t qiov_offset, int flags)
163
{
164
BlockDriver *drv = bs->drv;
165
int64_t sector_num;
166
@@ -XXX,XX +XXX,XX @@ out:
167
return ret;
168
}
169
170
-static int coroutine_fn bdrv_driver_pwritev(BlockDriverState *bs,
171
- int64_t offset, int64_t bytes,
172
- QEMUIOVector *qiov,
173
- size_t qiov_offset,
174
- BdrvRequestFlags flags)
175
+static int coroutine_fn GRAPH_RDLOCK
176
+bdrv_driver_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes,
177
+ QEMUIOVector *qiov, size_t qiov_offset,
178
+ BdrvRequestFlags flags)
179
{
180
BlockDriver *drv = bs->drv;
181
bool emulate_fua = false;
182
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_driver_pwritev(BlockDriverState *bs,
183
QEMUIOVector local_qiov;
184
int ret;
185
186
- assume_graph_lock(); /* FIXME */
187
-
86
-
188
bdrv_check_qiov_request(offset, bytes, qiov, qiov_offset, &error_abort);
87
trace_migration_block_activation("active");
189
88
190
if (!drv) {
89
bdrv_activate_all(errp);
191
@@ -XXX,XX +XXX,XX @@ emulate_flags:
90
@@ -XXX,XX +XXX,XX @@ bool migration_block_activate(Error **errp)
192
return ret;
91
return false;
193
}
92
}
194
93
195
-static int coroutine_fn
94
- migration_block_active = true;
196
+static int coroutine_fn GRAPH_RDLOCK
197
bdrv_driver_pwritev_compressed(BlockDriverState *bs, int64_t offset,
198
int64_t bytes, QEMUIOVector *qiov,
199
size_t qiov_offset)
200
@@ -XXX,XX +XXX,XX @@ bdrv_driver_pwritev_compressed(BlockDriverState *bs, int64_t offset,
201
return ret;
202
}
203
204
-static int coroutine_fn bdrv_co_do_copy_on_readv(BdrvChild *child,
205
- int64_t offset, int64_t bytes, QEMUIOVector *qiov,
206
- size_t qiov_offset, int flags)
207
+static int coroutine_fn GRAPH_RDLOCK
208
+bdrv_co_do_copy_on_readv(BdrvChild *child, int64_t offset, int64_t bytes,
209
+ QEMUIOVector *qiov, size_t qiov_offset, int flags)
210
{
211
BlockDriverState *bs = child->bs;
212
213
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_do_copy_on_readv(BdrvChild *child,
214
int64_t progress = 0;
215
bool skip_write;
216
217
- assume_graph_lock(); /* FIXME */
218
-
219
bdrv_check_qiov_request(offset, bytes, qiov, qiov_offset, &error_abort);
220
221
if (!drv) {
222
@@ -XXX,XX +XXX,XX @@ err:
223
* handles copy on read, zeroing after EOF, and fragmentation of large
224
* reads; any other features must be implemented by the caller.
225
*/
226
-static int coroutine_fn bdrv_aligned_preadv(BdrvChild *child,
227
- BdrvTrackedRequest *req, int64_t offset, int64_t bytes,
228
- int64_t align, QEMUIOVector *qiov, size_t qiov_offset, int flags)
229
+static int coroutine_fn GRAPH_RDLOCK
230
+bdrv_aligned_preadv(BdrvChild *child, BdrvTrackedRequest *req,
231
+ int64_t offset, int64_t bytes, int64_t align,
232
+ QEMUIOVector *qiov, size_t qiov_offset, int flags)
233
{
234
BlockDriverState *bs = child->bs;
235
int64_t total_bytes, max_bytes;
236
@@ -XXX,XX +XXX,XX @@ static bool bdrv_init_padding(BlockDriverState *bs,
237
return true;
95
return true;
238
}
96
}
239
97
240
-static coroutine_fn int bdrv_padding_rmw_read(BdrvChild *child,
98
@@ -XXX,XX +XXX,XX @@ bool migration_block_inactivate(void)
241
- BdrvTrackedRequest *req,
99
242
- BdrvRequestPadding *pad,
100
assert(bql_locked());
243
- bool zero_middle)
101
244
+static int coroutine_fn GRAPH_RDLOCK
102
- if (!migration_block_active) {
245
+bdrv_padding_rmw_read(BdrvChild *child, BdrvTrackedRequest *req,
103
- trace_migration_block_activation("inactive-skipped");
246
+ BdrvRequestPadding *pad, bool zero_middle)
104
- return true;
247
{
105
- }
248
QEMUIOVector local_qiov;
249
BlockDriverState *bs = child->bs;
250
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_preadv_part(BdrvChild *child,
251
int ret;
252
IO_CODE();
253
254
+ assume_graph_lock(); /* FIXME */
255
+
256
trace_bdrv_co_preadv_part(bs, offset, bytes, flags);
257
258
if (!bdrv_co_is_inserted(bs)) {
259
@@ -XXX,XX +XXX,XX @@ bdrv_co_write_req_finish(BdrvChild *child, int64_t offset, int64_t bytes,
260
* Forwards an already correctly aligned write request to the BlockDriver,
261
* after possibly fragmenting it.
262
*/
263
-static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child,
264
- BdrvTrackedRequest *req, int64_t offset, int64_t bytes,
265
- int64_t align, QEMUIOVector *qiov, size_t qiov_offset,
266
- BdrvRequestFlags flags)
267
+static int coroutine_fn GRAPH_RDLOCK
268
+bdrv_aligned_pwritev(BdrvChild *child, BdrvTrackedRequest *req,
269
+ int64_t offset, int64_t bytes, int64_t align,
270
+ QEMUIOVector *qiov, size_t qiov_offset,
271
+ BdrvRequestFlags flags)
272
{
273
BlockDriverState *bs = child->bs;
274
BlockDriver *drv = bs->drv;
275
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child,
276
int64_t bytes_remaining = bytes;
277
int max_transfer;
278
279
- assume_graph_lock(); /* FIXME */
280
-
106
-
281
bdrv_check_qiov_request(offset, bytes, qiov, qiov_offset, &error_abort);
107
trace_migration_block_activation("inactive");
282
108
283
if (!drv) {
109
ret = bdrv_inactivate_all();
284
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child,
110
@@ -XXX,XX +XXX,XX @@ bool migration_block_inactivate(void)
285
return ret;
111
return false;
112
}
113
114
- migration_block_active = false;
115
return true;
286
}
116
}
287
117
diff --git a/migration/migration.c b/migration/migration.c
288
-static int coroutine_fn bdrv_co_do_zero_pwritev(BdrvChild *child,
289
- int64_t offset,
290
- int64_t bytes,
291
- BdrvRequestFlags flags,
292
- BdrvTrackedRequest *req)
293
+static int coroutine_fn GRAPH_RDLOCK
294
+bdrv_co_do_zero_pwritev(BdrvChild *child, int64_t offset, int64_t bytes,
295
+ BdrvRequestFlags flags, BdrvTrackedRequest *req)
296
{
297
BlockDriverState *bs = child->bs;
298
QEMUIOVector local_qiov;
299
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_pwritev_part(BdrvChild *child,
300
bool padded = false;
301
IO_CODE();
302
303
+ assume_graph_lock(); /* FIXME */
304
+
305
trace_bdrv_co_pwritev_part(child->bs, offset, bytes, flags);
306
307
if (!bdrv_co_is_inserted(bs)) {
308
diff --git a/block/parallels.c b/block/parallels.c
309
index XXXXXXX..XXXXXXX 100644
118
index XXXXXXX..XXXXXXX 100644
310
--- a/block/parallels.c
119
--- a/migration/migration.c
311
+++ b/block/parallels.c
120
+++ b/migration/migration.c
312
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn parallels_co_block_status(BlockDriverState *bs,
121
@@ -XXX,XX +XXX,XX @@ void qmp_migrate_incoming(const char *uri, bool has_channels,
313
return BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID;
122
return;
123
}
124
125
- /*
126
- * Newly setup incoming QEMU. Mark the block active state to reflect
127
- * that the src currently owns the disks.
128
- */
129
- migration_block_active_setup(false);
130
-
131
once = false;
314
}
132
}
315
133
316
-static coroutine_fn int parallels_co_writev(BlockDriverState *bs,
134
@@ -XXX,XX +XXX,XX @@ static void migration_instance_init(Object *obj)
317
- int64_t sector_num, int nb_sectors,
135
ms->state = MIGRATION_STATUS_NONE;
318
- QEMUIOVector *qiov, int flags)
136
ms->mbps = -1;
319
+static int coroutine_fn GRAPH_RDLOCK
137
ms->pages_per_second = -1;
320
+parallels_co_writev(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
138
- /* Freshly started QEMU owns all the block devices */
321
+ QEMUIOVector *qiov, int flags)
139
- migration_block_active_setup(true);
322
{
140
qemu_sem_init(&ms->pause_sem, 0);
323
BDRVParallelsState *s = bs->opaque;
141
qemu_mutex_init(&ms->error_mutex);
324
uint64_t bytes_done = 0;
142
325
QEMUIOVector hd_qiov;
326
int ret = 0;
327
328
- assume_graph_lock(); /* FIXME */
329
-
330
qemu_iovec_init(&hd_qiov, qiov->niov);
331
332
while (nb_sectors > 0) {
333
diff --git a/block/qcow.c b/block/qcow.c
334
index XXXXXXX..XXXXXXX 100644
335
--- a/block/qcow.c
336
+++ b/block/qcow.c
337
@@ -XXX,XX +XXX,XX @@ static void qcow_refresh_limits(BlockDriverState *bs, Error **errp)
338
bs->bl.request_alignment = BDRV_SECTOR_SIZE;
339
}
340
341
-static coroutine_fn int qcow_co_preadv(BlockDriverState *bs, int64_t offset,
342
- int64_t bytes, QEMUIOVector *qiov,
343
- BdrvRequestFlags flags)
344
+static int coroutine_fn GRAPH_RDLOCK
345
+qcow_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
346
+ QEMUIOVector *qiov, BdrvRequestFlags flags)
347
{
348
BDRVQcowState *s = bs->opaque;
349
int offset_in_cluster;
350
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow_co_preadv(BlockDriverState *bs, int64_t offset,
351
uint8_t *buf;
352
void *orig_buf;
353
354
- assume_graph_lock(); /* FIXME */
355
-
356
if (qiov->niov > 1) {
357
buf = orig_buf = qemu_try_blockalign(bs, qiov->size);
358
if (buf == NULL) {
359
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow_co_preadv(BlockDriverState *bs, int64_t offset,
360
return ret;
361
}
362
363
-static coroutine_fn int qcow_co_pwritev(BlockDriverState *bs, int64_t offset,
364
- int64_t bytes, QEMUIOVector *qiov,
365
- BdrvRequestFlags flags)
366
+static int coroutine_fn GRAPH_RDLOCK
367
+qcow_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes,
368
+ QEMUIOVector *qiov, BdrvRequestFlags flags)
369
{
370
BDRVQcowState *s = bs->opaque;
371
int offset_in_cluster;
372
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow_co_pwritev(BlockDriverState *bs, int64_t offset,
373
uint8_t *buf;
374
void *orig_buf;
375
376
- assume_graph_lock(); /* FIXME */
377
-
378
s->cluster_cache_offset = -1; /* disable compressed cache */
379
380
/* We must always copy the iov when encrypting, so we
381
@@ -XXX,XX +XXX,XX @@ static int qcow_make_empty(BlockDriverState *bs)
382
383
/* XXX: put compressed sectors first, then all the cluster aligned
384
tables to avoid losing bytes in alignment */
385
-static coroutine_fn int
386
+static int coroutine_fn GRAPH_RDLOCK
387
qcow_co_pwritev_compressed(BlockDriverState *bs, int64_t offset, int64_t bytes,
388
QEMUIOVector *qiov)
389
{
390
@@ -XXX,XX +XXX,XX @@ qcow_co_pwritev_compressed(BlockDriverState *bs, int64_t offset, int64_t bytes,
391
uint8_t *buf, *out_buf;
392
uint64_t cluster_offset;
393
394
- assume_graph_lock(); /* FIXME */
395
-
396
buf = qemu_blockalign(bs, s->cluster_size);
397
if (bytes != s->cluster_size) {
398
if (bytes > s->cluster_size ||
399
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
400
index XXXXXXX..XXXXXXX 100644
401
--- a/block/qcow2-cluster.c
402
+++ b/block/qcow2-cluster.c
403
@@ -XXX,XX +XXX,XX @@ static int count_contiguous_subclusters(BlockDriverState *bs, int nb_clusters,
404
return count;
405
}
406
407
-static int coroutine_fn do_perform_cow_read(BlockDriverState *bs,
408
- uint64_t src_cluster_offset,
409
- unsigned offset_in_cluster,
410
- QEMUIOVector *qiov)
411
+static int coroutine_fn GRAPH_RDLOCK
412
+do_perform_cow_read(BlockDriverState *bs, uint64_t src_cluster_offset,
413
+ unsigned offset_in_cluster, QEMUIOVector *qiov)
414
{
415
int ret;
416
417
@@ -XXX,XX +XXX,XX @@ int coroutine_fn qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
418
return 0;
419
}
420
421
-static int coroutine_fn perform_cow(BlockDriverState *bs, QCowL2Meta *m)
422
+static int coroutine_fn GRAPH_RDLOCK
423
+perform_cow(BlockDriverState *bs, QCowL2Meta *m)
424
{
425
BDRVQcow2State *s = bs->opaque;
426
Qcow2COWRegion *start = &m->cow_start;
427
diff --git a/block/qcow2.c b/block/qcow2.c
428
index XXXXXXX..XXXXXXX 100644
429
--- a/block/qcow2.c
430
+++ b/block/qcow2.c
431
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_block_status(BlockDriverState *bs,
432
return status;
433
}
434
435
-static coroutine_fn int qcow2_handle_l2meta(BlockDriverState *bs,
436
- QCowL2Meta **pl2meta,
437
- bool link_l2)
438
+static int coroutine_fn GRAPH_RDLOCK
439
+qcow2_handle_l2meta(BlockDriverState *bs, QCowL2Meta **pl2meta, bool link_l2)
440
{
441
int ret = 0;
442
QCowL2Meta *l2meta = *pl2meta;
443
@@ -XXX,XX +XXX,XX @@ static coroutine_fn GRAPH_RDLOCK int qcow2_co_pwritev_task_entry(AioTask *task)
444
t->l2meta);
445
}
446
447
-static coroutine_fn int qcow2_co_pwritev_part(
448
- BlockDriverState *bs, int64_t offset, int64_t bytes,
449
- QEMUIOVector *qiov, size_t qiov_offset, BdrvRequestFlags flags)
450
+static int coroutine_fn GRAPH_RDLOCK
451
+qcow2_co_pwritev_part(BlockDriverState *bs, int64_t offset, int64_t bytes,
452
+ QEMUIOVector *qiov, size_t qiov_offset,
453
+ BdrvRequestFlags flags)
454
{
455
BDRVQcow2State *s = bs->opaque;
456
int offset_in_cluster;
457
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pwritev_part(
458
QCowL2Meta *l2meta = NULL;
459
AioTaskPool *aio = NULL;
460
461
- assume_graph_lock(); /* FIXME */
462
-
463
trace_qcow2_writev_start_req(qemu_coroutine_self(), offset, bytes);
464
465
while (bytes != 0 && aio_task_pool_status(aio) == 0) {
466
@@ -XXX,XX +XXX,XX @@ qcow2_co_copy_range_to(BlockDriverState *bs,
467
uint64_t host_offset;
468
QCowL2Meta *l2meta = NULL;
469
470
+ assume_graph_lock(); /* FIXME */
471
assert(!bs->encrypted);
472
473
qemu_co_mutex_lock(&s->lock);
474
@@ -XXX,XX +XXX,XX @@ fail:
475
return ret;
476
}
477
478
-static coroutine_fn int
479
+static int coroutine_fn GRAPH_RDLOCK
480
qcow2_co_pwritev_compressed_task(BlockDriverState *bs,
481
uint64_t offset, uint64_t bytes,
482
QEMUIOVector *qiov, size_t qiov_offset)
483
@@ -XXX,XX +XXX,XX @@ fail:
484
return ret;
485
}
486
487
-static coroutine_fn int qcow2_co_pwritev_compressed_task_entry(AioTask *task)
488
+/*
489
+ * This function can count as GRAPH_RDLOCK because
490
+ * qcow2_co_pwritev_compressed_part() holds the graph lock and keeps it until
491
+ * this coroutine has terminated.
492
+ */
493
+static int coroutine_fn GRAPH_RDLOCK
494
+qcow2_co_pwritev_compressed_task_entry(AioTask *task)
495
{
496
Qcow2AioTask *t = container_of(task, Qcow2AioTask, task);
497
498
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pwritev_compressed_task_entry(AioTask *task)
499
* XXX: put compressed sectors first, then all the cluster aligned
500
* tables to avoid losing bytes in alignment
501
*/
502
-static coroutine_fn int
503
+static int coroutine_fn GRAPH_RDLOCK
504
qcow2_co_pwritev_compressed_part(BlockDriverState *bs,
505
int64_t offset, int64_t bytes,
506
QEMUIOVector *qiov, size_t qiov_offset)
507
@@ -XXX,XX +XXX,XX @@ qcow2_co_pwritev_compressed_part(BlockDriverState *bs,
508
AioTaskPool *aio = NULL;
509
int ret = 0;
510
511
- assume_graph_lock(); /* FIXME */
512
-
513
if (has_data_file(bs)) {
514
return -ENOTSUP;
515
}
516
@@ -XXX,XX +XXX,XX @@ static int64_t qcow2_check_vmstate_request(BlockDriverState *bs,
517
return pos;
518
}
519
520
-static coroutine_fn int qcow2_co_save_vmstate(BlockDriverState *bs,
521
- QEMUIOVector *qiov, int64_t pos)
522
+static int coroutine_fn GRAPH_RDLOCK
523
+qcow2_co_save_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos)
524
{
525
int64_t offset = qcow2_check_vmstate_request(bs, qiov, pos);
526
if (offset < 0) {
527
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_save_vmstate(BlockDriverState *bs,
528
return bs->drv->bdrv_co_pwritev_part(bs, offset, qiov->size, qiov, 0, 0);
529
}
530
531
-static coroutine_fn int qcow2_co_load_vmstate(BlockDriverState *bs,
532
- QEMUIOVector *qiov, int64_t pos)
533
+static int coroutine_fn GRAPH_RDLOCK
534
+qcow2_co_load_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos)
535
{
536
int64_t offset = qcow2_check_vmstate_request(bs, qiov, pos);
537
if (offset < 0) {
538
diff --git a/block/qed.c b/block/qed.c
539
index XXXXXXX..XXXXXXX 100644
540
--- a/block/qed.c
541
+++ b/block/qed.c
542
@@ -XXX,XX +XXX,XX @@ qed_co_request(BlockDriverState *bs, int64_t sector_num, QEMUIOVector *qiov,
543
return qed_aio_next_io(&acb);
544
}
545
546
-static int coroutine_fn bdrv_qed_co_readv(BlockDriverState *bs,
547
- int64_t sector_num, int nb_sectors,
548
- QEMUIOVector *qiov)
549
+static int coroutine_fn GRAPH_RDLOCK
550
+bdrv_qed_co_readv(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
551
+ QEMUIOVector *qiov)
552
{
553
- assume_graph_lock(); /* FIXME */
554
return qed_co_request(bs, sector_num, qiov, nb_sectors, 0);
555
}
556
557
-static int coroutine_fn bdrv_qed_co_writev(BlockDriverState *bs,
558
- int64_t sector_num, int nb_sectors,
559
- QEMUIOVector *qiov, int flags)
560
+static int coroutine_fn GRAPH_RDLOCK
561
+bdrv_qed_co_writev(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
562
+ QEMUIOVector *qiov, int flags)
563
{
564
- assume_graph_lock(); /* FIXME */
565
return qed_co_request(bs, sector_num, qiov, nb_sectors, QED_AIOCB_WRITE);
566
}
567
568
diff --git a/block/quorum.c b/block/quorum.c
569
index XXXXXXX..XXXXXXX 100644
570
--- a/block/quorum.c
571
+++ b/block/quorum.c
572
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn GRAPH_RDLOCK write_quorum_entry(void *opaque)
573
}
574
}
575
576
-static int coroutine_fn quorum_co_pwritev(BlockDriverState *bs, int64_t offset,
577
- int64_t bytes, QEMUIOVector *qiov,
578
- BdrvRequestFlags flags)
579
+static int coroutine_fn GRAPH_RDLOCK
580
+quorum_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes,
581
+ QEMUIOVector *qiov, BdrvRequestFlags flags)
582
{
583
BDRVQuorumState *s = bs->opaque;
584
QuorumAIOCB *acb = quorum_aio_get(bs, qiov, offset, bytes, flags);
585
int i, ret;
586
587
- assume_graph_lock(); /* FIXME */
588
-
589
for (i = 0; i < s->num_children; i++) {
590
Coroutine *co;
591
QuorumCo data = {
592
diff --git a/block/vmdk.c b/block/vmdk.c
593
index XXXXXXX..XXXXXXX 100644
594
--- a/block/vmdk.c
595
+++ b/block/vmdk.c
596
@@ -XXX,XX +XXX,XX @@ vmdk_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes,
597
return ret;
598
}
599
600
-static int coroutine_fn
601
+static int coroutine_fn GRAPH_RDLOCK
602
vmdk_co_pwritev_compressed(BlockDriverState *bs, int64_t offset, int64_t bytes,
603
QEMUIOVector *qiov)
604
{
605
- assume_graph_lock(); /* FIXME */
606
-
607
if (bytes == 0) {
608
/* The caller will write bytes 0 to signal EOF.
609
* When receive it, we align EOF to a sector boundary. */
610
--
143
--
611
2.39.2
144
2.48.1
diff view generated by jsdifflib
1
This adds GRAPH_RDLOCK annotations to declare that callers of
1
An active node makes unrestricted use of its children and would possibly
2
bdrv_co_delete_file() need to hold a reader lock for the graph.
2
run into assertion failures when it operates on an inactive child node.
3
3
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Message-Id: <20230203152202.49054-22-kwolf@redhat.com>
5
Acked-by: Fabiano Rosas <farosas@suse.de>
6
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
8
Message-ID: <20250204211407.381505-6-kwolf@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
---
10
---
9
include/block/block-io.h | 8 ++++++--
11
block.c | 5 +++++
10
include/block/block_int-common.h | 4 ++--
12
1 file changed, 5 insertions(+)
11
block.c | 1 +
12
3 files changed, 9 insertions(+), 4 deletions(-)
13
13
14
diff --git a/include/block/block-io.h b/include/block/block-io.h
15
index XXXXXXX..XXXXXXX 100644
16
--- a/include/block/block-io.h
17
+++ b/include/block/block-io.h
18
@@ -XXX,XX +XXX,XX @@ int64_t co_wrapper bdrv_get_allocated_file_size(BlockDriverState *bs);
19
BlockMeasureInfo *bdrv_measure(BlockDriver *drv, QemuOpts *opts,
20
BlockDriverState *in_bs, Error **errp);
21
void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr);
22
-int coroutine_fn bdrv_co_delete_file(BlockDriverState *bs, Error **errp);
23
-void coroutine_fn bdrv_co_delete_file_noerr(BlockDriverState *bs);
24
+
25
+int coroutine_fn GRAPH_RDLOCK
26
+bdrv_co_delete_file(BlockDriverState *bs, Error **errp);
27
+
28
+void coroutine_fn GRAPH_RDLOCK
29
+bdrv_co_delete_file_noerr(BlockDriverState *bs);
30
31
32
/* async block I/O */
33
diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
34
index XXXXXXX..XXXXXXX 100644
35
--- a/include/block/block_int-common.h
36
+++ b/include/block/block_int-common.h
37
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
38
int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_flush)(BlockDriverState *bs);
39
40
/* Delete a created file. */
41
- int coroutine_fn (*bdrv_co_delete_file)(BlockDriverState *bs,
42
- Error **errp);
43
+ int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_delete_file)(
44
+ BlockDriverState *bs, Error **errp);
45
46
/*
47
* Flushes all data that was already written to the OS all the way down to
48
diff --git a/block.c b/block.c
14
diff --git a/block.c b/block.c
49
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
50
--- a/block.c
16
--- a/block.c
51
+++ b/block.c
17
+++ b/block.c
52
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_delete_file(BlockDriverState *bs, Error **errp)
18
@@ -XXX,XX +XXX,XX @@ bdrv_attach_child_noperm(BlockDriverState *parent_bs,
53
19
child_bs->node_name, child_name, parent_bs->node_name);
54
IO_CODE();
20
return NULL;
55
assert(bs != NULL);
21
}
56
+ assert_bdrv_graph_readable();
22
+ if (bdrv_is_inactive(child_bs) && !bdrv_is_inactive(parent_bs)) {
57
23
+ error_setg(errp, "Inactive '%s' can't be a %s child of active '%s'",
58
if (!bs->drv) {
24
+ child_bs->node_name, child_name, parent_bs->node_name);
59
error_setg(errp, "Block node '%s' is not opened", bs->filename);
25
+ return NULL;
26
+ }
27
28
bdrv_get_cumulative_perm(parent_bs, &perm, &shared_perm);
29
bdrv_child_perm(parent_bs, child_bs, NULL, child_role, NULL,
60
--
30
--
61
2.39.2
31
2.48.1
diff view generated by jsdifflib
1
From: Emanuele Giuseppe Esposito <eesposit@redhat.com>
1
In order for block_resize to fail gracefully on an inactive node instead
2
of crashing with an assertion failure in bdrv_co_write_req_prepare()
3
(called from bdrv_co_truncate()), we need to check for inactive nodes
4
also when they are attached as a root node and make sure that
5
BLK_PERM_RESIZE isn't among the permissions allowed for inactive nodes.
6
To this effect, don't enumerate the permissions that are incompatible
7
with inactive nodes any more, but allow only BLK_PERM_CONSISTENT_READ
8
for them.
2
9
3
This adds GRAPH_RDLOCK annotations to declare that callers of
4
bdrv_co_is_inserted() need to hold a reader lock for the graph.
5
6
blk_is_inserted() is done as a co_wrapper_mixed_bdrv_rdlock (unlike most
7
other blk_* functions) because it is called a lot from other blk_co_*()
8
functions that already hold the lock. These calls go through
9
blk_is_available(), which becomes a co_wrapper_mixed_bdrv_rdlock, too,
10
for the same reason.
11
12
Functions that run in a coroutine and can call bdrv_co_is_available()
13
directly are changed to do so, which results in better TSA coverage.
14
15
Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
Message-Id: <20230203152202.49054-19-kwolf@redhat.com>
11
Acked-by: Fabiano Rosas <farosas@suse.de>
18
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
12
Reviewed-by: Eric Blake <eblake@redhat.com>
13
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
14
Message-ID: <20250204211407.381505-7-kwolf@redhat.com>
19
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
20
---
16
---
21
include/block/block-io.h | 4 ++--
17
block.c | 7 +++++++
22
include/block/block_int-common.h | 3 ++-
18
block/block-backend.c | 2 +-
23
include/sysemu/block-backend-io.h | 7 ++++---
19
2 files changed, 8 insertions(+), 1 deletion(-)
24
block.c | 1 +
25
block/block-backend.c | 25 ++++++++++++++-----------
26
5 files changed, 23 insertions(+), 17 deletions(-)
27
20
28
diff --git a/include/block/block-io.h b/include/block/block-io.h
29
index XXXXXXX..XXXXXXX 100644
30
--- a/include/block/block-io.h
31
+++ b/include/block/block-io.h
32
@@ -XXX,XX +XXX,XX @@ bool bdrv_is_writable(BlockDriverState *bs);
33
bool bdrv_is_sg(BlockDriverState *bs);
34
int bdrv_get_flags(BlockDriverState *bs);
35
36
-bool coroutine_fn bdrv_co_is_inserted(BlockDriverState *bs);
37
-bool co_wrapper bdrv_is_inserted(BlockDriverState *bs);
38
+bool coroutine_fn GRAPH_RDLOCK bdrv_co_is_inserted(BlockDriverState *bs);
39
+bool co_wrapper_bdrv_rdlock bdrv_is_inserted(BlockDriverState *bs);
40
41
void coroutine_fn bdrv_co_lock_medium(BlockDriverState *bs, bool locked);
42
void coroutine_fn bdrv_co_eject(BlockDriverState *bs, bool eject_flag);
43
diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
44
index XXXXXXX..XXXXXXX 100644
45
--- a/include/block/block_int-common.h
46
+++ b/include/block/block_int-common.h
47
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
48
BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos);
49
50
/* removable device specific */
51
- bool coroutine_fn (*bdrv_co_is_inserted)(BlockDriverState *bs);
52
+ bool coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_is_inserted)(
53
+ BlockDriverState *bs);
54
void coroutine_fn (*bdrv_co_eject)(BlockDriverState *bs, bool eject_flag);
55
void coroutine_fn (*bdrv_co_lock_medium)(BlockDriverState *bs, bool locked);
56
57
diff --git a/include/sysemu/block-backend-io.h b/include/sysemu/block-backend-io.h
58
index XXXXXXX..XXXXXXX 100644
59
--- a/include/sysemu/block-backend-io.h
60
+++ b/include/sysemu/block-backend-io.h
61
@@ -XXX,XX +XXX,XX @@ BlockAIOCB *blk_aio_ioctl(BlockBackend *blk, unsigned long int req, void *buf,
62
void blk_inc_in_flight(BlockBackend *blk);
63
void blk_dec_in_flight(BlockBackend *blk);
64
65
-bool coroutine_fn blk_co_is_inserted(BlockBackend *blk);
66
-bool co_wrapper_mixed blk_is_inserted(BlockBackend *blk);
67
+bool coroutine_fn GRAPH_RDLOCK blk_co_is_inserted(BlockBackend *blk);
68
+bool co_wrapper_mixed_bdrv_rdlock blk_is_inserted(BlockBackend *blk);
69
70
-bool blk_is_available(BlockBackend *blk);
71
+bool coroutine_fn GRAPH_RDLOCK blk_co_is_available(BlockBackend *blk);
72
+bool co_wrapper_mixed_bdrv_rdlock blk_is_available(BlockBackend *blk);
73
74
void coroutine_fn blk_co_lock_medium(BlockBackend *blk, bool locked);
75
void co_wrapper blk_lock_medium(BlockBackend *blk, bool locked);
76
diff --git a/block.c b/block.c
21
diff --git a/block.c b/block.c
77
index XXXXXXX..XXXXXXX 100644
22
index XXXXXXX..XXXXXXX 100644
78
--- a/block.c
23
--- a/block.c
79
+++ b/block.c
24
+++ b/block.c
80
@@ -XXX,XX +XXX,XX @@ bool coroutine_fn bdrv_co_is_inserted(BlockDriverState *bs)
25
@@ -XXX,XX +XXX,XX @@ bdrv_attach_child_common(BlockDriverState *child_bs,
81
BlockDriver *drv = bs->drv;
26
assert(child_class->get_parent_desc);
82
BdrvChild *child;
27
GLOBAL_STATE_CODE();
83
IO_CODE();
28
84
+ assert_bdrv_graph_readable();
29
+ if (bdrv_is_inactive(child_bs) && (perm & ~BLK_PERM_CONSISTENT_READ)) {
85
30
+ g_autofree char *perm_names = bdrv_perm_names(perm);
86
if (!drv) {
31
+ error_setg(errp, "Permission '%s' unavailable on inactive node",
87
return false;
32
+ perm_names);
33
+ return NULL;
34
+ }
35
+
36
new_child = g_new(BdrvChild, 1);
37
*new_child = (BdrvChild) {
38
.bs = NULL,
88
diff --git a/block/block-backend.c b/block/block-backend.c
39
diff --git a/block/block-backend.c b/block/block-backend.c
89
index XXXXXXX..XXXXXXX 100644
40
index XXXXXXX..XXXXXXX 100644
90
--- a/block/block-backend.c
41
--- a/block/block-backend.c
91
+++ b/block/block-backend.c
42
+++ b/block/block-backend.c
92
@@ -XXX,XX +XXX,XX @@ void blk_set_disable_request_queuing(BlockBackend *blk, bool disable)
43
@@ -XXX,XX +XXX,XX @@ static bool blk_can_inactivate(BlockBackend *blk)
93
blk->disable_request_queuing = disable;
44
* guest. For block job BBs that satisfy this, we can just allow
94
}
45
* it. This is the case for mirror job source, which is required
95
46
* by libvirt non-shared block migration. */
96
-static coroutine_fn int blk_check_byte_request(BlockBackend *blk,
47
- if (!(blk->perm & (BLK_PERM_WRITE | BLK_PERM_WRITE_UNCHANGED))) {
97
- int64_t offset, int64_t bytes)
48
+ if (!(blk->perm & ~BLK_PERM_CONSISTENT_READ)) {
98
+static int coroutine_fn GRAPH_RDLOCK
49
return true;
99
+blk_check_byte_request(BlockBackend *blk, int64_t offset, int64_t bytes)
100
{
101
int64_t len;
102
103
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int blk_check_byte_request(BlockBackend *blk,
104
return -EIO;
105
}
50
}
106
51
107
- if (!blk_is_available(blk)) {
108
+ if (!blk_co_is_available(blk)) {
109
return -ENOMEDIUM;
110
}
111
112
@@ -XXX,XX +XXX,XX @@ BlockAIOCB *blk_aio_pwrite_zeroes(BlockBackend *blk, int64_t offset,
113
int64_t coroutine_fn blk_co_getlength(BlockBackend *blk)
114
{
115
IO_CODE();
116
+ GRAPH_RDLOCK_GUARD();
117
118
- if (!blk_is_available(blk)) {
119
+ if (!blk_co_is_available(blk)) {
120
return -ENOMEDIUM;
121
}
122
123
@@ -XXX,XX +XXX,XX @@ void blk_get_geometry(BlockBackend *blk, uint64_t *nb_sectors_ptr)
124
int64_t coroutine_fn blk_co_nb_sectors(BlockBackend *blk)
125
{
126
IO_CODE();
127
+ GRAPH_RDLOCK_GUARD();
128
129
- if (!blk_is_available(blk)) {
130
+ if (!blk_co_is_available(blk)) {
131
return -ENOMEDIUM;
132
}
133
134
@@ -XXX,XX +XXX,XX @@ blk_co_do_ioctl(BlockBackend *blk, unsigned long int req, void *buf)
135
blk_wait_while_drained(blk);
136
GRAPH_RDLOCK_GUARD();
137
138
- if (!blk_is_available(blk)) {
139
+ if (!blk_co_is_available(blk)) {
140
return -ENOMEDIUM;
141
}
142
143
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn blk_co_do_flush(BlockBackend *blk)
144
blk_wait_while_drained(blk);
145
GRAPH_RDLOCK_GUARD();
146
147
- if (!blk_is_available(blk)) {
148
+ if (!blk_co_is_available(blk)) {
149
return -ENOMEDIUM;
150
}
151
152
@@ -XXX,XX +XXX,XX @@ bool coroutine_fn blk_co_is_inserted(BlockBackend *blk)
153
{
154
BlockDriverState *bs = blk_bs(blk);
155
IO_CODE();
156
+ assert_bdrv_graph_readable();
157
158
return bs && bdrv_co_is_inserted(bs);
159
}
160
161
-bool blk_is_available(BlockBackend *blk)
162
+bool coroutine_fn blk_co_is_available(BlockBackend *blk)
163
{
164
IO_CODE();
165
- return blk_is_inserted(blk) && !blk_dev_is_tray_open(blk);
166
+ return blk_co_is_inserted(blk) && !blk_dev_is_tray_open(blk);
167
}
168
169
void coroutine_fn blk_co_lock_medium(BlockBackend *blk, bool locked)
170
@@ -XXX,XX +XXX,XX @@ int coroutine_fn blk_co_truncate(BlockBackend *blk, int64_t offset, bool exact,
171
{
172
IO_OR_GS_CODE();
173
GRAPH_RDLOCK_GUARD();
174
- if (!blk_is_available(blk)) {
175
+ if (!blk_co_is_available(blk)) {
176
error_setg(errp, "No medium inserted");
177
return -ENOMEDIUM;
178
}
179
@@ -XXX,XX +XXX,XX @@ int coroutine_fn blk_co_copy_range(BlockBackend *blk_in, int64_t off_in,
180
{
181
int r;
182
IO_CODE();
183
+ GRAPH_RDLOCK_GUARD();
184
185
r = blk_check_byte_request(blk_in, off_in, bytes);
186
if (r) {
187
@@ -XXX,XX +XXX,XX @@ int coroutine_fn blk_co_copy_range(BlockBackend *blk_in, int64_t off_in,
188
return r;
189
}
190
191
- GRAPH_RDLOCK_GUARD();
192
return bdrv_co_copy_range(blk_in->root, off_in,
193
blk_out->root, off_out,
194
bytes, read_flags, write_flags);
195
--
52
--
196
2.39.2
53
2.48.1
diff view generated by jsdifflib
1
From: Or Ozeri <oro@il.ibm.com>
1
In QEMU, nodes are automatically created inactive while expecting an
2
incoming migration (i.e. RUN_STATE_INMIGRATE). In qemu-storage-daemon,
3
the notion of runstates doesn't exist. It also wouldn't necessarily make
4
sense to introduce it because a single daemon can serve multiple VMs
5
that can be in different states.
2
6
3
Ceph RBD encryption API required specifying the encryption format
7
Therefore, allow the user to explicitly open images as inactive with a
4
for loading encryption. The supported formats were LUKS (v1) and LUKS2.
8
new option. The default is as before: Nodes are usually active, except
9
when created during RUN_STATE_INMIGRATE.
5
10
6
Starting from Reef release, RBD also supports loading with "luks-any" format,
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
which works for both versions of LUKS.
12
Acked-by: Fabiano Rosas <farosas@suse.de>
8
13
Reviewed-by: Eric Blake <eblake@redhat.com>
9
This commit extends the qemu rbd driver API to enable qemu users to use
14
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
10
this luks-any wildcard format.
15
Message-ID: <20250204211407.381505-8-kwolf@redhat.com>
11
12
Signed-off-by: Or Ozeri <oro@il.ibm.com>
13
Message-Id: <20230129113120.722708-3-oro@oro.sl.cloud9.ibm.com>
14
Reviewed-by: Ilya Dryomov <idryomov@gmail.com>
15
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
---
17
---
18
qapi/block-core.json | 16 ++++++++++++++--
18
qapi/block-core.json | 6 ++++++
19
block/rbd.c | 19 +++++++++++++++++++
19
include/block/block-common.h | 1 +
20
2 files changed, 33 insertions(+), 2 deletions(-)
20
block.c | 9 +++++++++
21
3 files changed, 16 insertions(+)
21
22
22
diff --git a/qapi/block-core.json b/qapi/block-core.json
23
diff --git a/qapi/block-core.json b/qapi/block-core.json
23
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
24
--- a/qapi/block-core.json
25
--- a/qapi/block-core.json
25
+++ b/qapi/block-core.json
26
+++ b/qapi/block-core.json
26
@@ -XXX,XX +XXX,XX @@
27
@@ -XXX,XX +XXX,XX @@
27
##
28
# @RbdImageEncryptionFormat:
29
#
28
#
30
+# @luks-any: Used for opening either luks or luks2 (Since 8.0)
29
# @cache: cache-related options
30
#
31
+# @active: whether the block node should be activated (default: true).
32
+# Having inactive block nodes is useful primarily for migration because it
33
+# allows opening an image on the destination while the source is still
34
+# holding locks for it. (Since 10.0)
31
+#
35
+#
32
# Since: 6.1
36
# @read-only: whether the block device should be read-only (default:
33
##
37
# false). Note that some block drivers support only read-only
34
{ 'enum': 'RbdImageEncryptionFormat',
38
# access, either generally or in certain configurations. In this
35
- 'data': [ 'luks', 'luks2' ] }
36
+ 'data': [ 'luks', 'luks2', 'luks-any' ] }
37
38
##
39
# @RbdEncryptionOptionsLUKSBase:
40
@@ -XXX,XX +XXX,XX @@
39
@@ -XXX,XX +XXX,XX @@
41
'base': 'RbdEncryptionOptionsLUKSBase',
40
'*node-name': 'str',
42
'data': { } }
41
'*discard': 'BlockdevDiscardOptions',
43
42
'*cache': 'BlockdevCacheOptions',
44
+##
43
+ '*active': 'bool',
45
+# @RbdEncryptionOptionsLUKSAny:
44
'*read-only': 'bool',
46
+#
45
'*auto-read-only': 'bool',
47
+# Since: 8.0
46
'*force-share': 'bool',
48
+##
47
diff --git a/include/block/block-common.h b/include/block/block-common.h
49
+{ 'struct': 'RbdEncryptionOptionsLUKSAny',
48
index XXXXXXX..XXXXXXX 100644
50
+ 'base': 'RbdEncryptionOptionsLUKSBase',
49
--- a/include/block/block-common.h
51
+ 'data': { } }
50
+++ b/include/block/block-common.h
51
@@ -XXX,XX +XXX,XX @@ typedef enum {
52
#define BDRV_OPT_AUTO_READ_ONLY "auto-read-only"
53
#define BDRV_OPT_DISCARD "discard"
54
#define BDRV_OPT_FORCE_SHARE "force-share"
55
+#define BDRV_OPT_ACTIVE "active"
56
57
58
#define BDRV_SECTOR_BITS 9
59
diff --git a/block.c b/block.c
60
index XXXXXXX..XXXXXXX 100644
61
--- a/block.c
62
+++ b/block.c
63
@@ -XXX,XX +XXX,XX @@ static void update_flags_from_options(int *flags, QemuOpts *opts)
64
if (qemu_opt_get_bool_del(opts, BDRV_OPT_AUTO_READ_ONLY, false)) {
65
*flags |= BDRV_O_AUTO_RDONLY;
66
}
52
+
67
+
53
##
68
+ if (!qemu_opt_get_bool_del(opts, BDRV_OPT_ACTIVE, true)) {
54
# @RbdEncryptionCreateOptionsLUKS:
69
+ *flags |= BDRV_O_INACTIVE;
55
#
70
+ }
56
@@ -XXX,XX +XXX,XX @@
71
}
57
'base': { 'format': 'RbdImageEncryptionFormat' },
72
58
'discriminator': 'format',
73
static void update_options_from_flags(QDict *options, int flags)
59
'data': { 'luks': 'RbdEncryptionOptionsLUKS',
74
@@ -XXX,XX +XXX,XX @@ QemuOptsList bdrv_runtime_opts = {
60
- 'luks2': 'RbdEncryptionOptionsLUKS2' } }
75
.type = QEMU_OPT_BOOL,
61
+ 'luks2': 'RbdEncryptionOptionsLUKS2',
76
.help = "Ignore flush requests",
62
+ 'luks-any': 'RbdEncryptionOptionsLUKSAny'} }
77
},
63
78
+ {
64
##
79
+ .name = BDRV_OPT_ACTIVE,
65
# @RbdEncryptionCreateOptions:
80
+ .type = QEMU_OPT_BOOL,
66
diff --git a/block/rbd.c b/block/rbd.c
81
+ .help = "Node is activated",
67
index XXXXXXX..XXXXXXX 100644
82
+ },
68
--- a/block/rbd.c
83
{
69
+++ b/block/rbd.c
84
.name = BDRV_OPT_READ_ONLY,
70
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_encryption_load(rbd_image_t image,
85
.type = QEMU_OPT_BOOL,
71
g_autofree char *passphrase = NULL;
72
rbd_encryption_luks1_format_options_t luks_opts;
73
rbd_encryption_luks2_format_options_t luks2_opts;
74
+#ifdef LIBRBD_SUPPORTS_ENCRYPTION_LOAD2
75
+ rbd_encryption_luks_format_options_t luks_any_opts;
76
+#endif
77
rbd_encryption_format_t format;
78
rbd_encryption_options_t opts;
79
size_t opts_size;
80
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_encryption_load(rbd_image_t image,
81
luks2_opts.passphrase = passphrase;
82
break;
83
}
84
+#ifdef LIBRBD_SUPPORTS_ENCRYPTION_LOAD2
85
+ case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS_ANY: {
86
+ memset(&luks_any_opts, 0, sizeof(luks_any_opts));
87
+ format = RBD_ENCRYPTION_FORMAT_LUKS;
88
+ opts = &luks_any_opts;
89
+ opts_size = sizeof(luks_any_opts);
90
+ r = qemu_rbd_convert_luks_options(
91
+ qapi_RbdEncryptionOptionsLUKSAny_base(&encrypt->u.luks_any),
92
+ &passphrase, &luks_any_opts.passphrase_size, errp);
93
+ if (r < 0) {
94
+ return r;
95
+ }
96
+ luks_any_opts.passphrase = passphrase;
97
+ break;
98
+ }
99
+#endif
100
default: {
101
r = -ENOTSUP;
102
error_setg_errno(
103
--
86
--
104
2.39.2
87
2.48.1
diff view generated by jsdifflib
1
From: Or Ozeri <oro@il.ibm.com>
1
The system emulator tries to automatically activate and inactivate block
2
nodes at the right point during migration. However, there are still
3
cases where it's necessary that the user can do this manually.
2
4
3
Starting from ceph Reef, RBD has built-in support for layered encryption,
5
Images are only activated on the destination VM of a migration when the
4
where each ancestor image (in a cloned image setting) can be possibly
6
VM is actually resumed. If the VM was paused, this doesn't happen
5
encrypted using a unique passphrase.
7
automatically. The user may want to perform some operation on a block
8
device (e.g. taking a snapshot or starting a block job) without also
9
resuming the VM yet. This is an example where a manual command is
10
necessary.
6
11
7
A new function, rbd_encryption_load2, was added to librbd API.
12
Another example is VM migration when the image files are opened by an
8
This new function supports an array of passphrases (via "spec" structs).
13
external qemu-storage-daemon instance on each side. In this case, the
14
process that needs to hand over the images isn't even part of the
15
migration and can't know when the migration completes. Management tools
16
need a way to explicitly inactivate images on the source and activate
17
them on the destination.
9
18
10
This commit extends the qemu rbd driver API to use this new librbd API,
19
This adds a new blockdev-set-active QMP command that lets the user
11
in order to support this new layered encryption feature.
20
change the status of individual nodes (this is necessary in
21
qemu-storage-daemon because it could be serving multiple VMs and only
22
one of them migrates at a time). For convenience, operating on all
23
devices (like QEMU does automatically during migration) is offered as an
24
option, too, and can be used in the context of single VM.
12
25
13
Signed-off-by: Or Ozeri <oro@il.ibm.com>
26
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
Message-Id: <20230129113120.722708-4-oro@oro.sl.cloud9.ibm.com>
27
Acked-by: Fabiano Rosas <farosas@suse.de>
15
Reviewed-by: Ilya Dryomov <idryomov@gmail.com>
28
Reviewed-by: Eric Blake <eblake@redhat.com>
16
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
29
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
30
Message-ID: <20250204211407.381505-9-kwolf@redhat.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
31
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
18
---
32
---
19
qapi/block-core.json | 11 +++-
33
qapi/block-core.json | 32 ++++++++++++++++++++++++++++++
20
block/rbd.c | 153 ++++++++++++++++++++++++++++++++++++++++++-
34
include/block/block-global-state.h | 3 +++
21
2 files changed, 162 insertions(+), 2 deletions(-)
35
block.c | 21 ++++++++++++++++++++
36
blockdev.c | 32 ++++++++++++++++++++++++++++++
37
4 files changed, 88 insertions(+)
22
38
23
diff --git a/qapi/block-core.json b/qapi/block-core.json
39
diff --git a/qapi/block-core.json b/qapi/block-core.json
24
index XXXXXXX..XXXXXXX 100644
40
index XXXXXXX..XXXXXXX 100644
25
--- a/qapi/block-core.json
41
--- a/qapi/block-core.json
26
+++ b/qapi/block-core.json
42
+++ b/qapi/block-core.json
27
@@ -XXX,XX +XXX,XX @@
43
@@ -XXX,XX +XXX,XX @@
44
{ 'command': 'blockdev-del', 'data': { 'node-name': 'str' },
45
'allow-preconfig': true }
46
47
+##
48
+# @blockdev-set-active:
49
+#
50
+# Activate or inactivate a block device. Use this to manage the handover of
51
+# block devices on migration with qemu-storage-daemon.
52
+#
53
+# Activating a node automatically activates all of its child nodes first.
54
+# Inactivating a node automatically inactivates any of its child nodes that are
55
+# not in use by a still active node.
56
+#
57
+# @node-name: Name of the graph node to activate or inactivate. By default, all
58
+# nodes are affected by the operation.
59
+#
60
+# @active: true if the nodes should be active when the command returns success,
61
+# false if they should be inactive.
62
+#
63
+# Since: 10.0
64
+#
65
+# .. qmp-example::
66
+#
67
+# -> { "execute": "blockdev-set-active",
68
+# "arguments": {
69
+# "node-name": "node0",
70
+# "active": false
71
+# }
72
+# }
73
+# <- { "return": {} }
74
+##
75
+{ 'command': 'blockdev-set-active',
76
+ 'data': { '*node-name': 'str', 'active': 'bool' },
77
+ 'allow-preconfig': true }
78
+
28
##
79
##
29
# @RbdEncryptionOptions:
80
# @BlockdevCreateOptionsFile:
30
#
81
#
31
+# @format: Encryption format.
82
diff --git a/include/block/block-global-state.h b/include/block/block-global-state.h
32
+#
33
+# @parent: Parent image encryption options (for cloned images).
34
+# Can be left unspecified if this cloned image is encrypted
35
+# using the same format and secret as its parent image (i.e.
36
+# not explicitly formatted) or if its parent image is not
37
+# encrypted. (Since 8.0)
38
+#
39
# Since: 6.1
40
##
41
{ 'union': 'RbdEncryptionOptions',
42
- 'base': { 'format': 'RbdImageEncryptionFormat' },
43
+ 'base': { 'format': 'RbdImageEncryptionFormat',
44
+ '*parent': 'RbdEncryptionOptions' },
45
'discriminator': 'format',
46
'data': { 'luks': 'RbdEncryptionOptionsLUKS',
47
'luks2': 'RbdEncryptionOptionsLUKS2',
48
diff --git a/block/rbd.c b/block/rbd.c
49
index XXXXXXX..XXXXXXX 100644
83
index XXXXXXX..XXXXXXX 100644
50
--- a/block/rbd.c
84
--- a/include/block/block-global-state.h
51
+++ b/block/rbd.c
85
+++ b/include/block/block-global-state.h
52
@@ -XXX,XX +XXX,XX @@ static const char rbd_luks2_header_verification[
86
@@ -XXX,XX +XXX,XX @@ bdrv_activate(BlockDriverState *bs, Error **errp);
53
'L', 'U', 'K', 'S', 0xBA, 0xBE, 0, 2
87
int coroutine_fn no_co_wrapper_bdrv_rdlock
54
};
88
bdrv_co_activate(BlockDriverState *bs, Error **errp);
55
89
56
+static const char rbd_layered_luks_header_verification[
90
+int no_coroutine_fn
57
+ RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN] = {
91
+bdrv_inactivate(BlockDriverState *bs, Error **errp);
58
+ 'R', 'B', 'D', 'L', 0xBA, 0xBE, 0, 1
59
+};
60
+
92
+
61
+static const char rbd_layered_luks2_header_verification[
93
void bdrv_activate_all(Error **errp);
62
+ RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN] = {
94
int bdrv_inactivate_all(void);
63
+ 'R', 'B', 'D', 'L', 0xBA, 0xBE, 0, 2
95
64
+};
96
diff --git a/block.c b/block.c
65
+
97
index XXXXXXX..XXXXXXX 100644
66
typedef enum {
98
--- a/block.c
67
RBD_AIO_READ,
99
+++ b/block.c
68
RBD_AIO_WRITE,
100
@@ -XXX,XX +XXX,XX @@ bdrv_inactivate_recurse(BlockDriverState *bs, bool top_level)
69
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_encryption_load(rbd_image_t image,
70
71
return 0;
101
return 0;
72
}
102
}
103
104
+int bdrv_inactivate(BlockDriverState *bs, Error **errp)
105
+{
106
+ int ret;
73
+
107
+
74
+#ifdef LIBRBD_SUPPORTS_ENCRYPTION_LOAD2
108
+ GLOBAL_STATE_CODE();
75
+static int qemu_rbd_encryption_load2(rbd_image_t image,
109
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
76
+ RbdEncryptionOptions *encrypt,
77
+ Error **errp)
78
+{
79
+ int r = 0;
80
+ int encrypt_count = 1;
81
+ int i;
82
+ RbdEncryptionOptions *curr_encrypt;
83
+ rbd_encryption_spec_t *specs;
84
+ rbd_encryption_luks1_format_options_t *luks_opts;
85
+ rbd_encryption_luks2_format_options_t *luks2_opts;
86
+ rbd_encryption_luks_format_options_t *luks_any_opts;
87
+
110
+
88
+ /* count encryption options */
111
+ if (bdrv_has_bds_parent(bs, true)) {
89
+ for (curr_encrypt = encrypt->parent; curr_encrypt;
112
+ error_setg(errp, "Node has active parent node");
90
+ curr_encrypt = curr_encrypt->parent) {
113
+ return -EPERM;
91
+ ++encrypt_count;
92
+ }
114
+ }
93
+
115
+
94
+ specs = g_new0(rbd_encryption_spec_t, encrypt_count);
116
+ ret = bdrv_inactivate_recurse(bs, true);
117
+ if (ret < 0) {
118
+ error_setg_errno(errp, -ret, "Failed to inactivate node");
119
+ return ret;
120
+ }
95
+
121
+
96
+ curr_encrypt = encrypt;
122
+ return 0;
97
+ for (i = 0; i < encrypt_count; ++i) {
123
+}
98
+ switch (curr_encrypt->format) {
99
+ case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS: {
100
+ specs[i].format = RBD_ENCRYPTION_FORMAT_LUKS1;
101
+
124
+
102
+ luks_opts = g_new0(rbd_encryption_luks1_format_options_t, 1);
125
int bdrv_inactivate_all(void)
103
+ specs[i].opts = luks_opts;
126
{
104
+ specs[i].opts_size = sizeof(*luks_opts);
127
BlockDriverState *bs = NULL;
128
diff --git a/blockdev.c b/blockdev.c
129
index XXXXXXX..XXXXXXX 100644
130
--- a/blockdev.c
131
+++ b/blockdev.c
132
@@ -XXX,XX +XXX,XX @@ void qmp_blockdev_del(const char *node_name, Error **errp)
133
bdrv_unref(bs);
134
}
135
136
+void qmp_blockdev_set_active(const char *node_name, bool active, Error **errp)
137
+{
138
+ int ret;
105
+
139
+
106
+ r = qemu_rbd_convert_luks_options(
140
+ GLOBAL_STATE_CODE();
107
+ qapi_RbdEncryptionOptionsLUKS_base(
141
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
108
+ &curr_encrypt->u.luks),
109
+ (char **)&luks_opts->passphrase,
110
+ &luks_opts->passphrase_size,
111
+ errp);
112
+ break;
113
+ }
114
+ case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS2: {
115
+ specs[i].format = RBD_ENCRYPTION_FORMAT_LUKS2;
116
+
142
+
117
+ luks2_opts = g_new0(rbd_encryption_luks2_format_options_t, 1);
143
+ if (!node_name) {
118
+ specs[i].opts = luks2_opts;
144
+ if (active) {
119
+ specs[i].opts_size = sizeof(*luks2_opts);
145
+ bdrv_activate_all(errp);
120
+
146
+ } else {
121
+ r = qemu_rbd_convert_luks_options(
147
+ ret = bdrv_inactivate_all();
122
+ qapi_RbdEncryptionOptionsLUKS2_base(
148
+ if (ret < 0) {
123
+ &curr_encrypt->u.luks2),
149
+ error_setg_errno(errp, -ret, "Failed to inactivate all nodes");
124
+ (char **)&luks2_opts->passphrase,
125
+ &luks2_opts->passphrase_size,
126
+ errp);
127
+ break;
128
+ }
129
+ case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS_ANY: {
130
+ specs[i].format = RBD_ENCRYPTION_FORMAT_LUKS;
131
+
132
+ luks_any_opts = g_new0(rbd_encryption_luks_format_options_t, 1);
133
+ specs[i].opts = luks_any_opts;
134
+ specs[i].opts_size = sizeof(*luks_any_opts);
135
+
136
+ r = qemu_rbd_convert_luks_options(
137
+ qapi_RbdEncryptionOptionsLUKSAny_base(
138
+ &curr_encrypt->u.luks_any),
139
+ (char **)&luks_any_opts->passphrase,
140
+ &luks_any_opts->passphrase_size,
141
+ errp);
142
+ break;
143
+ }
144
+ default: {
145
+ r = -ENOTSUP;
146
+ error_setg_errno(
147
+ errp, -r, "unknown image encryption format: %u",
148
+ curr_encrypt->format);
149
+ }
150
+ }
150
+ }
151
+ }
151
+
152
+ } else {
152
+ if (r < 0) {
153
+ BlockDriverState *bs = bdrv_find_node(node_name);
153
+ goto exit;
154
+ if (!bs) {
155
+ error_setg(errp, "Failed to find node with node-name='%s'",
156
+ node_name);
157
+ return;
154
+ }
158
+ }
155
+
159
+
156
+ curr_encrypt = curr_encrypt->parent;
160
+ if (active) {
161
+ bdrv_activate(bs, errp);
162
+ } else {
163
+ bdrv_inactivate(bs, errp);
164
+ }
157
+ }
165
+ }
166
+}
158
+
167
+
159
+ r = rbd_encryption_load2(image, specs, encrypt_count);
168
static BdrvChild * GRAPH_RDLOCK
160
+ if (r < 0) {
169
bdrv_find_child(BlockDriverState *parent_bs, const char *child_name)
161
+ error_setg_errno(errp, -r, "layered encryption load fail");
170
{
162
+ goto exit;
163
+ }
164
+
165
+exit:
166
+ for (i = 0; i < encrypt_count; ++i) {
167
+ if (!specs[i].opts) {
168
+ break;
169
+ }
170
+
171
+ switch (specs[i].format) {
172
+ case RBD_ENCRYPTION_FORMAT_LUKS1: {
173
+ luks_opts = specs[i].opts;
174
+ g_free((void *)luks_opts->passphrase);
175
+ break;
176
+ }
177
+ case RBD_ENCRYPTION_FORMAT_LUKS2: {
178
+ luks2_opts = specs[i].opts;
179
+ g_free((void *)luks2_opts->passphrase);
180
+ break;
181
+ }
182
+ case RBD_ENCRYPTION_FORMAT_LUKS: {
183
+ luks_any_opts = specs[i].opts;
184
+ g_free((void *)luks_any_opts->passphrase);
185
+ break;
186
+ }
187
+ }
188
+
189
+ g_free(specs[i].opts);
190
+ }
191
+ g_free(specs);
192
+ return r;
193
+}
194
+#endif
195
#endif
196
197
/* FIXME Deprecate and remove keypairs or make it available in QMP. */
198
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
199
200
if (opts->encrypt) {
201
#ifdef LIBRBD_SUPPORTS_ENCRYPTION
202
- r = qemu_rbd_encryption_load(s->image, opts->encrypt, errp);
203
+ if (opts->encrypt->parent) {
204
+#ifdef LIBRBD_SUPPORTS_ENCRYPTION_LOAD2
205
+ r = qemu_rbd_encryption_load2(s->image, opts->encrypt, errp);
206
+#else
207
+ r = -ENOTSUP;
208
+ error_setg(errp, "RBD library does not support layered encryption");
209
+#endif
210
+ } else {
211
+ r = qemu_rbd_encryption_load(s->image, opts->encrypt, errp);
212
+ }
213
if (r < 0) {
214
goto failed_post_open;
215
}
216
@@ -XXX,XX +XXX,XX @@ static ImageInfoSpecific *qemu_rbd_get_specific_info(BlockDriverState *bs,
217
spec_info->u.rbd.data->encryption_format =
218
RBD_IMAGE_ENCRYPTION_FORMAT_LUKS2;
219
spec_info->u.rbd.data->has_encryption_format = true;
220
+ } else if (memcmp(buf, rbd_layered_luks_header_verification,
221
+ RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN) == 0) {
222
+ spec_info->u.rbd.data->encryption_format =
223
+ RBD_IMAGE_ENCRYPTION_FORMAT_LUKS;
224
+ spec_info->u.rbd.data->has_encryption_format = true;
225
+ } else if (memcmp(buf, rbd_layered_luks2_header_verification,
226
+ RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN) == 0) {
227
+ spec_info->u.rbd.data->encryption_format =
228
+ RBD_IMAGE_ENCRYPTION_FORMAT_LUKS2;
229
+ spec_info->u.rbd.data->has_encryption_format = true;
230
} else {
231
spec_info->u.rbd.data->has_encryption_format = false;
232
}
233
--
171
--
234
2.39.2
172
2.48.1
diff view generated by jsdifflib
1
This adds GRAPH_RDLOCK annotations to declare that callers of
1
Device models have a relatively complex way to set up their block
2
bdrv_co_io_plug() and bdrv_co_io_unplug() need to hold a reader lock for
2
backends, in which blk_attach_dev() sets blk->disable_perm = true.
3
the graph.
3
We want to support inactive images in exports, too, so that
4
qemu-storage-daemon can be used with migration. Because they don't use
5
blk_attach_dev(), they need another way to set this flag. The most
6
convenient is to do this automatically when an inactive node is attached
7
to a BlockBackend that can be inactivated.
4
8
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Message-Id: <20230203152202.49054-18-kwolf@redhat.com>
10
Acked-by: Fabiano Rosas <farosas@suse.de>
7
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
11
Reviewed-by: Eric Blake <eblake@redhat.com>
12
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
13
Message-ID: <20250204211407.381505-10-kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
15
---
10
include/block/block-io.h | 4 ++--
16
block/block-backend.c | 14 ++++++++++++--
11
include/block/block_int-common.h | 5 +++--
17
1 file changed, 12 insertions(+), 2 deletions(-)
12
block/block-backend.c | 2 ++
13
block/io.c | 2 ++
14
4 files changed, 9 insertions(+), 4 deletions(-)
15
18
16
diff --git a/include/block/block-io.h b/include/block/block-io.h
17
index XXXXXXX..XXXXXXX 100644
18
--- a/include/block/block-io.h
19
+++ b/include/block/block-io.h
20
@@ -XXX,XX +XXX,XX @@ void coroutine_fn bdrv_co_leave(BlockDriverState *bs, AioContext *old_ctx);
21
22
AioContext *child_of_bds_get_parent_aio_context(BdrvChild *c);
23
24
-void coroutine_fn bdrv_co_io_plug(BlockDriverState *bs);
25
-void coroutine_fn bdrv_co_io_unplug(BlockDriverState *bs);
26
+void coroutine_fn GRAPH_RDLOCK bdrv_co_io_plug(BlockDriverState *bs);
27
+void coroutine_fn GRAPH_RDLOCK bdrv_co_io_unplug(BlockDriverState *bs);
28
29
bool coroutine_fn bdrv_co_can_store_new_dirty_bitmap(BlockDriverState *bs,
30
const char *name,
31
diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
32
index XXXXXXX..XXXXXXX 100644
33
--- a/include/block/block_int-common.h
34
+++ b/include/block/block_int-common.h
35
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
36
BlkdebugEvent event);
37
38
/* io queue for linux-aio */
39
- void coroutine_fn (*bdrv_co_io_plug)(BlockDriverState *bs);
40
- void coroutine_fn (*bdrv_co_io_unplug)(BlockDriverState *bs);
41
+ void coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_io_plug)(BlockDriverState *bs);
42
+ void coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_io_unplug)(
43
+ BlockDriverState *bs);
44
45
/**
46
* bdrv_drain_begin is called if implemented in the beginning of a
47
diff --git a/block/block-backend.c b/block/block-backend.c
19
diff --git a/block/block-backend.c b/block/block-backend.c
48
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
49
--- a/block/block-backend.c
21
--- a/block/block-backend.c
50
+++ b/block/block-backend.c
22
+++ b/block/block-backend.c
51
@@ -XXX,XX +XXX,XX @@ void coroutine_fn blk_co_io_plug(BlockBackend *blk)
23
@@ -XXX,XX +XXX,XX @@ void blk_remove_bs(BlockBackend *blk)
24
int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, Error **errp)
52
{
25
{
53
BlockDriverState *bs = blk_bs(blk);
26
ThrottleGroupMember *tgm = &blk->public.throttle_group_member;
54
IO_CODE();
27
+ uint64_t perm, shared_perm;
55
+ GRAPH_RDLOCK_GUARD();
28
56
29
GLOBAL_STATE_CODE();
57
if (bs) {
30
bdrv_ref(bs);
58
bdrv_co_io_plug(bs);
31
bdrv_graph_wrlock();
59
@@ -XXX,XX +XXX,XX @@ void coroutine_fn blk_co_io_unplug(BlockBackend *blk)
32
+
60
{
33
+ if ((bs->open_flags & BDRV_O_INACTIVE) && blk_can_inactivate(blk)) {
61
BlockDriverState *bs = blk_bs(blk);
34
+ blk->disable_perm = true;
62
IO_CODE();
35
+ perm = 0;
63
+ GRAPH_RDLOCK_GUARD();
36
+ shared_perm = BLK_PERM_ALL;
64
37
+ } else {
65
if (bs) {
38
+ perm = blk->perm;
66
bdrv_co_io_unplug(bs);
39
+ shared_perm = blk->shared_perm;
67
diff --git a/block/io.c b/block/io.c
40
+ }
68
index XXXXXXX..XXXXXXX 100644
41
+
69
--- a/block/io.c
42
blk->root = bdrv_root_attach_child(bs, "root", &child_root,
70
+++ b/block/io.c
43
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
71
@@ -XXX,XX +XXX,XX @@ void coroutine_fn bdrv_co_io_plug(BlockDriverState *bs)
44
- blk->perm, blk->shared_perm,
72
{
45
- blk, errp);
73
BdrvChild *child;
46
+ perm, shared_perm, blk, errp);
74
IO_CODE();
47
bdrv_graph_wrunlock();
75
+ assert_bdrv_graph_readable();
48
if (blk->root == NULL) {
76
49
return -EPERM;
77
QLIST_FOREACH(child, &bs->children, next) {
78
bdrv_co_io_plug(child->bs);
79
@@ -XXX,XX +XXX,XX @@ void coroutine_fn bdrv_co_io_unplug(BlockDriverState *bs)
80
{
81
BdrvChild *child;
82
IO_CODE();
83
+ assert_bdrv_graph_readable();
84
85
assert(bs->io_plugged);
86
if (qatomic_fetch_dec(&bs->io_plugged) == 1) {
87
--
50
--
88
2.39.2
51
2.48.1
diff view generated by jsdifflib
1
This adds GRAPH_RDLOCK annotations to declare that callers of
1
Currently, block exports can't handle inactive images correctly.
2
bdrv_register_buf() and bdrv_unregister_buf() need to hold a reader lock
2
Incoming write requests would run into assertion failures. Make sure
3
for the graph.
3
that we return an error when creating an export can't activate the
4
image.
4
5
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Message-Id: <20230203152202.49054-21-kwolf@redhat.com>
7
Acked-by: Fabiano Rosas <farosas@suse.de>
7
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
8
Reviewed-by: Eric Blake <eblake@redhat.com>
9
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
10
Message-ID: <20250204211407.381505-11-kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
12
---
10
include/block/block_int-common.h | 7 ++++---
13
block/export/export.c | 6 +++++-
11
block/io.c | 14 ++++++++++----
14
1 file changed, 5 insertions(+), 1 deletion(-)
12
2 files changed, 14 insertions(+), 7 deletions(-)
13
15
14
diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
16
diff --git a/block/export/export.c b/block/export/export.c
15
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
16
--- a/include/block/block_int-common.h
18
--- a/block/export/export.c
17
+++ b/include/block/block_int-common.h
19
+++ b/block/export/export.c
18
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
20
@@ -XXX,XX +XXX,XX @@ BlockExport *blk_exp_add(BlockExportOptions *export, Error **errp)
19
*
21
* ctx was acquired in the caller.
20
* Returns: true on success, false on failure
21
*/
22
*/
22
- bool (*bdrv_register_buf)(BlockDriverState *bs, void *host, size_t size,
23
bdrv_graph_rdlock_main_loop();
23
- Error **errp);
24
- bdrv_activate(bs, NULL);
24
- void (*bdrv_unregister_buf)(BlockDriverState *bs, void *host, size_t size);
25
+ ret = bdrv_activate(bs, errp);
25
+ bool GRAPH_RDLOCK_PTR (*bdrv_register_buf)(
26
+ if (ret < 0) {
26
+ BlockDriverState *bs, void *host, size_t size, Error **errp);
27
+ bdrv_graph_rdunlock_main_loop();
27
+ void GRAPH_RDLOCK_PTR (*bdrv_unregister_buf)(
28
+ goto fail;
28
+ BlockDriverState *bs, void *host, size_t size);
29
+ }
29
30
bdrv_graph_rdunlock_main_loop();
30
/*
31
31
* This field is modified only under the BQL, and is part of
32
perm = BLK_PERM_CONSISTENT_READ;
32
diff --git a/block/io.c b/block/io.c
33
index XXXXXXX..XXXXXXX 100644
34
--- a/block/io.c
35
+++ b/block/io.c
36
@@ -XXX,XX +XXX,XX @@ void coroutine_fn bdrv_co_io_unplug(BlockDriverState *bs)
37
}
38
39
/* Helper that undoes bdrv_register_buf() when it fails partway through */
40
-static void bdrv_register_buf_rollback(BlockDriverState *bs,
41
- void *host,
42
- size_t size,
43
- BdrvChild *final_child)
44
+static void GRAPH_RDLOCK
45
+bdrv_register_buf_rollback(BlockDriverState *bs, void *host, size_t size,
46
+ BdrvChild *final_child)
47
{
48
BdrvChild *child;
49
50
+ GLOBAL_STATE_CODE();
51
+ assert_bdrv_graph_readable();
52
+
53
QLIST_FOREACH(child, &bs->children, next) {
54
if (child == final_child) {
55
break;
56
@@ -XXX,XX +XXX,XX @@ bool bdrv_register_buf(BlockDriverState *bs, void *host, size_t size,
57
BdrvChild *child;
58
59
GLOBAL_STATE_CODE();
60
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
61
+
62
if (bs->drv && bs->drv->bdrv_register_buf) {
63
if (!bs->drv->bdrv_register_buf(bs, host, size, errp)) {
64
return false;
65
@@ -XXX,XX +XXX,XX @@ void bdrv_unregister_buf(BlockDriverState *bs, void *host, size_t size)
66
BdrvChild *child;
67
68
GLOBAL_STATE_CODE();
69
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
70
+
71
if (bs->drv && bs->drv->bdrv_unregister_buf) {
72
bs->drv->bdrv_unregister_buf(bs, host, size);
73
}
74
--
33
--
75
2.39.2
34
2.48.1
diff view generated by jsdifflib
1
It is never called outside of block.c.
1
So far the assumption has always been that if we try to inactivate a
2
node, it is already idle. This doesn't hold true any more if we allow
3
inactivating exported nodes because we can't know when new external
4
requests come in.
5
6
Drain the node around setting BDRV_O_INACTIVE so that requests can't
7
start operating on an active node and then in the middle it suddenly
8
becomes inactive. With this change, it's enough for exports to check
9
for new requests that they operate on an active node (or, like reads,
10
are allowed even on an inactive node).
2
11
3
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Message-Id: <20230203152202.49054-2-kwolf@redhat.com>
13
Acked-by: Fabiano Rosas <farosas@suse.de>
5
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
14
Message-ID: <20250204211407.381505-12-kwolf@redhat.com>
6
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
15
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
16
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
---
18
---
9
include/block/block-io.h | 2 --
19
block.c | 2 ++
10
block.c | 4 ++--
20
1 file changed, 2 insertions(+)
11
2 files changed, 2 insertions(+), 4 deletions(-)
12
21
13
diff --git a/include/block/block-io.h b/include/block/block-io.h
14
index XXXXXXX..XXXXXXX 100644
15
--- a/include/block/block-io.h
16
+++ b/include/block/block-io.h
17
@@ -XXX,XX +XXX,XX @@ int bdrv_is_allocated_above(BlockDriverState *top, BlockDriverState *base,
18
int coroutine_fn bdrv_co_is_zero_fast(BlockDriverState *bs, int64_t offset,
19
int64_t bytes);
20
21
-int bdrv_can_set_read_only(BlockDriverState *bs, bool read_only,
22
- bool ignore_allow_rdw, Error **errp);
23
int bdrv_apply_auto_read_only(BlockDriverState *bs, const char *errmsg,
24
Error **errp);
25
bool bdrv_is_read_only(BlockDriverState *bs);
26
diff --git a/block.c b/block.c
22
diff --git a/block.c b/block.c
27
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
28
--- a/block.c
24
--- a/block.c
29
+++ b/block.c
25
+++ b/block.c
30
@@ -XXX,XX +XXX,XX @@ bool bdrv_is_read_only(BlockDriverState *bs)
26
@@ -XXX,XX +XXX,XX @@ bdrv_inactivate_recurse(BlockDriverState *bs, bool top_level)
31
return !(bs->open_flags & BDRV_O_RDWR);
27
return -EPERM;
32
}
28
}
33
29
34
-int bdrv_can_set_read_only(BlockDriverState *bs, bool read_only,
30
+ bdrv_drained_begin(bs);
35
- bool ignore_allow_rdw, Error **errp)
31
bs->open_flags |= BDRV_O_INACTIVE;
36
+static int bdrv_can_set_read_only(BlockDriverState *bs, bool read_only,
32
+ bdrv_drained_end(bs);
37
+ bool ignore_allow_rdw, Error **errp)
33
38
{
34
/*
39
IO_CODE();
35
* Update permissions, they may differ for inactive nodes.
40
41
--
36
--
42
2.39.2
37
2.48.1
diff view generated by jsdifflib
1
This adds GRAPH_RDLOCK annotations to declare that callers of
1
Add an option in BlockExportOptions to allow creating an export on an
2
bdrv_co_pwrite_sync() need to hold a reader lock for the graph.
2
inactive node without activating the node. This mode needs to be
3
3
explicitly supported by the export type (so that it doesn't perform any
4
For some places, we know that they will hold the lock, but we don't have
4
operations that are forbidden for inactive nodes), so this patch alone
5
the GRAPH_RDLOCK annotations yet. In this case, add assume_graph_lock()
5
doesn't allow this option to be successfully used yet.
6
with a FIXME comment. These places will be removed once everything is
7
properly annotated.
8
6
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Message-Id: <20230203152202.49054-13-kwolf@redhat.com>
8
Acked-by: Fabiano Rosas <farosas@suse.de>
11
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
9
Reviewed-by: Eric Blake <eblake@redhat.com>
10
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
11
Message-ID: <20250204211407.381505-13-kwolf@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
---
13
---
14
block/qcow2.h | 2 +-
14
qapi/block-export.json | 10 +++++++++-
15
include/block/block-io.h | 7 ++++---
15
include/block/export.h | 3 +++
16
block/io.c | 3 +--
16
block/export/export.c | 31 +++++++++++++++++++++----------
17
3 files changed, 6 insertions(+), 6 deletions(-)
17
3 files changed, 33 insertions(+), 11 deletions(-)
18
18
19
diff --git a/block/qcow2.h b/block/qcow2.h
19
diff --git a/qapi/block-export.json b/qapi/block-export.json
20
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
21
--- a/block/qcow2.h
21
--- a/qapi/block-export.json
22
+++ b/block/qcow2.h
22
+++ b/qapi/block-export.json
23
@@ -XXX,XX +XXX,XX @@ int qcow2_inc_refcounts_imrt(BlockDriverState *bs, BdrvCheckResult *res,
23
@@ -XXX,XX +XXX,XX @@
24
int qcow2_change_refcount_order(BlockDriverState *bs, int refcount_order,
24
# cannot be moved to the iothread. The default is false.
25
BlockDriverAmendStatusCB *status_cb,
25
# (since: 5.2)
26
void *cb_opaque, Error **errp);
26
#
27
-int coroutine_fn qcow2_shrink_reftable(BlockDriverState *bs);
27
+# @allow-inactive: If true, the export allows the exported node to be inactive.
28
+int coroutine_fn GRAPH_RDLOCK qcow2_shrink_reftable(BlockDriverState *bs);
28
+# If it is created for an inactive block node, the node remains inactive. If
29
int64_t qcow2_get_last_cluster(BlockDriverState *bs, int64_t size);
29
+# the export type doesn't support running on an inactive node, an error is
30
int coroutine_fn qcow2_detect_metadata_preallocation(BlockDriverState *bs);
30
+# returned. If false, inactive block nodes are automatically activated before
31
31
+# creating the export and trying to inactivate them later fails.
32
diff --git a/include/block/block-io.h b/include/block/block-io.h
32
+# (since: 10.0; default: false)
33
+#
34
# Since: 4.2
35
##
36
{ 'union': 'BlockExportOptions',
37
@@ -XXX,XX +XXX,XX @@
38
'*iothread': 'str',
39
'node-name': 'str',
40
'*writable': 'bool',
41
- '*writethrough': 'bool' },
42
+ '*writethrough': 'bool',
43
+ '*allow-inactive': 'bool' },
44
'discriminator': 'type',
45
'data': {
46
'nbd': 'BlockExportOptionsNbd',
47
diff --git a/include/block/export.h b/include/block/export.h
33
index XXXXXXX..XXXXXXX 100644
48
index XXXXXXX..XXXXXXX 100644
34
--- a/include/block/block-io.h
49
--- a/include/block/export.h
35
+++ b/include/block/block-io.h
50
+++ b/include/block/export.h
36
@@ -XXX,XX +XXX,XX @@ int co_wrapper_mixed_bdrv_rdlock
51
@@ -XXX,XX +XXX,XX @@ typedef struct BlockExportDriver {
37
bdrv_pwrite_sync(BdrvChild *child, int64_t offset, int64_t bytes,
52
*/
38
const void *buf, BdrvRequestFlags flags);
53
size_t instance_size;
39
54
40
-int coroutine_fn bdrv_co_pwrite_sync(BdrvChild *child, int64_t offset,
55
+ /* True if the export type supports running on an inactive node */
41
- int64_t bytes, const void *buf,
56
+ bool supports_inactive;
42
- BdrvRequestFlags flags);
43
+int coroutine_fn GRAPH_RDLOCK
44
+bdrv_co_pwrite_sync(BdrvChild *child, int64_t offset, int64_t bytes,
45
+ const void *buf, BdrvRequestFlags flags);
46
+
57
+
47
/*
58
/* Creates and starts a new block export */
48
* Efficiently zero a region of the disk image. Note that this is a regular
59
int (*create)(BlockExport *, BlockExportOptions *, Error **);
49
* I/O request like read or write and should have a reasonable size. This
60
50
diff --git a/block/io.c b/block/io.c
61
diff --git a/block/export/export.c b/block/export/export.c
51
index XXXXXXX..XXXXXXX 100644
62
index XXXXXXX..XXXXXXX 100644
52
--- a/block/io.c
63
--- a/block/export/export.c
53
+++ b/block/io.c
64
+++ b/block/export/export.c
54
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_pwrite_sync(BdrvChild *child, int64_t offset,
65
@@ -XXX,XX +XXX,XX @@ static const BlockExportDriver *blk_exp_find_driver(BlockExportType type)
66
BlockExport *blk_exp_add(BlockExportOptions *export, Error **errp)
55
{
67
{
56
int ret;
68
bool fixed_iothread = export->has_fixed_iothread && export->fixed_iothread;
57
IO_CODE();
69
+ bool allow_inactive = export->has_allow_inactive && export->allow_inactive;
58
-
70
const BlockExportDriver *drv;
59
- assume_graph_lock(); /* FIXME */
71
BlockExport *exp = NULL;
60
+ assert_bdrv_graph_readable();
72
BlockDriverState *bs;
61
73
@@ -XXX,XX +XXX,XX @@ BlockExport *blk_exp_add(BlockExportOptions *export, Error **errp)
62
ret = bdrv_co_pwrite(child, offset, bytes, buf, flags);
74
}
75
}
76
77
- /*
78
- * Block exports are used for non-shared storage migration. Make sure
79
- * that BDRV_O_INACTIVE is cleared and the image is ready for write
80
- * access since the export could be available before migration handover.
81
- * ctx was acquired in the caller.
82
- */
83
bdrv_graph_rdlock_main_loop();
84
- ret = bdrv_activate(bs, errp);
85
- if (ret < 0) {
86
- bdrv_graph_rdunlock_main_loop();
87
- goto fail;
88
+ if (allow_inactive) {
89
+ if (!drv->supports_inactive) {
90
+ error_setg(errp, "Export type does not support inactive exports");
91
+ bdrv_graph_rdunlock_main_loop();
92
+ goto fail;
93
+ }
94
+ } else {
95
+ /*
96
+ * Block exports are used for non-shared storage migration. Make sure
97
+ * that BDRV_O_INACTIVE is cleared and the image is ready for write
98
+ * access since the export could be available before migration handover.
99
+ */
100
+ ret = bdrv_activate(bs, errp);
101
+ if (ret < 0) {
102
+ bdrv_graph_rdunlock_main_loop();
103
+ goto fail;
104
+ }
105
}
106
bdrv_graph_rdunlock_main_loop();
107
108
@@ -XXX,XX +XXX,XX @@ BlockExport *blk_exp_add(BlockExportOptions *export, Error **errp)
109
if (!fixed_iothread) {
110
blk_set_allow_aio_context_change(blk, true);
111
}
112
+ if (allow_inactive) {
113
+ blk_set_force_allow_inactivate(blk);
114
+ }
115
116
ret = blk_insert_bs(blk, bs, errp);
63
if (ret < 0) {
117
if (ret < 0) {
64
--
118
--
65
2.39.2
119
2.48.1
diff view generated by jsdifflib
1
This adds GRAPH_RDLOCK annotations to declare that callers of
1
In order to support running an NBD export on inactive nodes, we must
2
bdrv_co_pwrite_zeroes() need to hold a reader lock for the graph.
2
make sure to return errors for any operations that aren't allowed on
3
3
inactive nodes. Reads are the only operation we know we need for
4
For some places, we know that they will hold the lock, but we don't have
4
inactive images, so to err on the side of caution, return errors for
5
the GRAPH_RDLOCK annotations yet. In this case, add assume_graph_lock()
5
everything else, even if some operations could possibly be okay.
6
with a FIXME comment. These places will be removed once everything is
7
properly annotated.
8
6
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Message-Id: <20230203152202.49054-10-kwolf@redhat.com>
8
Acked-by: Fabiano Rosas <farosas@suse.de>
11
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
9
Message-ID: <20250204211407.381505-14-kwolf@redhat.com>
10
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
11
Reviewed-by: Eric Blake <eblake@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
---
13
---
14
block/qcow2.h | 6 ++++--
14
nbd/server.c | 17 +++++++++++++++++
15
include/block/block-io.h | 9 +++++----
15
1 file changed, 17 insertions(+)
16
include/block/block_int-common.h | 5 +++--
17
block/blkdebug.c | 6 +++---
18
block/blklogwrites.c | 5 ++---
19
block/blkreplay.c | 5 +++--
20
block/block-copy.c | 13 +++++++------
21
block/copy-before-write.c | 5 +++--
22
block/copy-on-read.c | 6 +++---
23
block/filter-compress.c | 6 +++---
24
block/io.c | 12 +++++++++---
25
block/mirror.c | 6 +++---
26
block/preallocate.c | 11 +++++++----
27
block/qcow2.c | 30 ++++++++++++++++++------------
28
block/qed.c | 9 +++------
29
block/quorum.c | 15 ++++++++++-----
30
block/raw-format.c | 6 +++---
31
block/throttle.c | 6 +++---
32
18 files changed, 92 insertions(+), 69 deletions(-)
33
16
34
diff --git a/block/qcow2.h b/block/qcow2.h
17
diff --git a/nbd/server.c b/nbd/server.c
35
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
36
--- a/block/qcow2.h
19
--- a/nbd/server.c
37
+++ b/block/qcow2.h
20
+++ b/nbd/server.c
38
@@ -XXX,XX +XXX,XX @@ void qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m);
21
@@ -XXX,XX +XXX,XX @@ static void nbd_export_delete(BlockExport *blk_exp)
39
int qcow2_cluster_discard(BlockDriverState *bs, uint64_t offset,
22
const BlockExportDriver blk_exp_nbd = {
40
uint64_t bytes, enum qcow2_discard_type type,
23
.type = BLOCK_EXPORT_TYPE_NBD,
41
bool full_discard);
24
.instance_size = sizeof(NBDExport),
42
-int coroutine_fn qcow2_subcluster_zeroize(BlockDriverState *bs, uint64_t offset,
25
+ .supports_inactive = true,
43
- uint64_t bytes, int flags);
26
.create = nbd_export_create,
27
.delete = nbd_export_delete,
28
.request_shutdown = nbd_export_request_shutdown,
29
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int nbd_handle_request(NBDClient *client,
30
NBDExport *exp = client->exp;
31
char *msg;
32
size_t i;
33
+ bool inactive;
44
+
34
+
45
+int coroutine_fn GRAPH_RDLOCK
46
+qcow2_subcluster_zeroize(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
47
+ int flags);
48
49
int qcow2_expand_zero_clusters(BlockDriverState *bs,
50
BlockDriverAmendStatusCB *status_cb,
51
diff --git a/include/block/block-io.h b/include/block/block-io.h
52
index XXXXXXX..XXXXXXX 100644
53
--- a/include/block/block-io.h
54
+++ b/include/block/block-io.h
55
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_pwrite_sync(BdrvChild *child, int64_t offset,
56
* function is not suitable for zeroing the entire image in a single request
57
* because it may allocate memory for the entire region.
58
*/
59
-int coroutine_fn bdrv_co_pwrite_zeroes(BdrvChild *child, int64_t offset,
60
- int64_t bytes, BdrvRequestFlags flags);
61
+int coroutine_fn GRAPH_RDLOCK
62
+bdrv_co_pwrite_zeroes(BdrvChild *child, int64_t offset, int64_t bytes,
63
+ BdrvRequestFlags flags);
64
65
int coroutine_fn GRAPH_RDLOCK
66
bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
67
@@ -XXX,XX +XXX,XX @@ int bdrv_is_allocated_above(BlockDriverState *top, BlockDriverState *base,
68
bool include_base, int64_t offset, int64_t bytes,
69
int64_t *pnum);
70
71
-int coroutine_fn bdrv_co_is_zero_fast(BlockDriverState *bs, int64_t offset,
72
- int64_t bytes);
73
+int coroutine_fn GRAPH_RDLOCK
74
+bdrv_co_is_zero_fast(BlockDriverState *bs, int64_t offset, int64_t bytes);
75
76
int bdrv_apply_auto_read_only(BlockDriverState *bs, const char *errmsg,
77
Error **errp);
78
diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
79
index XXXXXXX..XXXXXXX 100644
80
--- a/include/block/block_int-common.h
81
+++ b/include/block/block_int-common.h
82
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
83
* function pointer may be NULL or return -ENOSUP and .bdrv_co_writev()
84
* will be called instead.
85
*/
86
- int coroutine_fn (*bdrv_co_pwrite_zeroes)(BlockDriverState *bs,
87
- int64_t offset, int64_t bytes, BdrvRequestFlags flags);
88
+ int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_pwrite_zeroes)(
89
+ BlockDriverState *bs, int64_t offset, int64_t bytes,
90
+ BdrvRequestFlags flags);
91
92
int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_pdiscard)(
93
BlockDriverState *bs, int64_t offset, int64_t bytes);
94
diff --git a/block/blkdebug.c b/block/blkdebug.c
95
index XXXXXXX..XXXXXXX 100644
96
--- a/block/blkdebug.c
97
+++ b/block/blkdebug.c
98
@@ -XXX,XX +XXX,XX @@ static int GRAPH_RDLOCK coroutine_fn blkdebug_co_flush(BlockDriverState *bs)
99
return bdrv_co_flush(bs->file->bs);
100
}
101
102
-static int coroutine_fn blkdebug_co_pwrite_zeroes(BlockDriverState *bs,
103
- int64_t offset, int64_t bytes,
104
- BdrvRequestFlags flags)
105
+static int coroutine_fn GRAPH_RDLOCK
106
+blkdebug_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int64_t bytes,
107
+ BdrvRequestFlags flags)
108
{
109
uint32_t align = MAX(bs->bl.request_alignment,
110
bs->bl.pwrite_zeroes_alignment);
111
diff --git a/block/blklogwrites.c b/block/blklogwrites.c
112
index XXXXXXX..XXXXXXX 100644
113
--- a/block/blklogwrites.c
114
+++ b/block/blklogwrites.c
115
@@ -XXX,XX +XXX,XX @@ blk_log_writes_co_do_file_pwritev(BlkLogWritesFileReq *fr)
116
fr->qiov, fr->file_flags);
117
}
118
119
-static int coroutine_fn
120
+static int coroutine_fn GRAPH_RDLOCK
121
blk_log_writes_co_do_file_pwrite_zeroes(BlkLogWritesFileReq *fr)
122
{
123
return bdrv_co_pwrite_zeroes(fr->bs->file, fr->offset, fr->bytes,
124
@@ -XXX,XX +XXX,XX @@ blk_log_writes_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes,
125
blk_log_writes_co_do_file_pwritev, 0, false);
126
}
127
128
-static int coroutine_fn
129
+static int coroutine_fn GRAPH_RDLOCK
130
blk_log_writes_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset,
131
int64_t bytes, BdrvRequestFlags flags)
132
{
133
- assume_graph_lock(); /* FIXME */
134
return blk_log_writes_co_log(bs, offset, bytes, NULL, flags,
135
blk_log_writes_co_do_file_pwrite_zeroes, 0,
136
true);
137
diff --git a/block/blkreplay.c b/block/blkreplay.c
138
index XXXXXXX..XXXXXXX 100644
139
--- a/block/blkreplay.c
140
+++ b/block/blkreplay.c
141
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn blkreplay_co_pwritev(BlockDriverState *bs,
142
return ret;
143
}
144
145
-static int coroutine_fn blkreplay_co_pwrite_zeroes(BlockDriverState *bs,
146
- int64_t offset, int64_t bytes, BdrvRequestFlags flags)
147
+static int coroutine_fn GRAPH_RDLOCK
148
+blkreplay_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int64_t bytes,
149
+ BdrvRequestFlags flags)
150
{
151
uint64_t reqid = blkreplay_next_id();
152
int ret = bdrv_co_pwrite_zeroes(bs->file, offset, bytes, flags);
153
diff --git a/block/block-copy.c b/block/block-copy.c
154
index XXXXXXX..XXXXXXX 100644
155
--- a/block/block-copy.c
156
+++ b/block/block-copy.c
157
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int block_copy_task_run(AioTaskPool *pool,
158
* value of @method should be used for subsequent tasks.
159
* Returns 0 on success.
160
*/
161
-static int coroutine_fn block_copy_do_copy(BlockCopyState *s,
162
- int64_t offset, int64_t bytes,
163
- BlockCopyMethod *method,
164
- bool *error_is_read)
165
+static int coroutine_fn GRAPH_RDLOCK
166
+block_copy_do_copy(BlockCopyState *s, int64_t offset, int64_t bytes,
167
+ BlockCopyMethod *method, bool *error_is_read)
168
{
169
int ret;
170
int64_t nbytes = MIN(offset + bytes, s->len) - offset;
171
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int block_copy_task_entry(AioTask *task)
172
BlockCopyMethod method = t->method;
173
int ret;
174
175
- ret = block_copy_do_copy(s, t->req.offset, t->req.bytes, &method,
176
- &error_is_read);
177
+ WITH_GRAPH_RDLOCK_GUARD() {
35
+ WITH_GRAPH_RDLOCK_GUARD() {
178
+ ret = block_copy_do_copy(s, t->req.offset, t->req.bytes, &method,
36
+ inactive = bdrv_is_inactive(blk_bs(exp->common.blk));
179
+ &error_is_read);
37
+ if (inactive) {
38
+ switch (request->type) {
39
+ case NBD_CMD_READ:
40
+ /* These commands are allowed on inactive nodes */
41
+ break;
42
+ default:
43
+ /* Return an error for the rest */
44
+ return nbd_send_generic_reply(client, request, -EPERM,
45
+ "export is inactive", errp);
46
+ }
47
+ }
180
+ }
48
+ }
181
49
182
WITH_QEMU_LOCK_GUARD(&s->lock) {
50
switch (request->type) {
183
if (s->method == t->method) {
51
case NBD_CMD_CACHE:
184
diff --git a/block/copy-before-write.c b/block/copy-before-write.c
185
index XXXXXXX..XXXXXXX 100644
186
--- a/block/copy-before-write.c
187
+++ b/block/copy-before-write.c
188
@@ -XXX,XX +XXX,XX @@ cbw_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes)
189
return bdrv_co_pdiscard(bs->file, offset, bytes);
190
}
191
192
-static int coroutine_fn cbw_co_pwrite_zeroes(BlockDriverState *bs,
193
- int64_t offset, int64_t bytes, BdrvRequestFlags flags)
194
+static int coroutine_fn GRAPH_RDLOCK
195
+cbw_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int64_t bytes,
196
+ BdrvRequestFlags flags)
197
{
198
int ret = cbw_do_copy_before_write(bs, offset, bytes, flags);
199
if (ret < 0) {
200
diff --git a/block/copy-on-read.c b/block/copy-on-read.c
201
index XXXXXXX..XXXXXXX 100644
202
--- a/block/copy-on-read.c
203
+++ b/block/copy-on-read.c
204
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn cor_co_pwritev_part(BlockDriverState *bs,
205
}
206
207
208
-static int coroutine_fn cor_co_pwrite_zeroes(BlockDriverState *bs,
209
- int64_t offset, int64_t bytes,
210
- BdrvRequestFlags flags)
211
+static int coroutine_fn GRAPH_RDLOCK
212
+cor_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int64_t bytes,
213
+ BdrvRequestFlags flags)
214
{
215
return bdrv_co_pwrite_zeroes(bs->file, offset, bytes, flags);
216
}
217
diff --git a/block/filter-compress.c b/block/filter-compress.c
218
index XXXXXXX..XXXXXXX 100644
219
--- a/block/filter-compress.c
220
+++ b/block/filter-compress.c
221
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn compress_co_pwritev_part(BlockDriverState *bs,
222
}
223
224
225
-static int coroutine_fn compress_co_pwrite_zeroes(BlockDriverState *bs,
226
- int64_t offset, int64_t bytes,
227
- BdrvRequestFlags flags)
228
+static int coroutine_fn GRAPH_RDLOCK
229
+compress_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int64_t bytes,
230
+ BdrvRequestFlags flags)
231
{
232
return bdrv_co_pwrite_zeroes(bs->file, offset, bytes, flags);
233
}
234
diff --git a/block/io.c b/block/io.c
235
index XXXXXXX..XXXXXXX 100644
236
--- a/block/io.c
237
+++ b/block/io.c
238
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_do_copy_on_readv(BdrvChild *child,
239
int64_t progress = 0;
240
bool skip_write;
241
242
+ assume_graph_lock(); /* FIXME */
243
+
244
bdrv_check_qiov_request(offset, bytes, qiov, qiov_offset, &error_abort);
245
246
if (!drv) {
247
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
248
bs->bl.request_alignment);
249
int max_transfer = MIN_NON_ZERO(bs->bl.max_transfer, MAX_BOUNCE_BUFFER);
250
251
+ assert_bdrv_graph_readable();
252
bdrv_check_request(offset, bytes, &error_abort);
253
254
if (!drv) {
255
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child,
256
int64_t bytes_remaining = bytes;
257
int max_transfer;
258
259
+ assume_graph_lock(); /* FIXME */
260
+
261
bdrv_check_qiov_request(offset, bytes, qiov, qiov_offset, &error_abort);
262
263
if (!drv) {
264
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_pwrite_zeroes(BdrvChild *child, int64_t offset,
265
{
266
IO_CODE();
267
trace_bdrv_co_pwrite_zeroes(child->bs, offset, bytes, flags);
268
+ assert_bdrv_graph_readable();
269
270
if (!(child->bs->open_flags & BDRV_O_UNMAP)) {
271
flags &= ~BDRV_REQ_MAY_UNMAP;
272
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_is_zero_fast(BlockDriverState *bs, int64_t offset,
273
int64_t pnum = bytes;
274
IO_CODE();
275
276
- assume_graph_lock(); /* FIXME */
277
-
278
if (!bytes) {
279
return 1;
280
}
281
@@ -XXX,XX +XXX,XX @@ void bdrv_unregister_buf(BlockDriverState *bs, void *host, size_t size)
282
}
283
}
284
285
-static int coroutine_fn bdrv_co_copy_range_internal(
286
+static int coroutine_fn GRAPH_RDLOCK bdrv_co_copy_range_internal(
287
BdrvChild *src, int64_t src_offset, BdrvChild *dst,
288
int64_t dst_offset, int64_t bytes,
289
BdrvRequestFlags read_flags, BdrvRequestFlags write_flags,
290
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_copy_range_from(BdrvChild *src, int64_t src_offset,
291
BdrvRequestFlags write_flags)
292
{
293
IO_CODE();
294
+ assume_graph_lock(); /* FIXME */
295
trace_bdrv_co_copy_range_from(src, src_offset, dst, dst_offset, bytes,
296
read_flags, write_flags);
297
return bdrv_co_copy_range_internal(src, src_offset, dst, dst_offset,
298
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_copy_range_to(BdrvChild *src, int64_t src_offset,
299
BdrvRequestFlags write_flags)
300
{
301
IO_CODE();
302
+ assume_graph_lock(); /* FIXME */
303
trace_bdrv_co_copy_range_to(src, src_offset, dst, dst_offset, bytes,
304
read_flags, write_flags);
305
return bdrv_co_copy_range_internal(src, src_offset, dst, dst_offset,
306
diff --git a/block/mirror.c b/block/mirror.c
307
index XXXXXXX..XXXXXXX 100644
308
--- a/block/mirror.c
309
+++ b/block/mirror.c
310
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn GRAPH_RDLOCK bdrv_mirror_top_flush(BlockDriverState *bs)
311
return bdrv_co_flush(bs->backing->bs);
312
}
313
314
-static int coroutine_fn bdrv_mirror_top_pwrite_zeroes(BlockDriverState *bs,
315
- int64_t offset, int64_t bytes, BdrvRequestFlags flags)
316
+static int coroutine_fn GRAPH_RDLOCK
317
+bdrv_mirror_top_pwrite_zeroes(BlockDriverState *bs, int64_t offset,
318
+ int64_t bytes, BdrvRequestFlags flags)
319
{
320
- assume_graph_lock(); /* FIXME */
321
return bdrv_mirror_top_do_write(bs, MIRROR_METHOD_ZERO, offset, bytes, NULL,
322
flags);
323
}
324
diff --git a/block/preallocate.c b/block/preallocate.c
325
index XXXXXXX..XXXXXXX 100644
326
--- a/block/preallocate.c
327
+++ b/block/preallocate.c
328
@@ -XXX,XX +XXX,XX @@ static bool has_prealloc_perms(BlockDriverState *bs)
329
* want_merge_zero is used to merge write-zero request with preallocation in
330
* one bdrv_co_pwrite_zeroes() call.
331
*/
332
-static bool coroutine_fn handle_write(BlockDriverState *bs, int64_t offset,
333
- int64_t bytes, bool want_merge_zero)
334
+static bool coroutine_fn GRAPH_RDLOCK
335
+handle_write(BlockDriverState *bs, int64_t offset, int64_t bytes,
336
+ bool want_merge_zero)
337
{
338
BDRVPreallocateState *s = bs->opaque;
339
int64_t end = offset + bytes;
340
@@ -XXX,XX +XXX,XX @@ static bool coroutine_fn handle_write(BlockDriverState *bs, int64_t offset,
341
return want_merge_zero;
342
}
343
344
-static int coroutine_fn preallocate_co_pwrite_zeroes(BlockDriverState *bs,
345
- int64_t offset, int64_t bytes, BdrvRequestFlags flags)
346
+static int coroutine_fn GRAPH_RDLOCK
347
+preallocate_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset,
348
+ int64_t bytes, BdrvRequestFlags flags)
349
{
350
bool want_merge_zero =
351
!(flags & ~(BDRV_REQ_ZERO_WRITE | BDRV_REQ_NO_FALLBACK));
352
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int preallocate_co_pwritev_part(BlockDriverState *bs,
353
size_t qiov_offset,
354
BdrvRequestFlags flags)
355
{
356
+ assume_graph_lock(); /* FIXME */
357
handle_write(bs, offset, bytes, false);
358
359
return bdrv_co_pwritev_part(bs->file, offset, bytes, qiov, qiov_offset,
360
diff --git a/block/qcow2.c b/block/qcow2.c
361
index XXXXXXX..XXXXXXX 100644
362
--- a/block/qcow2.c
363
+++ b/block/qcow2.c
364
@@ -XXX,XX +XXX,XX @@ static bool merge_cow(uint64_t offset, unsigned bytes,
365
* Return 1 if the COW regions read as zeroes, 0 if not, < 0 on error.
366
* Note that returning 0 does not guarantee non-zero data.
367
*/
368
-static int coroutine_fn is_zero_cow(BlockDriverState *bs, QCowL2Meta *m)
369
+static int coroutine_fn GRAPH_RDLOCK
370
+is_zero_cow(BlockDriverState *bs, QCowL2Meta *m)
371
{
372
/*
373
* This check is designed for optimization shortcut so it must be
374
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn is_zero_cow(BlockDriverState *bs, QCowL2Meta *m)
375
m->cow_end.nb_bytes);
376
}
377
378
-static int coroutine_fn handle_alloc_space(BlockDriverState *bs,
379
- QCowL2Meta *l2meta)
380
+static int coroutine_fn GRAPH_RDLOCK
381
+handle_alloc_space(BlockDriverState *bs, QCowL2Meta *l2meta)
382
{
383
BDRVQcow2State *s = bs->opaque;
384
QCowL2Meta *m;
385
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn handle_alloc_space(BlockDriverState *bs,
386
* l2meta - if not NULL, qcow2_co_pwritev_task() will consume it. Caller must
387
* not use it somehow after qcow2_co_pwritev_task() call
388
*/
389
-static coroutine_fn int qcow2_co_pwritev_task(BlockDriverState *bs,
390
- uint64_t host_offset,
391
- uint64_t offset, uint64_t bytes,
392
- QEMUIOVector *qiov,
393
- uint64_t qiov_offset,
394
- QCowL2Meta *l2meta)
395
+static coroutine_fn GRAPH_RDLOCK
396
+int qcow2_co_pwritev_task(BlockDriverState *bs, uint64_t host_offset,
397
+ uint64_t offset, uint64_t bytes, QEMUIOVector *qiov,
398
+ uint64_t qiov_offset, QCowL2Meta *l2meta)
399
{
400
int ret;
401
BDRVQcow2State *s = bs->opaque;
402
@@ -XXX,XX +XXX,XX @@ out_locked:
403
return ret;
404
}
405
406
-static coroutine_fn int qcow2_co_pwritev_task_entry(AioTask *task)
407
+/*
408
+ * This function can count as GRAPH_RDLOCK because qcow2_co_pwritev_part() holds
409
+ * the graph lock and keeps it until this coroutine has terminated.
410
+ */
411
+static coroutine_fn GRAPH_RDLOCK int qcow2_co_pwritev_task_entry(AioTask *task)
412
{
413
Qcow2AioTask *t = container_of(task, Qcow2AioTask, task);
414
415
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pwritev_part(
416
QCowL2Meta *l2meta = NULL;
417
AioTaskPool *aio = NULL;
418
419
+ assume_graph_lock(); /* FIXME */
420
+
421
trace_qcow2_writev_start_req(qemu_coroutine_self(), offset, bytes);
422
423
while (bytes != 0 && aio_task_pool_status(aio) == 0) {
424
@@ -XXX,XX +XXX,XX @@ static bool is_zero(BlockDriverState *bs, int64_t offset, int64_t bytes)
425
return res >= 0 && (res & BDRV_BLOCK_ZERO) && bytes == 0;
426
}
427
428
-static coroutine_fn int qcow2_co_pwrite_zeroes(BlockDriverState *bs,
429
- int64_t offset, int64_t bytes, BdrvRequestFlags flags)
430
+static int coroutine_fn GRAPH_RDLOCK
431
+qcow2_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int64_t bytes,
432
+ BdrvRequestFlags flags)
433
{
434
int ret;
435
BDRVQcow2State *s = bs->opaque;
436
diff --git a/block/qed.c b/block/qed.c
437
index XXXXXXX..XXXXXXX 100644
438
--- a/block/qed.c
439
+++ b/block/qed.c
440
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_qed_co_writev(BlockDriverState *bs,
441
return qed_co_request(bs, sector_num, qiov, nb_sectors, QED_AIOCB_WRITE);
442
}
443
444
-static int coroutine_fn bdrv_qed_co_pwrite_zeroes(BlockDriverState *bs,
445
- int64_t offset,
446
- int64_t bytes,
447
- BdrvRequestFlags flags)
448
+static int coroutine_fn GRAPH_RDLOCK
449
+bdrv_qed_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int64_t bytes,
450
+ BdrvRequestFlags flags)
451
{
452
BDRVQEDState *s = bs->opaque;
453
454
- assume_graph_lock(); /* FIXME */
455
-
456
/*
457
* Zero writes start without an I/O buffer. If a buffer becomes necessary
458
* then it will be allocated during request processing.
459
diff --git a/block/quorum.c b/block/quorum.c
460
index XXXXXXX..XXXXXXX 100644
461
--- a/block/quorum.c
462
+++ b/block/quorum.c
463
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn quorum_co_preadv(BlockDriverState *bs,
464
return ret;
465
}
466
467
-static void coroutine_fn write_quorum_entry(void *opaque)
468
+/*
469
+ * This function can count as GRAPH_RDLOCK because quorum_co_pwritev() holds the
470
+ * graph lock and keeps it until this coroutine has terminated.
471
+ */
472
+static void coroutine_fn GRAPH_RDLOCK write_quorum_entry(void *opaque)
473
{
474
QuorumCo *co = opaque;
475
QuorumAIOCB *acb = co->acb;
476
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn quorum_co_pwritev(BlockDriverState *bs, int64_t offset,
477
QuorumAIOCB *acb = quorum_aio_get(bs, qiov, offset, bytes, flags);
478
int i, ret;
479
480
+ assume_graph_lock(); /* FIXME */
481
+
482
for (i = 0; i < s->num_children; i++) {
483
Coroutine *co;
484
QuorumCo data = {
485
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn quorum_co_pwritev(BlockDriverState *bs, int64_t offset,
486
return ret;
487
}
488
489
-static int coroutine_fn quorum_co_pwrite_zeroes(BlockDriverState *bs,
490
- int64_t offset, int64_t bytes,
491
- BdrvRequestFlags flags)
492
-
493
+static int coroutine_fn GRAPH_RDLOCK
494
+quorum_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int64_t bytes,
495
+ BdrvRequestFlags flags)
496
{
497
return quorum_co_pwritev(bs, offset, bytes, NULL,
498
flags | BDRV_REQ_ZERO_WRITE);
499
diff --git a/block/raw-format.c b/block/raw-format.c
500
index XXXXXXX..XXXXXXX 100644
501
--- a/block/raw-format.c
502
+++ b/block/raw-format.c
503
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_block_status(BlockDriverState *bs,
504
return BDRV_BLOCK_RAW | BDRV_BLOCK_OFFSET_VALID;
505
}
506
507
-static int coroutine_fn raw_co_pwrite_zeroes(BlockDriverState *bs,
508
- int64_t offset, int64_t bytes,
509
- BdrvRequestFlags flags)
510
+static int coroutine_fn GRAPH_RDLOCK
511
+raw_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int64_t bytes,
512
+ BdrvRequestFlags flags)
513
{
514
int ret;
515
516
diff --git a/block/throttle.c b/block/throttle.c
517
index XXXXXXX..XXXXXXX 100644
518
--- a/block/throttle.c
519
+++ b/block/throttle.c
520
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn throttle_co_pwritev(BlockDriverState *bs,
521
return bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags);
522
}
523
524
-static int coroutine_fn throttle_co_pwrite_zeroes(BlockDriverState *bs,
525
- int64_t offset, int64_t bytes,
526
- BdrvRequestFlags flags)
527
+static int coroutine_fn GRAPH_RDLOCK
528
+throttle_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int64_t bytes,
529
+ BdrvRequestFlags flags)
530
{
531
ThrottleGroupMember *tgm = bs->opaque;
532
throttle_group_co_io_limits_intercept(tgm, bytes, true);
533
--
52
--
534
2.39.2
53
2.48.1
diff view generated by jsdifflib
1
All callers are already GRAPH_RDLOCK, so just add the annotation and
1
The open-coded form of this filter has been copied into enough tests
2
remove assume_graph_lock().
2
that it's better to move it into iotests.py.
3
3
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Message-Id: <20230203152202.49054-14-kwolf@redhat.com>
5
Acked-by: Fabiano Rosas <farosas@suse.de>
6
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Message-ID: <20250204211407.381505-15-kwolf@redhat.com>
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
---
10
---
9
block/io.c | 7 +++----
11
tests/qemu-iotests/iotests.py | 4 ++++
10
1 file changed, 3 insertions(+), 4 deletions(-)
12
tests/qemu-iotests/041 | 4 +---
13
tests/qemu-iotests/165 | 4 +---
14
tests/qemu-iotests/tests/copy-before-write | 3 +--
15
tests/qemu-iotests/tests/migrate-bitmaps-test | 7 +++----
16
5 files changed, 10 insertions(+), 12 deletions(-)
11
17
12
diff --git a/block/io.c b/block/io.c
18
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
13
index XXXXXXX..XXXXXXX 100644
19
index XXXXXXX..XXXXXXX 100644
14
--- a/block/io.c
20
--- a/tests/qemu-iotests/iotests.py
15
+++ b/block/io.c
21
+++ b/tests/qemu-iotests/iotests.py
16
@@ -XXX,XX +XXX,XX @@ fail:
22
@@ -XXX,XX +XXX,XX @@ def _filter(_key, value):
17
return ret;
23
def filter_nbd_exports(output: str) -> str:
18
}
24
return re.sub(r'((min|opt|max) block): [0-9]+', r'\1: XXX', output)
19
25
20
-static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
26
+def filter_qtest(output: str) -> str:
21
- int64_t offset, int64_t bytes, BdrvRequestFlags flags)
27
+ output = re.sub(r'^\[I \d+\.\d+\] OPENED\n', '', output)
22
+static int coroutine_fn GRAPH_RDLOCK
28
+ output = re.sub(r'\n?\[I \+\d+\.\d+\] CLOSED\n?$', '', output)
23
+bdrv_co_do_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int64_t bytes,
29
+ return output
24
+ BdrvRequestFlags flags)
30
25
{
31
Msg = TypeVar('Msg', Dict[str, Any], List[Any], str)
26
BlockDriver *drv = bs->drv;
32
27
QEMUIOVector qiov;
33
diff --git a/tests/qemu-iotests/041 b/tests/qemu-iotests/041
28
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
34
index XXXXXXX..XXXXXXX 100755
29
int head = 0;
35
--- a/tests/qemu-iotests/041
30
int tail = 0;
36
+++ b/tests/qemu-iotests/041
31
37
@@ -XXX,XX +XXX,XX @@ class TestRepairQuorum(iotests.QMPTestCase):
32
- assume_graph_lock(); /* FIXME */
38
33
-
39
# Check the full error message now
34
int64_t max_write_zeroes = MIN_NON_ZERO(bs->bl.max_pwrite_zeroes,
40
self.vm.shutdown()
35
INT64_MAX);
41
- log = self.vm.get_log()
36
int alignment = MAX(bs->bl.pwrite_zeroes_alignment,
42
- log = re.sub(r'^\[I \d+\.\d+\] OPENED\n', '', log)
43
+ log = iotests.filter_qtest(self.vm.get_log())
44
log = re.sub(r'^Formatting.*\n', '', log)
45
- log = re.sub(r'\n\[I \+\d+\.\d+\] CLOSED\n?$', '', log)
46
log = re.sub(r'^%s: ' % os.path.basename(iotests.qemu_prog), '', log)
47
48
self.assertEqual(log,
49
diff --git a/tests/qemu-iotests/165 b/tests/qemu-iotests/165
50
index XXXXXXX..XXXXXXX 100755
51
--- a/tests/qemu-iotests/165
52
+++ b/tests/qemu-iotests/165
53
@@ -XXX,XX +XXX,XX @@ class TestPersistentDirtyBitmap(iotests.QMPTestCase):
54
self.vm.shutdown()
55
56
#catch 'Persistent bitmaps are lost' possible error
57
- log = self.vm.get_log()
58
- log = re.sub(r'^\[I \d+\.\d+\] OPENED\n', '', log)
59
- log = re.sub(r'\[I \+\d+\.\d+\] CLOSED\n?$', '', log)
60
+ log = iotests.filter_qtest(self.vm.get_log())
61
if log:
62
print(log)
63
64
diff --git a/tests/qemu-iotests/tests/copy-before-write b/tests/qemu-iotests/tests/copy-before-write
65
index XXXXXXX..XXXXXXX 100755
66
--- a/tests/qemu-iotests/tests/copy-before-write
67
+++ b/tests/qemu-iotests/tests/copy-before-write
68
@@ -XXX,XX +XXX,XX @@ class TestCbwError(iotests.QMPTestCase):
69
70
self.vm.shutdown()
71
log = self.vm.get_log()
72
- log = re.sub(r'^\[I \d+\.\d+\] OPENED\n', '', log)
73
- log = re.sub(r'\[I \+\d+\.\d+\] CLOSED\n?$', '', log)
74
+ log = iotests.filter_qtest(log)
75
log = iotests.filter_qemu_io(log)
76
return log
77
78
diff --git a/tests/qemu-iotests/tests/migrate-bitmaps-test b/tests/qemu-iotests/tests/migrate-bitmaps-test
79
index XXXXXXX..XXXXXXX 100755
80
--- a/tests/qemu-iotests/tests/migrate-bitmaps-test
81
+++ b/tests/qemu-iotests/tests/migrate-bitmaps-test
82
@@ -XXX,XX +XXX,XX @@ class TestDirtyBitmapMigration(iotests.QMPTestCase):
83
84
# catch 'Could not reopen qcow2 layer: Bitmap already exists'
85
# possible error
86
- log = self.vm_a.get_log()
87
- log = re.sub(r'^\[I \d+\.\d+\] OPENED\n', '', log)
88
- log = re.sub(r'^(wrote .* bytes at offset .*\n.*KiB.*ops.*sec.*\n){3}',
89
+ log = iotests.filter_qtest(self.vm_a.get_log())
90
+ log = re.sub(r'^(wrote .* bytes at offset .*\n'
91
+ r'.*KiB.*ops.*sec.*\n?){3}',
92
'', log)
93
- log = re.sub(r'\[I \+\d+\.\d+\] CLOSED\n?$', '', log)
94
self.assertEqual(log, '')
95
96
# test that bitmap is still persistent
37
--
97
--
38
2.39.2
98
2.48.1
diff view generated by jsdifflib
1
This adds GRAPH_RDLOCK annotations to declare that callers of
1
Test that it's possible to migrate a VM that uses an image on shared
2
bdrv_co_ioctl() need to hold a reader lock for the graph.
2
storage through qemu-storage-daemon.
3
3
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Message-Id: <20230203152202.49054-6-kwolf@redhat.com>
5
Acked-by: Fabiano Rosas <farosas@suse.de>
6
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Message-ID: <20250204211407.381505-16-kwolf@redhat.com>
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
---
10
---
9
include/block/block-io.h | 3 ++-
11
tests/qemu-iotests/tests/qsd-migrate | 140 +++++++++++++++++++++++
10
include/block/block_int-common.h | 9 +++++----
12
tests/qemu-iotests/tests/qsd-migrate.out | 59 ++++++++++
11
block/block-backend.c | 1 +
13
2 files changed, 199 insertions(+)
12
block/io.c | 1 +
14
create mode 100755 tests/qemu-iotests/tests/qsd-migrate
13
block/raw-format.c | 4 ++--
15
create mode 100644 tests/qemu-iotests/tests/qsd-migrate.out
14
5 files changed, 11 insertions(+), 7 deletions(-)
15
16
16
diff --git a/include/block/block-io.h b/include/block/block-io.h
17
diff --git a/tests/qemu-iotests/tests/qsd-migrate b/tests/qemu-iotests/tests/qsd-migrate
17
index XXXXXXX..XXXXXXX 100644
18
new file mode 100755
18
--- a/include/block/block-io.h
19
index XXXXXXX..XXXXXXX
19
+++ b/include/block/block-io.h
20
--- /dev/null
20
@@ -XXX,XX +XXX,XX @@ void bdrv_aio_cancel(BlockAIOCB *acb);
21
+++ b/tests/qemu-iotests/tests/qsd-migrate
21
void bdrv_aio_cancel_async(BlockAIOCB *acb);
22
@@ -XXX,XX +XXX,XX @@
22
23
+#!/usr/bin/env python3
23
/* sg packet commands */
24
+# group: rw quick
24
-int coroutine_fn bdrv_co_ioctl(BlockDriverState *bs, int req, void *buf);
25
+#
25
+int coroutine_fn GRAPH_RDLOCK
26
+# Copyright (C) Red Hat, Inc.
26
+bdrv_co_ioctl(BlockDriverState *bs, int req, void *buf);
27
+#
27
28
+# This program is free software; you can redistribute it and/or modify
28
/* Ensure contents are flushed to disk. */
29
+# it under the terms of the GNU General Public License as published by
29
int coroutine_fn bdrv_co_flush(BlockDriverState *bs);
30
+# the Free Software Foundation; either version 2 of the License, or
30
diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
31
+# (at your option) any later version.
31
index XXXXXXX..XXXXXXX 100644
32
+#
32
--- a/include/block/block_int-common.h
33
+# This program is distributed in the hope that it will be useful,
33
+++ b/include/block/block_int-common.h
34
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
34
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
35
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
35
void coroutine_fn (*bdrv_co_lock_medium)(BlockDriverState *bs, bool locked);
36
+# GNU General Public License for more details.
36
37
+#
37
/* to control generic scsi devices */
38
+# You should have received a copy of the GNU General Public License
38
- BlockAIOCB *(*bdrv_aio_ioctl)(BlockDriverState *bs,
39
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
39
- unsigned long int req, void *buf,
40
+#
40
+ BlockAIOCB *coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_aio_ioctl)(
41
+# Creator/Owner: Kevin Wolf <kwolf@redhat.com>
41
+ BlockDriverState *bs, unsigned long int req, void *buf,
42
+
42
BlockCompletionFunc *cb, void *opaque);
43
+import iotests
43
- int coroutine_fn (*bdrv_co_ioctl)(BlockDriverState *bs,
44
+
44
- unsigned long int req, void *buf);
45
+from iotests import filter_qemu_io, filter_qtest
45
+
46
+
46
+ int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_ioctl)(
47
+iotests.script_initialize(supported_fmts=['generic'],
47
+ BlockDriverState *bs, unsigned long int req, void *buf);
48
+ supported_protocols=['file'],
48
49
+ supported_platforms=['linux'])
49
/*
50
+
50
* Returns 0 for completed check, -errno for internal errors.
51
+with iotests.FilePath('disk.img') as path, \
51
diff --git a/block/block-backend.c b/block/block-backend.c
52
+ iotests.FilePath('nbd-src.sock', base_dir=iotests.sock_dir) as nbd_src, \
52
index XXXXXXX..XXXXXXX 100644
53
+ iotests.FilePath('nbd-dst.sock', base_dir=iotests.sock_dir) as nbd_dst, \
53
--- a/block/block-backend.c
54
+ iotests.FilePath('migrate.sock', base_dir=iotests.sock_dir) as mig_sock, \
54
+++ b/block/block-backend.c
55
+ iotests.VM(path_suffix="-src") as vm_src, \
55
@@ -XXX,XX +XXX,XX @@ blk_co_do_ioctl(BlockBackend *blk, unsigned long int req, void *buf)
56
+ iotests.VM(path_suffix="-dst") as vm_dst:
56
IO_CODE();
57
+
57
58
+ img_size = '10M'
58
blk_wait_while_drained(blk);
59
+
59
+ GRAPH_RDLOCK_GUARD();
60
+ iotests.log('Preparing disk...')
60
61
+ iotests.qemu_img_create('-f', iotests.imgfmt, path, img_size)
61
if (!blk_is_available(blk)) {
62
+
62
return -ENOMEDIUM;
63
+ iotests.log('Launching source QSD...')
63
diff --git a/block/io.c b/block/io.c
64
+ qsd_src = iotests.QemuStorageDaemon(
64
index XXXXXXX..XXXXXXX 100644
65
+ '--blockdev', f'file,node-name=disk-file,filename={path}',
65
--- a/block/io.c
66
+ '--blockdev', f'{iotests.imgfmt},file=disk-file,node-name=disk-fmt',
66
+++ b/block/io.c
67
+ '--nbd-server', f'addr.type=unix,addr.path={nbd_src}',
67
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_ioctl(BlockDriverState *bs, int req, void *buf)
68
+ '--export', 'nbd,id=exp0,node-name=disk-fmt,writable=true,'
68
};
69
+ 'allow-inactive=true',
69
BlockAIOCB *acb;
70
+ qmp=True,
70
IO_CODE();
71
+ )
71
+ assert_bdrv_graph_readable();
72
+
72
73
+ iotests.log('Launching source VM...')
73
bdrv_inc_in_flight(bs);
74
+ vm_src.add_args('-blockdev', f'nbd,node-name=disk,server.type=unix,'
74
if (!drv || (!drv->bdrv_aio_ioctl && !drv->bdrv_co_ioctl)) {
75
+ f'server.path={nbd_src},export=disk-fmt')
75
diff --git a/block/raw-format.c b/block/raw-format.c
76
+ vm_src.add_args('-device', 'virtio-blk,drive=disk,id=virtio0')
76
index XXXXXXX..XXXXXXX 100644
77
+ vm_src.launch()
77
--- a/block/raw-format.c
78
+
78
+++ b/block/raw-format.c
79
+ iotests.log('Launching destination QSD...')
79
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn raw_co_lock_medium(BlockDriverState *bs, bool locked)
80
+ qsd_dst = iotests.QemuStorageDaemon(
80
bdrv_co_lock_medium(bs->file->bs, locked);
81
+ '--blockdev', f'file,node-name=disk-file,filename={path},active=off',
81
}
82
+ '--blockdev', f'{iotests.imgfmt},file=disk-file,node-name=disk-fmt,'
82
83
+ f'active=off',
83
-static int coroutine_fn raw_co_ioctl(BlockDriverState *bs,
84
+ '--nbd-server', f'addr.type=unix,addr.path={nbd_dst}',
84
- unsigned long int req, void *buf)
85
+ '--export', 'nbd,id=exp0,node-name=disk-fmt,writable=true,'
85
+static int coroutine_fn GRAPH_RDLOCK
86
+ 'allow-inactive=true',
86
+raw_co_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
87
+ qmp=True,
87
{
88
+ instance_id='b',
88
BDRVRawState *s = bs->opaque;
89
+ )
89
if (s->offset || s->has_size) {
90
+
91
+ iotests.log('Launching destination VM...')
92
+ vm_dst.add_args('-blockdev', f'nbd,node-name=disk,server.type=unix,'
93
+ f'server.path={nbd_dst},export=disk-fmt')
94
+ vm_dst.add_args('-device', 'virtio-blk,drive=disk,id=virtio0')
95
+ vm_dst.add_args('-incoming', f'unix:{mig_sock}')
96
+ vm_dst.launch()
97
+
98
+ iotests.log('\nTest I/O on the source')
99
+ vm_src.hmp_qemu_io('virtio0/virtio-backend', 'write -P 0x11 0 4k',
100
+ use_log=True, qdev=True)
101
+ vm_src.hmp_qemu_io('virtio0/virtio-backend', 'read -P 0x11 0 4k',
102
+ use_log=True, qdev=True)
103
+
104
+ iotests.log('\nStarting migration...')
105
+
106
+ mig_caps = [
107
+ {'capability': 'events', 'state': True},
108
+ {'capability': 'pause-before-switchover', 'state': True},
109
+ ]
110
+ vm_src.qmp_log('migrate-set-capabilities', capabilities=mig_caps)
111
+ vm_dst.qmp_log('migrate-set-capabilities', capabilities=mig_caps)
112
+ vm_src.qmp_log('migrate', uri=f'unix:{mig_sock}',
113
+ filters=[iotests.filter_qmp_testfiles])
114
+
115
+ vm_src.event_wait('MIGRATION',
116
+ match={'data': {'status': 'pre-switchover'}})
117
+
118
+ iotests.log('\nPre-switchover: Reconfigure QSD instances')
119
+
120
+ iotests.log(qsd_src.qmp('blockdev-set-active', {'active': False}))
121
+
122
+ # Reading is okay from both sides while the image is inactive. Note that
123
+ # the destination may have stale data until it activates the image, though.
124
+ vm_src.hmp_qemu_io('virtio0/virtio-backend', 'read -P 0x11 0 4k',
125
+ use_log=True, qdev=True)
126
+ vm_dst.hmp_qemu_io('virtio0/virtio-backend', 'read 0 4k',
127
+ use_log=True, qdev=True)
128
+
129
+ iotests.log(qsd_dst.qmp('blockdev-set-active', {'active': True}))
130
+
131
+ iotests.log('\nCompleting migration...')
132
+
133
+ vm_src.qmp_log('migrate-continue', state='pre-switchover')
134
+ vm_dst.event_wait('MIGRATION', match={'data': {'status': 'completed'}})
135
+
136
+ iotests.log('\nTest I/O on the destination')
137
+
138
+ # Now the destination must see what the source wrote
139
+ vm_dst.hmp_qemu_io('virtio0/virtio-backend', 'read -P 0x11 0 4k',
140
+ use_log=True, qdev=True)
141
+
142
+ # And be able to overwrite it
143
+ vm_dst.hmp_qemu_io('virtio0/virtio-backend', 'write -P 0x22 0 4k',
144
+ use_log=True, qdev=True)
145
+ vm_dst.hmp_qemu_io('virtio0/virtio-backend', 'read -P 0x22 0 4k',
146
+ use_log=True, qdev=True)
147
+
148
+ iotests.log('\nDone')
149
+
150
+ vm_src.shutdown()
151
+ iotests.log('\n--- vm_src log ---')
152
+ log = vm_src.get_log()
153
+ if log:
154
+ iotests.log(log, [filter_qtest, filter_qemu_io])
155
+ qsd_src.stop()
156
+
157
+ vm_dst.shutdown()
158
+ iotests.log('\n--- vm_dst log ---')
159
+ log = vm_dst.get_log()
160
+ if log:
161
+ iotests.log(log, [filter_qtest, filter_qemu_io])
162
+ qsd_dst.stop()
163
diff --git a/tests/qemu-iotests/tests/qsd-migrate.out b/tests/qemu-iotests/tests/qsd-migrate.out
164
new file mode 100644
165
index XXXXXXX..XXXXXXX
166
--- /dev/null
167
+++ b/tests/qemu-iotests/tests/qsd-migrate.out
168
@@ -XXX,XX +XXX,XX @@
169
+Preparing disk...
170
+Launching source QSD...
171
+Launching source VM...
172
+Launching destination QSD...
173
+Launching destination VM...
174
+
175
+Test I/O on the source
176
+{"execute": "human-monitor-command", "arguments": {"command-line": "qemu-io -d virtio0/virtio-backend \"write -P 0x11 0 4k\""}}
177
+{"return": ""}
178
+{"execute": "human-monitor-command", "arguments": {"command-line": "qemu-io -d virtio0/virtio-backend \"read -P 0x11 0 4k\""}}
179
+{"return": ""}
180
+
181
+Starting migration...
182
+{"execute": "migrate-set-capabilities", "arguments": {"capabilities": [{"capability": "events", "state": true}, {"capability": "pause-before-switchover", "state": true}]}}
183
+{"return": {}}
184
+{"execute": "migrate-set-capabilities", "arguments": {"capabilities": [{"capability": "events", "state": true}, {"capability": "pause-before-switchover", "state": true}]}}
185
+{"return": {}}
186
+{"execute": "migrate", "arguments": {"uri": "unix:SOCK_DIR/PID-migrate.sock"}}
187
+{"return": {}}
188
+
189
+Pre-switchover: Reconfigure QSD instances
190
+{"return": {}}
191
+{"execute": "human-monitor-command", "arguments": {"command-line": "qemu-io -d virtio0/virtio-backend \"read -P 0x11 0 4k\""}}
192
+{"return": ""}
193
+{"execute": "human-monitor-command", "arguments": {"command-line": "qemu-io -d virtio0/virtio-backend \"read 0 4k\""}}
194
+{"return": ""}
195
+{"return": {}}
196
+
197
+Completing migration...
198
+{"execute": "migrate-continue", "arguments": {"state": "pre-switchover"}}
199
+{"return": {}}
200
+
201
+Test I/O on the destination
202
+{"execute": "human-monitor-command", "arguments": {"command-line": "qemu-io -d virtio0/virtio-backend \"read -P 0x11 0 4k\""}}
203
+{"return": ""}
204
+{"execute": "human-monitor-command", "arguments": {"command-line": "qemu-io -d virtio0/virtio-backend \"write -P 0x22 0 4k\""}}
205
+{"return": ""}
206
+{"execute": "human-monitor-command", "arguments": {"command-line": "qemu-io -d virtio0/virtio-backend \"read -P 0x22 0 4k\""}}
207
+{"return": ""}
208
+
209
+Done
210
+
211
+--- vm_src log ---
212
+wrote 4096/4096 bytes at offset 0
213
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
214
+read 4096/4096 bytes at offset 0
215
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
216
+read 4096/4096 bytes at offset 0
217
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
218
+
219
+--- vm_dst log ---
220
+read 4096/4096 bytes at offset 0
221
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
222
+read 4096/4096 bytes at offset 0
223
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
224
+wrote 4096/4096 bytes at offset 0
225
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
226
+read 4096/4096 bytes at offset 0
227
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
90
--
228
--
91
2.39.2
229
2.48.1
diff view generated by jsdifflib
1
This adds GRAPH_RDLOCK annotations to declare that callers of
1
This tests different types of operations on inactive block nodes
2
bdrv_co_truncate() need to hold a reader lock for the graph.
2
(including graph changes, block jobs and NBD exports) to make sure that
3
users manually activating and inactivating nodes doesn't break things.
3
4
4
For some places, we know that they will hold the lock, but we don't have
5
Support for inactive nodes in other export types will have to come with
5
the GRAPH_RDLOCK annotations yet. In this case, add assume_graph_lock()
6
separate test cases because they have different dependencies like blkio
6
with a FIXME comment. These places will be removed once everything is
7
or root permissions and we don't want to disable this basic test when
7
properly annotated.
8
they are not fulfilled.
8
9
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Message-Id: <20230203152202.49054-4-kwolf@redhat.com>
11
Acked-by: Fabiano Rosas <farosas@suse.de>
11
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
12
Message-ID: <20250204211407.381505-17-kwolf@redhat.com>
13
Reviewed-by: Eric Blake <eblake@redhat.com>
14
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
---
16
---
14
include/block/block-io.h | 6 +++---
17
tests/qemu-iotests/iotests.py | 4 +
15
include/block/block_int-common.h | 7 ++++---
18
tests/qemu-iotests/tests/inactive-node-nbd | 303 ++++++++++++++++++
16
block/block-backend.c | 1 +
19
.../qemu-iotests/tests/inactive-node-nbd.out | 239 ++++++++++++++
17
block/crypto.c | 2 +-
20
3 files changed, 546 insertions(+)
18
block/io.c | 1 +
21
create mode 100755 tests/qemu-iotests/tests/inactive-node-nbd
19
block/parallels.c | 14 ++++++++------
22
create mode 100644 tests/qemu-iotests/tests/inactive-node-nbd.out
20
block/preallocate.c | 2 +-
21
block/qcow.c | 17 ++++++++++++-----
22
block/qcow2.c | 14 ++++++++------
23
block/raw-format.c | 6 +++---
24
block/vmdk.c | 2 ++
25
11 files changed, 44 insertions(+), 28 deletions(-)
26
23
27
diff --git a/include/block/block-io.h b/include/block/block-io.h
24
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
28
index XXXXXXX..XXXXXXX 100644
25
index XXXXXXX..XXXXXXX 100644
29
--- a/include/block/block-io.h
26
--- a/tests/qemu-iotests/iotests.py
30
+++ b/include/block/block-io.h
27
+++ b/tests/qemu-iotests/iotests.py
31
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_pwrite_sync(BdrvChild *child, int64_t offset,
28
@@ -XXX,XX +XXX,XX @@ def add_incoming(self, addr):
32
int coroutine_fn bdrv_co_pwrite_zeroes(BdrvChild *child, int64_t offset,
29
self._args.append(addr)
33
int64_t bytes, BdrvRequestFlags flags);
30
return self
34
31
35
-int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
32
+ def add_paused(self):
36
- PreallocMode prealloc, BdrvRequestFlags flags,
33
+ self._args.append('-S')
37
- Error **errp);
34
+ return self
38
+int coroutine_fn GRAPH_RDLOCK
35
+
39
+bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
36
def hmp(self, command_line: str, use_log: bool = False) -> QMPMessage:
40
+ PreallocMode prealloc, BdrvRequestFlags flags, Error **errp);
37
cmd = 'human-monitor-command'
41
38
kwargs: Dict[str, Any] = {'command-line': command_line}
42
int64_t coroutine_fn bdrv_co_nb_sectors(BlockDriverState *bs);
39
diff --git a/tests/qemu-iotests/tests/inactive-node-nbd b/tests/qemu-iotests/tests/inactive-node-nbd
43
int64_t co_wrapper_mixed bdrv_nb_sectors(BlockDriverState *bs);
40
new file mode 100755
44
diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
41
index XXXXXXX..XXXXXXX
45
index XXXXXXX..XXXXXXX 100644
42
--- /dev/null
46
--- a/include/block/block_int-common.h
43
+++ b/tests/qemu-iotests/tests/inactive-node-nbd
47
+++ b/include/block/block_int-common.h
44
@@ -XXX,XX +XXX,XX @@
48
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
45
+#!/usr/bin/env python3
49
* If @exact is true and this function fails but would succeed
46
+# group: rw quick
50
* with @exact = false, it should return -ENOTSUP.
47
+#
51
*/
48
+# Copyright (C) Red Hat, Inc.
52
- int coroutine_fn (*bdrv_co_truncate)(BlockDriverState *bs, int64_t offset,
49
+#
53
- bool exact, PreallocMode prealloc,
50
+# This program is free software; you can redistribute it and/or modify
54
- BdrvRequestFlags flags, Error **errp);
51
+# it under the terms of the GNU General Public License as published by
55
+ int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_truncate)(
52
+# the Free Software Foundation; either version 2 of the License, or
56
+ BlockDriverState *bs, int64_t offset, bool exact,
53
+# (at your option) any later version.
57
+ PreallocMode prealloc, BdrvRequestFlags flags, Error **errp);
54
+#
58
+
55
+# This program is distributed in the hope that it will be useful,
59
int64_t coroutine_fn (*bdrv_co_getlength)(BlockDriverState *bs);
56
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
60
int64_t coroutine_fn (*bdrv_co_get_allocated_file_size)(
57
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
61
BlockDriverState *bs);
58
+# GNU General Public License for more details.
62
diff --git a/block/block-backend.c b/block/block-backend.c
59
+#
63
index XXXXXXX..XXXXXXX 100644
60
+# You should have received a copy of the GNU General Public License
64
--- a/block/block-backend.c
61
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
65
+++ b/block/block-backend.c
62
+#
66
@@ -XXX,XX +XXX,XX @@ int coroutine_fn blk_co_truncate(BlockBackend *blk, int64_t offset, bool exact,
63
+# Creator/Owner: Kevin Wolf <kwolf@redhat.com>
67
Error **errp)
64
+
68
{
65
+import iotests
69
IO_OR_GS_CODE();
66
+
70
+ GRAPH_RDLOCK_GUARD();
67
+from iotests import QemuIoInteractive
71
if (!blk_is_available(blk)) {
68
+from iotests import filter_qemu_io, filter_qtest, filter_qmp_testfiles
72
error_setg(errp, "No medium inserted");
69
+
73
return -ENOMEDIUM;
70
+iotests.script_initialize(supported_fmts=['generic'],
74
diff --git a/block/crypto.c b/block/crypto.c
71
+ supported_protocols=['file'],
75
index XXXXXXX..XXXXXXX 100644
72
+ supported_platforms=['linux'])
76
--- a/block/crypto.c
73
+
77
+++ b/block/crypto.c
74
+def get_export(node_name='disk-fmt', allow_inactive=None):
78
@@ -XXX,XX +XXX,XX @@ block_crypto_co_create_generic(BlockDriverState *bs, int64_t size,
75
+ exp = {
79
return ret;
76
+ 'id': 'exp0',
80
}
77
+ 'type': 'nbd',
81
78
+ 'node-name': node_name,
82
-static int coroutine_fn
79
+ 'writable': True,
83
+static int coroutine_fn GRAPH_RDLOCK
80
+ }
84
block_crypto_co_truncate(BlockDriverState *bs, int64_t offset, bool exact,
81
+
85
PreallocMode prealloc, BdrvRequestFlags flags,
82
+ if allow_inactive is not None:
86
Error **errp)
83
+ exp['allow-inactive'] = allow_inactive
87
diff --git a/block/io.c b/block/io.c
84
+
88
index XXXXXXX..XXXXXXX 100644
85
+ return exp
89
--- a/block/io.c
86
+
90
+++ b/block/io.c
87
+def node_is_active(_vm, node_name):
91
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
88
+ nodes = _vm.cmd('query-named-block-nodes', flat=True)
92
int64_t old_size, new_bytes;
89
+ node = next(n for n in nodes if n['node-name'] == node_name)
93
int ret;
90
+ return node['active']
94
IO_CODE();
91
+
95
+ assert_bdrv_graph_readable();
92
+with iotests.FilePath('disk.img') as path, \
96
93
+ iotests.FilePath('snap.qcow2') as snap_path, \
97
/* if bs->drv == NULL, bs is closed, so there's nothing to do here */
94
+ iotests.FilePath('snap2.qcow2') as snap2_path, \
98
if (!drv) {
95
+ iotests.FilePath('target.img') as target_path, \
99
diff --git a/block/parallels.c b/block/parallels.c
96
+ iotests.FilePath('nbd.sock', base_dir=iotests.sock_dir) as nbd_sock, \
100
index XXXXXXX..XXXXXXX 100644
97
+ iotests.VM() as vm:
101
--- a/block/parallels.c
98
+
102
+++ b/block/parallels.c
99
+ img_size = '10M'
103
@@ -XXX,XX +XXX,XX @@ static int64_t block_status(BDRVParallelsState *s, int64_t sector_num,
100
+
104
return start_off;
101
+ iotests.log('Preparing disk...')
105
}
102
+ iotests.qemu_img_create('-f', iotests.imgfmt, path, img_size)
106
103
+ iotests.qemu_img_create('-f', iotests.imgfmt, target_path, img_size)
107
-static coroutine_fn int64_t allocate_clusters(BlockDriverState *bs,
104
+
108
- int64_t sector_num,
105
+ iotests.qemu_img_create('-f', 'qcow2', '-b', path, '-F', iotests.imgfmt,
109
- int nb_sectors, int *pnum)
106
+ snap_path)
110
+static int64_t coroutine_fn GRAPH_RDLOCK
107
+ iotests.qemu_img_create('-f', 'qcow2', '-b', snap_path, '-F', 'qcow2',
111
+allocate_clusters(BlockDriverState *bs, int64_t sector_num,
108
+ snap2_path)
112
+ int nb_sectors, int *pnum)
109
+
113
{
110
+ iotests.log('Launching VM...')
114
int ret = 0;
111
+ vm.add_blockdev(f'file,node-name=disk-file,filename={path}')
115
BDRVParallelsState *s = bs->opaque;
112
+ vm.add_blockdev(f'{iotests.imgfmt},file=disk-file,node-name=disk-fmt,'
116
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int parallels_co_writev(BlockDriverState *bs,
113
+ 'active=off')
117
QEMUIOVector hd_qiov;
114
+ vm.add_blockdev(f'file,node-name=target-file,filename={target_path}')
118
int ret = 0;
115
+ vm.add_blockdev(f'{iotests.imgfmt},file=target-file,node-name=target-fmt')
119
116
+ vm.add_blockdev(f'file,node-name=snap-file,filename={snap_path}')
120
+ assume_graph_lock(); /* FIXME */
117
+ vm.add_blockdev(f'file,node-name=snap2-file,filename={snap2_path}')
121
+
118
+
122
qemu_iovec_init(&hd_qiov, qiov->niov);
119
+ # Actually running the VM activates all images
123
120
+ vm.add_paused()
124
while (nb_sectors > 0) {
121
+
125
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int parallels_co_readv(BlockDriverState *bs,
122
+ vm.launch()
126
}
123
+ vm.qmp_log('nbd-server-start',
127
124
+ addr={'type': 'unix', 'data':{'path': nbd_sock}},
128
125
+ filters=[filter_qmp_testfiles])
129
-static int coroutine_fn parallels_co_check(BlockDriverState *bs,
126
+
130
- BdrvCheckResult *res,
127
+ iotests.log('\n=== Creating export of inactive node ===')
131
- BdrvCheckMode fix)
128
+
132
+static int coroutine_fn GRAPH_RDLOCK
129
+ iotests.log('\nExports activate nodes without allow-inactive')
133
+parallels_co_check(BlockDriverState *bs, BdrvCheckResult *res,
130
+ iotests.log('disk-fmt active: %s' % node_is_active(vm, 'disk-fmt'))
134
+ BdrvCheckMode fix)
131
+ vm.qmp_log('block-export-add', **get_export())
135
{
132
+ iotests.log('disk-fmt active: %s' % node_is_active(vm, 'disk-fmt'))
136
BDRVParallelsState *s = bs->opaque;
133
+ vm.qmp_log('query-block-exports')
137
int64_t size, prev_off, high_off;
134
+ vm.qmp_log('block-export-del', id='exp0')
138
diff --git a/block/preallocate.c b/block/preallocate.c
135
+ vm.event_wait('BLOCK_EXPORT_DELETED')
139
index XXXXXXX..XXXXXXX 100644
136
+ vm.qmp_log('query-block-exports')
140
--- a/block/preallocate.c
137
+
141
+++ b/block/preallocate.c
138
+ iotests.log('\nExports activate nodes with allow-inactive=false')
142
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int preallocate_co_pwritev_part(BlockDriverState *bs,
139
+ vm.qmp_log('blockdev-set-active', node_name='disk-fmt', active=False)
143
flags);
140
+ iotests.log('disk-fmt active: %s' % node_is_active(vm, 'disk-fmt'))
144
}
141
+ vm.qmp_log('block-export-add', **get_export(allow_inactive=False))
145
142
+ iotests.log('disk-fmt active: %s' % node_is_active(vm, 'disk-fmt'))
146
-static int coroutine_fn
143
+ vm.qmp_log('query-block-exports')
147
+static int coroutine_fn GRAPH_RDLOCK
144
+ vm.qmp_log('block-export-del', id='exp0')
148
preallocate_co_truncate(BlockDriverState *bs, int64_t offset,
145
+ vm.event_wait('BLOCK_EXPORT_DELETED')
149
bool exact, PreallocMode prealloc,
146
+ vm.qmp_log('query-block-exports')
150
BdrvRequestFlags flags, Error **errp)
147
+
151
diff --git a/block/qcow.c b/block/qcow.c
148
+ iotests.log('\nExport leaves nodes inactive with allow-inactive=true')
152
index XXXXXXX..XXXXXXX 100644
149
+ vm.qmp_log('blockdev-set-active', node_name='disk-fmt', active=False)
153
--- a/block/qcow.c
150
+ iotests.log('disk-fmt active: %s' % node_is_active(vm, 'disk-fmt'))
154
+++ b/block/qcow.c
151
+ vm.qmp_log('block-export-add', **get_export(allow_inactive=True))
155
@@ -XXX,XX +XXX,XX @@ static int qcow_reopen_prepare(BDRVReopenState *state,
152
+ iotests.log('disk-fmt active: %s' % node_is_active(vm, 'disk-fmt'))
156
* return 0 if not allocated, 1 if *result is assigned, and negative
153
+ vm.qmp_log('query-block-exports')
157
* errno on failure.
154
+ vm.qmp_log('block-export-del', id='exp0')
158
*/
155
+ vm.event_wait('BLOCK_EXPORT_DELETED')
159
-static int coroutine_fn get_cluster_offset(BlockDriverState *bs,
156
+ vm.qmp_log('query-block-exports')
160
- uint64_t offset, int allocate,
157
+
161
- int compressed_size,
158
+ iotests.log('\n=== Inactivating node with existing export ===')
162
- int n_start, int n_end,
159
+
163
- uint64_t *result)
160
+ iotests.log('\nInactivating nodes with an export fails without '
164
+static int coroutine_fn GRAPH_RDLOCK
161
+ 'allow-inactive')
165
+get_cluster_offset(BlockDriverState *bs, uint64_t offset, int allocate,
162
+ vm.qmp_log('blockdev-set-active', node_name='disk-fmt', active=True)
166
+ int compressed_size, int n_start, int n_end,
163
+ vm.qmp_log('block-export-add', **get_export(node_name='disk-fmt'))
167
+ uint64_t *result)
164
+ vm.qmp_log('blockdev-set-active', node_name='disk-fmt', active=False)
168
{
165
+ iotests.log('disk-fmt active: %s' % node_is_active(vm, 'disk-fmt'))
169
BDRVQcowState *s = bs->opaque;
166
+ vm.qmp_log('query-block-exports')
170
int min_index, i, j, l1_index, l2_index, ret;
167
+ vm.qmp_log('block-export-del', id='exp0')
171
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow_co_block_status(BlockDriverState *bs,
168
+ vm.event_wait('BLOCK_EXPORT_DELETED')
172
int64_t n;
169
+ vm.qmp_log('query-block-exports')
173
uint64_t cluster_offset;
170
+
174
171
+ iotests.log('\nInactivating nodes with an export fails with '
175
+ assume_graph_lock(); /* FIXME */
172
+ 'allow-inactive=false')
176
+
173
+ vm.qmp_log('blockdev-set-active', node_name='disk-fmt', active=True)
177
qemu_co_mutex_lock(&s->lock);
174
+ vm.qmp_log('block-export-add',
178
ret = get_cluster_offset(bs, offset, 0, 0, 0, 0, &cluster_offset);
175
+ **get_export(node_name='disk-fmt', allow_inactive=False))
179
qemu_co_mutex_unlock(&s->lock);
176
+ vm.qmp_log('blockdev-set-active', node_name='disk-fmt', active=False)
180
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow_co_preadv(BlockDriverState *bs, int64_t offset,
177
+ iotests.log('disk-fmt active: %s' % node_is_active(vm, 'disk-fmt'))
181
uint8_t *buf;
178
+ vm.qmp_log('query-block-exports')
182
void *orig_buf;
179
+ vm.qmp_log('block-export-del', id='exp0')
183
180
+ vm.event_wait('BLOCK_EXPORT_DELETED')
184
+ assume_graph_lock(); /* FIXME */
181
+ vm.qmp_log('query-block-exports')
185
+
182
+
186
if (qiov->niov > 1) {
183
+ iotests.log('\nInactivating nodes with an export works with '
187
buf = orig_buf = qemu_try_blockalign(bs, qiov->size);
184
+ 'allow-inactive=true')
188
if (buf == NULL) {
185
+ vm.qmp_log('blockdev-set-active', node_name='disk-fmt', active=True)
189
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow_co_pwritev(BlockDriverState *bs, int64_t offset,
186
+ vm.qmp_log('block-export-add',
190
uint8_t *buf;
187
+ **get_export(node_name='disk-fmt', allow_inactive=True))
191
void *orig_buf;
188
+ vm.qmp_log('blockdev-set-active', node_name='disk-fmt', active=False)
192
189
+ iotests.log('disk-fmt active: %s' % node_is_active(vm, 'disk-fmt'))
193
+ assume_graph_lock(); /* FIXME */
190
+ vm.qmp_log('query-block-exports')
194
+
191
+ vm.qmp_log('block-export-del', id='exp0')
195
s->cluster_cache_offset = -1; /* disable compressed cache */
192
+ vm.event_wait('BLOCK_EXPORT_DELETED')
196
193
+ vm.qmp_log('query-block-exports')
197
/* We must always copy the iov when encrypting, so we
194
+
198
@@ -XXX,XX +XXX,XX @@ qcow_co_pwritev_compressed(BlockDriverState *bs, int64_t offset, int64_t bytes,
195
+ iotests.log('\n=== Inactive nodes with parent ===')
199
uint8_t *buf, *out_buf;
196
+
200
uint64_t cluster_offset;
197
+ iotests.log('\nInactivating nodes with an active parent fails')
201
198
+ vm.qmp_log('blockdev-set-active', node_name='disk-fmt', active=True)
202
+ assume_graph_lock(); /* FIXME */
199
+ vm.qmp_log('blockdev-set-active', node_name='disk-file', active=False)
203
+
200
+ iotests.log('disk-file active: %s' % node_is_active(vm, 'disk-file'))
204
buf = qemu_blockalign(bs, s->cluster_size);
201
+ iotests.log('disk-fmt active: %s' % node_is_active(vm, 'disk-fmt'))
205
if (bytes != s->cluster_size) {
202
+
206
if (bytes > s->cluster_size ||
203
+ iotests.log('\nInactivating nodes with an inactive parent works')
207
diff --git a/block/qcow2.c b/block/qcow2.c
204
+ vm.qmp_log('blockdev-set-active', node_name='disk-fmt', active=False)
208
index XXXXXXX..XXXXXXX 100644
205
+ vm.qmp_log('blockdev-set-active', node_name='disk-file', active=False)
209
--- a/block/qcow2.c
206
+ iotests.log('disk-file active: %s' % node_is_active(vm, 'disk-file'))
210
+++ b/block/qcow2.c
207
+ iotests.log('disk-fmt active: %s' % node_is_active(vm, 'disk-fmt'))
211
@@ -XXX,XX +XXX,XX @@ static int qcow2_set_up_encryption(BlockDriverState *bs,
208
+
212
*
209
+ iotests.log('\nCreating active parent node with an inactive child fails')
213
* Returns: 0 on success, -errno on failure.
210
+ vm.qmp_log('blockdev-add', driver='raw', file='disk-fmt',
214
*/
211
+ node_name='disk-filter')
215
-static int coroutine_fn preallocate_co(BlockDriverState *bs, uint64_t offset,
212
+ vm.qmp_log('blockdev-add', driver='raw', file='disk-fmt',
216
- uint64_t new_length, PreallocMode mode,
213
+ node_name='disk-filter', active=True)
217
- Error **errp)
214
+
218
+static int coroutine_fn GRAPH_RDLOCK
215
+ iotests.log('\nCreating inactive parent node with an inactive child works')
219
+preallocate_co(BlockDriverState *bs, uint64_t offset, uint64_t new_length,
216
+ vm.qmp_log('blockdev-add', driver='raw', file='disk-fmt',
220
+ PreallocMode mode, Error **errp)
217
+ node_name='disk-filter', active=False)
221
{
218
+ vm.qmp_log('blockdev-del', node_name='disk-filter')
222
BDRVQcow2State *s = bs->opaque;
219
+
223
uint64_t bytes;
220
+ iotests.log('\n=== Resizing an inactive node ===')
224
@@ -XXX,XX +XXX,XX @@ fail:
221
+ vm.qmp_log('block_resize', node_name='disk-fmt', size=16*1024*1024)
225
return ret;
222
+
226
}
223
+ iotests.log('\n=== Taking a snapshot of an inactive node ===')
227
224
+
228
-static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
225
+ iotests.log('\nActive overlay over inactive backing file automatically '
229
- bool exact, PreallocMode prealloc,
226
+ 'makes both inactive for compatibility')
230
- BdrvRequestFlags flags, Error **errp)
227
+ vm.qmp_log('blockdev-add', driver='qcow2', node_name='snap-fmt',
231
+static int coroutine_fn GRAPH_RDLOCK
228
+ file='snap-file', backing=None)
232
+qcow2_co_truncate(BlockDriverState *bs, int64_t offset, bool exact,
229
+ iotests.log('disk-fmt active: %s' % node_is_active(vm, 'disk-fmt'))
233
+ PreallocMode prealloc, BdrvRequestFlags flags, Error **errp)
230
+ iotests.log('snap-fmt active: %s' % node_is_active(vm, 'snap-fmt'))
234
{
231
+ vm.qmp_log('blockdev-snapshot', node='disk-fmt', overlay='snap-fmt')
235
BDRVQcow2State *s = bs->opaque;
232
+ iotests.log('disk-fmt active: %s' % node_is_active(vm, 'disk-fmt'))
236
uint64_t old_length;
233
+ iotests.log('snap-fmt active: %s' % node_is_active(vm, 'snap-fmt'))
237
@@ -XXX,XX +XXX,XX @@ qcow2_co_pwritev_compressed_part(BlockDriverState *bs,
234
+ vm.qmp_log('blockdev-del', node_name='snap-fmt')
238
AioTaskPool *aio = NULL;
235
+
239
int ret = 0;
236
+ iotests.log('\nInactive overlay over inactive backing file just works')
240
237
+ vm.qmp_log('blockdev-add', driver='qcow2', node_name='snap-fmt',
241
+ assume_graph_lock(); /* FIXME */
238
+ file='snap-file', backing=None, active=False)
242
+
239
+ vm.qmp_log('blockdev-snapshot', node='disk-fmt', overlay='snap-fmt')
243
if (has_data_file(bs)) {
240
+
244
return -ENOTSUP;
241
+ iotests.log('\n=== Block jobs with inactive nodes ===')
245
}
242
+
246
diff --git a/block/raw-format.c b/block/raw-format.c
243
+ iotests.log('\nStreaming into an inactive node')
247
index XXXXXXX..XXXXXXX 100644
244
+ vm.qmp_log('block-stream', device='snap-fmt',
248
--- a/block/raw-format.c
245
+ filters=[iotests.filter_qmp_generated_node_ids])
249
+++ b/block/raw-format.c
246
+
250
@@ -XXX,XX +XXX,XX @@ static void raw_refresh_limits(BlockDriverState *bs, Error **errp)
247
+ iotests.log('\nCommitting an inactive root node (active commit)')
251
}
248
+ vm.qmp_log('block-commit', job_id='job0', device='snap-fmt',
252
}
249
+ filters=[iotests.filter_qmp_generated_node_ids])
253
250
+
254
-static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset,
251
+ iotests.log('\nCommitting an inactive intermediate node to inactive base')
255
- bool exact, PreallocMode prealloc,
252
+ vm.qmp_log('blockdev-add', driver='qcow2', node_name='snap2-fmt',
256
- BdrvRequestFlags flags, Error **errp)
253
+ file='snap2-file', backing='snap-fmt', active=False)
257
+static int coroutine_fn GRAPH_RDLOCK
254
+
258
+raw_co_truncate(BlockDriverState *bs, int64_t offset, bool exact,
255
+ iotests.log('disk-fmt active: %s' % node_is_active(vm, 'disk-fmt'))
259
+ PreallocMode prealloc, BdrvRequestFlags flags, Error **errp)
256
+ iotests.log('snap-fmt active: %s' % node_is_active(vm, 'snap-fmt'))
260
{
257
+ iotests.log('snap2-fmt active: %s' % node_is_active(vm, 'snap2-fmt'))
261
BDRVRawState *s = bs->opaque;
258
+
262
259
+ vm.qmp_log('block-commit', job_id='job0', device='snap2-fmt',
263
diff --git a/block/vmdk.c b/block/vmdk.c
260
+ top_node='snap-fmt',
264
index XXXXXXX..XXXXXXX 100644
261
+ filters=[iotests.filter_qmp_generated_node_ids])
265
--- a/block/vmdk.c
262
+
266
+++ b/block/vmdk.c
263
+ iotests.log('\nCommitting an inactive intermediate node to active base')
267
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn
264
+ vm.qmp_log('blockdev-set-active', node_name='disk-fmt', active=True)
268
vmdk_co_pwritev_compressed(BlockDriverState *bs, int64_t offset, int64_t bytes,
265
+ vm.qmp_log('block-commit', job_id='job0', device='snap2-fmt',
269
QEMUIOVector *qiov)
266
+ top_node='snap-fmt',
270
{
267
+ filters=[iotests.filter_qmp_generated_node_ids])
271
+ assume_graph_lock(); /* FIXME */
268
+
272
+
269
+ iotests.log('\nMirror from inactive source to active target')
273
if (bytes == 0) {
270
+ vm.qmp_log('blockdev-mirror', job_id='job0', device='snap2-fmt',
274
/* The caller will write bytes 0 to signal EOF.
271
+ target='target-fmt', sync='full',
275
* When receive it, we align EOF to a sector boundary. */
272
+ filters=[iotests.filter_qmp_generated_node_ids])
273
+
274
+ iotests.log('\nMirror from active source to inactive target')
275
+
276
+ iotests.log('disk-fmt active: %s' % node_is_active(vm, 'disk-fmt'))
277
+ iotests.log('snap-fmt active: %s' % node_is_active(vm, 'snap-fmt'))
278
+ iotests.log('snap2-fmt active: %s' % node_is_active(vm, 'snap2-fmt'))
279
+ iotests.log('target-fmt active: %s' % node_is_active(vm, 'target-fmt'))
280
+
281
+ # Activating snap2-fmt recursively activates the whole backing chain
282
+ vm.qmp_log('blockdev-set-active', node_name='snap2-fmt', active=True)
283
+ vm.qmp_log('blockdev-set-active', node_name='target-fmt', active=False)
284
+
285
+ iotests.log('disk-fmt active: %s' % node_is_active(vm, 'disk-fmt'))
286
+ iotests.log('snap-fmt active: %s' % node_is_active(vm, 'snap-fmt'))
287
+ iotests.log('snap2-fmt active: %s' % node_is_active(vm, 'snap2-fmt'))
288
+ iotests.log('target-fmt active: %s' % node_is_active(vm, 'target-fmt'))
289
+
290
+ vm.qmp_log('blockdev-mirror', job_id='job0', device='snap2-fmt',
291
+ target='target-fmt', sync='full',
292
+ filters=[iotests.filter_qmp_generated_node_ids])
293
+
294
+ iotests.log('\nBackup from active source to inactive target')
295
+
296
+ vm.qmp_log('blockdev-backup', job_id='job0', device='snap2-fmt',
297
+ target='target-fmt', sync='full',
298
+ filters=[iotests.filter_qmp_generated_node_ids])
299
+
300
+ iotests.log('\nBackup from inactive source to active target')
301
+
302
+ # Inactivating snap2-fmt recursively inactivates the whole backing chain
303
+ vm.qmp_log('blockdev-set-active', node_name='snap2-fmt', active=False)
304
+ vm.qmp_log('blockdev-set-active', node_name='target-fmt', active=True)
305
+
306
+ iotests.log('disk-fmt active: %s' % node_is_active(vm, 'disk-fmt'))
307
+ iotests.log('snap-fmt active: %s' % node_is_active(vm, 'snap-fmt'))
308
+ iotests.log('snap2-fmt active: %s' % node_is_active(vm, 'snap2-fmt'))
309
+ iotests.log('target-fmt active: %s' % node_is_active(vm, 'target-fmt'))
310
+
311
+ vm.qmp_log('blockdev-backup', job_id='job0', device='snap2-fmt',
312
+ target='target-fmt', sync='full',
313
+ filters=[iotests.filter_qmp_generated_node_ids])
314
+
315
+ iotests.log('\n=== Accessing export on inactive node ===')
316
+
317
+ # Use the target node because it has the right image format and isn't the
318
+ # (read-only) backing file of a qcow2 node
319
+ vm.qmp_log('blockdev-set-active', node_name='target-fmt', active=False)
320
+ vm.qmp_log('block-export-add',
321
+ **get_export(node_name='target-fmt', allow_inactive=True))
322
+
323
+ # The read should succeed, everything else should fail gracefully
324
+ qemu_io = QemuIoInteractive('-f', 'raw',
325
+ f'nbd+unix:///target-fmt?socket={nbd_sock}')
326
+ iotests.log(qemu_io.cmd('read 0 64k'), filters=[filter_qemu_io])
327
+ iotests.log(qemu_io.cmd('write 0 64k'), filters=[filter_qemu_io])
328
+ iotests.log(qemu_io.cmd('write -z 0 64k'), filters=[filter_qemu_io])
329
+ iotests.log(qemu_io.cmd('write -zu 0 64k'), filters=[filter_qemu_io])
330
+ iotests.log(qemu_io.cmd('discard 0 64k'), filters=[filter_qemu_io])
331
+ iotests.log(qemu_io.cmd('flush'), filters=[filter_qemu_io])
332
+ iotests.log(qemu_io.cmd('map'), filters=[filter_qemu_io])
333
+ qemu_io.close()
334
+
335
+ iotests.log('\n=== Resuming VM activates all images ===')
336
+ vm.qmp_log('cont')
337
+
338
+ iotests.log('disk-fmt active: %s' % node_is_active(vm, 'disk-fmt'))
339
+ iotests.log('snap-fmt active: %s' % node_is_active(vm, 'snap-fmt'))
340
+ iotests.log('snap2-fmt active: %s' % node_is_active(vm, 'snap2-fmt'))
341
+ iotests.log('target-fmt active: %s' % node_is_active(vm, 'target-fmt'))
342
+
343
+ iotests.log('\nShutting down...')
344
+ vm.shutdown()
345
+ log = vm.get_log()
346
+ if log:
347
+ iotests.log(log, [filter_qtest, filter_qemu_io])
348
diff --git a/tests/qemu-iotests/tests/inactive-node-nbd.out b/tests/qemu-iotests/tests/inactive-node-nbd.out
349
new file mode 100644
350
index XXXXXXX..XXXXXXX
351
--- /dev/null
352
+++ b/tests/qemu-iotests/tests/inactive-node-nbd.out
353
@@ -XXX,XX +XXX,XX @@
354
+Preparing disk...
355
+Launching VM...
356
+{"execute": "nbd-server-start", "arguments": {"addr": {"data": {"path": "SOCK_DIR/PID-nbd.sock"}, "type": "unix"}}}
357
+{"return": {}}
358
+
359
+=== Creating export of inactive node ===
360
+
361
+Exports activate nodes without allow-inactive
362
+disk-fmt active: False
363
+{"execute": "block-export-add", "arguments": {"id": "exp0", "node-name": "disk-fmt", "type": "nbd", "writable": true}}
364
+{"return": {}}
365
+disk-fmt active: True
366
+{"execute": "query-block-exports", "arguments": {}}
367
+{"return": [{"id": "exp0", "node-name": "disk-fmt", "shutting-down": false, "type": "nbd"}]}
368
+{"execute": "block-export-del", "arguments": {"id": "exp0"}}
369
+{"return": {}}
370
+{"execute": "query-block-exports", "arguments": {}}
371
+{"return": []}
372
+
373
+Exports activate nodes with allow-inactive=false
374
+{"execute": "blockdev-set-active", "arguments": {"active": false, "node-name": "disk-fmt"}}
375
+{"return": {}}
376
+disk-fmt active: False
377
+{"execute": "block-export-add", "arguments": {"allow-inactive": false, "id": "exp0", "node-name": "disk-fmt", "type": "nbd", "writable": true}}
378
+{"return": {}}
379
+disk-fmt active: True
380
+{"execute": "query-block-exports", "arguments": {}}
381
+{"return": [{"id": "exp0", "node-name": "disk-fmt", "shutting-down": false, "type": "nbd"}]}
382
+{"execute": "block-export-del", "arguments": {"id": "exp0"}}
383
+{"return": {}}
384
+{"execute": "query-block-exports", "arguments": {}}
385
+{"return": []}
386
+
387
+Export leaves nodes inactive with allow-inactive=true
388
+{"execute": "blockdev-set-active", "arguments": {"active": false, "node-name": "disk-fmt"}}
389
+{"return": {}}
390
+disk-fmt active: False
391
+{"execute": "block-export-add", "arguments": {"allow-inactive": true, "id": "exp0", "node-name": "disk-fmt", "type": "nbd", "writable": true}}
392
+{"return": {}}
393
+disk-fmt active: False
394
+{"execute": "query-block-exports", "arguments": {}}
395
+{"return": [{"id": "exp0", "node-name": "disk-fmt", "shutting-down": false, "type": "nbd"}]}
396
+{"execute": "block-export-del", "arguments": {"id": "exp0"}}
397
+{"return": {}}
398
+{"execute": "query-block-exports", "arguments": {}}
399
+{"return": []}
400
+
401
+=== Inactivating node with existing export ===
402
+
403
+Inactivating nodes with an export fails without allow-inactive
404
+{"execute": "blockdev-set-active", "arguments": {"active": true, "node-name": "disk-fmt"}}
405
+{"return": {}}
406
+{"execute": "block-export-add", "arguments": {"id": "exp0", "node-name": "disk-fmt", "type": "nbd", "writable": true}}
407
+{"return": {}}
408
+{"execute": "blockdev-set-active", "arguments": {"active": false, "node-name": "disk-fmt"}}
409
+{"error": {"class": "GenericError", "desc": "Failed to inactivate node: Operation not permitted"}}
410
+disk-fmt active: True
411
+{"execute": "query-block-exports", "arguments": {}}
412
+{"return": [{"id": "exp0", "node-name": "disk-fmt", "shutting-down": false, "type": "nbd"}]}
413
+{"execute": "block-export-del", "arguments": {"id": "exp0"}}
414
+{"return": {}}
415
+{"execute": "query-block-exports", "arguments": {}}
416
+{"return": []}
417
+
418
+Inactivating nodes with an export fails with allow-inactive=false
419
+{"execute": "blockdev-set-active", "arguments": {"active": true, "node-name": "disk-fmt"}}
420
+{"return": {}}
421
+{"execute": "block-export-add", "arguments": {"allow-inactive": false, "id": "exp0", "node-name": "disk-fmt", "type": "nbd", "writable": true}}
422
+{"return": {}}
423
+{"execute": "blockdev-set-active", "arguments": {"active": false, "node-name": "disk-fmt"}}
424
+{"error": {"class": "GenericError", "desc": "Failed to inactivate node: Operation not permitted"}}
425
+disk-fmt active: True
426
+{"execute": "query-block-exports", "arguments": {}}
427
+{"return": [{"id": "exp0", "node-name": "disk-fmt", "shutting-down": false, "type": "nbd"}]}
428
+{"execute": "block-export-del", "arguments": {"id": "exp0"}}
429
+{"return": {}}
430
+{"execute": "query-block-exports", "arguments": {}}
431
+{"return": []}
432
+
433
+Inactivating nodes with an export works with allow-inactive=true
434
+{"execute": "blockdev-set-active", "arguments": {"active": true, "node-name": "disk-fmt"}}
435
+{"return": {}}
436
+{"execute": "block-export-add", "arguments": {"allow-inactive": true, "id": "exp0", "node-name": "disk-fmt", "type": "nbd", "writable": true}}
437
+{"return": {}}
438
+{"execute": "blockdev-set-active", "arguments": {"active": false, "node-name": "disk-fmt"}}
439
+{"return": {}}
440
+disk-fmt active: False
441
+{"execute": "query-block-exports", "arguments": {}}
442
+{"return": [{"id": "exp0", "node-name": "disk-fmt", "shutting-down": false, "type": "nbd"}]}
443
+{"execute": "block-export-del", "arguments": {"id": "exp0"}}
444
+{"return": {}}
445
+{"execute": "query-block-exports", "arguments": {}}
446
+{"return": []}
447
+
448
+=== Inactive nodes with parent ===
449
+
450
+Inactivating nodes with an active parent fails
451
+{"execute": "blockdev-set-active", "arguments": {"active": true, "node-name": "disk-fmt"}}
452
+{"return": {}}
453
+{"execute": "blockdev-set-active", "arguments": {"active": false, "node-name": "disk-file"}}
454
+{"error": {"class": "GenericError", "desc": "Node has active parent node"}}
455
+disk-file active: True
456
+disk-fmt active: True
457
+
458
+Inactivating nodes with an inactive parent works
459
+{"execute": "blockdev-set-active", "arguments": {"active": false, "node-name": "disk-fmt"}}
460
+{"return": {}}
461
+{"execute": "blockdev-set-active", "arguments": {"active": false, "node-name": "disk-file"}}
462
+{"return": {}}
463
+disk-file active: False
464
+disk-fmt active: False
465
+
466
+Creating active parent node with an inactive child fails
467
+{"execute": "blockdev-add", "arguments": {"driver": "raw", "file": "disk-fmt", "node-name": "disk-filter"}}
468
+{"error": {"class": "GenericError", "desc": "Inactive 'disk-fmt' can't be a file child of active 'disk-filter'"}}
469
+{"execute": "blockdev-add", "arguments": {"active": true, "driver": "raw", "file": "disk-fmt", "node-name": "disk-filter"}}
470
+{"error": {"class": "GenericError", "desc": "Inactive 'disk-fmt' can't be a file child of active 'disk-filter'"}}
471
+
472
+Creating inactive parent node with an inactive child works
473
+{"execute": "blockdev-add", "arguments": {"active": false, "driver": "raw", "file": "disk-fmt", "node-name": "disk-filter"}}
474
+{"return": {}}
475
+{"execute": "blockdev-del", "arguments": {"node-name": "disk-filter"}}
476
+{"return": {}}
477
+
478
+=== Resizing an inactive node ===
479
+{"execute": "block_resize", "arguments": {"node-name": "disk-fmt", "size": 16777216}}
480
+{"error": {"class": "GenericError", "desc": "Permission 'resize' unavailable on inactive node"}}
481
+
482
+=== Taking a snapshot of an inactive node ===
483
+
484
+Active overlay over inactive backing file automatically makes both inactive for compatibility
485
+{"execute": "blockdev-add", "arguments": {"backing": null, "driver": "qcow2", "file": "snap-file", "node-name": "snap-fmt"}}
486
+{"return": {}}
487
+disk-fmt active: False
488
+snap-fmt active: True
489
+{"execute": "blockdev-snapshot", "arguments": {"node": "disk-fmt", "overlay": "snap-fmt"}}
490
+{"return": {}}
491
+disk-fmt active: False
492
+snap-fmt active: False
493
+{"execute": "blockdev-del", "arguments": {"node-name": "snap-fmt"}}
494
+{"return": {}}
495
+
496
+Inactive overlay over inactive backing file just works
497
+{"execute": "blockdev-add", "arguments": {"active": false, "backing": null, "driver": "qcow2", "file": "snap-file", "node-name": "snap-fmt"}}
498
+{"return": {}}
499
+{"execute": "blockdev-snapshot", "arguments": {"node": "disk-fmt", "overlay": "snap-fmt"}}
500
+{"return": {}}
501
+
502
+=== Block jobs with inactive nodes ===
503
+
504
+Streaming into an inactive node
505
+{"execute": "block-stream", "arguments": {"device": "snap-fmt"}}
506
+{"error": {"class": "GenericError", "desc": "Could not create node: Inactive 'snap-fmt' can't be a file child of active 'NODE_NAME'"}}
507
+
508
+Committing an inactive root node (active commit)
509
+{"execute": "block-commit", "arguments": {"device": "snap-fmt", "job-id": "job0"}}
510
+{"error": {"class": "GenericError", "desc": "Inactive 'snap-fmt' can't be a backing child of active 'NODE_NAME'"}}
511
+
512
+Committing an inactive intermediate node to inactive base
513
+{"execute": "blockdev-add", "arguments": {"active": false, "backing": "snap-fmt", "driver": "qcow2", "file": "snap2-file", "node-name": "snap2-fmt"}}
514
+{"return": {}}
515
+disk-fmt active: False
516
+snap-fmt active: False
517
+snap2-fmt active: False
518
+{"execute": "block-commit", "arguments": {"device": "snap2-fmt", "job-id": "job0", "top-node": "snap-fmt"}}
519
+{"error": {"class": "GenericError", "desc": "Inactive 'snap-fmt' can't be a backing child of active 'NODE_NAME'"}}
520
+
521
+Committing an inactive intermediate node to active base
522
+{"execute": "blockdev-set-active", "arguments": {"active": true, "node-name": "disk-fmt"}}
523
+{"return": {}}
524
+{"execute": "block-commit", "arguments": {"device": "snap2-fmt", "job-id": "job0", "top-node": "snap-fmt"}}
525
+{"error": {"class": "GenericError", "desc": "Inactive 'snap-fmt' can't be a backing child of active 'NODE_NAME'"}}
526
+
527
+Mirror from inactive source to active target
528
+{"execute": "blockdev-mirror", "arguments": {"device": "snap2-fmt", "job-id": "job0", "sync": "full", "target": "target-fmt"}}
529
+{"error": {"class": "GenericError", "desc": "Inactive 'snap2-fmt' can't be a backing child of active 'NODE_NAME'"}}
530
+
531
+Mirror from active source to inactive target
532
+disk-fmt active: True
533
+snap-fmt active: False
534
+snap2-fmt active: False
535
+target-fmt active: True
536
+{"execute": "blockdev-set-active", "arguments": {"active": true, "node-name": "snap2-fmt"}}
537
+{"return": {}}
538
+{"execute": "blockdev-set-active", "arguments": {"active": false, "node-name": "target-fmt"}}
539
+{"return": {}}
540
+disk-fmt active: True
541
+snap-fmt active: True
542
+snap2-fmt active: True
543
+target-fmt active: False
544
+{"execute": "blockdev-mirror", "arguments": {"device": "snap2-fmt", "job-id": "job0", "sync": "full", "target": "target-fmt"}}
545
+{"error": {"class": "GenericError", "desc": "Permission 'write' unavailable on inactive node"}}
546
+
547
+Backup from active source to inactive target
548
+{"execute": "blockdev-backup", "arguments": {"device": "snap2-fmt", "job-id": "job0", "sync": "full", "target": "target-fmt"}}
549
+{"error": {"class": "GenericError", "desc": "Could not create node: Inactive 'target-fmt' can't be a target child of active 'NODE_NAME'"}}
550
+
551
+Backup from inactive source to active target
552
+{"execute": "blockdev-set-active", "arguments": {"active": false, "node-name": "snap2-fmt"}}
553
+{"return": {}}
554
+{"execute": "blockdev-set-active", "arguments": {"active": true, "node-name": "target-fmt"}}
555
+{"return": {}}
556
+disk-fmt active: False
557
+snap-fmt active: False
558
+snap2-fmt active: False
559
+target-fmt active: True
560
+{"execute": "blockdev-backup", "arguments": {"device": "snap2-fmt", "job-id": "job0", "sync": "full", "target": "target-fmt"}}
561
+{"error": {"class": "GenericError", "desc": "Could not create node: Inactive 'snap2-fmt' can't be a file child of active 'NODE_NAME'"}}
562
+
563
+=== Accessing export on inactive node ===
564
+{"execute": "blockdev-set-active", "arguments": {"active": false, "node-name": "target-fmt"}}
565
+{"return": {}}
566
+{"execute": "block-export-add", "arguments": {"allow-inactive": true, "id": "exp0", "node-name": "target-fmt", "type": "nbd", "writable": true}}
567
+{"return": {}}
568
+read 65536/65536 bytes at offset 0
569
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
570
+
571
+write failed: Operation not permitted
572
+
573
+write failed: Operation not permitted
574
+
575
+write failed: Operation not permitted
576
+
577
+discard failed: Operation not permitted
578
+
579
+
580
+qemu-io: Failed to get allocation status: Operation not permitted
581
+
582
+
583
+=== Resuming VM activates all images ===
584
+{"execute": "cont", "arguments": {}}
585
+{"return": {}}
586
+disk-fmt active: True
587
+snap-fmt active: True
588
+snap2-fmt active: True
589
+target-fmt active: True
590
+
591
+Shutting down...
592
+
276
--
593
--
277
2.39.2
594
2.48.1
diff view generated by jsdifflib
Deleted patch
1
This adds GRAPH_RDLOCK annotations to declare that callers of
2
bdrv_co_block_status() need to hold a reader lock for the graph.
3
1
4
For some places, we know that they will hold the lock, but we don't have
5
the GRAPH_RDLOCK annotations yet. In this case, add assume_graph_lock()
6
with a FIXME comment. These places will be removed once everything is
7
properly annotated.
8
9
Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Message-Id: <20230203152202.49054-5-kwolf@redhat.com>
12
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
---
15
block/coroutines.h | 2 +-
16
include/block/block-copy.h | 6 +++---
17
include/block/block-io.h | 22 +++++++++++-----------
18
include/block/block_int-common.h | 3 ++-
19
block/backup.c | 3 +++
20
block/block-backend.c | 2 ++
21
block/block-copy.c | 19 +++++++++++--------
22
block/io.c | 13 ++++++++-----
23
block/mirror.c | 14 +++++++++-----
24
block/qcow.c | 11 ++++-------
25
block/quorum.c | 9 ++++-----
26
block/stream.c | 32 ++++++++++++++++++--------------
27
qemu-img.c | 4 +++-
28
tests/unit/test-block-iothread.c | 3 ++-
29
14 files changed, 81 insertions(+), 62 deletions(-)
30
31
diff --git a/block/coroutines.h b/block/coroutines.h
32
index XXXXXXX..XXXXXXX 100644
33
--- a/block/coroutines.h
34
+++ b/block/coroutines.h
35
@@ -XXX,XX +XXX,XX @@ bdrv_co_check(BlockDriverState *bs, BdrvCheckResult *res, BdrvCheckMode fix);
36
int coroutine_fn GRAPH_RDLOCK
37
bdrv_co_invalidate_cache(BlockDriverState *bs, Error **errp);
38
39
-int coroutine_fn
40
+int coroutine_fn GRAPH_RDLOCK
41
bdrv_co_common_block_status_above(BlockDriverState *bs,
42
BlockDriverState *base,
43
bool include_base,
44
diff --git a/include/block/block-copy.h b/include/block/block-copy.h
45
index XXXXXXX..XXXXXXX 100644
46
--- a/include/block/block-copy.h
47
+++ b/include/block/block-copy.h
48
@@ -XXX,XX +XXX,XX @@ void block_copy_set_progress_meter(BlockCopyState *s, ProgressMeter *pm);
49
void block_copy_state_free(BlockCopyState *s);
50
51
void block_copy_reset(BlockCopyState *s, int64_t offset, int64_t bytes);
52
-int64_t coroutine_fn block_copy_reset_unallocated(BlockCopyState *s,
53
- int64_t offset,
54
- int64_t *count);
55
+
56
+int64_t coroutine_fn GRAPH_RDLOCK
57
+block_copy_reset_unallocated(BlockCopyState *s, int64_t offset, int64_t *count);
58
59
int coroutine_fn block_copy(BlockCopyState *s, int64_t offset, int64_t bytes,
60
bool ignore_ratelimit, uint64_t timeout_ns,
61
diff --git a/include/block/block-io.h b/include/block/block-io.h
62
index XXXXXXX..XXXXXXX 100644
63
--- a/include/block/block-io.h
64
+++ b/include/block/block-io.h
65
@@ -XXX,XX +XXX,XX @@ int bdrv_block_status(BlockDriverState *bs, int64_t offset,
66
int64_t bytes, int64_t *pnum, int64_t *map,
67
BlockDriverState **file);
68
69
-int coroutine_fn bdrv_co_block_status_above(BlockDriverState *bs,
70
- BlockDriverState *base,
71
- int64_t offset, int64_t bytes,
72
- int64_t *pnum, int64_t *map,
73
- BlockDriverState **file);
74
+int coroutine_fn GRAPH_RDLOCK
75
+bdrv_co_block_status_above(BlockDriverState *bs, BlockDriverState *base,
76
+ int64_t offset, int64_t bytes, int64_t *pnum,
77
+ int64_t *map, BlockDriverState **file);
78
int bdrv_block_status_above(BlockDriverState *bs, BlockDriverState *base,
79
int64_t offset, int64_t bytes, int64_t *pnum,
80
int64_t *map, BlockDriverState **file);
81
82
-int coroutine_fn bdrv_co_is_allocated(BlockDriverState *bs, int64_t offset,
83
- int64_t bytes, int64_t *pnum);
84
+int coroutine_fn GRAPH_RDLOCK
85
+bdrv_co_is_allocated(BlockDriverState *bs, int64_t offset, int64_t bytes,
86
+ int64_t *pnum);
87
int bdrv_is_allocated(BlockDriverState *bs, int64_t offset, int64_t bytes,
88
int64_t *pnum);
89
90
-int coroutine_fn bdrv_co_is_allocated_above(BlockDriverState *top,
91
- BlockDriverState *base,
92
- bool include_base, int64_t offset,
93
- int64_t bytes, int64_t *pnum);
94
+int coroutine_fn GRAPH_RDLOCK
95
+bdrv_co_is_allocated_above(BlockDriverState *top, BlockDriverState *base,
96
+ bool include_base, int64_t offset, int64_t bytes,
97
+ int64_t *pnum);
98
int bdrv_is_allocated_above(BlockDriverState *top, BlockDriverState *base,
99
bool include_base, int64_t offset, int64_t bytes,
100
int64_t *pnum);
101
diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
102
index XXXXXXX..XXXXXXX 100644
103
--- a/include/block/block_int-common.h
104
+++ b/include/block/block_int-common.h
105
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
106
* *pnum value for the block-status cache on protocol nodes, prior
107
* to clamping *pnum for return to its caller.
108
*/
109
- int coroutine_fn (*bdrv_co_block_status)(BlockDriverState *bs,
110
+ int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_block_status)(
111
+ BlockDriverState *bs,
112
bool want_zero, int64_t offset, int64_t bytes, int64_t *pnum,
113
int64_t *map, BlockDriverState **file);
114
115
diff --git a/block/backup.c b/block/backup.c
116
index XXXXXXX..XXXXXXX 100644
117
--- a/block/backup.c
118
+++ b/block/backup.c
119
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_run(Job *job, Error **errp)
120
return -ECANCELED;
121
}
122
123
+ /* rdlock protects the subsequent call to bdrv_is_allocated() */
124
+ bdrv_graph_co_rdlock();
125
ret = block_copy_reset_unallocated(s->bcs, offset, &count);
126
+ bdrv_graph_co_rdunlock();
127
if (ret < 0) {
128
return ret;
129
}
130
diff --git a/block/block-backend.c b/block/block-backend.c
131
index XXXXXXX..XXXXXXX 100644
132
--- a/block/block-backend.c
133
+++ b/block/block-backend.c
134
@@ -XXX,XX +XXX,XX @@ int coroutine_fn blk_co_block_status_above(BlockBackend *blk,
135
BlockDriverState **file)
136
{
137
IO_CODE();
138
+ GRAPH_RDLOCK_GUARD();
139
return bdrv_co_block_status_above(blk_bs(blk), base, offset, bytes, pnum,
140
map, file);
141
}
142
@@ -XXX,XX +XXX,XX @@ int coroutine_fn blk_co_is_allocated_above(BlockBackend *blk,
143
int64_t bytes, int64_t *pnum)
144
{
145
IO_CODE();
146
+ GRAPH_RDLOCK_GUARD();
147
return bdrv_co_is_allocated_above(blk_bs(blk), base, include_base, offset,
148
bytes, pnum);
149
}
150
diff --git a/block/block-copy.c b/block/block-copy.c
151
index XXXXXXX..XXXXXXX 100644
152
--- a/block/block-copy.c
153
+++ b/block/block-copy.c
154
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int block_copy_task_entry(AioTask *task)
155
return ret;
156
}
157
158
-static coroutine_fn int block_copy_block_status(BlockCopyState *s,
159
- int64_t offset,
160
- int64_t bytes, int64_t *pnum)
161
+static coroutine_fn GRAPH_RDLOCK
162
+int block_copy_block_status(BlockCopyState *s, int64_t offset, int64_t bytes,
163
+ int64_t *pnum)
164
{
165
int64_t num;
166
BlockDriverState *base;
167
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int block_copy_block_status(BlockCopyState *s,
168
* Check if the cluster starting at offset is allocated or not.
169
* return via pnum the number of contiguous clusters sharing this allocation.
170
*/
171
-static int coroutine_fn block_copy_is_cluster_allocated(BlockCopyState *s,
172
- int64_t offset,
173
- int64_t *pnum)
174
+static int coroutine_fn GRAPH_RDLOCK
175
+block_copy_is_cluster_allocated(BlockCopyState *s, int64_t offset,
176
+ int64_t *pnum)
177
{
178
BlockDriverState *bs = s->source->bs;
179
int64_t count, total_count = 0;
180
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn block_copy_is_cluster_allocated(BlockCopyState *s,
181
assert(QEMU_IS_ALIGNED(offset, s->cluster_size));
182
183
while (true) {
184
+ /* protected in backup_run() */
185
ret = bdrv_co_is_allocated(bs, offset, bytes, &count);
186
if (ret < 0) {
187
return ret;
188
@@ -XXX,XX +XXX,XX @@ int64_t coroutine_fn block_copy_reset_unallocated(BlockCopyState *s,
189
* Returns 1 if dirty clusters found and successfully copied, 0 if no dirty
190
* clusters found and -errno on failure.
191
*/
192
-static int coroutine_fn
193
+static int coroutine_fn GRAPH_RDLOCK
194
block_copy_dirty_clusters(BlockCopyCallState *call_state)
195
{
196
BlockCopyState *s = call_state->s;
197
@@ -XXX,XX +XXX,XX @@ void block_copy_kick(BlockCopyCallState *call_state)
198
* it means that some I/O operation failed in context of _this_ block_copy call,
199
* not some parallel operation.
200
*/
201
-static int coroutine_fn block_copy_common(BlockCopyCallState *call_state)
202
+static int coroutine_fn GRAPH_RDLOCK
203
+block_copy_common(BlockCopyCallState *call_state)
204
{
205
int ret;
206
BlockCopyState *s = call_state->s;
207
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn block_copy_common(BlockCopyCallState *call_state)
208
209
static void coroutine_fn block_copy_async_co_entry(void *opaque)
210
{
211
+ GRAPH_RDLOCK_GUARD();
212
block_copy_common(opaque);
213
}
214
215
diff --git a/block/io.c b/block/io.c
216
index XXXXXXX..XXXXXXX 100644
217
--- a/block/io.c
218
+++ b/block/io.c
219
@@ -XXX,XX +XXX,XX @@ int bdrv_flush_all(void)
220
* BDRV_BLOCK_OFFSET_VALID bit is set, 'map' and 'file' (if non-NULL) are
221
* set to the host mapping and BDS corresponding to the guest offset.
222
*/
223
-static int coroutine_fn bdrv_co_block_status(BlockDriverState *bs,
224
- bool want_zero,
225
- int64_t offset, int64_t bytes,
226
- int64_t *pnum, int64_t *map,
227
- BlockDriverState **file)
228
+static int coroutine_fn GRAPH_RDLOCK
229
+bdrv_co_block_status(BlockDriverState *bs, bool want_zero,
230
+ int64_t offset, int64_t bytes,
231
+ int64_t *pnum, int64_t *map, BlockDriverState **file)
232
{
233
int64_t total_size;
234
int64_t n; /* bytes */
235
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_block_status(BlockDriverState *bs,
236
bool has_filtered_child;
237
238
assert(pnum);
239
+ assert_bdrv_graph_readable();
240
*pnum = 0;
241
total_size = bdrv_getlength(bs);
242
if (total_size < 0) {
243
@@ -XXX,XX +XXX,XX @@ bdrv_co_common_block_status_above(BlockDriverState *bs,
244
IO_CODE();
245
246
assert(!include_base || base); /* Can't include NULL base */
247
+ assert_bdrv_graph_readable();
248
249
if (!depth) {
250
depth = &dummy;
251
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_is_zero_fast(BlockDriverState *bs, int64_t offset,
252
int64_t pnum = bytes;
253
IO_CODE();
254
255
+ assume_graph_lock(); /* FIXME */
256
+
257
if (!bytes) {
258
return 1;
259
}
260
diff --git a/block/mirror.c b/block/mirror.c
261
index XXXXXXX..XXXXXXX 100644
262
--- a/block/mirror.c
263
+++ b/block/mirror.c
264
@@ -XXX,XX +XXX,XX @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
265
MirrorMethod mirror_method = MIRROR_METHOD_COPY;
266
267
assert(!(offset % s->granularity));
268
- ret = bdrv_block_status_above(source, NULL, offset,
269
- nb_chunks * s->granularity,
270
- &io_bytes, NULL, NULL);
271
+ WITH_GRAPH_RDLOCK_GUARD() {
272
+ ret = bdrv_block_status_above(source, NULL, offset,
273
+ nb_chunks * s->granularity,
274
+ &io_bytes, NULL, NULL);
275
+ }
276
if (ret < 0) {
277
io_bytes = MIN(nb_chunks * s->granularity, max_io_bytes);
278
} else if (ret & BDRV_BLOCK_DATA) {
279
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn mirror_dirty_init(MirrorBlockJob *s)
280
return 0;
281
}
282
283
- ret = bdrv_is_allocated_above(bs, s->base_overlay, true, offset, bytes,
284
- &count);
285
+ WITH_GRAPH_RDLOCK_GUARD() {
286
+ ret = bdrv_is_allocated_above(bs, s->base_overlay, true, offset,
287
+ bytes, &count);
288
+ }
289
if (ret < 0) {
290
return ret;
291
}
292
diff --git a/block/qcow.c b/block/qcow.c
293
index XXXXXXX..XXXXXXX 100644
294
--- a/block/qcow.c
295
+++ b/block/qcow.c
296
@@ -XXX,XX +XXX,XX @@ get_cluster_offset(BlockDriverState *bs, uint64_t offset, int allocate,
297
return 1;
298
}
299
300
-static int coroutine_fn qcow_co_block_status(BlockDriverState *bs,
301
- bool want_zero,
302
- int64_t offset, int64_t bytes,
303
- int64_t *pnum, int64_t *map,
304
- BlockDriverState **file)
305
+static int coroutine_fn GRAPH_RDLOCK
306
+qcow_co_block_status(BlockDriverState *bs, bool want_zero,
307
+ int64_t offset, int64_t bytes, int64_t *pnum,
308
+ int64_t *map, BlockDriverState **file)
309
{
310
BDRVQcowState *s = bs->opaque;
311
int index_in_cluster, ret;
312
int64_t n;
313
uint64_t cluster_offset;
314
315
- assume_graph_lock(); /* FIXME */
316
-
317
qemu_co_mutex_lock(&s->lock);
318
ret = get_cluster_offset(bs, offset, 0, 0, 0, 0, &cluster_offset);
319
qemu_co_mutex_unlock(&s->lock);
320
diff --git a/block/quorum.c b/block/quorum.c
321
index XXXXXXX..XXXXXXX 100644
322
--- a/block/quorum.c
323
+++ b/block/quorum.c
324
@@ -XXX,XX +XXX,XX @@ static void quorum_child_perm(BlockDriverState *bs, BdrvChild *c,
325
* return BDRV_BLOCK_ZERO if *all* children agree that a certain
326
* region contains zeroes, and BDRV_BLOCK_DATA otherwise.
327
*/
328
-static int coroutine_fn quorum_co_block_status(BlockDriverState *bs,
329
- bool want_zero,
330
- int64_t offset, int64_t count,
331
- int64_t *pnum, int64_t *map,
332
- BlockDriverState **file)
333
+static int coroutine_fn GRAPH_RDLOCK
334
+quorum_co_block_status(BlockDriverState *bs, bool want_zero,
335
+ int64_t offset, int64_t count,
336
+ int64_t *pnum, int64_t *map, BlockDriverState **file)
337
{
338
BDRVQuorumState *s = bs->opaque;
339
int i, ret;
340
diff --git a/block/stream.c b/block/stream.c
341
index XXXXXXX..XXXXXXX 100644
342
--- a/block/stream.c
343
+++ b/block/stream.c
344
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn stream_run(Job *job, Error **errp)
345
346
copy = false;
347
348
- ret = bdrv_is_allocated(unfiltered_bs, offset, STREAM_CHUNK, &n);
349
- if (ret == 1) {
350
- /* Allocated in the top, no need to copy. */
351
- } else if (ret >= 0) {
352
- /* Copy if allocated in the intermediate images. Limit to the
353
- * known-unallocated area [offset, offset+n*BDRV_SECTOR_SIZE). */
354
- ret = bdrv_is_allocated_above(bdrv_cow_bs(unfiltered_bs),
355
- s->base_overlay, true,
356
- offset, n, &n);
357
- /* Finish early if end of backing file has been reached */
358
- if (ret == 0 && n == 0) {
359
- n = len - offset;
360
+ WITH_GRAPH_RDLOCK_GUARD() {
361
+ ret = bdrv_is_allocated(unfiltered_bs, offset, STREAM_CHUNK, &n);
362
+ if (ret == 1) {
363
+ /* Allocated in the top, no need to copy. */
364
+ } else if (ret >= 0) {
365
+ /*
366
+ * Copy if allocated in the intermediate images. Limit to the
367
+ * known-unallocated area [offset, offset+n*BDRV_SECTOR_SIZE).
368
+ */
369
+ ret = bdrv_is_allocated_above(bdrv_cow_bs(unfiltered_bs),
370
+ s->base_overlay, true,
371
+ offset, n, &n);
372
+ /* Finish early if end of backing file has been reached */
373
+ if (ret == 0 && n == 0) {
374
+ n = len - offset;
375
+ }
376
+
377
+ copy = (ret > 0);
378
}
379
-
380
- copy = (ret > 0);
381
}
382
trace_stream_one_iteration(s, offset, n, ret);
383
if (copy) {
384
diff --git a/qemu-img.c b/qemu-img.c
385
index XXXXXXX..XXXXXXX 100644
386
--- a/qemu-img.c
387
+++ b/qemu-img.c
388
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn convert_co_do_copy(void *opaque)
389
qemu_co_mutex_unlock(&s->lock);
390
break;
391
}
392
- n = convert_iteration_sectors(s, s->sector_num);
393
+ WITH_GRAPH_RDLOCK_GUARD() {
394
+ n = convert_iteration_sectors(s, s->sector_num);
395
+ }
396
if (n < 0) {
397
qemu_co_mutex_unlock(&s->lock);
398
s->ret = n;
399
diff --git a/tests/unit/test-block-iothread.c b/tests/unit/test-block-iothread.c
400
index XXXXXXX..XXXXXXX 100644
401
--- a/tests/unit/test-block-iothread.c
402
+++ b/tests/unit/test-block-iothread.c
403
@@ -XXX,XX +XXX,XX @@ static void test_sync_op_blk_truncate(BlockBackend *blk)
404
g_assert_cmpint(ret, ==, -EINVAL);
405
}
406
407
-static void test_sync_op_block_status(BdrvChild *c)
408
+/* Disable TSA to make bdrv_test.bdrv_co_block_status writable */
409
+static void TSA_NO_TSA test_sync_op_block_status(BdrvChild *c)
410
{
411
int ret;
412
int64_t n;
413
--
414
2.39.2
diff view generated by jsdifflib
Deleted patch
1
From: Emanuele Giuseppe Esposito <eesposit@redhat.com>
2
1
3
This function is called in two different places:
4
- timer callback, which does not take the graph rdlock.
5
- bdrv_qed_drain_begin(), which is .bdrv_drain_begin()
6
callback documented as function that does not take the lock.
7
8
Since it calls recursive functions that traverse the
9
graph, we need to protect them with the graph rdlock.
10
11
Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
Message-Id: <20230203152202.49054-7-kwolf@redhat.com>
14
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
---
17
block/qed.c | 4 +++-
18
1 file changed, 3 insertions(+), 1 deletion(-)
19
20
diff --git a/block/qed.c b/block/qed.c
21
index XXXXXXX..XXXXXXX 100644
22
--- a/block/qed.c
23
+++ b/block/qed.c
24
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn qed_unplug_allocating_write_reqs(BDRVQEDState *s)
25
qemu_co_mutex_unlock(&s->table_lock);
26
}
27
28
-static void coroutine_fn qed_need_check_timer(BDRVQEDState *s)
29
+static void coroutine_fn GRAPH_RDLOCK qed_need_check_timer(BDRVQEDState *s)
30
{
31
int ret;
32
33
trace_qed_need_check_timer_cb(s);
34
+ assert_bdrv_graph_readable();
35
36
if (!qed_plug_allocating_write_reqs(s)) {
37
return;
38
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn qed_need_check_timer(BDRVQEDState *s)
39
static void coroutine_fn qed_need_check_timer_entry(void *opaque)
40
{
41
BDRVQEDState *s = opaque;
42
+ GRAPH_RDLOCK_GUARD();
43
44
qed_need_check_timer(opaque);
45
bdrv_dec_in_flight(s->bs);
46
--
47
2.39.2
diff view generated by jsdifflib
Deleted patch
1
From: Emanuele Giuseppe Esposito <eesposit@redhat.com>
2
1
3
This adds GRAPH_RDLOCK annotations to declare that callers of
4
bdrv_co_flush() need to hold a reader lock for the graph.
5
6
For some places, we know that they will hold the lock, but we don't have
7
the GRAPH_RDLOCK annotations yet. In this case, add assume_graph_lock()
8
with a FIXME comment. These places will be removed once everything is
9
properly annotated.
10
11
Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
Message-Id: <20230203152202.49054-8-kwolf@redhat.com>
14
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
---
17
block/qcow2.h | 5 +++-
18
block/qed.h | 29 +++++++++++++--------
19
include/block/block-io.h | 2 +-
20
include/block/block_int-common.h | 12 +++++----
21
block/blkdebug.c | 2 +-
22
block/blklogwrites.c | 21 ++++++++++-----
23
block/blkreplay.c | 2 +-
24
block/blkverify.c | 2 +-
25
block/block-backend.c | 3 ++-
26
block/copy-before-write.c | 2 +-
27
block/file-posix.c | 4 +--
28
block/io.c | 7 +++++
29
block/mirror.c | 2 +-
30
block/preallocate.c | 2 +-
31
block/qed-check.c | 3 ++-
32
block/qed-table.c | 6 ++---
33
block/qed.c | 44 +++++++++++++++++++-------------
34
block/quorum.c | 2 +-
35
block/throttle.c | 2 +-
36
block/vmdk.c | 6 +++--
37
20 files changed, 98 insertions(+), 60 deletions(-)
38
39
diff --git a/block/qcow2.h b/block/qcow2.h
40
index XXXXXXX..XXXXXXX 100644
41
--- a/block/qcow2.h
42
+++ b/block/qcow2.h
43
@@ -XXX,XX +XXX,XX @@ int coroutine_fn qcow2_detect_metadata_preallocation(BlockDriverState *bs);
44
/* qcow2-cluster.c functions */
45
int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
46
bool exact_size);
47
-int coroutine_fn qcow2_shrink_l1_table(BlockDriverState *bs, uint64_t max_size);
48
+
49
+int coroutine_fn GRAPH_RDLOCK
50
+qcow2_shrink_l1_table(BlockDriverState *bs, uint64_t max_size);
51
+
52
int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index);
53
int qcow2_encrypt_sectors(BDRVQcow2State *s, int64_t sector_num,
54
uint8_t *buf, int nb_sectors, bool enc, Error **errp);
55
diff --git a/block/qed.h b/block/qed.h
56
index XXXXXXX..XXXXXXX 100644
57
--- a/block/qed.h
58
+++ b/block/qed.h
59
@@ -XXX,XX +XXX,XX @@ void qed_commit_l2_cache_entry(L2TableCache *l2_cache, CachedL2Table *l2_table);
60
* Table I/O functions
61
*/
62
int coroutine_fn qed_read_l1_table_sync(BDRVQEDState *s);
63
-int coroutine_fn qed_write_l1_table(BDRVQEDState *s, unsigned int index,
64
- unsigned int n);
65
-int coroutine_fn qed_write_l1_table_sync(BDRVQEDState *s, unsigned int index,
66
- unsigned int n);
67
+
68
+int coroutine_fn GRAPH_RDLOCK
69
+qed_write_l1_table(BDRVQEDState *s, unsigned int index, unsigned int n);
70
+
71
+int coroutine_fn GRAPH_RDLOCK
72
+qed_write_l1_table_sync(BDRVQEDState *s, unsigned int index, unsigned int n);
73
+
74
int coroutine_fn qed_read_l2_table_sync(BDRVQEDState *s, QEDRequest *request,
75
uint64_t offset);
76
int coroutine_fn qed_read_l2_table(BDRVQEDState *s, QEDRequest *request,
77
uint64_t offset);
78
-int coroutine_fn qed_write_l2_table(BDRVQEDState *s, QEDRequest *request,
79
- unsigned int index, unsigned int n,
80
- bool flush);
81
-int coroutine_fn qed_write_l2_table_sync(BDRVQEDState *s, QEDRequest *request,
82
- unsigned int index, unsigned int n,
83
- bool flush);
84
+
85
+int coroutine_fn GRAPH_RDLOCK
86
+qed_write_l2_table(BDRVQEDState *s, QEDRequest *request, unsigned int index,
87
+ unsigned int n, bool flush);
88
+
89
+int coroutine_fn GRAPH_RDLOCK
90
+qed_write_l2_table_sync(BDRVQEDState *s, QEDRequest *request,
91
+ unsigned int index, unsigned int n, bool flush);
92
93
/**
94
* Cluster functions
95
@@ -XXX,XX +XXX,XX @@ int coroutine_fn qed_find_cluster(BDRVQEDState *s, QEDRequest *request,
96
/**
97
* Consistency check
98
*/
99
-int coroutine_fn qed_check(BDRVQEDState *s, BdrvCheckResult *result, bool fix);
100
+int coroutine_fn GRAPH_RDLOCK
101
+qed_check(BDRVQEDState *s, BdrvCheckResult *result, bool fix);
102
+
103
104
QEDTable *qed_alloc_table(BDRVQEDState *s);
105
106
diff --git a/include/block/block-io.h b/include/block/block-io.h
107
index XXXXXXX..XXXXXXX 100644
108
--- a/include/block/block-io.h
109
+++ b/include/block/block-io.h
110
@@ -XXX,XX +XXX,XX @@ int coroutine_fn GRAPH_RDLOCK
111
bdrv_co_ioctl(BlockDriverState *bs, int req, void *buf);
112
113
/* Ensure contents are flushed to disk. */
114
-int coroutine_fn bdrv_co_flush(BlockDriverState *bs);
115
+int coroutine_fn GRAPH_RDLOCK bdrv_co_flush(BlockDriverState *bs);
116
117
int coroutine_fn bdrv_co_pdiscard(BdrvChild *child, int64_t offset,
118
int64_t bytes);
119
diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
120
index XXXXXXX..XXXXXXX 100644
121
--- a/include/block/block_int-common.h
122
+++ b/include/block/block_int-common.h
123
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
124
BlockAIOCB *(*bdrv_aio_pwritev)(BlockDriverState *bs,
125
int64_t offset, int64_t bytes, QEMUIOVector *qiov,
126
BdrvRequestFlags flags, BlockCompletionFunc *cb, void *opaque);
127
- BlockAIOCB *(*bdrv_aio_flush)(BlockDriverState *bs,
128
- BlockCompletionFunc *cb, void *opaque);
129
+ BlockAIOCB * GRAPH_RDLOCK_PTR (*bdrv_aio_flush)(
130
+ BlockDriverState *bs, BlockCompletionFunc *cb, void *opaque);
131
BlockAIOCB *(*bdrv_aio_pdiscard)(BlockDriverState *bs,
132
int64_t offset, int bytes,
133
BlockCompletionFunc *cb, void *opaque);
134
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
135
* layers, if needed. This function is needed for deterministic
136
* synchronization of the flush finishing callback.
137
*/
138
- int coroutine_fn (*bdrv_co_flush)(BlockDriverState *bs);
139
+ int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_flush)(BlockDriverState *bs);
140
141
/* Delete a created file. */
142
int coroutine_fn (*bdrv_co_delete_file)(BlockDriverState *bs,
143
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
144
* Flushes all data that was already written to the OS all the way down to
145
* the disk (for example file-posix.c calls fsync()).
146
*/
147
- int coroutine_fn (*bdrv_co_flush_to_disk)(BlockDriverState *bs);
148
+ int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_flush_to_disk)(
149
+ BlockDriverState *bs);
150
151
/*
152
* Flushes all internal caches to the OS. The data may still sit in a
153
* writeback cache of the host OS, but it will survive a crash of the qemu
154
* process.
155
*/
156
- int coroutine_fn (*bdrv_co_flush_to_os)(BlockDriverState *bs);
157
+ int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_flush_to_os)(
158
+ BlockDriverState *bs);
159
160
/*
161
* Truncate @bs to @offset bytes using the given @prealloc mode
162
diff --git a/block/blkdebug.c b/block/blkdebug.c
163
index XXXXXXX..XXXXXXX 100644
164
--- a/block/blkdebug.c
165
+++ b/block/blkdebug.c
166
@@ -XXX,XX +XXX,XX @@ blkdebug_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes,
167
return bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags);
168
}
169
170
-static int coroutine_fn blkdebug_co_flush(BlockDriverState *bs)
171
+static int GRAPH_RDLOCK coroutine_fn blkdebug_co_flush(BlockDriverState *bs)
172
{
173
int err = rule_check(bs, 0, 0, BLKDEBUG_IO_TYPE_FLUSH);
174
175
diff --git a/block/blklogwrites.c b/block/blklogwrites.c
176
index XXXXXXX..XXXXXXX 100644
177
--- a/block/blklogwrites.c
178
+++ b/block/blklogwrites.c
179
@@ -XXX,XX +XXX,XX @@ typedef struct BlkLogWritesFileReq {
180
uint64_t bytes;
181
int file_flags;
182
QEMUIOVector *qiov;
183
- int (*func)(struct BlkLogWritesFileReq *r);
184
+ int GRAPH_RDLOCK_PTR (*func)(struct BlkLogWritesFileReq *r);
185
int file_ret;
186
} BlkLogWritesFileReq;
187
188
@@ -XXX,XX +XXX,XX @@ typedef struct {
189
int log_ret;
190
} BlkLogWritesLogReq;
191
192
-static void coroutine_fn blk_log_writes_co_do_log(BlkLogWritesLogReq *lr)
193
+static void coroutine_fn GRAPH_RDLOCK
194
+blk_log_writes_co_do_log(BlkLogWritesLogReq *lr)
195
{
196
BDRVBlkLogWritesState *s = lr->bs->opaque;
197
uint64_t cur_log_offset = s->cur_log_sector << s->sectorbits;
198
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn blk_log_writes_co_do_log(BlkLogWritesLogReq *lr)
199
}
200
}
201
202
-static void coroutine_fn blk_log_writes_co_do_file(BlkLogWritesFileReq *fr)
203
+static void coroutine_fn GRAPH_RDLOCK
204
+blk_log_writes_co_do_file(BlkLogWritesFileReq *fr)
205
{
206
fr->file_ret = fr->func(fr);
207
}
208
209
-static int coroutine_fn
210
+static int coroutine_fn GRAPH_RDLOCK
211
blk_log_writes_co_log(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
212
QEMUIOVector *qiov, int flags,
213
- int (*file_func)(BlkLogWritesFileReq *r),
214
+ int /*GRAPH_RDLOCK*/ (*file_func)(BlkLogWritesFileReq *r),
215
uint64_t entry_flags, bool is_zero_write)
216
{
217
QEMUIOVector log_qiov;
218
@@ -XXX,XX +XXX,XX @@ blk_log_writes_co_do_file_pwrite_zeroes(BlkLogWritesFileReq *fr)
219
fr->file_flags);
220
}
221
222
-static int coroutine_fn blk_log_writes_co_do_file_flush(BlkLogWritesFileReq *fr)
223
+static int coroutine_fn GRAPH_RDLOCK
224
+blk_log_writes_co_do_file_flush(BlkLogWritesFileReq *fr)
225
{
226
return bdrv_co_flush(fr->bs->file->bs);
227
}
228
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn
229
blk_log_writes_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes,
230
QEMUIOVector *qiov, BdrvRequestFlags flags)
231
{
232
+ assume_graph_lock(); /* FIXME */
233
return blk_log_writes_co_log(bs, offset, bytes, qiov, flags,
234
blk_log_writes_co_do_file_pwritev, 0, false);
235
}
236
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn
237
blk_log_writes_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset,
238
int64_t bytes, BdrvRequestFlags flags)
239
{
240
+ assume_graph_lock(); /* FIXME */
241
return blk_log_writes_co_log(bs, offset, bytes, NULL, flags,
242
blk_log_writes_co_do_file_pwrite_zeroes, 0,
243
true);
244
}
245
246
-static int coroutine_fn blk_log_writes_co_flush_to_disk(BlockDriverState *bs)
247
+static int coroutine_fn GRAPH_RDLOCK
248
+blk_log_writes_co_flush_to_disk(BlockDriverState *bs)
249
{
250
return blk_log_writes_co_log(bs, 0, 0, NULL, 0,
251
blk_log_writes_co_do_file_flush,
252
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn blk_log_writes_co_flush_to_disk(BlockDriverState *bs)
253
static int coroutine_fn
254
blk_log_writes_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes)
255
{
256
+ assume_graph_lock(); /* FIXME */
257
return blk_log_writes_co_log(bs, offset, bytes, NULL, 0,
258
blk_log_writes_co_do_file_pdiscard,
259
LOG_DISCARD_FLAG, false);
260
diff --git a/block/blkreplay.c b/block/blkreplay.c
261
index XXXXXXX..XXXXXXX 100644
262
--- a/block/blkreplay.c
263
+++ b/block/blkreplay.c
264
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn blkreplay_co_pdiscard(BlockDriverState *bs,
265
return ret;
266
}
267
268
-static int coroutine_fn blkreplay_co_flush(BlockDriverState *bs)
269
+static int coroutine_fn GRAPH_RDLOCK blkreplay_co_flush(BlockDriverState *bs)
270
{
271
uint64_t reqid = blkreplay_next_id();
272
int ret = bdrv_co_flush(bs->file->bs);
273
diff --git a/block/blkverify.c b/block/blkverify.c
274
index XXXXXXX..XXXXXXX 100644
275
--- a/block/blkverify.c
276
+++ b/block/blkverify.c
277
@@ -XXX,XX +XXX,XX @@ blkverify_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes,
278
return blkverify_co_prwv(bs, &r, offset, bytes, qiov, qiov, flags, true);
279
}
280
281
-static int coroutine_fn blkverify_co_flush(BlockDriverState *bs)
282
+static int coroutine_fn GRAPH_RDLOCK blkverify_co_flush(BlockDriverState *bs)
283
{
284
BDRVBlkverifyState *s = bs->opaque;
285
286
diff --git a/block/block-backend.c b/block/block-backend.c
287
index XXXXXXX..XXXXXXX 100644
288
--- a/block/block-backend.c
289
+++ b/block/block-backend.c
290
@@ -XXX,XX +XXX,XX @@ int coroutine_fn blk_co_pdiscard(BlockBackend *blk, int64_t offset,
291
/* To be called between exactly one pair of blk_inc/dec_in_flight() */
292
static int coroutine_fn blk_co_do_flush(BlockBackend *blk)
293
{
294
- blk_wait_while_drained(blk);
295
IO_CODE();
296
+ blk_wait_while_drained(blk);
297
+ GRAPH_RDLOCK_GUARD();
298
299
if (!blk_is_available(blk)) {
300
return -ENOMEDIUM;
301
diff --git a/block/copy-before-write.c b/block/copy-before-write.c
302
index XXXXXXX..XXXXXXX 100644
303
--- a/block/copy-before-write.c
304
+++ b/block/copy-before-write.c
305
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int cbw_co_pwritev(BlockDriverState *bs,
306
return bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags);
307
}
308
309
-static int coroutine_fn cbw_co_flush(BlockDriverState *bs)
310
+static int coroutine_fn GRAPH_RDLOCK cbw_co_flush(BlockDriverState *bs)
311
{
312
if (!bs->file) {
313
return 0;
314
diff --git a/block/file-posix.c b/block/file-posix.c
315
index XXXXXXX..XXXXXXX 100644
316
--- a/block/file-posix.c
317
+++ b/block/file-posix.c
318
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn check_cache_dropped(BlockDriverState *bs, Error **errp)
319
}
320
#endif /* __linux__ */
321
322
-static void coroutine_fn raw_co_invalidate_cache(BlockDriverState *bs,
323
- Error **errp)
324
+static void coroutine_fn GRAPH_RDLOCK
325
+raw_co_invalidate_cache(BlockDriverState *bs, Error **errp)
326
{
327
BDRVRawState *s = bs->opaque;
328
int ret;
329
diff --git a/block/io.c b/block/io.c
330
index XXXXXXX..XXXXXXX 100644
331
--- a/block/io.c
332
+++ b/block/io.c
333
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_pwrite_sync(BdrvChild *child, int64_t offset,
334
int ret;
335
IO_CODE();
336
337
+ assume_graph_lock(); /* FIXME */
338
+
339
ret = bdrv_co_pwrite(child, offset, bytes, buf, flags);
340
if (ret < 0) {
341
return ret;
342
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_driver_pwritev(BlockDriverState *bs,
343
QEMUIOVector local_qiov;
344
int ret;
345
346
+ assume_graph_lock(); /* FIXME */
347
+
348
bdrv_check_qiov_request(offset, bytes, qiov, qiov_offset, &error_abort);
349
350
if (!drv) {
351
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
352
int head = 0;
353
int tail = 0;
354
355
+ assume_graph_lock(); /* FIXME */
356
+
357
int64_t max_write_zeroes = MIN_NON_ZERO(bs->bl.max_pwrite_zeroes,
358
INT64_MAX);
359
int alignment = MAX(bs->bl.pwrite_zeroes_alignment,
360
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_flush(BlockDriverState *bs)
361
int ret = 0;
362
IO_CODE();
363
364
+ assert_bdrv_graph_readable();
365
bdrv_inc_in_flight(bs);
366
367
if (!bdrv_co_is_inserted(bs) || bdrv_is_read_only(bs) ||
368
diff --git a/block/mirror.c b/block/mirror.c
369
index XXXXXXX..XXXXXXX 100644
370
--- a/block/mirror.c
371
+++ b/block/mirror.c
372
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_mirror_top_pwritev(BlockDriverState *bs,
373
return ret;
374
}
375
376
-static int coroutine_fn bdrv_mirror_top_flush(BlockDriverState *bs)
377
+static int coroutine_fn GRAPH_RDLOCK bdrv_mirror_top_flush(BlockDriverState *bs)
378
{
379
if (bs->backing == NULL) {
380
/* we can be here after failed bdrv_append in mirror_start_job */
381
diff --git a/block/preallocate.c b/block/preallocate.c
382
index XXXXXXX..XXXXXXX 100644
383
--- a/block/preallocate.c
384
+++ b/block/preallocate.c
385
@@ -XXX,XX +XXX,XX @@ preallocate_co_truncate(BlockDriverState *bs, int64_t offset,
386
return 0;
387
}
388
389
-static int coroutine_fn preallocate_co_flush(BlockDriverState *bs)
390
+static int coroutine_fn GRAPH_RDLOCK preallocate_co_flush(BlockDriverState *bs)
391
{
392
return bdrv_co_flush(bs->file->bs);
393
}
394
diff --git a/block/qed-check.c b/block/qed-check.c
395
index XXXXXXX..XXXXXXX 100644
396
--- a/block/qed-check.c
397
+++ b/block/qed-check.c
398
@@ -XXX,XX +XXX,XX @@ static unsigned int qed_check_l2_table(QEDCheck *check, QEDTable *table)
399
/**
400
* Descend tables and check each cluster is referenced once only
401
*/
402
-static int coroutine_fn qed_check_l1_table(QEDCheck *check, QEDTable *table)
403
+static int coroutine_fn GRAPH_RDLOCK
404
+qed_check_l1_table(QEDCheck *check, QEDTable *table)
405
{
406
BDRVQEDState *s = check->s;
407
unsigned int i, num_invalid_l1 = 0;
408
diff --git a/block/qed-table.c b/block/qed-table.c
409
index XXXXXXX..XXXXXXX 100644
410
--- a/block/qed-table.c
411
+++ b/block/qed-table.c
412
@@ -XXX,XX +XXX,XX @@ out:
413
*
414
* Called with table_lock held.
415
*/
416
-static int coroutine_fn qed_write_table(BDRVQEDState *s, uint64_t offset,
417
- QEDTable *table, unsigned int index,
418
- unsigned int n, bool flush)
419
+static int coroutine_fn GRAPH_RDLOCK
420
+qed_write_table(BDRVQEDState *s, uint64_t offset, QEDTable *table,
421
+ unsigned int index, unsigned int n, bool flush)
422
{
423
unsigned int sector_mask = BDRV_SECTOR_SIZE / sizeof(uint64_t) - 1;
424
unsigned int start, end, i;
425
diff --git a/block/qed.c b/block/qed.c
426
index XXXXXXX..XXXXXXX 100644
427
--- a/block/qed.c
428
+++ b/block/qed.c
429
@@ -XXX,XX +XXX,XX @@ static void bdrv_qed_init_state(BlockDriverState *bs)
430
}
431
432
/* Called with table_lock held. */
433
-static int coroutine_fn bdrv_qed_do_open(BlockDriverState *bs, QDict *options,
434
- int flags, Error **errp)
435
+static int coroutine_fn GRAPH_RDLOCK
436
+bdrv_qed_do_open(BlockDriverState *bs, QDict *options, int flags, Error **errp)
437
{
438
BDRVQEDState *s = bs->opaque;
439
QEDHeader le_header;
440
@@ -XXX,XX +XXX,XX @@ typedef struct QEDOpenCo {
441
int ret;
442
} QEDOpenCo;
443
444
-static void coroutine_fn bdrv_qed_open_entry(void *opaque)
445
+static void coroutine_fn GRAPH_RDLOCK bdrv_qed_open_entry(void *opaque)
446
{
447
QEDOpenCo *qoc = opaque;
448
BDRVQEDState *s = qoc->bs->opaque;
449
@@ -XXX,XX +XXX,XX @@ static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags,
450
};
451
int ret;
452
453
+ assume_graph_lock(); /* FIXME */
454
+
455
ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
456
if (ret < 0) {
457
return ret;
458
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn qed_aio_complete(QEDAIOCB *acb)
459
*
460
* Called with table_lock held.
461
*/
462
-static int coroutine_fn qed_aio_write_l1_update(QEDAIOCB *acb)
463
+static int coroutine_fn GRAPH_RDLOCK qed_aio_write_l1_update(QEDAIOCB *acb)
464
{
465
BDRVQEDState *s = acb_to_s(acb);
466
CachedL2Table *l2_table = acb->request.l2_table;
467
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qed_aio_write_l1_update(QEDAIOCB *acb)
468
*
469
* Called with table_lock held.
470
*/
471
-static int coroutine_fn qed_aio_write_l2_update(QEDAIOCB *acb, uint64_t offset)
472
+static int coroutine_fn GRAPH_RDLOCK
473
+qed_aio_write_l2_update(QEDAIOCB *acb, uint64_t offset)
474
{
475
BDRVQEDState *s = acb_to_s(acb);
476
bool need_alloc = acb->find_cluster_ret == QED_CLUSTER_L1;
477
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qed_aio_write_main(QEDAIOCB *acb)
478
*
479
* Called with table_lock held.
480
*/
481
-static int coroutine_fn qed_aio_write_cow(QEDAIOCB *acb)
482
+static int coroutine_fn GRAPH_RDLOCK qed_aio_write_cow(QEDAIOCB *acb)
483
{
484
BDRVQEDState *s = acb_to_s(acb);
485
uint64_t start, len, offset;
486
@@ -XXX,XX +XXX,XX @@ static bool qed_should_set_need_check(BDRVQEDState *s)
487
*
488
* Called with table_lock held.
489
*/
490
-static int coroutine_fn qed_aio_write_alloc(QEDAIOCB *acb, size_t len)
491
+static int coroutine_fn GRAPH_RDLOCK
492
+qed_aio_write_alloc(QEDAIOCB *acb, size_t len)
493
{
494
BDRVQEDState *s = acb_to_s(acb);
495
int ret;
496
@@ -XXX,XX +XXX,XX @@ out:
497
*
498
* Called with table_lock held.
499
*/
500
-static int coroutine_fn qed_aio_write_data(void *opaque, int ret,
501
- uint64_t offset, size_t len)
502
+static int coroutine_fn GRAPH_RDLOCK
503
+qed_aio_write_data(void *opaque, int ret, uint64_t offset, size_t len)
504
{
505
QEDAIOCB *acb = opaque;
506
507
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qed_aio_read_data(void *opaque, int ret,
508
/**
509
* Begin next I/O or complete the request
510
*/
511
-static int coroutine_fn qed_aio_next_io(QEDAIOCB *acb)
512
+static int coroutine_fn GRAPH_RDLOCK qed_aio_next_io(QEDAIOCB *acb)
513
{
514
BDRVQEDState *s = acb_to_s(acb);
515
uint64_t offset;
516
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qed_aio_next_io(QEDAIOCB *acb)
517
return ret;
518
}
519
520
-static int coroutine_fn qed_co_request(BlockDriverState *bs, int64_t sector_num,
521
- QEMUIOVector *qiov, int nb_sectors,
522
- int flags)
523
+static int coroutine_fn GRAPH_RDLOCK
524
+qed_co_request(BlockDriverState *bs, int64_t sector_num, QEMUIOVector *qiov,
525
+ int nb_sectors, int flags)
526
{
527
QEDAIOCB acb = {
528
.bs = bs,
529
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_qed_co_readv(BlockDriverState *bs,
530
int64_t sector_num, int nb_sectors,
531
QEMUIOVector *qiov)
532
{
533
+ assume_graph_lock(); /* FIXME */
534
return qed_co_request(bs, sector_num, qiov, nb_sectors, 0);
535
}
536
537
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_qed_co_writev(BlockDriverState *bs,
538
int64_t sector_num, int nb_sectors,
539
QEMUIOVector *qiov, int flags)
540
{
541
+ assume_graph_lock(); /* FIXME */
542
return qed_co_request(bs, sector_num, qiov, nb_sectors, QED_AIOCB_WRITE);
543
}
544
545
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_qed_co_pwrite_zeroes(BlockDriverState *bs,
546
{
547
BDRVQEDState *s = bs->opaque;
548
549
+ assume_graph_lock(); /* FIXME */
550
+
551
/*
552
* Zero writes start without an I/O buffer. If a buffer becomes necessary
553
* then it will be allocated during request processing.
554
@@ -XXX,XX +XXX,XX @@ static int bdrv_qed_change_backing_file(BlockDriverState *bs,
555
return ret;
556
}
557
558
-static void coroutine_fn bdrv_qed_co_invalidate_cache(BlockDriverState *bs,
559
- Error **errp)
560
+static void coroutine_fn GRAPH_RDLOCK
561
+bdrv_qed_co_invalidate_cache(BlockDriverState *bs, Error **errp)
562
{
563
BDRVQEDState *s = bs->opaque;
564
int ret;
565
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_qed_co_invalidate_cache(BlockDriverState *bs,
566
}
567
}
568
569
-static int coroutine_fn bdrv_qed_co_check(BlockDriverState *bs,
570
- BdrvCheckResult *result,
571
- BdrvCheckMode fix)
572
+static int coroutine_fn GRAPH_RDLOCK
573
+bdrv_qed_co_check(BlockDriverState *bs, BdrvCheckResult *result,
574
+ BdrvCheckMode fix)
575
{
576
BDRVQEDState *s = bs->opaque;
577
int ret;
578
diff --git a/block/quorum.c b/block/quorum.c
579
index XXXXXXX..XXXXXXX 100644
580
--- a/block/quorum.c
581
+++ b/block/quorum.c
582
@@ -XXX,XX +XXX,XX @@ static int64_t coroutine_fn quorum_co_getlength(BlockDriverState *bs)
583
return result;
584
}
585
586
-static coroutine_fn int quorum_co_flush(BlockDriverState *bs)
587
+static coroutine_fn GRAPH_RDLOCK int quorum_co_flush(BlockDriverState *bs)
588
{
589
BDRVQuorumState *s = bs->opaque;
590
QuorumVoteVersion *winner = NULL;
591
diff --git a/block/throttle.c b/block/throttle.c
592
index XXXXXXX..XXXXXXX 100644
593
--- a/block/throttle.c
594
+++ b/block/throttle.c
595
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn throttle_co_pwritev_compressed(BlockDriverState *bs,
596
BDRV_REQ_WRITE_COMPRESSED);
597
}
598
599
-static int coroutine_fn throttle_co_flush(BlockDriverState *bs)
600
+static int coroutine_fn GRAPH_RDLOCK throttle_co_flush(BlockDriverState *bs)
601
{
602
return bdrv_co_flush(bs->file->bs);
603
}
604
diff --git a/block/vmdk.c b/block/vmdk.c
605
index XXXXXXX..XXXXXXX 100644
606
--- a/block/vmdk.c
607
+++ b/block/vmdk.c
608
@@ -XXX,XX +XXX,XX @@ exit:
609
return ret;
610
}
611
612
-static int coroutine_fn vmdk_L2update(VmdkExtent *extent, VmdkMetaData *m_data,
613
- uint32_t offset)
614
+static int coroutine_fn GRAPH_RDLOCK
615
+vmdk_L2update(VmdkExtent *extent, VmdkMetaData *m_data, uint32_t offset)
616
{
617
offset = cpu_to_le32(offset);
618
/* update L2 table */
619
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vmdk_pwritev(BlockDriverState *bs, uint64_t offset,
620
uint64_t bytes_done = 0;
621
VmdkMetaData m_data;
622
623
+ assume_graph_lock(); /* FIXME */
624
+
625
if (DIV_ROUND_UP(offset, BDRV_SECTOR_SIZE) > bs->total_sectors) {
626
error_report("Wrong offset: offset=0x%" PRIx64
627
" total_sectors=0x%" PRIx64,
628
--
629
2.39.2
diff view generated by jsdifflib
Deleted patch
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2
Message-Id: <20230203152202.49054-16-kwolf@redhat.com>
3
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
---
6
include/block/block_int-common.h | 12 +++++++-----
7
include/block/block_int-io.h | 8 ++++----
8
block/copy-before-write.c | 6 ++----
9
block/io.c | 2 ++
10
block/snapshot-access.c | 4 ++--
11
5 files changed, 17 insertions(+), 15 deletions(-)
12
1
13
diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
14
index XXXXXXX..XXXXXXX 100644
15
--- a/include/block/block_int-common.h
16
+++ b/include/block/block_int-common.h
17
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
18
* - receive the snapshot's actual length (which may differ from bs's
19
* length)
20
*/
21
- int coroutine_fn (*bdrv_co_preadv_snapshot)(BlockDriverState *bs,
22
- int64_t offset, int64_t bytes, QEMUIOVector *qiov, size_t qiov_offset);
23
- int coroutine_fn (*bdrv_co_snapshot_block_status)(BlockDriverState *bs,
24
- bool want_zero, int64_t offset, int64_t bytes, int64_t *pnum,
25
- int64_t *map, BlockDriverState **file);
26
+ int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_preadv_snapshot)(
27
+ BlockDriverState *bs, int64_t offset, int64_t bytes,
28
+ QEMUIOVector *qiov, size_t qiov_offset);
29
+
30
+ int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_snapshot_block_status)(
31
+ BlockDriverState *bs, bool want_zero, int64_t offset, int64_t bytes,
32
+ int64_t *pnum, int64_t *map, BlockDriverState **file);
33
34
int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_pdiscard_snapshot)(
35
BlockDriverState *bs, int64_t offset, int64_t bytes);
36
diff --git a/include/block/block_int-io.h b/include/block/block_int-io.h
37
index XXXXXXX..XXXXXXX 100644
38
--- a/include/block/block_int-io.h
39
+++ b/include/block/block_int-io.h
40
@@ -XXX,XX +XXX,XX @@
41
* the I/O API.
42
*/
43
44
-int coroutine_fn bdrv_co_preadv_snapshot(BdrvChild *child,
45
+int coroutine_fn GRAPH_RDLOCK bdrv_co_preadv_snapshot(BdrvChild *child,
46
int64_t offset, int64_t bytes, QEMUIOVector *qiov, size_t qiov_offset);
47
-int coroutine_fn bdrv_co_snapshot_block_status(BlockDriverState *bs,
48
- bool want_zero, int64_t offset, int64_t bytes, int64_t *pnum,
49
- int64_t *map, BlockDriverState **file);
50
+int coroutine_fn GRAPH_RDLOCK bdrv_co_snapshot_block_status(
51
+ BlockDriverState *bs, bool want_zero, int64_t offset, int64_t bytes,
52
+ int64_t *pnum, int64_t *map, BlockDriverState **file);
53
int coroutine_fn GRAPH_RDLOCK bdrv_co_pdiscard_snapshot(BlockDriverState *bs,
54
int64_t offset, int64_t bytes);
55
56
diff --git a/block/copy-before-write.c b/block/copy-before-write.c
57
index XXXXXXX..XXXXXXX 100644
58
--- a/block/copy-before-write.c
59
+++ b/block/copy-before-write.c
60
@@ -XXX,XX +XXX,XX @@ cbw_snapshot_read_unlock(BlockDriverState *bs, BlockReq *req)
61
g_free(req);
62
}
63
64
-static coroutine_fn int
65
+static int coroutine_fn GRAPH_RDLOCK
66
cbw_co_preadv_snapshot(BlockDriverState *bs, int64_t offset, int64_t bytes,
67
QEMUIOVector *qiov, size_t qiov_offset)
68
{
69
@@ -XXX,XX +XXX,XX @@ cbw_co_preadv_snapshot(BlockDriverState *bs, int64_t offset, int64_t bytes,
70
BdrvChild *file;
71
int ret;
72
73
- assume_graph_lock(); /* FIXME */
74
-
75
/* TODO: upgrade to async loop using AioTask */
76
while (bytes) {
77
int64_t cur_bytes;
78
@@ -XXX,XX +XXX,XX @@ cbw_co_preadv_snapshot(BlockDriverState *bs, int64_t offset, int64_t bytes,
79
return 0;
80
}
81
82
-static int coroutine_fn
83
+static int coroutine_fn GRAPH_RDLOCK
84
cbw_co_snapshot_block_status(BlockDriverState *bs,
85
bool want_zero, int64_t offset, int64_t bytes,
86
int64_t *pnum, int64_t *map,
87
diff --git a/block/io.c b/block/io.c
88
index XXXXXXX..XXXXXXX 100644
89
--- a/block/io.c
90
+++ b/block/io.c
91
@@ -XXX,XX +XXX,XX @@ bdrv_co_preadv_snapshot(BdrvChild *child, int64_t offset, int64_t bytes,
92
BlockDriver *drv = bs->drv;
93
int ret;
94
IO_CODE();
95
+ assert_bdrv_graph_readable();
96
97
if (!drv) {
98
return -ENOMEDIUM;
99
@@ -XXX,XX +XXX,XX @@ bdrv_co_snapshot_block_status(BlockDriverState *bs,
100
BlockDriver *drv = bs->drv;
101
int ret;
102
IO_CODE();
103
+ assert_bdrv_graph_readable();
104
105
if (!drv) {
106
return -ENOMEDIUM;
107
diff --git a/block/snapshot-access.c b/block/snapshot-access.c
108
index XXXXXXX..XXXXXXX 100644
109
--- a/block/snapshot-access.c
110
+++ b/block/snapshot-access.c
111
@@ -XXX,XX +XXX,XX @@
112
#include "qemu/cutils.h"
113
#include "block/block_int.h"
114
115
-static coroutine_fn int
116
+static int coroutine_fn GRAPH_RDLOCK
117
snapshot_access_co_preadv_part(BlockDriverState *bs,
118
int64_t offset, int64_t bytes,
119
QEMUIOVector *qiov, size_t qiov_offset,
120
@@ -XXX,XX +XXX,XX @@ snapshot_access_co_preadv_part(BlockDriverState *bs,
121
return bdrv_co_preadv_snapshot(bs->file, offset, bytes, qiov, qiov_offset);
122
}
123
124
-static int coroutine_fn
125
+static int coroutine_fn GRAPH_RDLOCK
126
snapshot_access_co_block_status(BlockDriverState *bs,
127
bool want_zero, int64_t offset,
128
int64_t bytes, int64_t *pnum,
129
--
130
2.39.2
diff view generated by jsdifflib
1
From: Stefan Hajnoczi <stefanha@redhat.com>
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
2
3
When an IOThread is configured, the ctrl virtqueue is processed in the
3
BLOCK_OP_TYPE_DATAPLANE prevents BlockDriverState from being used by
4
IOThread. TMFs that reset SCSI devices are currently called directly
4
virtio-blk/virtio-scsi with IOThread. Commit b112a65c52aa ("block:
5
from the IOThread and trigger an assertion failure in blk_drain() from
5
declare blockjobs and dataplane friends!") eliminated the main reason
6
the following call stack:
6
for this blocker in 2014.
7
7
8
virtio_scsi_handle_ctrl_req -> virtio_scsi_do_tmf -> device_code_reset
8
Nowadays the block layer supports I/O from multiple AioContexts, so
9
-> scsi_disk_reset -> scsi_device_purge_requests -> blk_drain
9
there is even less reason to block IOThread users. Any legitimate
10
reasons related to interference would probably also apply to
11
non-IOThread users.
10
12
11
../block/block-backend.c:1780: void blk_drain(BlockBackend *): Assertion `qemu_in_main_thread()' failed.
13
The only remaining users are bdrv_op_unblock(BLOCK_OP_TYPE_DATAPLANE)
14
calls after bdrv_op_block_all(). If we remove BLOCK_OP_TYPE_DATAPLANE
15
their behavior doesn't change.
12
16
13
The blk_drain() function is not designed to be called from an IOThread
17
Existing bdrv_op_block_all() callers that don't explicitly unblock
14
because it needs the Big QEMU Lock (BQL).
18
BLOCK_OP_TYPE_DATAPLANE seem to do so simply because no one bothered to
19
rather than because it is necessary to keep BLOCK_OP_TYPE_DATAPLANE
20
blocked.
15
21
16
This patch defers TMFs that reset SCSI devices to a Bottom Half (BH)
22
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
17
that runs in the main loop thread under the BQL. This way it's safe to
23
Message-ID: <20250203182529.269066-1-stefanha@redhat.com>
18
call blk_drain() and the assertion failure is avoided.
19
20
Introduce s->tmf_bh_list for tracking TMF requests that have been
21
deferred to the BH. When the BH runs it will grab the entire list and
22
process all requests. Care must be taken to clear the list when the
23
virtio-scsi device is reset or unrealized. Otherwise deferred TMF
24
requests could execute later and lead to use-after-free or other
25
undefined behavior.
26
27
The s->resetting counter that's used by TMFs that reset SCSI devices is
28
accessed from multiple threads. This patch makes that explicit by using
29
atomic accessor functions. With this patch applied the counter is only
30
modified by the main loop thread under the BQL but can be read by any
31
thread.
32
33
Reported-by: Qing Wang <qinwang@redhat.com>
34
Cc: Paolo Bonzini <pbonzini@redhat.com>
35
Reviewed-by: Eric Blake <eblake@redhat.com>
24
Reviewed-by: Eric Blake <eblake@redhat.com>
36
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
25
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
37
Message-Id: <20230221212218.1378734-4-stefanha@redhat.com>
38
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
26
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
39
---
27
---
40
include/hw/virtio/virtio-scsi.h | 11 ++-
28
include/block/block-common.h | 1 -
41
hw/scsi/virtio-scsi.c | 169 +++++++++++++++++++++++++-------
29
block/replication.c | 1 -
42
2 files changed, 143 insertions(+), 37 deletions(-)
30
blockjob.c | 2 --
31
hw/block/virtio-blk.c | 9 ---------
32
hw/scsi/virtio-scsi.c | 3 ---
33
5 files changed, 16 deletions(-)
43
34
44
diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h
35
diff --git a/include/block/block-common.h b/include/block/block-common.h
45
index XXXXXXX..XXXXXXX 100644
36
index XXXXXXX..XXXXXXX 100644
46
--- a/include/hw/virtio/virtio-scsi.h
37
--- a/include/block/block-common.h
47
+++ b/include/hw/virtio/virtio-scsi.h
38
+++ b/include/block/block-common.h
48
@@ -XXX,XX +XXX,XX @@ struct VirtIOSCSICommon {
39
@@ -XXX,XX +XXX,XX @@ typedef enum BlockOpType {
49
VirtQueue **cmd_vqs;
40
BLOCK_OP_TYPE_CHANGE,
50
};
41
BLOCK_OP_TYPE_COMMIT_SOURCE,
51
42
BLOCK_OP_TYPE_COMMIT_TARGET,
52
+struct VirtIOSCSIReq;
43
- BLOCK_OP_TYPE_DATAPLANE,
53
+
44
BLOCK_OP_TYPE_DRIVE_DEL,
54
struct VirtIOSCSI {
45
BLOCK_OP_TYPE_EJECT,
55
VirtIOSCSICommon parent_obj;
46
BLOCK_OP_TYPE_EXTERNAL_SNAPSHOT,
56
47
diff --git a/block/replication.c b/block/replication.c
57
SCSIBus bus;
48
index XXXXXXX..XXXXXXX 100644
58
- int resetting;
49
--- a/block/replication.c
59
+ int resetting; /* written from main loop thread, read from any thread */
50
+++ b/block/replication.c
60
bool events_dropped;
51
@@ -XXX,XX +XXX,XX @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
61
52
return;
62
+ /*
53
}
63
+ * TMFs deferred to main loop BH. These fields are protected by
54
bdrv_op_block_all(top_bs, s->blocker);
64
+ * virtio_scsi_acquire().
55
- bdrv_op_unblock(top_bs, BLOCK_OP_TYPE_DATAPLANE, s->blocker);
65
+ */
56
66
+ QEMUBH *tmf_bh;
57
bdrv_graph_wrunlock();
67
+ QTAILQ_HEAD(, VirtIOSCSIReq) tmf_bh_list;
58
68
+
59
diff --git a/blockjob.c b/blockjob.c
69
/* Fields for dataplane below */
60
index XXXXXXX..XXXXXXX 100644
70
AioContext *ctx; /* one iothread per virtio-scsi-pci for now */
61
--- a/blockjob.c
71
62
+++ b/blockjob.c
63
@@ -XXX,XX +XXX,XX @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
64
goto fail;
65
}
66
67
- bdrv_op_unblock(bs, BLOCK_OP_TYPE_DATAPLANE, job->blocker);
68
-
69
if (!block_job_set_speed(job, speed, errp)) {
70
goto fail;
71
}
72
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
73
index XXXXXXX..XXXXXXX 100644
74
--- a/hw/block/virtio-blk.c
75
+++ b/hw/block/virtio-blk.c
76
@@ -XXX,XX +XXX,XX @@ static bool virtio_blk_vq_aio_context_init(VirtIOBlock *s, Error **errp)
77
error_setg(errp, "ioeventfd is required for iothread");
78
return false;
79
}
80
-
81
- /*
82
- * If ioeventfd is (re-)enabled while the guest is running there could
83
- * be block jobs that can conflict.
84
- */
85
- if (blk_op_is_blocked(conf->conf.blk, BLOCK_OP_TYPE_DATAPLANE, errp)) {
86
- error_prepend(errp, "cannot start virtio-blk ioeventfd: ");
87
- return false;
88
- }
89
}
90
91
s->vq_aio_context = g_new(AioContext *, conf->num_queues);
72
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
92
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
73
index XXXXXXX..XXXXXXX 100644
93
index XXXXXXX..XXXXXXX 100644
74
--- a/hw/scsi/virtio-scsi.c
94
--- a/hw/scsi/virtio-scsi.c
75
+++ b/hw/scsi/virtio-scsi.c
95
+++ b/hw/scsi/virtio-scsi.c
76
@@ -XXX,XX +XXX,XX @@ typedef struct VirtIOSCSIReq {
96
@@ -XXX,XX +XXX,XX @@ static void virtio_scsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev,
77
QEMUSGList qsgl;
97
int ret;
78
QEMUIOVector resp_iov;
98
79
99
if (s->ctx && !s->dataplane_fenced) {
80
- union {
100
- if (blk_op_is_blocked(sd->conf.blk, BLOCK_OP_TYPE_DATAPLANE, errp)) {
81
- /* Used for two-stage request submission */
101
- return;
82
- QTAILQ_ENTRY(VirtIOSCSIReq) next;
83
+ /* Used for two-stage request submission and TMFs deferred to BH */
84
+ QTAILQ_ENTRY(VirtIOSCSIReq) next;
85
86
- /* Used for cancellation of request during TMFs */
87
- int remaining;
88
- };
89
+ /* Used for cancellation of request during TMFs */
90
+ int remaining;
91
92
SCSIRequest *sreq;
93
size_t resp_size;
94
@@ -XXX,XX +XXX,XX @@ static inline void virtio_scsi_ctx_check(VirtIOSCSI *s, SCSIDevice *d)
95
}
96
}
97
98
+static void virtio_scsi_do_one_tmf_bh(VirtIOSCSIReq *req)
99
+{
100
+ VirtIOSCSI *s = req->dev;
101
+ SCSIDevice *d = virtio_scsi_device_get(s, req->req.tmf.lun);
102
+ BusChild *kid;
103
+ int target;
104
+
105
+ switch (req->req.tmf.subtype) {
106
+ case VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET:
107
+ if (!d) {
108
+ req->resp.tmf.response = VIRTIO_SCSI_S_BAD_TARGET;
109
+ goto out;
110
+ }
111
+ if (d->lun != virtio_scsi_get_lun(req->req.tmf.lun)) {
112
+ req->resp.tmf.response = VIRTIO_SCSI_S_INCORRECT_LUN;
113
+ goto out;
114
+ }
115
+ qatomic_inc(&s->resetting);
116
+ device_cold_reset(&d->qdev);
117
+ qatomic_dec(&s->resetting);
118
+ break;
119
+
120
+ case VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET:
121
+ target = req->req.tmf.lun[1];
122
+ qatomic_inc(&s->resetting);
123
+
124
+ rcu_read_lock();
125
+ QTAILQ_FOREACH_RCU(kid, &s->bus.qbus.children, sibling) {
126
+ SCSIDevice *d1 = SCSI_DEVICE(kid->child);
127
+ if (d1->channel == 0 && d1->id == target) {
128
+ device_cold_reset(&d1->qdev);
129
+ }
130
+ }
131
+ rcu_read_unlock();
132
+
133
+ qatomic_dec(&s->resetting);
134
+ break;
135
+
136
+ default:
137
+ g_assert_not_reached();
138
+ break;
139
+ }
140
+
141
+out:
142
+ object_unref(OBJECT(d));
143
+
144
+ virtio_scsi_acquire(s);
145
+ virtio_scsi_complete_req(req);
146
+ virtio_scsi_release(s);
147
+}
148
+
149
+/* Some TMFs must be processed from the main loop thread */
150
+static void virtio_scsi_do_tmf_bh(void *opaque)
151
+{
152
+ VirtIOSCSI *s = opaque;
153
+ QTAILQ_HEAD(, VirtIOSCSIReq) reqs = QTAILQ_HEAD_INITIALIZER(reqs);
154
+ VirtIOSCSIReq *req;
155
+ VirtIOSCSIReq *tmp;
156
+
157
+ GLOBAL_STATE_CODE();
158
+
159
+ virtio_scsi_acquire(s);
160
+
161
+ QTAILQ_FOREACH_SAFE(req, &s->tmf_bh_list, next, tmp) {
162
+ QTAILQ_REMOVE(&s->tmf_bh_list, req, next);
163
+ QTAILQ_INSERT_TAIL(&reqs, req, next);
164
+ }
165
+
166
+ qemu_bh_delete(s->tmf_bh);
167
+ s->tmf_bh = NULL;
168
+
169
+ virtio_scsi_release(s);
170
+
171
+ QTAILQ_FOREACH_SAFE(req, &reqs, next, tmp) {
172
+ QTAILQ_REMOVE(&reqs, req, next);
173
+ virtio_scsi_do_one_tmf_bh(req);
174
+ }
175
+}
176
+
177
+static void virtio_scsi_reset_tmf_bh(VirtIOSCSI *s)
178
+{
179
+ VirtIOSCSIReq *req;
180
+ VirtIOSCSIReq *tmp;
181
+
182
+ GLOBAL_STATE_CODE();
183
+
184
+ virtio_scsi_acquire(s);
185
+
186
+ if (s->tmf_bh) {
187
+ qemu_bh_delete(s->tmf_bh);
188
+ s->tmf_bh = NULL;
189
+ }
190
+
191
+ QTAILQ_FOREACH_SAFE(req, &s->tmf_bh_list, next, tmp) {
192
+ QTAILQ_REMOVE(&s->tmf_bh_list, req, next);
193
+
194
+ /* SAM-6 6.3.2 Hard reset */
195
+ req->resp.tmf.response = VIRTIO_SCSI_S_TARGET_FAILURE;
196
+ virtio_scsi_complete_req(req);
197
+ }
198
+
199
+ virtio_scsi_release(s);
200
+}
201
+
202
+static void virtio_scsi_defer_tmf_to_bh(VirtIOSCSIReq *req)
203
+{
204
+ VirtIOSCSI *s = req->dev;
205
+
206
+ QTAILQ_INSERT_TAIL(&s->tmf_bh_list, req, next);
207
+
208
+ if (!s->tmf_bh) {
209
+ s->tmf_bh = qemu_bh_new(virtio_scsi_do_tmf_bh, s);
210
+ qemu_bh_schedule(s->tmf_bh);
211
+ }
212
+}
213
+
214
/* Return 0 if the request is ready to be completed and return to guest;
215
* -EINPROGRESS if the request is submitted and will be completed later, in the
216
* case of async cancellation. */
217
@@ -XXX,XX +XXX,XX @@ static int virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req)
218
{
219
SCSIDevice *d = virtio_scsi_device_get(s, req->req.tmf.lun);
220
SCSIRequest *r, *next;
221
- BusChild *kid;
222
- int target;
223
int ret = 0;
224
225
virtio_scsi_ctx_check(s, d);
226
@@ -XXX,XX +XXX,XX @@ static int virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req)
227
break;
228
229
case VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET:
230
- if (!d) {
231
- goto fail;
232
- }
102
- }
233
- if (d->lun != virtio_scsi_get_lun(req->req.tmf.lun)) {
103
ret = blk_set_aio_context(sd->conf.blk, s->ctx, errp);
234
- goto incorrect_lun;
104
if (ret < 0) {
235
- }
105
return;
236
- s->resetting++;
237
- device_cold_reset(&d->qdev);
238
- s->resetting--;
239
+ case VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET:
240
+ virtio_scsi_defer_tmf_to_bh(req);
241
+ ret = -EINPROGRESS;
242
break;
243
244
case VIRTIO_SCSI_T_TMF_ABORT_TASK_SET:
245
@@ -XXX,XX +XXX,XX @@ static int virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req)
246
}
247
break;
248
249
- case VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET:
250
- target = req->req.tmf.lun[1];
251
- s->resetting++;
252
-
253
- rcu_read_lock();
254
- QTAILQ_FOREACH_RCU(kid, &s->bus.qbus.children, sibling) {
255
- SCSIDevice *d1 = SCSI_DEVICE(kid->child);
256
- if (d1->channel == 0 && d1->id == target) {
257
- device_cold_reset(&d1->qdev);
258
- }
259
- }
260
- rcu_read_unlock();
261
-
262
- s->resetting--;
263
- break;
264
-
265
case VIRTIO_SCSI_T_TMF_CLEAR_ACA:
266
default:
267
req->resp.tmf.response = VIRTIO_SCSI_S_FUNCTION_REJECTED;
268
@@ -XXX,XX +XXX,XX @@ static void virtio_scsi_request_cancelled(SCSIRequest *r)
269
if (!req) {
270
return;
271
}
272
- if (req->dev->resetting) {
273
+ if (qatomic_read(&req->dev->resetting)) {
274
req->resp.cmd.response = VIRTIO_SCSI_S_RESET;
275
} else {
276
req->resp.cmd.response = VIRTIO_SCSI_S_ABORTED;
277
@@ -XXX,XX +XXX,XX @@ static void virtio_scsi_reset(VirtIODevice *vdev)
278
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
279
280
assert(!s->dataplane_started);
281
- s->resetting++;
282
+
283
+ virtio_scsi_reset_tmf_bh(s);
284
+
285
+ qatomic_inc(&s->resetting);
286
bus_cold_reset(BUS(&s->bus));
287
- s->resetting--;
288
+ qatomic_dec(&s->resetting);
289
290
vs->sense_size = VIRTIO_SCSI_SENSE_DEFAULT_SIZE;
291
vs->cdb_size = VIRTIO_SCSI_CDB_DEFAULT_SIZE;
292
@@ -XXX,XX +XXX,XX @@ static void virtio_scsi_device_realize(DeviceState *dev, Error **errp)
293
VirtIOSCSI *s = VIRTIO_SCSI(dev);
294
Error *err = NULL;
295
296
+ QTAILQ_INIT(&s->tmf_bh_list);
297
+
298
virtio_scsi_common_realize(dev,
299
virtio_scsi_handle_ctrl,
300
virtio_scsi_handle_event,
301
@@ -XXX,XX +XXX,XX @@ static void virtio_scsi_device_unrealize(DeviceState *dev)
302
{
303
VirtIOSCSI *s = VIRTIO_SCSI(dev);
304
305
+ virtio_scsi_reset_tmf_bh(s);
306
+
307
qbus_set_hotplug_handler(BUS(&s->bus), NULL);
308
virtio_scsi_common_unrealize(dev);
309
}
310
--
106
--
311
2.39.2
107
2.48.1
diff view generated by jsdifflib