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 |