1 | The following changes since commit 42f6c9179be4401974dd3a75ee72defd16b5092d: | 1 | The following changes since commit 79b677d658d3d35e1e776826ac4abb28cdce69b8: |
---|---|---|---|
2 | 2 | ||
3 | Merge tag 'pull-ppc-20211112' of https://github.com/legoater/qemu into staging (2021-11-12 12:28:25 +0100) | 3 | Merge tag 'net-pull-request' of https://github.com/jasowang/qemu into staging (2023-02-21 11:28:31 +0000) |
4 | 4 | ||
5 | are available in the Git repository at: | 5 | are available in the Git repository at: |
6 | 6 | ||
7 | git://repo.or.cz/qemu/kevin.git tags/for-upstream | 7 | https://repo.or.cz/qemu/kevin.git tags/for-upstream |
8 | 8 | ||
9 | for you to fetch changes up to 7461272c5f6032436ef9032c091c0118539483e4: | 9 | for you to fetch changes up to 0f385a2420d2c3f8ae7ed65fbe2712027664059e: |
10 | 10 | ||
11 | softmmu/qdev-monitor: fix use-after-free in qdev_set_id() (2021-11-15 15:49:46 +0100) | 11 | block/rbd: Add support for layered encryption (2023-02-23 19:49:35 +0100) |
12 | 12 | ||
13 | ---------------------------------------------------------------- | 13 | ---------------------------------------------------------------- |
14 | Block layer patches | 14 | Block layer patches |
15 | 15 | ||
16 | - Fixes to image streaming job and block layer reconfiguration to make | 16 | - Lock the graph, part 2 (BlockDriver callbacks) |
17 | iotest 030 pass again | 17 | - virtio-scsi: fix SCSIDevice hot unplug with IOThread |
18 | - docs: Deprecate incorrectly typed device_add arguments | 18 | - rbd: Add support for layered encryption |
19 | - file-posix: Fix alignment after reopen changing O_DIRECT | ||
20 | 19 | ||
21 | ---------------------------------------------------------------- | 20 | ---------------------------------------------------------------- |
22 | Hanna Reitz (10): | 21 | Emanuele Giuseppe Esposito (5): |
23 | stream: Traverse graph after modification | 22 | block/qed: add missing graph rdlock in qed_need_check_timer_entry |
24 | block: Manipulate children list in .attach/.detach | 23 | block: Mark bdrv_co_flush() and callers GRAPH_RDLOCK |
25 | block: Unite remove_empty_child and child_free | 24 | block: Mark bdrv_co_pdiscard() and callers GRAPH_RDLOCK |
26 | block: Drop detached child from ignore list | 25 | block: Mark bdrv_co_copy_range() GRAPH_RDLOCK |
27 | block: Pass BdrvChild ** to replace_child_noperm | 26 | block: Mark bdrv_co_is_inserted() and callers GRAPH_RDLOCK |
28 | block: Restructure remove_file_or_backing_child() | ||
29 | transactions: Invoke clean() after everything else | ||
30 | block: Let replace_child_tran keep indirect pointer | ||
31 | block: Let replace_child_noperm free children | ||
32 | iotests/030: Unthrottle parallel jobs in reverse | ||
33 | 27 | ||
34 | Kevin Wolf (2): | 28 | Kevin Wolf (18): |
35 | docs: Deprecate incorrectly typed device_add arguments | 29 | block: Make bdrv_can_set_read_only() static |
36 | file-posix: Fix alignment after reopen changing O_DIRECT | 30 | mirror: Fix access of uninitialised fields during start |
31 | block: Mark bdrv_co_truncate() and callers GRAPH_RDLOCK | ||
32 | block: Mark bdrv_co_block_status() and callers GRAPH_RDLOCK | ||
33 | block: Mark bdrv_co_ioctl() and callers GRAPH_RDLOCK | ||
34 | block: Mark bdrv_co_pwrite_zeroes() and callers GRAPH_RDLOCK | ||
35 | block: Mark read/write in block/io.c GRAPH_RDLOCK | ||
36 | block: Mark public read/write functions GRAPH_RDLOCK | ||
37 | block: Mark bdrv_co_pwrite_sync() and callers GRAPH_RDLOCK | ||
38 | block: Mark bdrv_co_do_pwrite_zeroes() GRAPH_RDLOCK | ||
39 | block: Mark preadv_snapshot/snapshot_block_status GRAPH_RDLOCK | ||
40 | block: Mark bdrv_co_create() and callers GRAPH_RDLOCK | ||
41 | block: Mark bdrv_co_io_(un)plug() and callers GRAPH_RDLOCK | ||
42 | block: Mark bdrv_co_eject/lock_medium() and callers GRAPH_RDLOCK | ||
43 | block: Mark bdrv_(un)register_buf() GRAPH_RDLOCK | ||
44 | block: Mark bdrv_co_delete_file() and callers GRAPH_RDLOCK | ||
45 | block: Mark bdrv_*_dirty_bitmap() and callers GRAPH_RDLOCK | ||
46 | block: Mark bdrv_co_refresh_total_sectors() and callers GRAPH_RDLOCK | ||
37 | 47 | ||
38 | Stefan Hajnoczi (1): | 48 | Or Ozeri (3): |
39 | softmmu/qdev-monitor: fix use-after-free in qdev_set_id() | 49 | block/rbd: Remove redundant stack variable passphrase_len |
50 | block/rbd: Add luks-any encryption opening option | ||
51 | block/rbd: Add support for layered encryption | ||
40 | 52 | ||
41 | docs/about/deprecated.rst | 14 +++ | 53 | Stefan Hajnoczi (3): |
42 | include/qemu/transactions.h | 3 + | 54 | scsi: protect req->aiocb with AioContext lock |
43 | block.c | 233 +++++++++++++++++++++++++++++++++----------- | 55 | dma-helpers: prevent dma_blk_cb() vs dma_aio_cancel() race |
44 | block/file-posix.c | 20 +++- | 56 | virtio-scsi: reset SCSI devices from main loop thread |
45 | block/stream.c | 7 +- | ||
46 | softmmu/qdev-monitor.c | 2 +- | ||
47 | util/transactions.c | 8 +- | ||
48 | tests/qemu-iotests/030 | 11 ++- | ||
49 | tests/qemu-iotests/142 | 22 +++++ | ||
50 | tests/qemu-iotests/142.out | 15 +++ | ||
51 | 10 files changed, 269 insertions(+), 66 deletions(-) | ||
52 | 57 | ||
53 | 58 | qapi/block-core.json | 27 +++++- | |
59 | block/coroutines.h | 2 +- | ||
60 | block/qcow2.h | 27 ++++-- | ||
61 | block/qed.h | 45 +++++---- | ||
62 | include/block/block-copy.h | 6 +- | ||
63 | include/block/block-global-state.h | 14 +-- | ||
64 | include/block/block-io.h | 110 ++++++++++++---------- | ||
65 | include/block/block_int-common.h | 173 ++++++++++++++++++---------------- | ||
66 | include/block/block_int-io.h | 53 ++++++----- | ||
67 | include/block/dirty-bitmap.h | 12 +-- | ||
68 | include/hw/virtio/virtio-scsi.h | 11 ++- | ||
69 | include/sysemu/block-backend-io.h | 7 +- | ||
70 | block.c | 12 ++- | ||
71 | block/backup.c | 3 + | ||
72 | block/blkdebug.c | 19 ++-- | ||
73 | block/blklogwrites.c | 35 ++++--- | ||
74 | block/blkreplay.c | 24 +++-- | ||
75 | block/blkverify.c | 5 +- | ||
76 | block/block-backend.c | 39 +++++--- | ||
77 | block/block-copy.c | 32 ++++--- | ||
78 | block/bochs.c | 2 +- | ||
79 | block/commit.c | 5 +- | ||
80 | block/copy-before-write.c | 33 ++++--- | ||
81 | block/copy-on-read.c | 44 +++++---- | ||
82 | block/create.c | 9 +- | ||
83 | block/crypto.c | 16 ++-- | ||
84 | block/dirty-bitmap.c | 2 + | ||
85 | block/file-posix.c | 27 +++--- | ||
86 | block/file-win32.c | 7 +- | ||
87 | block/filter-compress.c | 36 ++++--- | ||
88 | block/io.c | 108 +++++++++++++-------- | ||
89 | block/iscsi.c | 28 +++--- | ||
90 | block/mirror.c | 59 ++++++++---- | ||
91 | block/parallels.c | 33 +++---- | ||
92 | block/preallocate.c | 38 ++++---- | ||
93 | block/qcow.c | 46 +++++---- | ||
94 | block/qcow2-cluster.c | 17 ++-- | ||
95 | block/qcow2.c | 136 +++++++++++++++------------ | ||
96 | block/qed-check.c | 3 +- | ||
97 | block/qed-table.c | 10 +- | ||
98 | block/qed.c | 101 ++++++++++---------- | ||
99 | block/quorum.c | 62 +++++++----- | ||
100 | block/raw-format.c | 76 ++++++++------- | ||
101 | block/rbd.c | 188 ++++++++++++++++++++++++++++++++++--- | ||
102 | block/replication.c | 18 ++-- | ||
103 | block/snapshot-access.c | 8 +- | ||
104 | block/stream.c | 40 ++++---- | ||
105 | block/throttle.c | 36 ++++--- | ||
106 | block/vdi.c | 11 +-- | ||
107 | block/vhdx.c | 18 ++-- | ||
108 | block/vmdk.c | 132 ++++++++++++-------------- | ||
109 | block/vpc.c | 11 +-- | ||
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 | From: Hanna Reitz <hreitz@redhat.com> | 1 | It is never called outside of block.c. |
---|---|---|---|
2 | 2 | ||
3 | bdrv_attach_child_common_abort() restores the parent's AioContext. To | 3 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
4 | do so, the child (which was supposed to be attached, but is now detached | 4 | Message-Id: <20230203152202.49054-2-kwolf@redhat.com> |
5 | again by this abort handler) is added to the ignore list for the | 5 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
6 | AioContext changing functions. | 6 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> |
7 | |||
8 | However, since we modify a BDS's children list in the BdrvChildClass's | ||
9 | .attach and .detach handlers, the child is already effectively detached | ||
10 | from the parent by this point. We do not need to put it into the ignore | ||
11 | list. | ||
12 | |||
13 | Use this opportunity to clean up the empty line structure: Keep setting | ||
14 | the ignore list, invoking the AioContext function, and freeing the | ||
15 | ignore list in blocks separated by empty lines. | ||
16 | |||
17 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
18 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
19 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
20 | Message-Id: <20211111120829.81329-5-hreitz@redhat.com> | ||
21 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
22 | --- | 8 | --- |
23 | block.c | 8 +++++--- | 9 | include/block/block-io.h | 2 -- |
24 | 1 file changed, 5 insertions(+), 3 deletions(-) | 10 | block.c | 4 ++-- |
11 | 2 files changed, 2 insertions(+), 4 deletions(-) | ||
25 | 12 | ||
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 | 26 | diff --git a/block.c b/block.c |
27 | index XXXXXXX..XXXXXXX 100644 | 27 | index XXXXXXX..XXXXXXX 100644 |
28 | --- a/block.c | 28 | --- a/block.c |
29 | +++ b/block.c | 29 | +++ b/block.c |
30 | @@ -XXX,XX +XXX,XX @@ static void bdrv_attach_child_common_abort(void *opaque) | 30 | @@ -XXX,XX +XXX,XX @@ bool bdrv_is_read_only(BlockDriverState *bs) |
31 | } | 31 | return !(bs->open_flags & BDRV_O_RDWR); |
32 | 32 | } | |
33 | if (bdrv_child_get_parent_aio_context(child) != s->old_parent_ctx) { | 33 | |
34 | - GSList *ignore = g_slist_prepend(NULL, child); | 34 | -int bdrv_can_set_read_only(BlockDriverState *bs, bool read_only, |
35 | + GSList *ignore; | 35 | - bool ignore_allow_rdw, Error **errp) |
36 | 36 | +static int bdrv_can_set_read_only(BlockDriverState *bs, bool read_only, | |
37 | + /* No need to ignore `child`, because it has been detached already */ | 37 | + bool ignore_allow_rdw, Error **errp) |
38 | + ignore = NULL; | 38 | { |
39 | child->klass->can_set_aio_ctx(child, s->old_parent_ctx, &ignore, | 39 | IO_CODE(); |
40 | &error_abort); | ||
41 | g_slist_free(ignore); | ||
42 | - ignore = g_slist_prepend(NULL, child); | ||
43 | - child->klass->set_aio_ctx(child, s->old_parent_ctx, &ignore); | ||
44 | |||
45 | + ignore = NULL; | ||
46 | + child->klass->set_aio_ctx(child, s->old_parent_ctx, &ignore); | ||
47 | g_slist_free(ignore); | ||
48 | } | ||
49 | 40 | ||
50 | -- | 41 | -- |
51 | 2.31.1 | 42 | 2.39.2 |
52 | |||
53 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | bdrv_mirror_top_pwritev() accesses the job object when active mirroring | ||
2 | is enabled. It disables this code during early initialisation while | ||
3 | s->job isn't set yet. | ||
1 | 4 | ||
5 | However, s->job is still set way too early when the job object isn't | ||
6 | fully initialised. For example, &s->ops_in_flight isn't initialised yet | ||
7 | and the in_flight bitmap doesn't exist yet. This causes crashes when a | ||
8 | write request comes in too early. | ||
9 | |||
10 | Move the assignment of s->job to when the mirror job is actually fully | ||
11 | initialised to make sure that the mirror_top driver doesn't access it | ||
12 | too early. | ||
13 | |||
14 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
15 | Message-Id: <20230203152202.49054-3-kwolf@redhat.com> | ||
16 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
17 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> | ||
18 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
19 | --- | ||
20 | block/mirror.c | 8 +++++++- | ||
21 | 1 file changed, 7 insertions(+), 1 deletion(-) | ||
22 | |||
23 | diff --git a/block/mirror.c b/block/mirror.c | ||
24 | index XXXXXXX..XXXXXXX 100644 | ||
25 | --- a/block/mirror.c | ||
26 | +++ b/block/mirror.c | ||
27 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn mirror_run(Job *job, Error **errp) | ||
28 | { | ||
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 | } | ||
38 | |||
39 | + /* | ||
40 | + * Only now the job is fully initialised and mirror_top_bs should start | ||
41 | + * accessing it. | ||
42 | + */ | ||
43 | + mirror_top_opaque->job = s; | ||
44 | + | ||
45 | assert(!s->dbi); | ||
46 | s->dbi = bdrv_dirty_iter_new(s->dirty_bitmap); | ||
47 | for (;;) { | ||
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 | -- | ||
57 | 2.39.2 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | This adds GRAPH_RDLOCK annotations to declare that callers of | ||
2 | bdrv_co_truncate() need to hold a reader lock for the graph. | ||
1 | 3 | ||
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: Kevin Wolf <kwolf@redhat.com> | ||
10 | Message-Id: <20230203152202.49054-4-kwolf@redhat.com> | ||
11 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
13 | --- | ||
14 | include/block/block-io.h | 6 +++--- | ||
15 | include/block/block_int-common.h | 7 ++++--- | ||
16 | block/block-backend.c | 1 + | ||
17 | block/crypto.c | 2 +- | ||
18 | block/io.c | 1 + | ||
19 | block/parallels.c | 14 ++++++++------ | ||
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 | |||
27 | diff --git a/include/block/block-io.h b/include/block/block-io.h | ||
28 | index XXXXXXX..XXXXXXX 100644 | ||
29 | --- a/include/block/block-io.h | ||
30 | +++ b/include/block/block-io.h | ||
31 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_pwrite_sync(BdrvChild *child, int64_t offset, | ||
32 | int coroutine_fn bdrv_co_pwrite_zeroes(BdrvChild *child, int64_t offset, | ||
33 | int64_t bytes, BdrvRequestFlags flags); | ||
34 | |||
35 | -int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact, | ||
36 | - PreallocMode prealloc, BdrvRequestFlags flags, | ||
37 | - Error **errp); | ||
38 | +int coroutine_fn GRAPH_RDLOCK | ||
39 | +bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact, | ||
40 | + PreallocMode prealloc, BdrvRequestFlags flags, Error **errp); | ||
41 | |||
42 | int64_t coroutine_fn bdrv_co_nb_sectors(BlockDriverState *bs); | ||
43 | int64_t co_wrapper_mixed bdrv_nb_sectors(BlockDriverState *bs); | ||
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 | * If @exact is true and this function fails but would succeed | ||
50 | * with @exact = false, it should return -ENOTSUP. | ||
51 | */ | ||
52 | - int coroutine_fn (*bdrv_co_truncate)(BlockDriverState *bs, int64_t offset, | ||
53 | - bool exact, PreallocMode prealloc, | ||
54 | - BdrvRequestFlags flags, Error **errp); | ||
55 | + int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_truncate)( | ||
56 | + BlockDriverState *bs, int64_t offset, bool exact, | ||
57 | + PreallocMode prealloc, BdrvRequestFlags flags, Error **errp); | ||
58 | + | ||
59 | int64_t coroutine_fn (*bdrv_co_getlength)(BlockDriverState *bs); | ||
60 | int64_t coroutine_fn (*bdrv_co_get_allocated_file_size)( | ||
61 | BlockDriverState *bs); | ||
62 | diff --git a/block/block-backend.c b/block/block-backend.c | ||
63 | index XXXXXXX..XXXXXXX 100644 | ||
64 | --- a/block/block-backend.c | ||
65 | +++ b/block/block-backend.c | ||
66 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn blk_co_truncate(BlockBackend *blk, int64_t offset, bool exact, | ||
67 | Error **errp) | ||
68 | { | ||
69 | IO_OR_GS_CODE(); | ||
70 | + GRAPH_RDLOCK_GUARD(); | ||
71 | if (!blk_is_available(blk)) { | ||
72 | error_setg(errp, "No medium inserted"); | ||
73 | return -ENOMEDIUM; | ||
74 | diff --git a/block/crypto.c b/block/crypto.c | ||
75 | index XXXXXXX..XXXXXXX 100644 | ||
76 | --- a/block/crypto.c | ||
77 | +++ b/block/crypto.c | ||
78 | @@ -XXX,XX +XXX,XX @@ block_crypto_co_create_generic(BlockDriverState *bs, int64_t size, | ||
79 | return ret; | ||
80 | } | ||
81 | |||
82 | -static int coroutine_fn | ||
83 | +static int coroutine_fn GRAPH_RDLOCK | ||
84 | block_crypto_co_truncate(BlockDriverState *bs, int64_t offset, bool exact, | ||
85 | PreallocMode prealloc, BdrvRequestFlags flags, | ||
86 | Error **errp) | ||
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 @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact, | ||
92 | int64_t old_size, new_bytes; | ||
93 | int ret; | ||
94 | IO_CODE(); | ||
95 | + assert_bdrv_graph_readable(); | ||
96 | |||
97 | /* if bs->drv == NULL, bs is closed, so there's nothing to do here */ | ||
98 | if (!drv) { | ||
99 | diff --git a/block/parallels.c b/block/parallels.c | ||
100 | index XXXXXXX..XXXXXXX 100644 | ||
101 | --- a/block/parallels.c | ||
102 | +++ b/block/parallels.c | ||
103 | @@ -XXX,XX +XXX,XX @@ static int64_t block_status(BDRVParallelsState *s, int64_t sector_num, | ||
104 | return start_off; | ||
105 | } | ||
106 | |||
107 | -static coroutine_fn int64_t allocate_clusters(BlockDriverState *bs, | ||
108 | - int64_t sector_num, | ||
109 | - int nb_sectors, int *pnum) | ||
110 | +static int64_t coroutine_fn GRAPH_RDLOCK | ||
111 | +allocate_clusters(BlockDriverState *bs, int64_t sector_num, | ||
112 | + int nb_sectors, int *pnum) | ||
113 | { | ||
114 | int ret = 0; | ||
115 | BDRVParallelsState *s = bs->opaque; | ||
116 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int parallels_co_writev(BlockDriverState *bs, | ||
117 | QEMUIOVector hd_qiov; | ||
118 | int ret = 0; | ||
119 | |||
120 | + assume_graph_lock(); /* FIXME */ | ||
121 | + | ||
122 | qemu_iovec_init(&hd_qiov, qiov->niov); | ||
123 | |||
124 | while (nb_sectors > 0) { | ||
125 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int parallels_co_readv(BlockDriverState *bs, | ||
126 | } | ||
127 | |||
128 | |||
129 | -static int coroutine_fn parallels_co_check(BlockDriverState *bs, | ||
130 | - BdrvCheckResult *res, | ||
131 | - BdrvCheckMode fix) | ||
132 | +static int coroutine_fn GRAPH_RDLOCK | ||
133 | +parallels_co_check(BlockDriverState *bs, BdrvCheckResult *res, | ||
134 | + BdrvCheckMode fix) | ||
135 | { | ||
136 | BDRVParallelsState *s = bs->opaque; | ||
137 | int64_t size, prev_off, high_off; | ||
138 | diff --git a/block/preallocate.c b/block/preallocate.c | ||
139 | index XXXXXXX..XXXXXXX 100644 | ||
140 | --- a/block/preallocate.c | ||
141 | +++ b/block/preallocate.c | ||
142 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int preallocate_co_pwritev_part(BlockDriverState *bs, | ||
143 | flags); | ||
144 | } | ||
145 | |||
146 | -static int coroutine_fn | ||
147 | +static int coroutine_fn GRAPH_RDLOCK | ||
148 | preallocate_co_truncate(BlockDriverState *bs, int64_t offset, | ||
149 | bool exact, PreallocMode prealloc, | ||
150 | BdrvRequestFlags flags, Error **errp) | ||
151 | diff --git a/block/qcow.c b/block/qcow.c | ||
152 | index XXXXXXX..XXXXXXX 100644 | ||
153 | --- a/block/qcow.c | ||
154 | +++ b/block/qcow.c | ||
155 | @@ -XXX,XX +XXX,XX @@ static int qcow_reopen_prepare(BDRVReopenState *state, | ||
156 | * return 0 if not allocated, 1 if *result is assigned, and negative | ||
157 | * errno on failure. | ||
158 | */ | ||
159 | -static int coroutine_fn get_cluster_offset(BlockDriverState *bs, | ||
160 | - uint64_t offset, int allocate, | ||
161 | - int compressed_size, | ||
162 | - int n_start, int n_end, | ||
163 | - uint64_t *result) | ||
164 | +static int coroutine_fn GRAPH_RDLOCK | ||
165 | +get_cluster_offset(BlockDriverState *bs, uint64_t offset, int allocate, | ||
166 | + int compressed_size, int n_start, int n_end, | ||
167 | + uint64_t *result) | ||
168 | { | ||
169 | BDRVQcowState *s = bs->opaque; | ||
170 | int min_index, i, j, l1_index, l2_index, ret; | ||
171 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow_co_block_status(BlockDriverState *bs, | ||
172 | int64_t n; | ||
173 | uint64_t cluster_offset; | ||
174 | |||
175 | + assume_graph_lock(); /* FIXME */ | ||
176 | + | ||
177 | qemu_co_mutex_lock(&s->lock); | ||
178 | ret = get_cluster_offset(bs, offset, 0, 0, 0, 0, &cluster_offset); | ||
179 | qemu_co_mutex_unlock(&s->lock); | ||
180 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow_co_preadv(BlockDriverState *bs, int64_t offset, | ||
181 | uint8_t *buf; | ||
182 | void *orig_buf; | ||
183 | |||
184 | + assume_graph_lock(); /* FIXME */ | ||
185 | + | ||
186 | if (qiov->niov > 1) { | ||
187 | buf = orig_buf = qemu_try_blockalign(bs, qiov->size); | ||
188 | if (buf == NULL) { | ||
189 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow_co_pwritev(BlockDriverState *bs, int64_t offset, | ||
190 | uint8_t *buf; | ||
191 | void *orig_buf; | ||
192 | |||
193 | + assume_graph_lock(); /* FIXME */ | ||
194 | + | ||
195 | s->cluster_cache_offset = -1; /* disable compressed cache */ | ||
196 | |||
197 | /* We must always copy the iov when encrypting, so we | ||
198 | @@ -XXX,XX +XXX,XX @@ qcow_co_pwritev_compressed(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
199 | uint8_t *buf, *out_buf; | ||
200 | uint64_t cluster_offset; | ||
201 | |||
202 | + assume_graph_lock(); /* FIXME */ | ||
203 | + | ||
204 | buf = qemu_blockalign(bs, s->cluster_size); | ||
205 | if (bytes != s->cluster_size) { | ||
206 | if (bytes > s->cluster_size || | ||
207 | diff --git a/block/qcow2.c b/block/qcow2.c | ||
208 | index XXXXXXX..XXXXXXX 100644 | ||
209 | --- a/block/qcow2.c | ||
210 | +++ b/block/qcow2.c | ||
211 | @@ -XXX,XX +XXX,XX @@ static int qcow2_set_up_encryption(BlockDriverState *bs, | ||
212 | * | ||
213 | * Returns: 0 on success, -errno on failure. | ||
214 | */ | ||
215 | -static int coroutine_fn preallocate_co(BlockDriverState *bs, uint64_t offset, | ||
216 | - uint64_t new_length, PreallocMode mode, | ||
217 | - Error **errp) | ||
218 | +static int coroutine_fn GRAPH_RDLOCK | ||
219 | +preallocate_co(BlockDriverState *bs, uint64_t offset, uint64_t new_length, | ||
220 | + PreallocMode mode, Error **errp) | ||
221 | { | ||
222 | BDRVQcow2State *s = bs->opaque; | ||
223 | uint64_t bytes; | ||
224 | @@ -XXX,XX +XXX,XX @@ fail: | ||
225 | return ret; | ||
226 | } | ||
227 | |||
228 | -static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset, | ||
229 | - bool exact, PreallocMode prealloc, | ||
230 | - BdrvRequestFlags flags, Error **errp) | ||
231 | +static int coroutine_fn GRAPH_RDLOCK | ||
232 | +qcow2_co_truncate(BlockDriverState *bs, int64_t offset, bool exact, | ||
233 | + PreallocMode prealloc, BdrvRequestFlags flags, Error **errp) | ||
234 | { | ||
235 | BDRVQcow2State *s = bs->opaque; | ||
236 | uint64_t old_length; | ||
237 | @@ -XXX,XX +XXX,XX @@ qcow2_co_pwritev_compressed_part(BlockDriverState *bs, | ||
238 | AioTaskPool *aio = NULL; | ||
239 | int ret = 0; | ||
240 | |||
241 | + assume_graph_lock(); /* FIXME */ | ||
242 | + | ||
243 | if (has_data_file(bs)) { | ||
244 | return -ENOTSUP; | ||
245 | } | ||
246 | diff --git a/block/raw-format.c b/block/raw-format.c | ||
247 | index XXXXXXX..XXXXXXX 100644 | ||
248 | --- a/block/raw-format.c | ||
249 | +++ b/block/raw-format.c | ||
250 | @@ -XXX,XX +XXX,XX @@ static void raw_refresh_limits(BlockDriverState *bs, Error **errp) | ||
251 | } | ||
252 | } | ||
253 | |||
254 | -static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset, | ||
255 | - bool exact, PreallocMode prealloc, | ||
256 | - BdrvRequestFlags flags, Error **errp) | ||
257 | +static int coroutine_fn GRAPH_RDLOCK | ||
258 | +raw_co_truncate(BlockDriverState *bs, int64_t offset, bool exact, | ||
259 | + PreallocMode prealloc, BdrvRequestFlags flags, Error **errp) | ||
260 | { | ||
261 | BDRVRawState *s = bs->opaque; | ||
262 | |||
263 | diff --git a/block/vmdk.c b/block/vmdk.c | ||
264 | index XXXXXXX..XXXXXXX 100644 | ||
265 | --- a/block/vmdk.c | ||
266 | +++ b/block/vmdk.c | ||
267 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn | ||
268 | vmdk_co_pwritev_compressed(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
269 | QEMUIOVector *qiov) | ||
270 | { | ||
271 | + assume_graph_lock(); /* FIXME */ | ||
272 | + | ||
273 | if (bytes == 0) { | ||
274 | /* The caller will write bytes 0 to signal EOF. | ||
275 | * When receive it, we align EOF to a sector boundary. */ | ||
276 | -- | ||
277 | 2.39.2 | diff view generated by jsdifflib |
1 | From: Hanna Reitz <hreitz@redhat.com> | 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. | ||
2 | 3 | ||
3 | bdrv_cor_filter_drop() modifies the block graph. That means that other | 4 | For some places, we know that they will hold the lock, but we don't have |
4 | parties can also modify the block graph before it returns. Therefore, | 5 | the GRAPH_RDLOCK annotations yet. In this case, add assume_graph_lock() |
5 | we cannot assume that the result of a graph traversal we did before | 6 | with a FIXME comment. These places will be removed once everything is |
6 | remains valid afterwards. | 7 | properly annotated. |
7 | 8 | ||
8 | We should thus fetch `base` and `unfiltered_base` afterwards instead of | 9 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
9 | before. | 10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
10 | 11 | Message-Id: <20230203152202.49054-5-kwolf@redhat.com> | |
11 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | 12 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
12 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
13 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
14 | Message-Id: <20211111120829.81329-2-hreitz@redhat.com> | ||
15 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 13 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
16 | --- | 14 | --- |
17 | block/stream.c | 7 +++++-- | 15 | block/coroutines.h | 2 +- |
18 | 1 file changed, 5 insertions(+), 2 deletions(-) | 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(-) | ||
19 | 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; | ||
20 | diff --git a/block/stream.c b/block/stream.c | 340 | diff --git a/block/stream.c b/block/stream.c |
21 | index XXXXXXX..XXXXXXX 100644 | 341 | index XXXXXXX..XXXXXXX 100644 |
22 | --- a/block/stream.c | 342 | --- a/block/stream.c |
23 | +++ b/block/stream.c | 343 | +++ b/block/stream.c |
24 | @@ -XXX,XX +XXX,XX @@ static int stream_prepare(Job *job) | 344 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn stream_run(Job *job, Error **errp) |
25 | { | 345 | |
26 | StreamBlockJob *s = container_of(job, StreamBlockJob, common.job); | 346 | copy = false; |
27 | BlockDriverState *unfiltered_bs = bdrv_skip_filters(s->target_bs); | 347 | |
28 | - BlockDriverState *base = bdrv_filter_or_cow_bs(s->above_base); | 348 | - ret = bdrv_is_allocated(unfiltered_bs, offset, STREAM_CHUNK, &n); |
29 | - BlockDriverState *unfiltered_base = bdrv_skip_filters(base); | 349 | - if (ret == 1) { |
30 | + BlockDriverState *base; | 350 | - /* Allocated in the top, no need to copy. */ |
31 | + BlockDriverState *unfiltered_base; | 351 | - } else if (ret >= 0) { |
32 | Error *local_err = NULL; | 352 | - /* Copy if allocated in the intermediate images. Limit to the |
33 | int ret = 0; | 353 | - * known-unallocated area [offset, offset+n*BDRV_SECTOR_SIZE). */ |
34 | 354 | - ret = bdrv_is_allocated_above(bdrv_cow_bs(unfiltered_bs), | |
35 | @@ -XXX,XX +XXX,XX @@ static int stream_prepare(Job *job) | 355 | - s->base_overlay, true, |
36 | bdrv_cor_filter_drop(s->cor_filter_bs); | 356 | - offset, n, &n); |
37 | s->cor_filter_bs = NULL; | 357 | - /* Finish early if end of backing file has been reached */ |
38 | 358 | - if (ret == 0 && n == 0) { | |
39 | + base = bdrv_filter_or_cow_bs(s->above_base); | 359 | - n = len - offset; |
40 | + unfiltered_base = bdrv_skip_filters(base); | 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 | + } | ||
41 | + | 376 | + |
42 | if (bdrv_cow_child(unfiltered_bs)) { | 377 | + copy = (ret > 0); |
43 | const char *base_id = NULL, *base_fmt = NULL; | 378 | } |
44 | if (unfiltered_base) { | 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; | ||
45 | -- | 413 | -- |
46 | 2.31.1 | 414 | 2.39.2 |
47 | |||
48 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | This adds GRAPH_RDLOCK annotations to declare that callers of | ||
2 | bdrv_co_ioctl() need to hold a reader lock for the graph. | ||
1 | 3 | ||
4 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
5 | Message-Id: <20230203152202.49054-6-kwolf@redhat.com> | ||
6 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
8 | --- | ||
9 | include/block/block-io.h | 3 ++- | ||
10 | include/block/block_int-common.h | 9 +++++---- | ||
11 | block/block-backend.c | 1 + | ||
12 | block/io.c | 1 + | ||
13 | block/raw-format.c | 4 ++-- | ||
14 | 5 files changed, 11 insertions(+), 7 deletions(-) | ||
15 | |||
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 bdrv_aio_cancel(BlockAIOCB *acb); | ||
21 | void bdrv_aio_cancel_async(BlockAIOCB *acb); | ||
22 | |||
23 | /* sg packet commands */ | ||
24 | -int coroutine_fn bdrv_co_ioctl(BlockDriverState *bs, int req, void *buf); | ||
25 | +int coroutine_fn GRAPH_RDLOCK | ||
26 | +bdrv_co_ioctl(BlockDriverState *bs, int req, void *buf); | ||
27 | |||
28 | /* Ensure contents are flushed to disk. */ | ||
29 | int coroutine_fn bdrv_co_flush(BlockDriverState *bs); | ||
30 | diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h | ||
31 | index XXXXXXX..XXXXXXX 100644 | ||
32 | --- a/include/block/block_int-common.h | ||
33 | +++ b/include/block/block_int-common.h | ||
34 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | ||
35 | void coroutine_fn (*bdrv_co_lock_medium)(BlockDriverState *bs, bool locked); | ||
36 | |||
37 | /* to control generic scsi devices */ | ||
38 | - BlockAIOCB *(*bdrv_aio_ioctl)(BlockDriverState *bs, | ||
39 | - unsigned long int req, void *buf, | ||
40 | + BlockAIOCB *coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_aio_ioctl)( | ||
41 | + BlockDriverState *bs, unsigned long int req, void *buf, | ||
42 | BlockCompletionFunc *cb, void *opaque); | ||
43 | - int coroutine_fn (*bdrv_co_ioctl)(BlockDriverState *bs, | ||
44 | - unsigned long int req, void *buf); | ||
45 | + | ||
46 | + int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_ioctl)( | ||
47 | + BlockDriverState *bs, unsigned long int req, void *buf); | ||
48 | |||
49 | /* | ||
50 | * Returns 0 for completed check, -errno for internal errors. | ||
51 | diff --git a/block/block-backend.c b/block/block-backend.c | ||
52 | index XXXXXXX..XXXXXXX 100644 | ||
53 | --- a/block/block-backend.c | ||
54 | +++ b/block/block-backend.c | ||
55 | @@ -XXX,XX +XXX,XX @@ blk_co_do_ioctl(BlockBackend *blk, unsigned long int req, void *buf) | ||
56 | IO_CODE(); | ||
57 | |||
58 | blk_wait_while_drained(blk); | ||
59 | + GRAPH_RDLOCK_GUARD(); | ||
60 | |||
61 | if (!blk_is_available(blk)) { | ||
62 | return -ENOMEDIUM; | ||
63 | diff --git a/block/io.c b/block/io.c | ||
64 | index XXXXXXX..XXXXXXX 100644 | ||
65 | --- a/block/io.c | ||
66 | +++ b/block/io.c | ||
67 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_ioctl(BlockDriverState *bs, int req, void *buf) | ||
68 | }; | ||
69 | BlockAIOCB *acb; | ||
70 | IO_CODE(); | ||
71 | + assert_bdrv_graph_readable(); | ||
72 | |||
73 | bdrv_inc_in_flight(bs); | ||
74 | if (!drv || (!drv->bdrv_aio_ioctl && !drv->bdrv_co_ioctl)) { | ||
75 | diff --git a/block/raw-format.c b/block/raw-format.c | ||
76 | index XXXXXXX..XXXXXXX 100644 | ||
77 | --- a/block/raw-format.c | ||
78 | +++ b/block/raw-format.c | ||
79 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn raw_co_lock_medium(BlockDriverState *bs, bool locked) | ||
80 | bdrv_co_lock_medium(bs->file->bs, locked); | ||
81 | } | ||
82 | |||
83 | -static int coroutine_fn raw_co_ioctl(BlockDriverState *bs, | ||
84 | - unsigned long int req, void *buf) | ||
85 | +static int coroutine_fn GRAPH_RDLOCK | ||
86 | +raw_co_ioctl(BlockDriverState *bs, unsigned long int req, void *buf) | ||
87 | { | ||
88 | BDRVRawState *s = bs->opaque; | ||
89 | if (s->offset || s->has_size) { | ||
90 | -- | ||
91 | 2.39.2 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
1 | 2 | ||
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 |
New patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
1 | 2 | ||
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 |
New patch | |||
---|---|---|---|
1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
1 | 2 | ||
3 | This adds GRAPH_RDLOCK annotations to declare that callers of | ||
4 | bdrv_co_pdiscard() 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: 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> | ||
15 | --- | ||
16 | include/block/block-io.h | 5 +++-- | ||
17 | include/block/block_int-common.h | 15 +++++++++------ | ||
18 | include/block/block_int-io.h | 2 +- | ||
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 | |||
34 | diff --git a/include/block/block-io.h b/include/block/block-io.h | ||
35 | index XXXXXXX..XXXXXXX 100644 | ||
36 | --- a/include/block/block-io.h | ||
37 | +++ b/include/block/block-io.h | ||
38 | @@ -XXX,XX +XXX,XX @@ bdrv_co_ioctl(BlockDriverState *bs, int req, void *buf); | ||
39 | /* Ensure contents are flushed to disk. */ | ||
40 | int coroutine_fn GRAPH_RDLOCK bdrv_co_flush(BlockDriverState *bs); | ||
41 | |||
42 | -int coroutine_fn bdrv_co_pdiscard(BdrvChild *child, int64_t offset, | ||
43 | - int64_t bytes); | ||
44 | +int coroutine_fn GRAPH_RDLOCK bdrv_co_pdiscard(BdrvChild *child, int64_t offset, | ||
45 | + int64_t bytes); | ||
46 | + | ||
47 | bool bdrv_can_write_zeroes_with_unmap(BlockDriverState *bs); | ||
48 | int bdrv_block_status(BlockDriverState *bs, int64_t offset, | ||
49 | int64_t bytes, int64_t *pnum, int64_t *map, | ||
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 | 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 | ||
159 | index XXXXXXX..XXXXXXX 100644 | ||
160 | --- a/block/block-backend.c | ||
161 | +++ b/block/block-backend.c | ||
162 | @@ -XXX,XX +XXX,XX @@ blk_co_do_pdiscard(BlockBackend *blk, int64_t offset, int64_t bytes) | ||
163 | IO_CODE(); | ||
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 | } | ||
177 | |||
178 | -static int coroutine_fn cbw_co_pdiscard(BlockDriverState *bs, | ||
179 | - int64_t offset, int64_t bytes) | ||
180 | +static int coroutine_fn GRAPH_RDLOCK | ||
181 | +cbw_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes) | ||
182 | { | ||
183 | int ret = cbw_do_copy_before_write(bs, offset, bytes, 0); | ||
184 | if (ret < 0) { | ||
185 | @@ -XXX,XX +XXX,XX @@ cbw_co_snapshot_block_status(BlockDriverState *bs, | ||
186 | return ret; | ||
187 | } | ||
188 | |||
189 | -static int coroutine_fn cbw_co_pdiscard_snapshot(BlockDriverState *bs, | ||
190 | - int64_t offset, int64_t bytes) | ||
191 | +static int coroutine_fn GRAPH_RDLOCK | ||
192 | +cbw_co_pdiscard_snapshot(BlockDriverState *bs, int64_t offset, int64_t bytes) | ||
193 | { | ||
194 | BDRVCopyBeforeWriteState *s = bs->opaque; | ||
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 | } | ||
202 | |||
203 | |||
204 | -static int coroutine_fn cor_co_pdiscard(BlockDriverState *bs, | ||
205 | - int64_t offset, int64_t bytes) | ||
206 | +static int coroutine_fn GRAPH_RDLOCK | ||
207 | +cor_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes) | ||
208 | { | ||
209 | return bdrv_co_pdiscard(bs->file, offset, bytes); | ||
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 | -- | ||
350 | 2.39.2 | diff view generated by jsdifflib |
1 | From: Hanna Reitz <hreitz@redhat.com> | 1 | This adds GRAPH_RDLOCK annotations to declare that callers of |
---|---|---|---|
2 | bdrv_co_pwrite_zeroes() need to hold a reader lock for the graph. | ||
2 | 3 | ||
3 | Invoke the transaction drivers' .clean() methods only after all | 4 | For some places, we know that they will hold the lock, but we don't have |
4 | .commit() or .abort() handlers are done. | 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. | ||
5 | 8 | ||
6 | This makes it easier to have nested transactions where the top-level | 9 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
7 | transactions pass objects to lower transactions that the latter can | 10 | Message-Id: <20230203152202.49054-10-kwolf@redhat.com> |
8 | still use throughout their commit/abort phases, while the top-level | 11 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
9 | transaction keeps a reference that is released in its .clean() method. | ||
10 | |||
11 | (Before this commit, that is also possible, but the top-level | ||
12 | transaction would need to take care to invoke tran_add() before the | ||
13 | lower-level transaction does. This commit makes the ordering | ||
14 | irrelevant, which is just a bit nicer.) | ||
15 | |||
16 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
17 | Message-Id: <20211111120829.81329-8-hreitz@redhat.com> | ||
18 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
19 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
20 | --- | 13 | --- |
21 | include/qemu/transactions.h | 3 +++ | 14 | block/qcow2.h | 6 ++++-- |
22 | util/transactions.c | 8 ++++++-- | 15 | include/block/block-io.h | 9 +++++---- |
23 | 2 files changed, 9 insertions(+), 2 deletions(-) | 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(-) | ||
24 | 33 | ||
25 | diff --git a/include/qemu/transactions.h b/include/qemu/transactions.h | 34 | diff --git a/block/qcow2.h b/block/qcow2.h |
26 | index XXXXXXX..XXXXXXX 100644 | 35 | index XXXXXXX..XXXXXXX 100644 |
27 | --- a/include/qemu/transactions.h | 36 | --- a/block/qcow2.h |
28 | +++ b/include/qemu/transactions.h | 37 | +++ b/block/qcow2.h |
29 | @@ -XXX,XX +XXX,XX @@ | 38 | @@ -XXX,XX +XXX,XX @@ void qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m); |
30 | * tran_create(), call your "prepare" functions on it, and finally call | 39 | int qcow2_cluster_discard(BlockDriverState *bs, uint64_t offset, |
31 | * tran_abort() or tran_commit() to finalize the transaction by corresponding | 40 | uint64_t bytes, enum qcow2_discard_type type, |
32 | * finalization actions in reverse order. | 41 | bool full_discard); |
33 | + * | 42 | -int coroutine_fn qcow2_subcluster_zeroize(BlockDriverState *bs, uint64_t offset, |
34 | + * The clean() functions registered by the drivers in a transaction are called | 43 | - uint64_t bytes, int flags); |
35 | + * last, after all abort() or commit() functions have been called. | 44 | + |
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. | ||
36 | */ | 58 | */ |
37 | 59 | -int coroutine_fn bdrv_co_pwrite_zeroes(BdrvChild *child, int64_t offset, | |
38 | #ifndef QEMU_TRANSACTIONS_H | 60 | - int64_t bytes, BdrvRequestFlags flags); |
39 | diff --git a/util/transactions.c b/util/transactions.c | 61 | +int coroutine_fn GRAPH_RDLOCK |
40 | index XXXXXXX..XXXXXXX 100644 | 62 | +bdrv_co_pwrite_zeroes(BdrvChild *child, int64_t offset, int64_t bytes, |
41 | --- a/util/transactions.c | 63 | + BdrvRequestFlags flags); |
42 | +++ b/util/transactions.c | 64 | |
43 | @@ -XXX,XX +XXX,XX @@ void tran_abort(Transaction *tran) | 65 | int coroutine_fn GRAPH_RDLOCK |
44 | { | 66 | bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact, |
45 | TransactionAction *act, *next; | 67 | @@ -XXX,XX +XXX,XX @@ int bdrv_is_allocated_above(BlockDriverState *top, BlockDriverState *base, |
46 | 68 | bool include_base, int64_t offset, int64_t bytes, | |
47 | - QSLIST_FOREACH_SAFE(act, &tran->actions, entry, next) { | 69 | int64_t *pnum); |
48 | + QSLIST_FOREACH(act, &tran->actions, entry) { | 70 | |
49 | if (act->drv->abort) { | 71 | -int coroutine_fn bdrv_co_is_zero_fast(BlockDriverState *bs, int64_t offset, |
50 | act->drv->abort(act->opaque); | 72 | - int64_t bytes); |
51 | } | 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() { | ||
178 | + ret = block_copy_do_copy(s, t->req.offset, t->req.bytes, &method, | ||
179 | + &error_is_read); | ||
52 | + } | 180 | + } |
53 | 181 | ||
54 | + QSLIST_FOREACH_SAFE(act, &tran->actions, entry, next) { | 182 | WITH_QEMU_LOCK_GUARD(&s->lock) { |
55 | if (act->drv->clean) { | 183 | if (s->method == t->method) { |
56 | act->drv->clean(act->opaque); | 184 | diff --git a/block/copy-before-write.c b/block/copy-before-write.c |
57 | } | 185 | index XXXXXXX..XXXXXXX 100644 |
58 | @@ -XXX,XX +XXX,XX @@ void tran_commit(Transaction *tran) | 186 | --- a/block/copy-before-write.c |
59 | { | 187 | +++ b/block/copy-before-write.c |
60 | TransactionAction *act, *next; | 188 | @@ -XXX,XX +XXX,XX @@ cbw_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes) |
61 | 189 | return bdrv_co_pdiscard(bs->file, offset, bytes); | |
62 | - QSLIST_FOREACH_SAFE(act, &tran->actions, entry, next) { | 190 | } |
63 | + QSLIST_FOREACH(act, &tran->actions, entry) { | 191 | |
64 | if (act->drv->commit) { | 192 | -static int coroutine_fn cbw_co_pwrite_zeroes(BlockDriverState *bs, |
65 | act->drv->commit(act->opaque); | 193 | - int64_t offset, int64_t bytes, BdrvRequestFlags flags) |
66 | } | 194 | +static int coroutine_fn GRAPH_RDLOCK |
67 | + } | 195 | +cbw_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int64_t bytes, |
68 | 196 | + BdrvRequestFlags flags) | |
69 | + QSLIST_FOREACH_SAFE(act, &tran->actions, entry, next) { | 197 | { |
70 | if (act->drv->clean) { | 198 | int ret = cbw_do_copy_before_write(bs, offset, bytes, flags); |
71 | act->drv->clean(act->opaque); | 199 | if (ret < 0) { |
72 | } | 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); | ||
73 | -- | 533 | -- |
74 | 2.31.1 | 534 | 2.39.2 |
75 | |||
76 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | This adds GRAPH_RDLOCK annotations to declare that callers of | ||
2 | bdrv_driver_*() need to hold a reader lock for the graph. It doesn't add | ||
3 | the annotation to public functions yet. | ||
1 | 4 | ||
5 | For some places, we know that they will hold the lock, but we don't have | ||
6 | the GRAPH_RDLOCK annotations yet. In this case, add assume_graph_lock() | ||
7 | with a FIXME comment. These places will be removed once everything is | ||
8 | properly annotated. | ||
9 | |||
10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
11 | Message-Id: <20230203152202.49054-11-kwolf@redhat.com> | ||
12 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
13 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
14 | --- | ||
15 | block/qcow2.h | 5 ++- | ||
16 | include/block/block_int-common.h | 40 ++++++++++--------- | ||
17 | block/io.c | 66 +++++++++++++++----------------- | ||
18 | block/parallels.c | 8 ++-- | ||
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 | |||
27 | diff --git a/block/qcow2.h b/block/qcow2.h | ||
28 | index XXXXXXX..XXXXXXX 100644 | ||
29 | --- a/block/qcow2.h | ||
30 | +++ b/block/qcow2.h | ||
31 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, | ||
32 | void qcow2_parse_compressed_l2_entry(BlockDriverState *bs, uint64_t l2_entry, | ||
33 | uint64_t *coffset, int *csize); | ||
34 | |||
35 | -int coroutine_fn qcow2_alloc_cluster_link_l2(BlockDriverState *bs, | ||
36 | - QCowL2Meta *m); | ||
37 | +int coroutine_fn GRAPH_RDLOCK | ||
38 | +qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m); | ||
39 | + | ||
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 | ||
45 | --- a/include/block/block_int-common.h | ||
46 | +++ b/include/block/block_int-common.h | ||
47 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | ||
48 | Error **errp); | ||
49 | |||
50 | /* aio */ | ||
51 | - BlockAIOCB *(*bdrv_aio_preadv)(BlockDriverState *bs, | ||
52 | + BlockAIOCB * GRAPH_RDLOCK_PTR (*bdrv_aio_preadv)(BlockDriverState *bs, | ||
53 | int64_t offset, int64_t bytes, QEMUIOVector *qiov, | ||
54 | BdrvRequestFlags flags, BlockCompletionFunc *cb, void *opaque); | ||
55 | - BlockAIOCB *(*bdrv_aio_pwritev)(BlockDriverState *bs, | ||
56 | + | ||
57 | + BlockAIOCB * GRAPH_RDLOCK_PTR (*bdrv_aio_pwritev)(BlockDriverState *bs, | ||
58 | int64_t offset, int64_t bytes, QEMUIOVector *qiov, | ||
59 | BdrvRequestFlags flags, BlockCompletionFunc *cb, void *opaque); | ||
60 | + | ||
61 | BlockAIOCB * GRAPH_RDLOCK_PTR (*bdrv_aio_flush)( | ||
62 | BlockDriverState *bs, BlockCompletionFunc *cb, void *opaque); | ||
63 | |||
64 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | ||
65 | BlockDriverState *bs, int64_t offset, int bytes, | ||
66 | BlockCompletionFunc *cb, void *opaque); | ||
67 | |||
68 | - int coroutine_fn (*bdrv_co_readv)(BlockDriverState *bs, | ||
69 | + int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_readv)(BlockDriverState *bs, | ||
70 | int64_t sector_num, int nb_sectors, QEMUIOVector *qiov); | ||
71 | |||
72 | /** | ||
73 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | ||
74 | * | ||
75 | * The buffer in @qiov may point directly to guest memory. | ||
76 | */ | ||
77 | - int coroutine_fn (*bdrv_co_preadv)(BlockDriverState *bs, | ||
78 | + int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_preadv)(BlockDriverState *bs, | ||
79 | int64_t offset, int64_t bytes, QEMUIOVector *qiov, | ||
80 | BdrvRequestFlags flags); | ||
81 | |||
82 | - int coroutine_fn (*bdrv_co_preadv_part)(BlockDriverState *bs, | ||
83 | - int64_t offset, int64_t bytes, | ||
84 | + int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_preadv_part)( | ||
85 | + BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
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 | { | ||
138 | return drv->bdrv_co_pwritev_compressed || | ||
139 | drv->bdrv_co_pwritev_compressed_part; | ||
140 | diff --git a/block/io.c b/block/io.c | ||
141 | index XXXXXXX..XXXXXXX 100644 | ||
142 | --- a/block/io.c | ||
143 | +++ b/block/io.c | ||
144 | @@ -XXX,XX +XXX,XX @@ void bdrv_refresh_limits(BlockDriverState *bs, Transaction *tran, Error **errp) | ||
145 | bool have_limits; | ||
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 | - | ||
188 | bdrv_check_qiov_request(offset, bytes, qiov, qiov_offset, &error_abort); | ||
189 | |||
190 | if (!drv) { | ||
191 | @@ -XXX,XX +XXX,XX @@ emulate_flags: | ||
192 | return ret; | ||
193 | } | ||
194 | |||
195 | -static int coroutine_fn | ||
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; | ||
238 | } | ||
239 | |||
240 | -static coroutine_fn int bdrv_padding_rmw_read(BdrvChild *child, | ||
241 | - BdrvTrackedRequest *req, | ||
242 | - BdrvRequestPadding *pad, | ||
243 | - bool zero_middle) | ||
244 | +static int coroutine_fn GRAPH_RDLOCK | ||
245 | +bdrv_padding_rmw_read(BdrvChild *child, BdrvTrackedRequest *req, | ||
246 | + BdrvRequestPadding *pad, bool zero_middle) | ||
247 | { | ||
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 | - | ||
281 | bdrv_check_qiov_request(offset, bytes, qiov, qiov_offset, &error_abort); | ||
282 | |||
283 | if (!drv) { | ||
284 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child, | ||
285 | return ret; | ||
286 | } | ||
287 | |||
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 | ||
310 | --- a/block/parallels.c | ||
311 | +++ b/block/parallels.c | ||
312 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn parallels_co_block_status(BlockDriverState *bs, | ||
313 | return BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID; | ||
314 | } | ||
315 | |||
316 | -static coroutine_fn int parallels_co_writev(BlockDriverState *bs, | ||
317 | - int64_t sector_num, int nb_sectors, | ||
318 | - QEMUIOVector *qiov, int flags) | ||
319 | +static int coroutine_fn GRAPH_RDLOCK | ||
320 | +parallels_co_writev(BlockDriverState *bs, int64_t sector_num, int nb_sectors, | ||
321 | + QEMUIOVector *qiov, int flags) | ||
322 | { | ||
323 | BDRVParallelsState *s = bs->opaque; | ||
324 | uint64_t bytes_done = 0; | ||
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 | -- | ||
611 | 2.39.2 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | This adds GRAPH_RDLOCK annotations to declare that callers of | ||
2 | bdrv_co_pread*/pwrite*() need to hold a reader lock for the graph. | ||
1 | 3 | ||
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: Kevin Wolf <kwolf@redhat.com> | ||
10 | Message-Id: <20230203152202.49054-12-kwolf@redhat.com> | ||
11 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
13 | --- | ||
14 | block/qcow2.h | 9 ++--- | ||
15 | block/qed.h | 18 +++++----- | ||
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 | |||
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 | ||
1273 | index XXXXXXX..XXXXXXX 100644 | ||
1274 | --- a/block/vpc.c | ||
1275 | +++ b/block/vpc.c | ||
1276 | @@ -XXX,XX +XXX,XX @@ vpc_co_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) | ||
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 | } | ||
1300 | } | ||
1301 | |||
1302 | -static int coroutine_fn bdrv_test_top_co_preadv(BlockDriverState *bs, | ||
1303 | - int64_t offset, int64_t bytes, | ||
1304 | - QEMUIOVector *qiov, | ||
1305 | - BdrvRequestFlags flags) | ||
1306 | +static int coroutine_fn GRAPH_RDLOCK | ||
1307 | +bdrv_test_top_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
1308 | + QEMUIOVector *qiov, BdrvRequestFlags flags) | ||
1309 | { | ||
1310 | BDRVTestTopState *tts = bs->opaque; | ||
1311 | return bdrv_co_preadv(tts->wait_child, offset, bytes, qiov, flags); | ||
1312 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn test_co_delete_by_drain(void *opaque) | ||
1313 | void *buffer = g_malloc(65536); | ||
1314 | QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buffer, 65536); | ||
1315 | |||
1316 | + GRAPH_RDLOCK_GUARD(); | ||
1317 | + | ||
1318 | /* Pretend some internal write operation from parent to child. | ||
1319 | * Important: We have to read from the child, not from the parent! | ||
1320 | * Draining works by first propagating it all up the tree to the | ||
1321 | @@ -XXX,XX +XXX,XX @@ static void bdrv_replace_test_close(BlockDriverState *bs) | ||
1322 | * Otherwise: | ||
1323 | * Set .has_read to true and return success. | ||
1324 | */ | ||
1325 | -static int coroutine_fn bdrv_replace_test_co_preadv(BlockDriverState *bs, | ||
1326 | - int64_t offset, | ||
1327 | - int64_t bytes, | ||
1328 | - QEMUIOVector *qiov, | ||
1329 | - BdrvRequestFlags flags) | ||
1330 | +static int coroutine_fn GRAPH_RDLOCK | ||
1331 | +bdrv_replace_test_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
1332 | + QEMUIOVector *qiov, BdrvRequestFlags flags) | ||
1333 | { | ||
1334 | BDRVReplaceTestState *s = bs->opaque; | ||
1335 | |||
1336 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_replace_test_read_entry(void *opaque) | ||
1337 | int ret; | ||
1338 | |||
1339 | /* Queue a read request post-drain */ | ||
1340 | + bdrv_graph_co_rdlock(); | ||
1341 | ret = bdrv_replace_test_co_preadv(bs, 0, 1, &qiov, 0); | ||
1342 | + bdrv_graph_co_rdunlock(); | ||
1343 | + | ||
1344 | g_assert(ret >= 0); | ||
1345 | bdrv_dec_in_flight(bs); | ||
1346 | } | ||
1347 | -- | ||
1348 | 2.39.2 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | This adds GRAPH_RDLOCK annotations to declare that callers of | ||
2 | bdrv_co_pwrite_sync() need to hold a reader lock for the graph. | ||
1 | 3 | ||
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: Kevin Wolf <kwolf@redhat.com> | ||
10 | Message-Id: <20230203152202.49054-13-kwolf@redhat.com> | ||
11 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
13 | --- | ||
14 | block/qcow2.h | 2 +- | ||
15 | include/block/block-io.h | 7 ++++--- | ||
16 | block/io.c | 3 +-- | ||
17 | 3 files changed, 6 insertions(+), 6 deletions(-) | ||
18 | |||
19 | diff --git a/block/qcow2.h b/block/qcow2.h | ||
20 | index XXXXXXX..XXXXXXX 100644 | ||
21 | --- a/block/qcow2.h | ||
22 | +++ b/block/qcow2.h | ||
23 | @@ -XXX,XX +XXX,XX @@ int qcow2_inc_refcounts_imrt(BlockDriverState *bs, BdrvCheckResult *res, | ||
24 | int qcow2_change_refcount_order(BlockDriverState *bs, int refcount_order, | ||
25 | BlockDriverAmendStatusCB *status_cb, | ||
26 | void *cb_opaque, Error **errp); | ||
27 | -int coroutine_fn qcow2_shrink_reftable(BlockDriverState *bs); | ||
28 | +int coroutine_fn GRAPH_RDLOCK qcow2_shrink_reftable(BlockDriverState *bs); | ||
29 | int64_t qcow2_get_last_cluster(BlockDriverState *bs, int64_t size); | ||
30 | int coroutine_fn qcow2_detect_metadata_preallocation(BlockDriverState *bs); | ||
31 | |||
32 | diff --git a/include/block/block-io.h b/include/block/block-io.h | ||
33 | index XXXXXXX..XXXXXXX 100644 | ||
34 | --- a/include/block/block-io.h | ||
35 | +++ b/include/block/block-io.h | ||
36 | @@ -XXX,XX +XXX,XX @@ int co_wrapper_mixed_bdrv_rdlock | ||
37 | bdrv_pwrite_sync(BdrvChild *child, int64_t offset, int64_t bytes, | ||
38 | const void *buf, BdrvRequestFlags flags); | ||
39 | |||
40 | -int coroutine_fn bdrv_co_pwrite_sync(BdrvChild *child, int64_t offset, | ||
41 | - int64_t bytes, const void *buf, | ||
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 | + | ||
47 | /* | ||
48 | * Efficiently zero a region of the disk image. Note that this is a regular | ||
49 | * I/O request like read or write and should have a reasonable size. This | ||
50 | diff --git a/block/io.c b/block/io.c | ||
51 | index XXXXXXX..XXXXXXX 100644 | ||
52 | --- a/block/io.c | ||
53 | +++ b/block/io.c | ||
54 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_pwrite_sync(BdrvChild *child, int64_t offset, | ||
55 | { | ||
56 | int ret; | ||
57 | IO_CODE(); | ||
58 | - | ||
59 | - assume_graph_lock(); /* FIXME */ | ||
60 | + assert_bdrv_graph_readable(); | ||
61 | |||
62 | ret = bdrv_co_pwrite(child, offset, bytes, buf, flags); | ||
63 | if (ret < 0) { | ||
64 | -- | ||
65 | 2.39.2 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | All callers are already GRAPH_RDLOCK, so just add the annotation and | ||
2 | remove assume_graph_lock(). | ||
1 | 3 | ||
4 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
5 | Message-Id: <20230203152202.49054-14-kwolf@redhat.com> | ||
6 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
8 | --- | ||
9 | block/io.c | 7 +++---- | ||
10 | 1 file changed, 3 insertions(+), 4 deletions(-) | ||
11 | |||
12 | diff --git a/block/io.c b/block/io.c | ||
13 | index XXXXXXX..XXXXXXX 100644 | ||
14 | --- a/block/io.c | ||
15 | +++ b/block/io.c | ||
16 | @@ -XXX,XX +XXX,XX @@ fail: | ||
17 | return ret; | ||
18 | } | ||
19 | |||
20 | -static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs, | ||
21 | - int64_t offset, int64_t bytes, BdrvRequestFlags flags) | ||
22 | +static int coroutine_fn GRAPH_RDLOCK | ||
23 | +bdrv_co_do_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
24 | + BdrvRequestFlags flags) | ||
25 | { | ||
26 | BlockDriver *drv = bs->drv; | ||
27 | QEMUIOVector qiov; | ||
28 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs, | ||
29 | int head = 0; | ||
30 | int tail = 0; | ||
31 | |||
32 | - assume_graph_lock(); /* FIXME */ | ||
33 | - | ||
34 | int64_t max_write_zeroes = MIN_NON_ZERO(bs->bl.max_pwrite_zeroes, | ||
35 | INT64_MAX); | ||
36 | int alignment = MAX(bs->bl.pwrite_zeroes_alignment, | ||
37 | -- | ||
38 | 2.39.2 | diff view generated by jsdifflib |
1 | At the end of a reopen, we already call bdrv_refresh_limits(), which | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
---|---|---|---|
2 | should update bs->request_alignment according to the new file | ||
3 | descriptor. However, raw_probe_alignment() relies on s->needs_alignment | ||
4 | and just uses 1 if it isn't set. We neglected to update this field, so | ||
5 | starting with cache=writeback and then reopening with cache=none means | ||
6 | that we get an incorrect bs->request_alignment == 1 and unaligned | ||
7 | requests fail instead of being automatically aligned. | ||
8 | 2 | ||
9 | Fix this by recalculating s->needs_alignment in raw_refresh_limits() | 3 | This adds GRAPH_RDLOCK annotations to declare that callers of |
10 | before calling raw_probe_alignment(). | 4 | bdrv_co_copy_range() need to hold a reader lock for the graph. |
11 | 5 | ||
6 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
13 | Message-Id: <20211104113109.56336-1-kwolf@redhat.com> | 8 | Message-Id: <20230203152202.49054-15-kwolf@redhat.com> |
14 | Reviewed-by: Hanna Reitz <hreitz@redhat.com> | 9 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
15 | Reviewed-by: Stefano Garzarella <sgarzare@redhat.com> | ||
16 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
17 | --- | 11 | --- |
18 | block/file-posix.c | 20 ++++++++++++++++---- | 12 | include/block/block-io.h | 9 +++++---- |
19 | tests/qemu-iotests/142 | 22 ++++++++++++++++++++++ | 13 | include/block/block_int-common.h | 24 ++++++++---------------- |
20 | tests/qemu-iotests/142.out | 15 +++++++++++++++ | 14 | include/block/block_int-io.h | 20 ++++++++++---------- |
21 | 3 files changed, 53 insertions(+), 4 deletions(-) | 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(-) | ||
22 | 23 | ||
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 | ||
118 | index XXXXXXX..XXXXXXX 100644 | ||
119 | --- a/block/block-backend.c | ||
120 | +++ b/block/block-backend.c | ||
121 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn blk_co_copy_range(BlockBackend *blk_in, int64_t off_in, | ||
122 | if (r) { | ||
123 | return r; | ||
124 | } | ||
125 | + | ||
126 | + GRAPH_RDLOCK_GUARD(); | ||
127 | return bdrv_co_copy_range(blk_in->root, off_in, | ||
128 | blk_out->root, off_out, | ||
129 | bytes, read_flags, write_flags); | ||
23 | diff --git a/block/file-posix.c b/block/file-posix.c | 130 | diff --git a/block/file-posix.c b/block/file-posix.c |
24 | index XXXXXXX..XXXXXXX 100644 | 131 | index XXXXXXX..XXXXXXX 100644 |
25 | --- a/block/file-posix.c | 132 | --- a/block/file-posix.c |
26 | +++ b/block/file-posix.c | 133 | +++ b/block/file-posix.c |
27 | @@ -XXX,XX +XXX,XX @@ typedef struct BDRVRawState { | 134 | @@ -XXX,XX +XXX,XX @@ static void raw_abort_perm_update(BlockDriverState *bs) |
28 | int page_cache_inconsistent; /* errno from fdatasync failure */ | 135 | raw_handle_perm_lock(bs, RAW_PL_ABORT, 0, 0, NULL); |
29 | bool has_fallocate; | 136 | } |
30 | bool needs_alignment; | 137 | |
31 | + bool force_alignment; | 138 | -static int coroutine_fn raw_co_copy_range_from( |
32 | bool drop_cache; | 139 | +static int coroutine_fn GRAPH_RDLOCK raw_co_copy_range_from( |
33 | bool check_cache_dropped; | 140 | BlockDriverState *bs, BdrvChild *src, int64_t src_offset, |
34 | struct { | 141 | BdrvChild *dst, int64_t dst_offset, int64_t bytes, |
35 | @@ -XXX,XX +XXX,XX @@ static bool dio_byte_aligned(int fd) | 142 | BdrvRequestFlags read_flags, BdrvRequestFlags write_flags) |
36 | return false; | 143 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_copy_range_from( |
37 | } | 144 | read_flags, write_flags); |
38 | 145 | } | |
39 | +static bool raw_needs_alignment(BlockDriverState *bs) | 146 | |
40 | +{ | 147 | -static int coroutine_fn raw_co_copy_range_to(BlockDriverState *bs, |
41 | + BDRVRawState *s = bs->opaque; | 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(); | ||
42 | + | 199 | + |
43 | + if ((bs->open_flags & BDRV_O_NOCACHE) != 0 && !dio_byte_aligned(s->fd)) { | 200 | return bdrv_co_copy_range_from(src, src_offset, |
44 | + return true; | 201 | dst, dst_offset, |
45 | + } | 202 | bytes, read_flags, write_flags); |
46 | + | 203 | diff --git a/block/iscsi.c b/block/iscsi.c |
47 | + return s->force_alignment; | 204 | index XXXXXXX..XXXXXXX 100644 |
48 | +} | 205 | --- a/block/iscsi.c |
49 | + | 206 | +++ b/block/iscsi.c |
50 | /* Check if read is allowed with given memory buffer and length. | 207 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn iscsi_co_invalidate_cache(BlockDriverState *bs, |
51 | * | 208 | iscsi_allocmap_invalidate(iscsilun); |
52 | * This function is used to check O_DIRECT memory buffer and request alignment. | 209 | } |
53 | @@ -XXX,XX +XXX,XX @@ static int raw_open_common(BlockDriverState *bs, QDict *options, | 210 | |
54 | 211 | -static int coroutine_fn iscsi_co_copy_range_from(BlockDriverState *bs, | |
55 | s->has_discard = true; | 212 | - BdrvChild *src, |
56 | s->has_write_zeroes = true; | 213 | - int64_t src_offset, |
57 | - if ((bs->open_flags & BDRV_O_NOCACHE) != 0 && !dio_byte_aligned(s->fd)) { | 214 | - BdrvChild *dst, |
58 | - s->needs_alignment = true; | 215 | - int64_t dst_offset, |
59 | - } | 216 | - int64_t bytes, |
60 | 217 | - BdrvRequestFlags read_flags, | |
61 | if (fstat(s->fd, &st) < 0) { | 218 | - BdrvRequestFlags write_flags) |
62 | ret = -errno; | 219 | +static int coroutine_fn GRAPH_RDLOCK |
63 | @@ -XXX,XX +XXX,XX @@ static int raw_open_common(BlockDriverState *bs, QDict *options, | 220 | +iscsi_co_copy_range_from(BlockDriverState *bs, |
64 | * so QEMU makes sure all IO operations on the device are aligned | 221 | + BdrvChild *src, int64_t src_offset, |
65 | * to sector size, or else FreeBSD will reject them with EINVAL. | 222 | + BdrvChild *dst, int64_t dst_offset, |
66 | */ | 223 | + int64_t bytes, BdrvRequestFlags read_flags, |
67 | - s->needs_alignment = true; | 224 | + BdrvRequestFlags write_flags) |
68 | + s->force_alignment = true; | 225 | { |
69 | } | 226 | return bdrv_co_copy_range_to(src, src_offset, dst, dst_offset, bytes, |
70 | #endif | 227 | read_flags, write_flags); |
71 | + s->needs_alignment = raw_needs_alignment(bs); | 228 | @@ -XXX,XX +XXX,XX @@ static void iscsi_xcopy_data(struct iscsi_data *data, |
72 | 229 | src_lba, dst_lba); | |
73 | #ifdef CONFIG_XFS | 230 | } |
74 | if (platform_test_xfs_fd(s->fd)) { | 231 | |
75 | @@ -XXX,XX +XXX,XX @@ static void raw_refresh_limits(BlockDriverState *bs, Error **errp) | 232 | -static int coroutine_fn iscsi_co_copy_range_to(BlockDriverState *bs, |
76 | BDRVRawState *s = bs->opaque; | 233 | - BdrvChild *src, |
77 | struct stat st; | 234 | - int64_t src_offset, |
78 | 235 | - BdrvChild *dst, | |
79 | + s->needs_alignment = raw_needs_alignment(bs); | 236 | - int64_t dst_offset, |
80 | raw_probe_alignment(bs, s->fd, errp); | 237 | - int64_t bytes, |
81 | + | 238 | - BdrvRequestFlags read_flags, |
82 | bs->bl.min_mem_alignment = s->buf_align; | 239 | - BdrvRequestFlags write_flags) |
83 | bs->bl.opt_mem_alignment = MAX(s->buf_align, qemu_real_host_page_size); | 240 | +static int coroutine_fn GRAPH_RDLOCK |
84 | 241 | +iscsi_co_copy_range_to(BlockDriverState *bs, | |
85 | diff --git a/tests/qemu-iotests/142 b/tests/qemu-iotests/142 | 242 | + BdrvChild *src, int64_t src_offset, |
86 | index XXXXXXX..XXXXXXX 100755 | 243 | + BdrvChild *dst, int64_t dst_offset, |
87 | --- a/tests/qemu-iotests/142 | 244 | + int64_t bytes, BdrvRequestFlags read_flags, |
88 | +++ b/tests/qemu-iotests/142 | 245 | + BdrvRequestFlags write_flags) |
89 | @@ -XXX,XX +XXX,XX @@ info block backing-file" | 246 | { |
90 | 247 | IscsiLun *dst_lun = dst->bs->opaque; | |
91 | echo "$hmp_cmds" | run_qemu -drive "$files","$ids" | grep "Cache" | 248 | IscsiLun *src_lun; |
92 | 249 | diff --git a/block/qcow2.c b/block/qcow2.c | |
93 | +echo | 250 | index XXXXXXX..XXXXXXX 100644 |
94 | +echo "--- Alignment after changing O_DIRECT ---" | 251 | --- a/block/qcow2.c |
95 | +echo | 252 | +++ b/block/qcow2.c |
96 | + | 253 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pdiscard(BlockDriverState *bs, |
97 | +# Directly test the protocol level: Can unaligned requests succeed even if | 254 | return ret; |
98 | +# O_DIRECT was only enabled through a reopen and vice versa? | 255 | } |
99 | + | 256 | |
100 | +$QEMU_IO --cache=writeback -f file $TEST_IMG <<EOF | _filter_qemu_io | 257 | -static int coroutine_fn |
101 | +read 42 42 | 258 | +static int coroutine_fn GRAPH_RDLOCK |
102 | +reopen -o cache.direct=on | 259 | qcow2_co_copy_range_from(BlockDriverState *bs, |
103 | +read 42 42 | 260 | BdrvChild *src, int64_t src_offset, |
104 | +reopen -o cache.direct=off | 261 | BdrvChild *dst, int64_t dst_offset, |
105 | +read 42 42 | 262 | @@ -XXX,XX +XXX,XX @@ out: |
106 | +EOF | 263 | return ret; |
107 | +$QEMU_IO --cache=none -f file $TEST_IMG <<EOF | _filter_qemu_io | 264 | } |
108 | +read 42 42 | 265 | |
109 | +reopen -o cache.direct=off | 266 | -static int coroutine_fn |
110 | +read 42 42 | 267 | +static int coroutine_fn GRAPH_RDLOCK |
111 | +reopen -o cache.direct=on | 268 | qcow2_co_copy_range_to(BlockDriverState *bs, |
112 | +read 42 42 | 269 | BdrvChild *src, int64_t src_offset, |
113 | +EOF | 270 | BdrvChild *dst, int64_t dst_offset, |
114 | + | 271 | @@ -XXX,XX +XXX,XX @@ qcow2_co_copy_range_to(BlockDriverState *bs, |
115 | # success, all done | 272 | uint64_t host_offset; |
116 | echo "*** done" | 273 | QCowL2Meta *l2meta = NULL; |
117 | rm -f $seq.full | 274 | |
118 | diff --git a/tests/qemu-iotests/142.out b/tests/qemu-iotests/142.out | 275 | - assume_graph_lock(); /* FIXME */ |
119 | index XXXXXXX..XXXXXXX 100644 | 276 | assert(!bs->encrypted); |
120 | --- a/tests/qemu-iotests/142.out | 277 | |
121 | +++ b/tests/qemu-iotests/142.out | 278 | qemu_co_mutex_lock(&s->lock); |
122 | @@ -XXX,XX +XXX,XX @@ cache.no-flush=on on backing-file | 279 | diff --git a/block/raw-format.c b/block/raw-format.c |
123 | Cache mode: writeback | 280 | index XXXXXXX..XXXXXXX 100644 |
124 | Cache mode: writeback, direct | 281 | --- a/block/raw-format.c |
125 | Cache mode: writeback, ignore flushes | 282 | +++ b/block/raw-format.c |
126 | + | 283 | @@ -XXX,XX +XXX,XX @@ static int raw_probe_geometry(BlockDriverState *bs, HDGeometry *geo) |
127 | +--- Alignment after changing O_DIRECT --- | 284 | return bdrv_probe_geometry(bs->file->bs, geo); |
128 | + | 285 | } |
129 | +read 42/42 bytes at offset 42 | 286 | |
130 | +42 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | 287 | -static int coroutine_fn raw_co_copy_range_from(BlockDriverState *bs, |
131 | +read 42/42 bytes at offset 42 | 288 | - BdrvChild *src, |
132 | +42 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | 289 | - int64_t src_offset, |
133 | +read 42/42 bytes at offset 42 | 290 | - BdrvChild *dst, |
134 | +42 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | 291 | - int64_t dst_offset, |
135 | +read 42/42 bytes at offset 42 | 292 | - int64_t bytes, |
136 | +42 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | 293 | - BdrvRequestFlags read_flags, |
137 | +read 42/42 bytes at offset 42 | 294 | - BdrvRequestFlags write_flags) |
138 | +42 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | 295 | +static int coroutine_fn GRAPH_RDLOCK |
139 | +read 42/42 bytes at offset 42 | 296 | +raw_co_copy_range_from(BlockDriverState *bs, |
140 | +42 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | 297 | + BdrvChild *src, int64_t src_offset, |
141 | *** done | 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; | ||
142 | -- | 340 | -- |
143 | 2.31.1 | 341 | 2.39.2 |
144 | |||
145 | diff view generated by jsdifflib |
1 | From: Hanna Reitz <hreitz@redhat.com> | 1 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
---|---|---|---|
2 | 2 | Message-Id: <20230203152202.49054-16-kwolf@redhat.com> | |
3 | bdrv_replace_child_noperm() modifies BdrvChild.bs, and can potentially | 3 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
4 | set it to NULL. That is dangerous, because BDS parents generally assume | ||
5 | that their children's .bs pointer is never NULL. We therefore want to | ||
6 | let bdrv_replace_child_noperm() set the corresponding BdrvChild pointer | ||
7 | to NULL, too. | ||
8 | |||
9 | This patch lays the foundation for it by passing a BdrvChild ** pointer | ||
10 | to bdrv_replace_child_noperm() so that it can later use it to NULL the | ||
11 | BdrvChild pointer immediately after setting BdrvChild.bs to NULL. | ||
12 | |||
13 | (We will still need to undertake some intermediate steps, though.) | ||
14 | |||
15 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
16 | Message-Id: <20211111120829.81329-6-hreitz@redhat.com> | ||
17 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
18 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 4 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
19 | --- | 5 | --- |
20 | block.c | 23 ++++++++++++----------- | 6 | include/block/block_int-common.h | 12 +++++++----- |
21 | 1 file changed, 12 insertions(+), 11 deletions(-) | 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(-) | ||
22 | 12 | ||
23 | diff --git a/block.c b/block.c | 13 | diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h |
24 | index XXXXXXX..XXXXXXX 100644 | 14 | index XXXXXXX..XXXXXXX 100644 |
25 | --- a/block.c | 15 | --- a/include/block/block_int-common.h |
26 | +++ b/block.c | 16 | +++ b/include/block/block_int-common.h |
27 | @@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_open_inherit(const char *filename, | 17 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { |
28 | static bool bdrv_recurse_has_child(BlockDriverState *bs, | 18 | * - receive the snapshot's actual length (which may differ from bs's |
29 | BlockDriverState *child); | 19 | * length) |
30 | 20 | */ | |
31 | -static void bdrv_replace_child_noperm(BdrvChild *child, | 21 | - int coroutine_fn (*bdrv_co_preadv_snapshot)(BlockDriverState *bs, |
32 | +static void bdrv_replace_child_noperm(BdrvChild **child, | 22 | - int64_t offset, int64_t bytes, QEMUIOVector *qiov, size_t qiov_offset); |
33 | BlockDriverState *new_bs); | 23 | - int coroutine_fn (*bdrv_co_snapshot_block_status)(BlockDriverState *bs, |
34 | static void bdrv_remove_file_or_backing_child(BlockDriverState *bs, | 24 | - bool want_zero, int64_t offset, int64_t bytes, int64_t *pnum, |
35 | BdrvChild *child, | 25 | - int64_t *map, BlockDriverState **file); |
36 | @@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_abort(void *opaque) | 26 | + int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_preadv_snapshot)( |
37 | BlockDriverState *new_bs = s->child->bs; | 27 | + BlockDriverState *bs, int64_t offset, int64_t bytes, |
38 | 28 | + QEMUIOVector *qiov, size_t qiov_offset); | |
39 | /* old_bs reference is transparently moved from @s to @s->child */ | 29 | + |
40 | - bdrv_replace_child_noperm(s->child, s->old_bs); | 30 | + int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_snapshot_block_status)( |
41 | + bdrv_replace_child_noperm(&s->child, s->old_bs); | 31 | + BlockDriverState *bs, bool want_zero, int64_t offset, int64_t bytes, |
42 | bdrv_unref(new_bs); | 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); | ||
43 | } | 62 | } |
44 | 63 | ||
45 | @@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_tran(BdrvChild *child, BlockDriverState *new_bs, | 64 | -static coroutine_fn int |
46 | if (new_bs) { | 65 | +static int coroutine_fn GRAPH_RDLOCK |
47 | bdrv_ref(new_bs); | 66 | cbw_co_preadv_snapshot(BlockDriverState *bs, int64_t offset, int64_t bytes, |
48 | } | 67 | QEMUIOVector *qiov, size_t qiov_offset) |
49 | - bdrv_replace_child_noperm(child, new_bs); | ||
50 | + bdrv_replace_child_noperm(&child, new_bs); | ||
51 | /* old_bs reference is transparently moved from @child to @s */ | ||
52 | } | ||
53 | |||
54 | @@ -XXX,XX +XXX,XX @@ uint64_t bdrv_qapi_perm_to_blk_perm(BlockPermission qapi_perm) | ||
55 | return permissions[qapi_perm]; | ||
56 | } | ||
57 | |||
58 | -static void bdrv_replace_child_noperm(BdrvChild *child, | ||
59 | +static void bdrv_replace_child_noperm(BdrvChild **childp, | ||
60 | BlockDriverState *new_bs) | ||
61 | { | 68 | { |
62 | + BdrvChild *child = *childp; | 69 | @@ -XXX,XX +XXX,XX @@ cbw_co_preadv_snapshot(BlockDriverState *bs, int64_t offset, int64_t bytes, |
63 | BlockDriverState *old_bs = child->bs; | 70 | BdrvChild *file; |
64 | int new_bs_quiesce_counter; | 71 | int ret; |
65 | int drain_saldo; | 72 | |
66 | @@ -XXX,XX +XXX,XX @@ static void bdrv_attach_child_common_abort(void *opaque) | 73 | - assume_graph_lock(); /* FIXME */ |
67 | BdrvChild *child = *s->child; | 74 | - |
68 | BlockDriverState *bs = child->bs; | 75 | /* TODO: upgrade to async loop using AioTask */ |
69 | 76 | while (bytes) { | |
70 | - bdrv_replace_child_noperm(child, NULL); | 77 | int64_t cur_bytes; |
71 | + bdrv_replace_child_noperm(s->child, NULL); | 78 | @@ -XXX,XX +XXX,XX @@ cbw_co_preadv_snapshot(BlockDriverState *bs, int64_t offset, int64_t bytes, |
72 | |||
73 | if (bdrv_get_aio_context(bs) != s->old_child_ctx) { | ||
74 | bdrv_try_set_aio_context(bs, s->old_child_ctx, &error_abort); | ||
75 | @@ -XXX,XX +XXX,XX @@ static int bdrv_attach_child_common(BlockDriverState *child_bs, | ||
76 | } | ||
77 | |||
78 | bdrv_ref(child_bs); | ||
79 | - bdrv_replace_child_noperm(new_child, child_bs); | ||
80 | + bdrv_replace_child_noperm(&new_child, child_bs); | ||
81 | |||
82 | *child = new_child; | ||
83 | |||
84 | @@ -XXX,XX +XXX,XX @@ static int bdrv_attach_child_noperm(BlockDriverState *parent_bs, | ||
85 | return 0; | 79 | return 0; |
86 | } | 80 | } |
87 | 81 | ||
88 | -static void bdrv_detach_child(BdrvChild *child) | 82 | -static int coroutine_fn |
89 | +static void bdrv_detach_child(BdrvChild **childp) | 83 | +static int coroutine_fn GRAPH_RDLOCK |
90 | { | 84 | cbw_co_snapshot_block_status(BlockDriverState *bs, |
91 | - BlockDriverState *old_bs = child->bs; | 85 | bool want_zero, int64_t offset, int64_t bytes, |
92 | + BlockDriverState *old_bs = (*childp)->bs; | 86 | int64_t *pnum, int64_t *map, |
93 | 87 | diff --git a/block/io.c b/block/io.c | |
94 | - bdrv_replace_child_noperm(child, NULL); | 88 | index XXXXXXX..XXXXXXX 100644 |
95 | - bdrv_child_free(child); | 89 | --- a/block/io.c |
96 | + bdrv_replace_child_noperm(childp, NULL); | 90 | +++ b/block/io.c |
97 | + bdrv_child_free(*childp); | 91 | @@ -XXX,XX +XXX,XX @@ bdrv_co_preadv_snapshot(BdrvChild *child, int64_t offset, int64_t bytes, |
98 | 92 | BlockDriver *drv = bs->drv; | |
99 | if (old_bs) { | 93 | int ret; |
100 | /* | 94 | IO_CODE(); |
101 | @@ -XXX,XX +XXX,XX @@ void bdrv_root_unref_child(BdrvChild *child) | 95 | + assert_bdrv_graph_readable(); |
102 | BlockDriverState *child_bs; | 96 | |
103 | 97 | if (!drv) { | |
104 | child_bs = child->bs; | 98 | return -ENOMEDIUM; |
105 | - bdrv_detach_child(child); | 99 | @@ -XXX,XX +XXX,XX @@ bdrv_co_snapshot_block_status(BlockDriverState *bs, |
106 | + bdrv_detach_child(&child); | 100 | BlockDriver *drv = bs->drv; |
107 | bdrv_unref(child_bs); | 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); | ||
108 | } | 122 | } |
109 | 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, | ||
110 | -- | 129 | -- |
111 | 2.31.1 | 130 | 2.39.2 |
112 | |||
113 | diff view generated by jsdifflib |
1 | From: Hanna Reitz <hreitz@redhat.com> | 1 | This adds GRAPH_RDLOCK annotations to declare that callers of |
---|---|---|---|
2 | bdrv_co_create() need to hold a reader lock for the graph. | ||
2 | 3 | ||
3 | As of a future commit, bdrv_replace_child_noperm() will clear the | 4 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
4 | indirect BdrvChild pointer passed to it if the new child BDS is NULL. | 5 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
5 | bdrv_replace_child_tran() will want to let it do that, but revert this | 6 | Message-Id: <20230203152202.49054-17-kwolf@redhat.com> |
6 | change in its abort handler. For that, we need to have it receive a | 7 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
7 | BdrvChild ** pointer, too, and keep it stored in the | ||
8 | BdrvReplaceChildState object that we attach to the transaction. | ||
9 | |||
10 | Note that we do not need to store it in the BdrvReplaceChildState when | ||
11 | new_bs is not NULL, because then there is nothing to revert. This is | ||
12 | important so that bdrv_replace_node_noperm() can pass a pointer to a | ||
13 | loop-local variable to bdrv_replace_child_tran() without worrying that | ||
14 | this pointer will outlive one loop iteration. | ||
15 | |||
16 | (Of course, for that to work, bdrv_replace_node_noperm() and in turn | ||
17 | bdrv_replace_node() and its relatives may not be called with a NULL @to | ||
18 | node. Luckily, they already are not, but now we should assert this.) | ||
19 | |||
20 | bdrv_remove_file_or_backing_child() on the other hand needs to ensure | ||
21 | that the indirect pointer it passes will stay valid for the duration of | ||
22 | the transaction. Ensure this by keeping a strong reference to the BDS | ||
23 | whose &bs->backing or &bs->file it passes to bdrv_replace_child_tran(), | ||
24 | and giving up that reference only in the transaction .clean() handler. | ||
25 | |||
26 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
27 | Message-Id: <20211111120829.81329-9-hreitz@redhat.com> | ||
28 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
29 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 8 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
30 | --- | 9 | --- |
31 | block.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++------- | 10 | include/block/block-global-state.h | 14 ++++--- |
32 | 1 file changed, 73 insertions(+), 10 deletions(-) | 11 | include/block/block_int-common.h | 11 +++--- |
12 | block.c | 1 + | ||
13 | block/create.c | 9 ++++- | ||
14 | block/crypto.c | 7 ++-- | ||
15 | block/file-posix.c | 7 ++-- | ||
16 | block/file-win32.c | 7 ++-- | ||
17 | block/parallels.c | 7 ++-- | ||
18 | block/qcow.c | 6 +-- | ||
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(-) | ||
33 | 27 | ||
28 | diff --git a/include/block/block-global-state.h b/include/block/block-global-state.h | ||
29 | index XXXXXXX..XXXXXXX 100644 | ||
30 | --- a/include/block/block-global-state.h | ||
31 | +++ b/include/block/block-global-state.h | ||
32 | @@ -XXX,XX +XXX,XX @@ BlockDriver *bdrv_find_protocol(const char *filename, | ||
33 | Error **errp); | ||
34 | BlockDriver *bdrv_find_format(const char *format_name); | ||
35 | |||
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 | + | ||
49 | +int coroutine_fn GRAPH_RDLOCK | ||
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 | + | ||
71 | + int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_create_opts)( | ||
72 | + BlockDriver *drv, const char *filename, QemuOpts *opts, Error **errp); | ||
73 | |||
74 | int (*bdrv_amend_options)(BlockDriverState *bs, | ||
75 | QemuOpts *opts, | ||
34 | diff --git a/block.c b/block.c | 76 | diff --git a/block.c b/block.c |
35 | index XXXXXXX..XXXXXXX 100644 | 77 | index XXXXXXX..XXXXXXX 100644 |
36 | --- a/block.c | 78 | --- a/block.c |
37 | +++ b/block.c | 79 | +++ b/block.c |
38 | @@ -XXX,XX +XXX,XX @@ static int bdrv_drv_set_perm(BlockDriverState *bs, uint64_t perm, | 80 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_create(BlockDriver *drv, const char *filename, |
39 | 81 | int ret; | |
40 | typedef struct BdrvReplaceChildState { | 82 | GLOBAL_STATE_CODE(); |
41 | BdrvChild *child; | 83 | ERRP_GUARD(); |
42 | + BdrvChild **childp; | 84 | + assert_bdrv_graph_readable(); |
43 | BlockDriverState *old_bs; | 85 | |
44 | } BdrvReplaceChildState; | 86 | if (!drv->bdrv_co_create_opts) { |
45 | 87 | error_setg(errp, "Driver '%s' does not support image creation", | |
46 | @@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_abort(void *opaque) | 88 | diff --git a/block/create.c b/block/create.c |
47 | BdrvReplaceChildState *s = opaque; | 89 | index XXXXXXX..XXXXXXX 100644 |
48 | BlockDriverState *new_bs = s->child->bs; | 90 | --- a/block/create.c |
49 | 91 | +++ b/block/create.c | |
50 | - /* old_bs reference is transparently moved from @s to @s->child */ | 92 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn blockdev_create_run(Job *job, Error **errp) |
51 | + /* | 93 | int ret; |
52 | + * old_bs reference is transparently moved from @s to s->child. | 94 | |
53 | + * | 95 | GLOBAL_STATE_CODE(); |
54 | + * Pass &s->child here instead of s->childp, because: | 96 | + GRAPH_RDLOCK_GUARD(); |
55 | + * (1) s->old_bs must be non-NULL, so bdrv_replace_child_noperm() will not | 97 | |
56 | + * modify the BdrvChild * pointer we indirectly pass to it, i.e. it | 98 | job_progress_set_remaining(&s->common, 1); |
57 | + * will not modify s->child. From that perspective, it does not matter | 99 | ret = s->drv->bdrv_co_create(s->opts, errp); |
58 | + * whether we pass s->childp or &s->child. | 100 | @@ -XXX,XX +XXX,XX @@ static const JobDriver blockdev_create_job_driver = { |
59 | + * (TODO: Right now, bdrv_replace_child_noperm() never modifies that | 101 | .run = blockdev_create_run, |
60 | + * pointer anyway (though it will in the future), so at this point it | 102 | }; |
61 | + * absolutely does not matter whether we pass s->childp or &s->child.) | 103 | |
62 | + * (2) If new_bs is not NULL, s->childp will be NULL. We then cannot use | 104 | +/* Checking whether the function is present doesn't require the graph lock */ |
63 | + * it here. | 105 | +static inline bool TSA_NO_TSA has_bdrv_co_create(BlockDriver *drv) |
64 | + * (3) If new_bs is NULL, *s->childp will have been NULLed by | ||
65 | + * bdrv_replace_child_tran()'s bdrv_replace_child_noperm() call, and we | ||
66 | + * must not pass a NULL *s->childp here. | ||
67 | + * (TODO: In its current state, bdrv_replace_child_noperm() will not | ||
68 | + * have NULLed *s->childp, so this does not apply yet. It will in the | ||
69 | + * future.) | ||
70 | + * | ||
71 | + * So whether new_bs was NULL or not, we cannot pass s->childp here; and in | ||
72 | + * any case, there is no reason to pass it anyway. | ||
73 | + */ | ||
74 | bdrv_replace_child_noperm(&s->child, s->old_bs); | ||
75 | bdrv_unref(new_bs); | ||
76 | } | ||
77 | @@ -XXX,XX +XXX,XX @@ static TransactionActionDrv bdrv_replace_child_drv = { | ||
78 | * Note: real unref of old_bs is done only on commit. | ||
79 | * | ||
80 | * The function doesn't update permissions, caller is responsible for this. | ||
81 | + * | ||
82 | + * Note that if new_bs == NULL, @childp is stored in a state object attached | ||
83 | + * to @tran, so that the old child can be reinstated in the abort handler. | ||
84 | + * Therefore, if @new_bs can be NULL, @childp must stay valid until the | ||
85 | + * transaction is committed or aborted. | ||
86 | + * | ||
87 | + * (TODO: The reinstating does not happen yet, but it will once | ||
88 | + * bdrv_replace_child_noperm() NULLs *childp when new_bs is NULL.) | ||
89 | */ | ||
90 | -static void bdrv_replace_child_tran(BdrvChild *child, BlockDriverState *new_bs, | ||
91 | +static void bdrv_replace_child_tran(BdrvChild **childp, | ||
92 | + BlockDriverState *new_bs, | ||
93 | Transaction *tran) | ||
94 | { | ||
95 | BdrvReplaceChildState *s = g_new(BdrvReplaceChildState, 1); | ||
96 | *s = (BdrvReplaceChildState) { | ||
97 | - .child = child, | ||
98 | - .old_bs = child->bs, | ||
99 | + .child = *childp, | ||
100 | + .childp = new_bs == NULL ? childp : NULL, | ||
101 | + .old_bs = (*childp)->bs, | ||
102 | }; | ||
103 | tran_add(tran, &bdrv_replace_child_drv, s); | ||
104 | |||
105 | if (new_bs) { | ||
106 | bdrv_ref(new_bs); | ||
107 | } | ||
108 | - bdrv_replace_child_noperm(&child, new_bs); | ||
109 | - /* old_bs reference is transparently moved from @child to @s */ | ||
110 | + bdrv_replace_child_noperm(childp, new_bs); | ||
111 | + /* old_bs reference is transparently moved from *childp to @s */ | ||
112 | } | ||
113 | |||
114 | /* | ||
115 | @@ -XXX,XX +XXX,XX @@ static bool should_update_child(BdrvChild *c, BlockDriverState *to) | ||
116 | |||
117 | typedef struct BdrvRemoveFilterOrCowChild { | ||
118 | BdrvChild *child; | ||
119 | + BlockDriverState *bs; | ||
120 | bool is_backing; | ||
121 | } BdrvRemoveFilterOrCowChild; | ||
122 | |||
123 | @@ -XXX,XX +XXX,XX @@ static void bdrv_remove_filter_or_cow_child_commit(void *opaque) | ||
124 | bdrv_child_free(s->child); | ||
125 | } | ||
126 | |||
127 | +static void bdrv_remove_filter_or_cow_child_clean(void *opaque) | ||
128 | +{ | 106 | +{ |
129 | + BdrvRemoveFilterOrCowChild *s = opaque; | 107 | + return drv->bdrv_co_create; |
130 | + | ||
131 | + /* Drop the bs reference after the transaction is done */ | ||
132 | + bdrv_unref(s->bs); | ||
133 | + g_free(s); | ||
134 | +} | 108 | +} |
135 | + | 109 | + |
136 | static TransactionActionDrv bdrv_remove_filter_or_cow_child_drv = { | 110 | void qmp_blockdev_create(const char *job_id, BlockdevCreateOptions *options, |
137 | .abort = bdrv_remove_filter_or_cow_child_abort, | 111 | Error **errp) |
138 | .commit = bdrv_remove_filter_or_cow_child_commit, | 112 | { |
139 | - .clean = g_free, | 113 | @@ -XXX,XX +XXX,XX @@ void qmp_blockdev_create(const char *job_id, BlockdevCreateOptions *options, |
140 | + .clean = bdrv_remove_filter_or_cow_child_clean, | 114 | } |
141 | }; | 115 | |
142 | 116 | /* Error out if the driver doesn't support .bdrv_co_create */ | |
143 | /* | 117 | - if (!drv->bdrv_co_create) { |
144 | @@ -XXX,XX +XXX,XX @@ static void bdrv_remove_file_or_backing_child(BlockDriverState *bs, | 118 | + if (!has_bdrv_co_create(drv)) { |
119 | error_setg(errp, "Driver does not support blockdev-create"); | ||
145 | return; | 120 | return; |
146 | } | 121 | } |
147 | 122 | diff --git a/block/crypto.c b/block/crypto.c | |
148 | + /* | 123 | index XXXXXXX..XXXXXXX 100644 |
149 | + * Keep a reference to @bs so @childp will stay valid throughout the | 124 | --- a/block/crypto.c |
150 | + * transaction (required by bdrv_replace_child_tran()) | 125 | +++ b/block/crypto.c |
151 | + */ | 126 | @@ -XXX,XX +XXX,XX @@ fail: |
152 | + bdrv_ref(bs); | 127 | return ret; |
153 | if (child == bs->backing) { | 128 | } |
154 | childp = &bs->backing; | 129 | |
155 | } else if (child == bs->file) { | 130 | -static int coroutine_fn block_crypto_co_create_opts_luks(BlockDriver *drv, |
156 | @@ -XXX,XX +XXX,XX @@ static void bdrv_remove_file_or_backing_child(BlockDriverState *bs, | 131 | - const char *filename, |
157 | } | 132 | - QemuOpts *opts, |
158 | 133 | - Error **errp) | |
159 | if (child->bs) { | 134 | +static int coroutine_fn GRAPH_RDLOCK |
160 | - bdrv_replace_child_tran(*childp, NULL, tran); | 135 | +block_crypto_co_create_opts_luks(BlockDriver *drv, const char *filename, |
161 | + bdrv_replace_child_tran(childp, NULL, tran); | 136 | + QemuOpts *opts, Error **errp) |
162 | } | 137 | { |
163 | 138 | QCryptoBlockCreateOptions *create_opts = NULL; | |
164 | s = g_new(BdrvRemoveFilterOrCowChild, 1); | 139 | BlockDriverState *bs = NULL; |
165 | *s = (BdrvRemoveFilterOrCowChild) { | 140 | diff --git a/block/file-posix.c b/block/file-posix.c |
166 | .child = child, | 141 | index XXXXXXX..XXXXXXX 100644 |
167 | + .bs = bs, | 142 | --- a/block/file-posix.c |
168 | .is_backing = (childp == &bs->backing), | 143 | +++ b/block/file-posix.c |
169 | }; | 144 | @@ -XXX,XX +XXX,XX @@ out: |
170 | tran_add(tran, &bdrv_remove_filter_or_cow_child_drv, s); | 145 | return result; |
171 | @@ -XXX,XX +XXX,XX @@ static int bdrv_replace_node_noperm(BlockDriverState *from, | 146 | } |
172 | { | 147 | |
173 | BdrvChild *c, *next; | 148 | -static int coroutine_fn raw_co_create_opts(BlockDriver *drv, |
174 | 149 | - const char *filename, | |
175 | + assert(to != NULL); | 150 | - QemuOpts *opts, |
176 | + | 151 | - Error **errp) |
177 | QLIST_FOREACH_SAFE(c, &from->parents, next_parent, next) { | 152 | +static int coroutine_fn GRAPH_RDLOCK |
178 | assert(c->bs == from); | 153 | +raw_co_create_opts(BlockDriver *drv, const char *filename, |
179 | if (!should_update_child(c, to)) { | 154 | + QemuOpts *opts, Error **errp) |
180 | @@ -XXX,XX +XXX,XX @@ static int bdrv_replace_node_noperm(BlockDriverState *from, | 155 | { |
181 | c->name, from->node_name); | 156 | BlockdevCreateOptions options; |
182 | return -EPERM; | 157 | int64_t total_size = 0; |
183 | } | 158 | diff --git a/block/file-win32.c b/block/file-win32.c |
184 | - bdrv_replace_child_tran(c, to, tran); | 159 | index XXXXXXX..XXXXXXX 100644 |
185 | + | 160 | --- a/block/file-win32.c |
186 | + /* | 161 | +++ b/block/file-win32.c |
187 | + * Passing a pointer to the local variable @c is fine here, because | 162 | @@ -XXX,XX +XXX,XX @@ static int raw_co_create(BlockdevCreateOptions *options, Error **errp) |
188 | + * @to is not NULL, and so &c will not be attached to the transaction. | ||
189 | + */ | ||
190 | + bdrv_replace_child_tran(&c, to, tran); | ||
191 | } | ||
192 | |||
193 | return 0; | 163 | return 0; |
194 | @@ -XXX,XX +XXX,XX @@ static int bdrv_replace_node_noperm(BlockDriverState *from, | 164 | } |
195 | * | 165 | |
196 | * With @detach_subchain=true @to must be in a backing chain of @from. In this | 166 | -static int coroutine_fn raw_co_create_opts(BlockDriver *drv, |
197 | * case backing link of the cow-parent of @to is removed. | 167 | - const char *filename, |
198 | + * | 168 | - QemuOpts *opts, |
199 | + * @to must not be NULL. | 169 | - Error **errp) |
170 | +static int coroutine_fn GRAPH_RDLOCK | ||
171 | +raw_co_create_opts(BlockDriver *drv, const char *filename, | ||
172 | + QemuOpts *opts, Error **errp) | ||
173 | { | ||
174 | BlockdevCreateOptions options; | ||
175 | int64_t total_size = 0; | ||
176 | diff --git a/block/parallels.c b/block/parallels.c | ||
177 | index XXXXXXX..XXXXXXX 100644 | ||
178 | --- a/block/parallels.c | ||
179 | +++ b/block/parallels.c | ||
180 | @@ -XXX,XX +XXX,XX @@ exit: | ||
181 | goto out; | ||
182 | } | ||
183 | |||
184 | -static int coroutine_fn parallels_co_create_opts(BlockDriver *drv, | ||
185 | - const char *filename, | ||
186 | - QemuOpts *opts, | ||
187 | - Error **errp) | ||
188 | +static int coroutine_fn GRAPH_RDLOCK | ||
189 | +parallels_co_create_opts(BlockDriver *drv, const char *filename, | ||
190 | + QemuOpts *opts, Error **errp) | ||
191 | { | ||
192 | BlockdevCreateOptions *create_options = NULL; | ||
193 | BlockDriverState *bs = NULL; | ||
194 | diff --git a/block/qcow.c b/block/qcow.c | ||
195 | index XXXXXXX..XXXXXXX 100644 | ||
196 | --- a/block/qcow.c | ||
197 | +++ b/block/qcow.c | ||
198 | @@ -XXX,XX +XXX,XX @@ exit: | ||
199 | return ret; | ||
200 | } | ||
201 | |||
202 | -static int coroutine_fn qcow_co_create_opts(BlockDriver *drv, | ||
203 | - const char *filename, | ||
204 | - QemuOpts *opts, Error **errp) | ||
205 | +static int coroutine_fn GRAPH_RDLOCK | ||
206 | +qcow_co_create_opts(BlockDriver *drv, const char *filename, | ||
207 | + QemuOpts *opts, Error **errp) | ||
208 | { | ||
209 | BlockdevCreateOptions *create_options = NULL; | ||
210 | BlockDriverState *bs = NULL; | ||
211 | diff --git a/block/qcow2.c b/block/qcow2.c | ||
212 | index XXXXXXX..XXXXXXX 100644 | ||
213 | --- a/block/qcow2.c | ||
214 | +++ b/block/qcow2.c | ||
215 | @@ -XXX,XX +XXX,XX @@ out: | ||
216 | return ret; | ||
217 | } | ||
218 | |||
219 | -static int coroutine_fn qcow2_co_create_opts(BlockDriver *drv, | ||
220 | - const char *filename, | ||
221 | - QemuOpts *opts, | ||
222 | - Error **errp) | ||
223 | +static int coroutine_fn GRAPH_RDLOCK | ||
224 | +qcow2_co_create_opts(BlockDriver *drv, const char *filename, QemuOpts *opts, | ||
225 | + Error **errp) | ||
226 | { | ||
227 | BlockdevCreateOptions *create_options = NULL; | ||
228 | QDict *qdict; | ||
229 | diff --git a/block/qed.c b/block/qed.c | ||
230 | index XXXXXXX..XXXXXXX 100644 | ||
231 | --- a/block/qed.c | ||
232 | +++ b/block/qed.c | ||
233 | @@ -XXX,XX +XXX,XX @@ out: | ||
234 | return ret; | ||
235 | } | ||
236 | |||
237 | -static int coroutine_fn bdrv_qed_co_create_opts(BlockDriver *drv, | ||
238 | - const char *filename, | ||
239 | - QemuOpts *opts, | ||
240 | - Error **errp) | ||
241 | +static int coroutine_fn GRAPH_RDLOCK | ||
242 | +bdrv_qed_co_create_opts(BlockDriver *drv, const char *filename, | ||
243 | + QemuOpts *opts, Error **errp) | ||
244 | { | ||
245 | BlockdevCreateOptions *create_options = NULL; | ||
246 | QDict *qdict; | ||
247 | diff --git a/block/raw-format.c b/block/raw-format.c | ||
248 | index XXXXXXX..XXXXXXX 100644 | ||
249 | --- a/block/raw-format.c | ||
250 | +++ b/block/raw-format.c | ||
251 | @@ -XXX,XX +XXX,XX @@ static int raw_has_zero_init(BlockDriverState *bs) | ||
252 | return bdrv_has_zero_init(bs->file->bs); | ||
253 | } | ||
254 | |||
255 | -static int coroutine_fn raw_co_create_opts(BlockDriver *drv, | ||
256 | - const char *filename, | ||
257 | - QemuOpts *opts, | ||
258 | - Error **errp) | ||
259 | +static int coroutine_fn GRAPH_RDLOCK | ||
260 | +raw_co_create_opts(BlockDriver *drv, const char *filename, | ||
261 | + QemuOpts *opts, Error **errp) | ||
262 | { | ||
263 | return bdrv_co_create_file(filename, opts, errp); | ||
264 | } | ||
265 | diff --git a/block/vdi.c b/block/vdi.c | ||
266 | index XXXXXXX..XXXXXXX 100644 | ||
267 | --- a/block/vdi.c | ||
268 | +++ b/block/vdi.c | ||
269 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn vdi_co_create(BlockdevCreateOptions *create_options, | ||
270 | return vdi_co_do_create(create_options, DEFAULT_CLUSTER_SIZE, errp); | ||
271 | } | ||
272 | |||
273 | -static int coroutine_fn vdi_co_create_opts(BlockDriver *drv, | ||
274 | - const char *filename, | ||
275 | - QemuOpts *opts, | ||
276 | - Error **errp) | ||
277 | +static int coroutine_fn GRAPH_RDLOCK | ||
278 | +vdi_co_create_opts(BlockDriver *drv, const char *filename, | ||
279 | + QemuOpts *opts, Error **errp) | ||
280 | { | ||
281 | QDict *qdict = NULL; | ||
282 | BlockdevCreateOptions *create_options = NULL; | ||
283 | diff --git a/block/vhdx.c b/block/vhdx.c | ||
284 | index XXXXXXX..XXXXXXX 100644 | ||
285 | --- a/block/vhdx.c | ||
286 | +++ b/block/vhdx.c | ||
287 | @@ -XXX,XX +XXX,XX @@ delete_and_exit: | ||
288 | return ret; | ||
289 | } | ||
290 | |||
291 | -static int coroutine_fn vhdx_co_create_opts(BlockDriver *drv, | ||
292 | - const char *filename, | ||
293 | - QemuOpts *opts, | ||
294 | - Error **errp) | ||
295 | +static int coroutine_fn GRAPH_RDLOCK | ||
296 | +vhdx_co_create_opts(BlockDriver *drv, const char *filename, | ||
297 | + QemuOpts *opts, Error **errp) | ||
298 | { | ||
299 | BlockdevCreateOptions *create_options = NULL; | ||
300 | QDict *qdict; | ||
301 | diff --git a/block/vmdk.c b/block/vmdk.c | ||
302 | index XXXXXXX..XXXXXXX 100644 | ||
303 | --- a/block/vmdk.c | ||
304 | +++ b/block/vmdk.c | ||
305 | @@ -XXX,XX +XXX,XX @@ exit: | ||
306 | return ret; | ||
307 | } | ||
308 | |||
309 | -static int coroutine_fn vmdk_create_extent(const char *filename, | ||
310 | - int64_t filesize, bool flat, | ||
311 | - bool compress, bool zeroed_grain, | ||
312 | - BlockBackend **pbb, | ||
313 | - QemuOpts *opts, Error **errp) | ||
314 | +static int coroutine_fn GRAPH_RDLOCK | ||
315 | +vmdk_create_extent(const char *filename, int64_t filesize, bool flat, | ||
316 | + bool compress, bool zeroed_grain, BlockBackend **pbb, | ||
317 | + QemuOpts *opts, Error **errp) | ||
318 | { | ||
319 | int ret; | ||
320 | BlockBackend *blk = NULL; | ||
321 | @@ -XXX,XX +XXX,XX @@ static int filename_decompose(const char *filename, char *path, char *prefix, | ||
322 | * non-split format. | ||
323 | * idx >= 1: get the n-th extent if in a split subformat | ||
200 | */ | 324 | */ |
201 | static int bdrv_replace_node_common(BlockDriverState *from, | 325 | -typedef BlockBackend * coroutine_fn (*vmdk_create_extent_fn)(int64_t size, |
202 | BlockDriverState *to, | 326 | - int idx, |
203 | @@ -XXX,XX +XXX,XX @@ static int bdrv_replace_node_common(BlockDriverState *from, | 327 | - bool flat, |
204 | BlockDriverState *to_cow_parent = NULL; | 328 | - bool split, |
205 | int ret; | 329 | - bool compress, |
206 | 330 | - bool zeroed_grain, | |
207 | + assert(to != NULL); | 331 | - void *opaque, |
208 | + | 332 | - Error **errp); |
209 | if (detach_subchain) { | 333 | +typedef BlockBackend * coroutine_fn /* GRAPH_RDLOCK */ |
210 | assert(bdrv_chain_contains(from, to)); | 334 | + (*vmdk_create_extent_fn)(int64_t size, int idx, bool flat, bool split, |
211 | assert(from != to); | 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 | ||
212 | @@ -XXX,XX +XXX,XX @@ out: | 414 | @@ -XXX,XX +XXX,XX @@ out: |
213 | return ret; | 415 | return ret; |
214 | } | 416 | } |
215 | 417 | ||
216 | +/** | 418 | -static int coroutine_fn vpc_co_create_opts(BlockDriver *drv, |
217 | + * Replace node @from by @to (where neither may be NULL). | 419 | - const char *filename, |
218 | + */ | 420 | - QemuOpts *opts, |
219 | int bdrv_replace_node(BlockDriverState *from, BlockDriverState *to, | 421 | - Error **errp) |
220 | Error **errp) | 422 | +static int coroutine_fn GRAPH_RDLOCK |
221 | { | 423 | +vpc_co_create_opts(BlockDriver *drv, const char *filename, |
222 | @@ -XXX,XX +XXX,XX @@ int bdrv_replace_child_bs(BdrvChild *child, BlockDriverState *new_bs, | 424 | + QemuOpts *opts, Error **errp) |
223 | bdrv_drained_begin(old_bs); | 425 | { |
224 | bdrv_drained_begin(new_bs); | 426 | BlockdevCreateOptions *create_options = NULL; |
225 | 427 | QDict *qdict; | |
226 | - bdrv_replace_child_tran(child, new_bs, tran); | ||
227 | + bdrv_replace_child_tran(&child, new_bs, tran); | ||
228 | |||
229 | found = g_hash_table_new(NULL, NULL); | ||
230 | refresh_list = bdrv_topological_dfs(refresh_list, found, old_bs); | ||
231 | -- | 428 | -- |
232 | 2.31.1 | 429 | 2.39.2 |
233 | |||
234 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | This adds GRAPH_RDLOCK annotations to declare that callers of | ||
2 | bdrv_co_io_plug() and bdrv_co_io_unplug() need to hold a reader lock for | ||
3 | the graph. | ||
1 | 4 | ||
5 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
6 | Message-Id: <20230203152202.49054-18-kwolf@redhat.com> | ||
7 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
8 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
9 | --- | ||
10 | include/block/block-io.h | 4 ++-- | ||
11 | include/block/block_int-common.h | 5 +++-- | ||
12 | block/block-backend.c | 2 ++ | ||
13 | block/io.c | 2 ++ | ||
14 | 4 files changed, 9 insertions(+), 4 deletions(-) | ||
15 | |||
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 | ||
48 | index XXXXXXX..XXXXXXX 100644 | ||
49 | --- a/block/block-backend.c | ||
50 | +++ b/block/block-backend.c | ||
51 | @@ -XXX,XX +XXX,XX @@ void coroutine_fn blk_co_io_plug(BlockBackend *blk) | ||
52 | { | ||
53 | BlockDriverState *bs = blk_bs(blk); | ||
54 | IO_CODE(); | ||
55 | + GRAPH_RDLOCK_GUARD(); | ||
56 | |||
57 | if (bs) { | ||
58 | bdrv_co_io_plug(bs); | ||
59 | @@ -XXX,XX +XXX,XX @@ void coroutine_fn blk_co_io_unplug(BlockBackend *blk) | ||
60 | { | ||
61 | BlockDriverState *bs = blk_bs(blk); | ||
62 | IO_CODE(); | ||
63 | + GRAPH_RDLOCK_GUARD(); | ||
64 | |||
65 | if (bs) { | ||
66 | bdrv_co_io_unplug(bs); | ||
67 | diff --git a/block/io.c b/block/io.c | ||
68 | index XXXXXXX..XXXXXXX 100644 | ||
69 | --- a/block/io.c | ||
70 | +++ b/block/io.c | ||
71 | @@ -XXX,XX +XXX,XX @@ void coroutine_fn bdrv_co_io_plug(BlockDriverState *bs) | ||
72 | { | ||
73 | BdrvChild *child; | ||
74 | IO_CODE(); | ||
75 | + assert_bdrv_graph_readable(); | ||
76 | |||
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 | -- | ||
88 | 2.39.2 | diff view generated by jsdifflib |
1 | From: Hanna Reitz <hreitz@redhat.com> | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | The children list is specific to BDS parents. We should not modify it | 3 | This adds GRAPH_RDLOCK annotations to declare that callers of |
4 | in the general children modification code, but let BDS parents deal with | 4 | bdrv_co_is_inserted() need to hold a reader lock for the graph. |
5 | it in their .attach() and .detach() methods. | ||
6 | 5 | ||
7 | This also has the advantage that a BdrvChild is removed from the | 6 | blk_is_inserted() is done as a co_wrapper_mixed_bdrv_rdlock (unlike most |
8 | children list before its .bs pointer can become NULL. BDS parents | 7 | other blk_* functions) because it is called a lot from other blk_co_*() |
9 | generally assume that their children's .bs pointer is never NULL, so | 8 | functions that already hold the lock. These calls go through |
10 | this is actually a bug fix. | 9 | blk_is_available(), which becomes a co_wrapper_mixed_bdrv_rdlock, too, |
10 | for the same reason. | ||
11 | 11 | ||
12 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | 12 | Functions that run in a coroutine and can call bdrv_co_is_available() |
13 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 13 | directly are changed to do so, which results in better TSA coverage. |
14 | Message-Id: <20211111120829.81329-3-hreitz@redhat.com> | 14 | |
15 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
16 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
17 | Message-Id: <20230203152202.49054-19-kwolf@redhat.com> | ||
18 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
15 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 19 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
16 | --- | 20 | --- |
17 | block.c | 14 +++++--------- | 21 | include/block/block-io.h | 4 ++-- |
18 | 1 file changed, 5 insertions(+), 9 deletions(-) | 22 | include/block/block_int-common.h | 3 ++- |
23 | include/sysemu/block-backend-io.h | 7 ++++--- | ||
24 | block.c | 1 + | ||
25 | block/block-backend.c | 25 ++++++++++++++----------- | ||
26 | 5 files changed, 23 insertions(+), 17 deletions(-) | ||
19 | 27 | ||
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); | ||
20 | diff --git a/block.c b/block.c | 76 | diff --git a/block.c b/block.c |
21 | index XXXXXXX..XXXXXXX 100644 | 77 | index XXXXXXX..XXXXXXX 100644 |
22 | --- a/block.c | 78 | --- a/block.c |
23 | +++ b/block.c | 79 | +++ b/block.c |
24 | @@ -XXX,XX +XXX,XX @@ static void bdrv_child_cb_attach(BdrvChild *child) | 80 | @@ -XXX,XX +XXX,XX @@ bool coroutine_fn bdrv_co_is_inserted(BlockDriverState *bs) |
81 | BlockDriver *drv = bs->drv; | ||
82 | BdrvChild *child; | ||
83 | IO_CODE(); | ||
84 | + assert_bdrv_graph_readable(); | ||
85 | |||
86 | if (!drv) { | ||
87 | return false; | ||
88 | diff --git a/block/block-backend.c b/block/block-backend.c | ||
89 | index XXXXXXX..XXXXXXX 100644 | ||
90 | --- a/block/block-backend.c | ||
91 | +++ b/block/block-backend.c | ||
92 | @@ -XXX,XX +XXX,XX @@ void blk_set_disable_request_queuing(BlockBackend *blk, bool disable) | ||
93 | blk->disable_request_queuing = disable; | ||
94 | } | ||
95 | |||
96 | -static coroutine_fn int blk_check_byte_request(BlockBackend *blk, | ||
97 | - int64_t offset, int64_t bytes) | ||
98 | +static int coroutine_fn GRAPH_RDLOCK | ||
99 | +blk_check_byte_request(BlockBackend *blk, int64_t offset, int64_t bytes) | ||
25 | { | 100 | { |
26 | BlockDriverState *bs = child->opaque; | 101 | int64_t len; |
27 | 102 | ||
28 | + QLIST_INSERT_HEAD(&bs->children, child, next); | 103 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int blk_check_byte_request(BlockBackend *blk, |
29 | + | 104 | return -EIO; |
30 | if (child->role & BDRV_CHILD_COW) { | ||
31 | bdrv_backing_attach(child); | ||
32 | } | 105 | } |
33 | @@ -XXX,XX +XXX,XX @@ static void bdrv_child_cb_detach(BdrvChild *child) | 106 | |
107 | - if (!blk_is_available(blk)) { | ||
108 | + if (!blk_co_is_available(blk)) { | ||
109 | return -ENOMEDIUM; | ||
34 | } | 110 | } |
35 | 111 | ||
36 | bdrv_unapply_subtree_drain(child, bs); | 112 | @@ -XXX,XX +XXX,XX @@ BlockAIOCB *blk_aio_pwrite_zeroes(BlockBackend *blk, int64_t offset, |
37 | + | 113 | int64_t coroutine_fn blk_co_getlength(BlockBackend *blk) |
38 | + QLIST_REMOVE(child, next); | 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); | ||
39 | } | 159 | } |
40 | 160 | ||
41 | static int bdrv_child_cb_update_filename(BdrvChild *c, BlockDriverState *base, | 161 | -bool blk_is_available(BlockBackend *blk) |
42 | @@ -XXX,XX +XXX,XX @@ static void bdrv_child_free(void *opaque) | 162 | +bool coroutine_fn blk_co_is_available(BlockBackend *blk) |
43 | static void bdrv_remove_empty_child(BdrvChild *child) | ||
44 | { | 163 | { |
45 | assert(!child->bs); | 164 | IO_CODE(); |
46 | - QLIST_SAFE_REMOVE(child, next); | 165 | - return blk_is_inserted(blk) && !blk_dev_is_tray_open(blk); |
47 | + assert(!child->next.le_prev); /* not in children list */ | 166 | + return blk_co_is_inserted(blk) && !blk_dev_is_tray_open(blk); |
48 | bdrv_child_free(child); | ||
49 | } | 167 | } |
50 | 168 | ||
51 | @@ -XXX,XX +XXX,XX @@ static int bdrv_attach_child_noperm(BlockDriverState *parent_bs, | 169 | void coroutine_fn blk_co_lock_medium(BlockBackend *blk, bool locked) |
52 | return ret; | 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; | ||
53 | } | 178 | } |
54 | 179 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn blk_co_copy_range(BlockBackend *blk_in, int64_t off_in, | |
55 | - QLIST_INSERT_HEAD(&parent_bs->children, *child, next); | 180 | { |
56 | - /* | 181 | int r; |
57 | - * child is removed in bdrv_attach_child_common_abort(), so don't care to | 182 | IO_CODE(); |
58 | - * abort this change separately. | 183 | + GRAPH_RDLOCK_GUARD(); |
59 | - */ | 184 | |
60 | - | 185 | r = blk_check_byte_request(blk_in, off_in, bytes); |
61 | return 0; | 186 | if (r) { |
62 | } | 187 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn blk_co_copy_range(BlockBackend *blk_in, int64_t off_in, |
63 | 188 | return r; | |
64 | @@ -XXX,XX +XXX,XX @@ static void bdrv_remove_filter_or_cow_child_abort(void *opaque) | 189 | } |
65 | BdrvRemoveFilterOrCowChild *s = opaque; | 190 | |
66 | BlockDriverState *parent_bs = s->child->opaque; | 191 | - GRAPH_RDLOCK_GUARD(); |
67 | 192 | return bdrv_co_copy_range(blk_in->root, off_in, | |
68 | - QLIST_INSERT_HEAD(&parent_bs->children, s->child, next); | 193 | blk_out->root, off_out, |
69 | if (s->is_backing) { | 194 | bytes, read_flags, write_flags); |
70 | parent_bs->backing = s->child; | ||
71 | } else { | ||
72 | @@ -XXX,XX +XXX,XX @@ static void bdrv_remove_file_or_backing_child(BlockDriverState *bs, | ||
73 | }; | ||
74 | tran_add(tran, &bdrv_remove_filter_or_cow_child_drv, s); | ||
75 | |||
76 | - QLIST_SAFE_REMOVE(child, next); | ||
77 | if (s->is_backing) { | ||
78 | bs->backing = NULL; | ||
79 | } else { | ||
80 | -- | 195 | -- |
81 | 2.31.1 | 196 | 2.39.2 |
82 | |||
83 | diff view generated by jsdifflib |
1 | From: Hanna Reitz <hreitz@redhat.com> | 1 | This adds GRAPH_RDLOCK annotations to declare that callers of |
---|---|---|---|
2 | bdrv_co_eject() and bdrv_co_lock_medium() need to hold a reader lock for | ||
3 | the graph. | ||
2 | 4 | ||
3 | In most of the block layer, especially when traversing down from other | 5 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
4 | BlockDriverStates, we assume that BdrvChild.bs can never be NULL. When | 6 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
5 | it becomes NULL, it is expected that the corresponding BdrvChild pointer | 7 | Message-Id: <20230203152202.49054-20-kwolf@redhat.com> |
6 | also becomes NULL and the BdrvChild object is freed. | 8 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
7 | |||
8 | Therefore, once bdrv_replace_child_noperm() sets the BdrvChild.bs | ||
9 | pointer to NULL, it should also immediately set the corresponding | ||
10 | BdrvChild pointer (like bs->file or bs->backing) to NULL. | ||
11 | |||
12 | In that context, it also makes sense for this function to free the | ||
13 | child. Sometimes we cannot do so, though, because it is called in a | ||
14 | transactional context where the caller might still want to reinstate the | ||
15 | child in the abort branch (and free it only on commit), so this behavior | ||
16 | has to remain optional. | ||
17 | |||
18 | In bdrv_replace_child_tran()'s abort handler, we now rely on the fact | ||
19 | that the BdrvChild passed to bdrv_replace_child_tran() must have had a | ||
20 | non-NULL .bs pointer initially. Make a note of that and assert it. | ||
21 | |||
22 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
23 | Message-Id: <20211111120829.81329-10-hreitz@redhat.com> | ||
24 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 9 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
25 | --- | 10 | --- |
26 | block.c | 102 +++++++++++++++++++++++++++++++++++++++++++------------- | 11 | include/block/block-io.h | 7 +++++-- |
27 | 1 file changed, 79 insertions(+), 23 deletions(-) | 12 | include/block/block_int-common.h | 6 ++++-- |
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(-) | ||
28 | 19 | ||
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)( | ||
29 | diff --git a/block.c b/block.c | 55 | diff --git a/block.c b/block.c |
30 | index XXXXXXX..XXXXXXX 100644 | 56 | index XXXXXXX..XXXXXXX 100644 |
31 | --- a/block.c | 57 | --- a/block.c |
32 | +++ b/block.c | 58 | +++ b/block.c |
33 | @@ -XXX,XX +XXX,XX @@ static BlockDriverState *bdrv_open_inherit(const char *filename, | 59 | @@ -XXX,XX +XXX,XX @@ void coroutine_fn bdrv_co_eject(BlockDriverState *bs, bool eject_flag) |
34 | static bool bdrv_recurse_has_child(BlockDriverState *bs, | ||
35 | BlockDriverState *child); | ||
36 | |||
37 | +static void bdrv_child_free(BdrvChild *child); | ||
38 | static void bdrv_replace_child_noperm(BdrvChild **child, | ||
39 | - BlockDriverState *new_bs); | ||
40 | + BlockDriverState *new_bs, | ||
41 | + bool free_empty_child); | ||
42 | static void bdrv_remove_file_or_backing_child(BlockDriverState *bs, | ||
43 | BdrvChild *child, | ||
44 | Transaction *tran); | ||
45 | @@ -XXX,XX +XXX,XX @@ typedef struct BdrvReplaceChildState { | ||
46 | BdrvChild *child; | ||
47 | BdrvChild **childp; | ||
48 | BlockDriverState *old_bs; | ||
49 | + bool free_empty_child; | ||
50 | } BdrvReplaceChildState; | ||
51 | |||
52 | static void bdrv_replace_child_commit(void *opaque) | ||
53 | { | 60 | { |
54 | BdrvReplaceChildState *s = opaque; | 61 | BlockDriver *drv = bs->drv; |
55 | 62 | IO_CODE(); | |
56 | + if (s->free_empty_child && !s->child->bs) { | 63 | + assert_bdrv_graph_readable(); |
57 | + bdrv_child_free(s->child); | 64 | |
58 | + } | 65 | if (drv && drv->bdrv_co_eject) { |
59 | bdrv_unref(s->old_bs); | 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 | ||
76 | index XXXXXXX..XXXXXXX 100644 | ||
77 | --- a/block/block-backend.c | ||
78 | +++ b/block/block-backend.c | ||
79 | @@ -XXX,XX +XXX,XX @@ void coroutine_fn blk_co_lock_medium(BlockBackend *blk, bool locked) | ||
80 | { | ||
81 | BlockDriverState *bs = blk_bs(blk); | ||
82 | IO_CODE(); | ||
83 | + GRAPH_RDLOCK_GUARD(); | ||
84 | |||
85 | if (bs) { | ||
86 | bdrv_co_lock_medium(bs, locked); | ||
87 | @@ -XXX,XX +XXX,XX @@ void coroutine_fn blk_co_eject(BlockBackend *blk, bool eject_flag) | ||
88 | BlockDriverState *bs = blk_bs(blk); | ||
89 | char *id; | ||
90 | IO_CODE(); | ||
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, | ||
60 | } | 100 | } |
61 | 101 | ||
62 | @@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_abort(void *opaque) | 102 | |
63 | * modify the BdrvChild * pointer we indirectly pass to it, i.e. it | 103 | -static void coroutine_fn cor_co_eject(BlockDriverState *bs, bool eject_flag) |
64 | * will not modify s->child. From that perspective, it does not matter | 104 | +static void coroutine_fn GRAPH_RDLOCK |
65 | * whether we pass s->childp or &s->child. | 105 | +cor_co_eject(BlockDriverState *bs, bool eject_flag) |
66 | - * (TODO: Right now, bdrv_replace_child_noperm() never modifies that | 106 | { |
67 | - * pointer anyway (though it will in the future), so at this point it | 107 | bdrv_co_eject(bs->file->bs, eject_flag); |
68 | - * absolutely does not matter whether we pass s->childp or &s->child.) | ||
69 | * (2) If new_bs is not NULL, s->childp will be NULL. We then cannot use | ||
70 | * it here. | ||
71 | * (3) If new_bs is NULL, *s->childp will have been NULLed by | ||
72 | * bdrv_replace_child_tran()'s bdrv_replace_child_noperm() call, and we | ||
73 | * must not pass a NULL *s->childp here. | ||
74 | - * (TODO: In its current state, bdrv_replace_child_noperm() will not | ||
75 | - * have NULLed *s->childp, so this does not apply yet. It will in the | ||
76 | - * future.) | ||
77 | * | ||
78 | * So whether new_bs was NULL or not, we cannot pass s->childp here; and in | ||
79 | * any case, there is no reason to pass it anyway. | ||
80 | */ | ||
81 | - bdrv_replace_child_noperm(&s->child, s->old_bs); | ||
82 | + bdrv_replace_child_noperm(&s->child, s->old_bs, true); | ||
83 | + /* | ||
84 | + * The child was pre-existing, so s->old_bs must be non-NULL, and | ||
85 | + * s->child thus must not have been freed | ||
86 | + */ | ||
87 | + assert(s->child != NULL); | ||
88 | + if (!new_bs) { | ||
89 | + /* As described above, *s->childp was cleared, so restore it */ | ||
90 | + assert(s->childp != NULL); | ||
91 | + *s->childp = s->child; | ||
92 | + } | ||
93 | bdrv_unref(new_bs); | ||
94 | } | 108 | } |
95 | 109 | ||
96 | @@ -XXX,XX +XXX,XX @@ static TransactionActionDrv bdrv_replace_child_drv = { | 110 | |
97 | * | 111 | -static void coroutine_fn cor_co_lock_medium(BlockDriverState *bs, bool locked) |
98 | * The function doesn't update permissions, caller is responsible for this. | 112 | +static void coroutine_fn GRAPH_RDLOCK |
99 | * | 113 | +cor_co_lock_medium(BlockDriverState *bs, bool locked) |
100 | + * (*childp)->bs must not be NULL. | ||
101 | + * | ||
102 | * Note that if new_bs == NULL, @childp is stored in a state object attached | ||
103 | * to @tran, so that the old child can be reinstated in the abort handler. | ||
104 | * Therefore, if @new_bs can be NULL, @childp must stay valid until the | ||
105 | * transaction is committed or aborted. | ||
106 | * | ||
107 | - * (TODO: The reinstating does not happen yet, but it will once | ||
108 | - * bdrv_replace_child_noperm() NULLs *childp when new_bs is NULL.) | ||
109 | + * If @free_empty_child is true and @new_bs is NULL, the BdrvChild is | ||
110 | + * freed (on commit). @free_empty_child should only be false if the | ||
111 | + * caller will free the BDrvChild themselves (which may be important | ||
112 | + * if this is in turn called in another transactional context). | ||
113 | */ | ||
114 | static void bdrv_replace_child_tran(BdrvChild **childp, | ||
115 | BlockDriverState *new_bs, | ||
116 | - Transaction *tran) | ||
117 | + Transaction *tran, | ||
118 | + bool free_empty_child) | ||
119 | { | 114 | { |
120 | BdrvReplaceChildState *s = g_new(BdrvReplaceChildState, 1); | 115 | bdrv_co_lock_medium(bs->file->bs, locked); |
121 | *s = (BdrvReplaceChildState) { | ||
122 | .child = *childp, | ||
123 | .childp = new_bs == NULL ? childp : NULL, | ||
124 | .old_bs = (*childp)->bs, | ||
125 | + .free_empty_child = free_empty_child, | ||
126 | }; | ||
127 | tran_add(tran, &bdrv_replace_child_drv, s); | ||
128 | |||
129 | + /* The abort handler relies on this */ | ||
130 | + assert(s->old_bs != NULL); | ||
131 | + | ||
132 | if (new_bs) { | ||
133 | bdrv_ref(new_bs); | ||
134 | } | ||
135 | - bdrv_replace_child_noperm(childp, new_bs); | ||
136 | + /* | ||
137 | + * Pass free_empty_child=false, we will free the child (if | ||
138 | + * necessary) in bdrv_replace_child_commit() (if our | ||
139 | + * @free_empty_child parameter was true). | ||
140 | + */ | ||
141 | + bdrv_replace_child_noperm(childp, new_bs, false); | ||
142 | /* old_bs reference is transparently moved from *childp to @s */ | ||
143 | } | 116 | } |
144 | 117 | diff --git a/block/filter-compress.c b/block/filter-compress.c | |
145 | @@ -XXX,XX +XXX,XX @@ uint64_t bdrv_qapi_perm_to_blk_perm(BlockPermission qapi_perm) | 118 | index XXXXXXX..XXXXXXX 100644 |
146 | return permissions[qapi_perm]; | 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) | ||
147 | } | 122 | } |
148 | 123 | ||
149 | +/** | 124 | |
150 | + * Replace (*childp)->bs by @new_bs. | 125 | -static void coroutine_fn |
151 | + * | 126 | +static void coroutine_fn GRAPH_RDLOCK |
152 | + * If @new_bs is NULL, *childp will be set to NULL, too: BDS parents | 127 | compress_co_eject(BlockDriverState *bs, bool eject_flag) |
153 | + * generally cannot handle a BdrvChild with .bs == NULL, so clearing | ||
154 | + * BdrvChild.bs should generally immediately be followed by the | ||
155 | + * BdrvChild pointer being cleared as well. | ||
156 | + * | ||
157 | + * If @free_empty_child is true and @new_bs is NULL, the BdrvChild is | ||
158 | + * freed. @free_empty_child should only be false if the caller will | ||
159 | + * free the BdrvChild themselves (this may be important in a | ||
160 | + * transactional context, where it may only be freed on commit). | ||
161 | + */ | ||
162 | static void bdrv_replace_child_noperm(BdrvChild **childp, | ||
163 | - BlockDriverState *new_bs) | ||
164 | + BlockDriverState *new_bs, | ||
165 | + bool free_empty_child) | ||
166 | { | 128 | { |
167 | BdrvChild *child = *childp; | 129 | bdrv_co_eject(bs->file->bs, eject_flag); |
168 | BlockDriverState *old_bs = child->bs; | ||
169 | @@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_noperm(BdrvChild **childp, | ||
170 | } | ||
171 | |||
172 | child->bs = new_bs; | ||
173 | + if (!new_bs) { | ||
174 | + *childp = NULL; | ||
175 | + } | ||
176 | |||
177 | if (new_bs) { | ||
178 | QLIST_INSERT_HEAD(&new_bs->parents, child, next_parent); | ||
179 | @@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_noperm(BdrvChild **childp, | ||
180 | bdrv_parent_drained_end_single(child); | ||
181 | drain_saldo++; | ||
182 | } | ||
183 | + | ||
184 | + if (free_empty_child && !child->bs) { | ||
185 | + bdrv_child_free(child); | ||
186 | + } | ||
187 | } | 130 | } |
188 | 131 | ||
189 | /** | 132 | |
190 | @@ -XXX,XX +XXX,XX @@ static void bdrv_attach_child_common_abort(void *opaque) | 133 | -static void coroutine_fn |
191 | BdrvChild *child = *s->child; | 134 | +static void coroutine_fn GRAPH_RDLOCK |
192 | BlockDriverState *bs = child->bs; | 135 | compress_co_lock_medium(BlockDriverState *bs, bool locked) |
193 | 136 | { | |
194 | - bdrv_replace_child_noperm(s->child, NULL); | 137 | bdrv_co_lock_medium(bs->file->bs, locked); |
195 | + /* | 138 | diff --git a/block/raw-format.c b/block/raw-format.c |
196 | + * Pass free_empty_child=false, because we still need the child | 139 | index XXXXXXX..XXXXXXX 100644 |
197 | + * for the AioContext operations on the parent below; those | 140 | --- a/block/raw-format.c |
198 | + * BdrvChildClass methods all work on a BdrvChild object, so we | 141 | +++ b/block/raw-format.c |
199 | + * need to keep it as an empty shell (after this function, it will | 142 | @@ -XXX,XX +XXX,XX @@ raw_co_truncate(BlockDriverState *bs, int64_t offset, bool exact, |
200 | + * not be attached to any parent, and it will not have a .bs). | 143 | return bdrv_co_truncate(bs->file, offset, exact, prealloc, flags, errp); |
201 | + */ | ||
202 | + bdrv_replace_child_noperm(s->child, NULL, false); | ||
203 | |||
204 | if (bdrv_get_aio_context(bs) != s->old_child_ctx) { | ||
205 | bdrv_try_set_aio_context(bs, s->old_child_ctx, &error_abort); | ||
206 | @@ -XXX,XX +XXX,XX @@ static void bdrv_attach_child_common_abort(void *opaque) | ||
207 | |||
208 | bdrv_unref(bs); | ||
209 | bdrv_child_free(child); | ||
210 | - *s->child = NULL; | ||
211 | } | 144 | } |
212 | 145 | ||
213 | static TransactionActionDrv bdrv_attach_child_common_drv = { | 146 | -static void coroutine_fn raw_co_eject(BlockDriverState *bs, bool eject_flag) |
214 | @@ -XXX,XX +XXX,XX @@ static int bdrv_attach_child_common(BlockDriverState *child_bs, | 147 | +static void coroutine_fn GRAPH_RDLOCK |
215 | } | 148 | +raw_co_eject(BlockDriverState *bs, bool eject_flag) |
216 | |||
217 | bdrv_ref(child_bs); | ||
218 | - bdrv_replace_child_noperm(&new_child, child_bs); | ||
219 | + bdrv_replace_child_noperm(&new_child, child_bs, true); | ||
220 | + /* child_bs was non-NULL, so new_child must not have been freed */ | ||
221 | + assert(new_child != NULL); | ||
222 | |||
223 | *child = new_child; | ||
224 | |||
225 | @@ -XXX,XX +XXX,XX @@ static void bdrv_detach_child(BdrvChild **childp) | ||
226 | { | 149 | { |
227 | BlockDriverState *old_bs = (*childp)->bs; | 150 | bdrv_co_eject(bs->file->bs, eject_flag); |
228 | |||
229 | - bdrv_replace_child_noperm(childp, NULL); | ||
230 | - bdrv_child_free(*childp); | ||
231 | + bdrv_replace_child_noperm(childp, NULL, true); | ||
232 | |||
233 | if (old_bs) { | ||
234 | /* | ||
235 | @@ -XXX,XX +XXX,XX @@ static void bdrv_remove_file_or_backing_child(BlockDriverState *bs, | ||
236 | } | ||
237 | |||
238 | if (child->bs) { | ||
239 | - bdrv_replace_child_tran(childp, NULL, tran); | ||
240 | + /* | ||
241 | + * Pass free_empty_child=false, we will free the child in | ||
242 | + * bdrv_remove_filter_or_cow_child_commit() | ||
243 | + */ | ||
244 | + bdrv_replace_child_tran(childp, NULL, tran, false); | ||
245 | } | ||
246 | |||
247 | s = g_new(BdrvRemoveFilterOrCowChild, 1); | ||
248 | @@ -XXX,XX +XXX,XX @@ static void bdrv_remove_file_or_backing_child(BlockDriverState *bs, | ||
249 | .is_backing = (childp == &bs->backing), | ||
250 | }; | ||
251 | tran_add(tran, &bdrv_remove_filter_or_cow_child_drv, s); | ||
252 | - | ||
253 | - *childp = NULL; | ||
254 | } | 151 | } |
255 | 152 | ||
256 | /* | 153 | -static void coroutine_fn raw_co_lock_medium(BlockDriverState *bs, bool locked) |
257 | @@ -XXX,XX +XXX,XX @@ static int bdrv_replace_node_noperm(BlockDriverState *from, | 154 | +static void coroutine_fn GRAPH_RDLOCK |
258 | * Passing a pointer to the local variable @c is fine here, because | 155 | +raw_co_lock_medium(BlockDriverState *bs, bool locked) |
259 | * @to is not NULL, and so &c will not be attached to the transaction. | 156 | { |
260 | */ | 157 | bdrv_co_lock_medium(bs->file->bs, locked); |
261 | - bdrv_replace_child_tran(&c, to, tran); | 158 | } |
262 | + bdrv_replace_child_tran(&c, to, tran, true); | ||
263 | } | ||
264 | |||
265 | return 0; | ||
266 | @@ -XXX,XX +XXX,XX @@ int bdrv_replace_child_bs(BdrvChild *child, BlockDriverState *new_bs, | ||
267 | bdrv_drained_begin(old_bs); | ||
268 | bdrv_drained_begin(new_bs); | ||
269 | |||
270 | - bdrv_replace_child_tran(&child, new_bs, tran); | ||
271 | + bdrv_replace_child_tran(&child, new_bs, tran, true); | ||
272 | + /* @new_bs must have been non-NULL, so @child must not have been freed */ | ||
273 | + assert(child != NULL); | ||
274 | |||
275 | found = g_hash_table_new(NULL, NULL); | ||
276 | refresh_list = bdrv_topological_dfs(refresh_list, found, old_bs); | ||
277 | -- | 159 | -- |
278 | 2.31.1 | 160 | 2.39.2 |
279 | |||
280 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | This adds GRAPH_RDLOCK annotations to declare that callers of | ||
2 | bdrv_register_buf() and bdrv_unregister_buf() need to hold a reader lock | ||
3 | for the graph. | ||
1 | 4 | ||
5 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
6 | Message-Id: <20230203152202.49054-21-kwolf@redhat.com> | ||
7 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
8 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
9 | --- | ||
10 | include/block/block_int-common.h | 7 ++++--- | ||
11 | block/io.c | 14 ++++++++++---- | ||
12 | 2 files changed, 14 insertions(+), 7 deletions(-) | ||
13 | |||
14 | diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h | ||
15 | index XXXXXXX..XXXXXXX 100644 | ||
16 | --- a/include/block/block_int-common.h | ||
17 | +++ b/include/block/block_int-common.h | ||
18 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | ||
19 | * | ||
20 | * Returns: true on success, false on failure | ||
21 | */ | ||
22 | - bool (*bdrv_register_buf)(BlockDriverState *bs, void *host, size_t size, | ||
23 | - Error **errp); | ||
24 | - void (*bdrv_unregister_buf)(BlockDriverState *bs, void *host, size_t size); | ||
25 | + bool GRAPH_RDLOCK_PTR (*bdrv_register_buf)( | ||
26 | + BlockDriverState *bs, void *host, size_t size, Error **errp); | ||
27 | + void GRAPH_RDLOCK_PTR (*bdrv_unregister_buf)( | ||
28 | + BlockDriverState *bs, void *host, size_t size); | ||
29 | |||
30 | /* | ||
31 | * This field is modified only under the BQL, and is part of | ||
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 | -- | ||
75 | 2.39.2 | diff view generated by jsdifflib |
1 | From: Hanna Reitz <hreitz@redhat.com> | 1 | This adds GRAPH_RDLOCK annotations to declare that callers of |
---|---|---|---|
2 | bdrv_co_delete_file() need to hold a reader lock for the graph. | ||
2 | 3 | ||
3 | Now that bdrv_remove_empty_child() no longer removes the child from the | 4 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
4 | parent's children list but only checks that it is not in such a list, it | 5 | Message-Id: <20230203152202.49054-22-kwolf@redhat.com> |
5 | is only a wrapper around bdrv_child_free() that checks that the child is | 6 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
6 | empty and unused. That should apply to all children that we free, so | ||
7 | put those checks into bdrv_child_free() and drop | ||
8 | bdrv_remove_empty_child(). | ||
9 | |||
10 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
11 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
12 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
13 | Message-Id: <20211111120829.81329-4-hreitz@redhat.com> | ||
14 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
15 | --- | 8 | --- |
16 | block.c | 26 +++++++++++++------------- | 9 | include/block/block-io.h | 8 ++++++-- |
17 | 1 file changed, 13 insertions(+), 13 deletions(-) | 10 | include/block/block_int-common.h | 4 ++-- |
11 | block.c | 1 + | ||
12 | 3 files changed, 9 insertions(+), 4 deletions(-) | ||
18 | 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 | ||
19 | diff --git a/block.c b/block.c | 48 | diff --git a/block.c b/block.c |
20 | index XXXXXXX..XXXXXXX 100644 | 49 | index XXXXXXX..XXXXXXX 100644 |
21 | --- a/block.c | 50 | --- a/block.c |
22 | +++ b/block.c | 51 | +++ b/block.c |
23 | @@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_noperm(BdrvChild *child, | 52 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_delete_file(BlockDriverState *bs, Error **errp) |
24 | } | 53 | |
25 | } | 54 | IO_CODE(); |
26 | 55 | assert(bs != NULL); | |
27 | -static void bdrv_child_free(void *opaque) | 56 | + assert_bdrv_graph_readable(); |
28 | -{ | 57 | |
29 | - BdrvChild *c = opaque; | 58 | if (!bs->drv) { |
30 | - | 59 | error_setg(errp, "Block node '%s' is not opened", bs->filename); |
31 | - g_free(c->name); | ||
32 | - g_free(c); | ||
33 | -} | ||
34 | - | ||
35 | -static void bdrv_remove_empty_child(BdrvChild *child) | ||
36 | +/** | ||
37 | + * Free the given @child. | ||
38 | + * | ||
39 | + * The child must be empty (i.e. `child->bs == NULL`) and it must be | ||
40 | + * unused (i.e. not in a children list). | ||
41 | + */ | ||
42 | +static void bdrv_child_free(BdrvChild *child) | ||
43 | { | ||
44 | assert(!child->bs); | ||
45 | assert(!child->next.le_prev); /* not in children list */ | ||
46 | - bdrv_child_free(child); | ||
47 | + | ||
48 | + g_free(child->name); | ||
49 | + g_free(child); | ||
50 | } | ||
51 | |||
52 | typedef struct BdrvAttachChildCommonState { | ||
53 | @@ -XXX,XX +XXX,XX @@ static void bdrv_attach_child_common_abort(void *opaque) | ||
54 | } | ||
55 | |||
56 | bdrv_unref(bs); | ||
57 | - bdrv_remove_empty_child(child); | ||
58 | + bdrv_child_free(child); | ||
59 | *s->child = NULL; | ||
60 | } | ||
61 | |||
62 | @@ -XXX,XX +XXX,XX @@ static int bdrv_attach_child_common(BlockDriverState *child_bs, | ||
63 | |||
64 | if (ret < 0) { | ||
65 | error_propagate(errp, local_err); | ||
66 | - bdrv_remove_empty_child(new_child); | ||
67 | + bdrv_child_free(new_child); | ||
68 | return ret; | ||
69 | } | ||
70 | } | ||
71 | @@ -XXX,XX +XXX,XX @@ static void bdrv_detach_child(BdrvChild *child) | ||
72 | BlockDriverState *old_bs = child->bs; | ||
73 | |||
74 | bdrv_replace_child_noperm(child, NULL); | ||
75 | - bdrv_remove_empty_child(child); | ||
76 | + bdrv_child_free(child); | ||
77 | |||
78 | if (old_bs) { | ||
79 | /* | ||
80 | -- | 60 | -- |
81 | 2.31.1 | 61 | 2.39.2 |
82 | |||
83 | diff view generated by jsdifflib |
1 | While introducing a non-QemuOpts code path for device creation for JSON | 1 | This adds GRAPH_RDLOCK annotations to declare that callers of |
---|---|---|---|
2 | -device, we noticed that QMP device_add doesn't check its input | 2 | bdrv_*_dirty_bitmap() need to hold a reader lock for the graph. |
3 | correctly (accepting arguments that should have been rejected), and that | ||
4 | users may be relying on this behaviour (libvirt did until it was fixed | ||
5 | recently). | ||
6 | |||
7 | Let's use a deprecation period before we fix this bug in QEMU to avoid | ||
8 | nasty surprises for users. | ||
9 | 3 | ||
10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 4 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
11 | Message-Id: <20211111143530.18985-1-kwolf@redhat.com> | 5 | Message-Id: <20230203152202.49054-23-kwolf@redhat.com> |
12 | Reviewed-by: Markus Armbruster <armbru@redhat.com> | 6 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
13 | Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> | ||
14 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
15 | --- | 8 | --- |
16 | docs/about/deprecated.rst | 14 ++++++++++++++ | 9 | include/block/block-io.h | 14 ++++++-------- |
17 | 1 file changed, 14 insertions(+) | 10 | include/block/block_int-common.h | 6 ++++-- |
11 | include/block/dirty-bitmap.h | 12 ++++++------ | ||
12 | block/dirty-bitmap.c | 2 ++ | ||
13 | 4 files changed, 18 insertions(+), 16 deletions(-) | ||
18 | 14 | ||
19 | diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst | 15 | diff --git a/include/block/block-io.h b/include/block/block-io.h |
20 | index XXXXXXX..XXXXXXX 100644 | 16 | index XXXXXXX..XXXXXXX 100644 |
21 | --- a/docs/about/deprecated.rst | 17 | --- a/include/block/block-io.h |
22 | +++ b/docs/about/deprecated.rst | 18 | +++ b/include/block/block-io.h |
23 | @@ -XXX,XX +XXX,XX @@ options are removed in favor of using explicit ``blockdev-create`` and | 19 | @@ -XXX,XX +XXX,XX @@ AioContext *child_of_bds_get_parent_aio_context(BdrvChild *c); |
24 | ``blockdev-add`` calls. See :doc:`/interop/live-block-operations` for | 20 | void coroutine_fn GRAPH_RDLOCK bdrv_co_io_plug(BlockDriverState *bs); |
25 | details. | 21 | void coroutine_fn GRAPH_RDLOCK bdrv_co_io_unplug(BlockDriverState *bs); |
26 | 22 | ||
27 | +Incorrectly typed ``device_add`` arguments (since 6.2) | 23 | -bool coroutine_fn bdrv_co_can_store_new_dirty_bitmap(BlockDriverState *bs, |
28 | +'''''''''''''''''''''''''''''''''''''''''''''''''''''' | 24 | - const char *name, |
25 | - uint32_t granularity, | ||
26 | - Error **errp); | ||
27 | -bool co_wrapper bdrv_can_store_new_dirty_bitmap(BlockDriverState *bs, | ||
28 | - const char *name, | ||
29 | - uint32_t granularity, | ||
30 | - Error **errp); | ||
31 | +bool coroutine_fn GRAPH_RDLOCK | ||
32 | +bdrv_co_can_store_new_dirty_bitmap(BlockDriverState *bs, const char *name, | ||
33 | + uint32_t granularity, Error **errp); | ||
34 | +bool co_wrapper_bdrv_rdlock | ||
35 | +bdrv_can_store_new_dirty_bitmap(BlockDriverState *bs, const char *name, | ||
36 | + uint32_t granularity, Error **errp); | ||
37 | |||
38 | /** | ||
39 | * | ||
40 | diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h | ||
41 | index XXXXXXX..XXXXXXX 100644 | ||
42 | --- a/include/block/block_int-common.h | ||
43 | +++ b/include/block/block_int-common.h | ||
44 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | ||
45 | void (*bdrv_drain_end)(BlockDriverState *bs); | ||
46 | |||
47 | bool (*bdrv_supports_persistent_dirty_bitmap)(BlockDriverState *bs); | ||
48 | - bool coroutine_fn (*bdrv_co_can_store_new_dirty_bitmap)( | ||
29 | + | 49 | + |
30 | +Due to shortcomings in the internal implementation of ``device_add``, QEMU | 50 | + bool coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_can_store_new_dirty_bitmap)( |
31 | +incorrectly accepts certain invalid arguments: Any object or list arguments are | 51 | BlockDriverState *bs, const char *name, uint32_t granularity, |
32 | +silently ignored. Other argument types are not checked, but an implicit | 52 | Error **errp); |
33 | +conversion happens, so that e.g. string values can be assigned to integer | 53 | - int coroutine_fn (*bdrv_co_remove_persistent_dirty_bitmap)( |
34 | +device properties or vice versa. | ||
35 | + | 54 | + |
36 | +This is a bug in QEMU that will be fixed in the future so that previously | 55 | + int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_remove_persistent_dirty_bitmap)( |
37 | +accepted incorrect commands will return an error. Users should make sure that | 56 | BlockDriverState *bs, const char *name, Error **errp); |
38 | +all arguments passed to ``device_add`` are consistent with the documented | 57 | }; |
39 | +property types. | 58 | |
40 | + | 59 | diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h |
41 | System accelerators | 60 | index XXXXXXX..XXXXXXX 100644 |
42 | ------------------- | 61 | --- a/include/block/dirty-bitmap.h |
43 | 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, | ||
44 | -- | 102 | -- |
45 | 2.31.1 | 103 | 2.39.2 |
46 | |||
47 | diff view generated by jsdifflib |
1 | From: Hanna Reitz <hreitz@redhat.com> | 1 | This adds GRAPH_RDLOCK annotations to declare that callers of |
---|---|---|---|
2 | bdrv_co_refresh_total_sectors() need to hold a reader lock for the | ||
3 | graph. | ||
2 | 4 | ||
3 | As of a future patch, bdrv_replace_child_tran() will take a BdrvChild ** | 5 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
4 | pointer. Prepare for that by getting such a pointer and using it where | 6 | Message-Id: <20230203152202.49054-24-kwolf@redhat.com> |
5 | applicable, and (dereferenced) as a parameter for | 7 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
6 | bdrv_replace_child_tran(). | ||
7 | |||
8 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
9 | Message-Id: <20211111120829.81329-7-hreitz@redhat.com> | ||
10 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 8 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
12 | --- | 9 | --- |
13 | block.c | 21 ++++++++++++--------- | 10 | include/block/block-io.h | 8 ++++---- |
14 | 1 file changed, 12 insertions(+), 9 deletions(-) | 11 | include/block/block_int-common.h | 4 +++- |
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(-) | ||
15 | 29 | ||
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); | ||
16 | diff --git a/block.c b/block.c | 83 | diff --git a/block.c b/block.c |
17 | index XXXXXXX..XXXXXXX 100644 | 84 | index XXXXXXX..XXXXXXX 100644 |
18 | --- a/block.c | 85 | --- a/block.c |
19 | +++ b/block.c | 86 | +++ b/block.c |
20 | @@ -XXX,XX +XXX,XX @@ static void bdrv_remove_file_or_backing_child(BlockDriverState *bs, | 87 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_refresh_total_sectors(BlockDriverState *bs, |
21 | BdrvChild *child, | 88 | { |
22 | Transaction *tran) | 89 | BlockDriver *drv = bs->drv; |
23 | { | 90 | IO_CODE(); |
24 | + BdrvChild **childp; | 91 | + assert_bdrv_graph_readable(); |
25 | BdrvRemoveFilterOrCowChild *s; | 92 | |
26 | 93 | if (!drv) { | |
27 | - assert(child == bs->backing || child == bs->file); | 94 | return -ENOMEDIUM; |
28 | - | 95 | @@ -XXX,XX +XXX,XX @@ int64_t coroutine_fn bdrv_co_nb_sectors(BlockDriverState *bs) |
29 | if (!child) { | 96 | { |
30 | return; | 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; | ||
117 | } | ||
118 | |||
119 | -static int64_t coroutine_fn blkdebug_co_getlength(BlockDriverState *bs) | ||
120 | +static int64_t coroutine_fn GRAPH_RDLOCK | ||
121 | +blkdebug_co_getlength(BlockDriverState *bs) | ||
122 | { | ||
123 | return bdrv_co_getlength(bs->file->bs); | ||
124 | } | ||
125 | diff --git a/block/blklogwrites.c b/block/blklogwrites.c | ||
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; | ||
31 | } | 214 | } |
32 | 215 | ||
33 | + if (child == bs->backing) { | 216 | + bdrv_graph_co_rdlock(); |
34 | + childp = &bs->backing; | 217 | s->bdev_length = bdrv_co_getlength(bs); |
35 | + } else if (child == bs->file) { | 218 | + bdrv_graph_co_rdunlock(); |
36 | + childp = &bs->file; | ||
37 | + } else { | ||
38 | + g_assert_not_reached(); | ||
39 | + } | ||
40 | + | 219 | + |
41 | if (child->bs) { | 220 | if (s->bdev_length < 0) { |
42 | - bdrv_replace_child_tran(child, NULL, tran); | 221 | ret = s->bdev_length; |
43 | + bdrv_replace_child_tran(*childp, NULL, tran); | 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; | ||
44 | } | 285 | } |
45 | 286 | ||
46 | s = g_new(BdrvRemoveFilterOrCowChild, 1); | 287 | - len = bdrv_getlength(s->target_bs); |
47 | *s = (BdrvRemoveFilterOrCowChild) { | 288 | - if (len < 0) { |
48 | .child = child, | 289 | - return len; |
49 | - .is_backing = (child == bs->backing), | 290 | + WITH_GRAPH_RDLOCK_GUARD() { |
50 | + .is_backing = (childp == &bs->backing), | 291 | + len = bdrv_co_getlength(s->target_bs); |
51 | }; | 292 | + if (len < 0) { |
52 | tran_add(tran, &bdrv_remove_filter_or_cow_child_drv, s); | 293 | + return len; |
53 | 294 | + } | |
54 | - if (s->is_backing) { | 295 | } |
55 | - bs->backing = NULL; | 296 | job_progress_set_remaining(&s->common.job, len); |
56 | - } else { | 297 | |
57 | - bs->file = NULL; | 298 | diff --git a/block/throttle.c b/block/throttle.c |
58 | - } | 299 | index XXXXXXX..XXXXXXX 100644 |
59 | + *childp = NULL; | 300 | --- a/block/throttle.c |
60 | } | 301 | +++ b/block/throttle.c |
61 | 302 | @@ -XXX,XX +XXX,XX @@ static void throttle_close(BlockDriverState *bs) | |
62 | /* | 303 | } |
304 | |||
305 | |||
306 | -static int64_t coroutine_fn throttle_co_getlength(BlockDriverState *bs) | ||
307 | +static int64_t coroutine_fn GRAPH_RDLOCK | ||
308 | +throttle_co_getlength(BlockDriverState *bs) | ||
309 | { | ||
310 | return bdrv_co_getlength(bs->file->bs); | ||
311 | } | ||
63 | -- | 312 | -- |
64 | 2.31.1 | 313 | 2.39.2 |
65 | |||
66 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Stefan Hajnoczi <stefanha@redhat.com> | ||
1 | 2 | ||
3 | If requests are being processed in the IOThread when a SCSIDevice is | ||
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 | |||
9 | Protect r->req.aiocb with the AioContext lock to prevent the race. | ||
10 | |||
11 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
12 | 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> | ||
16 | --- | ||
17 | hw/scsi/scsi-disk.c | 23 ++++++++++++++++------- | ||
18 | hw/scsi/scsi-generic.c | 11 ++++++----- | ||
19 | 2 files changed, 22 insertions(+), 12 deletions(-) | ||
20 | |||
21 | diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c | ||
22 | index XXXXXXX..XXXXXXX 100644 | ||
23 | --- a/hw/scsi/scsi-disk.c | ||
24 | +++ b/hw/scsi/scsi-disk.c | ||
25 | @@ -XXX,XX +XXX,XX @@ static void scsi_aio_complete(void *opaque, int ret) | ||
26 | SCSIDiskReq *r = (SCSIDiskReq *)opaque; | ||
27 | SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); | ||
28 | |||
29 | + aio_context_acquire(blk_get_aio_context(s->qdev.conf.blk)); | ||
30 | + | ||
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 | -- | ||
162 | 2.39.2 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Stefan Hajnoczi <stefanha@redhat.com> | ||
1 | 2 | ||
3 | dma_blk_cb() only takes the AioContext lock around ->io_func(). That | ||
4 | means the rest of dma_blk_cb() is not protected. In particular, the | ||
5 | DMAAIOCB field accesses happen outside the lock. | ||
6 | |||
7 | There is a race when the main loop thread holds the AioContext lock and | ||
8 | invokes scsi_device_purge_requests() -> bdrv_aio_cancel() -> | ||
9 | dma_aio_cancel() while an IOThread executes dma_blk_cb(). The dbs->acb | ||
10 | field determines how cancellation proceeds. If dma_aio_cancel() sees | ||
11 | dbs->acb == NULL while dma_blk_cb() is still running, the request can be | ||
12 | completed twice (-ECANCELED and the actual return value). | ||
13 | |||
14 | The following assertion can occur with virtio-scsi when an IOThread is | ||
15 | used: | ||
16 | |||
17 | ../hw/scsi/scsi-disk.c:368: scsi_dma_complete: Assertion `r->req.aiocb != NULL' failed. | ||
18 | |||
19 | Fix the race by holding the AioContext across dma_blk_cb(). Now | ||
20 | dma_aio_cancel() under the AioContext lock will not see | ||
21 | inconsistent/intermediate states. | ||
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 | --- | ||
29 | hw/scsi/scsi-disk.c | 4 +--- | ||
30 | softmmu/dma-helpers.c | 12 +++++++----- | ||
31 | 2 files changed, 8 insertions(+), 8 deletions(-) | ||
32 | |||
33 | diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c | ||
34 | index XXXXXXX..XXXXXXX 100644 | ||
35 | --- a/hw/scsi/scsi-disk.c | ||
36 | +++ b/hw/scsi/scsi-disk.c | ||
37 | @@ -XXX,XX +XXX,XX @@ done: | ||
38 | scsi_req_unref(&r->req); | ||
39 | } | ||
40 | |||
41 | +/* Called with AioContext lock held */ | ||
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 | -- | ||
112 | 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 | Reported by Coverity (CID 1465222). | 3 | When an IOThread is configured, the ctrl virtqueue is processed in the |
4 | 4 | IOThread. TMFs that reset SCSI devices are currently called directly | |
5 | Fixes: 4a1d937796de0fecd8b22d7dbebf87f38e8282fd ("softmmu/qdev-monitor: add error handling in qdev_set_id") | 5 | from the IOThread and trigger an assertion failure in blk_drain() from |
6 | Cc: Damien Hedde <damien.hedde@greensocs.com> | 6 | the following call stack: |
7 | Cc: Kevin Wolf <kwolf@redhat.com> | 7 | |
8 | Cc: Michael S. Tsirkin <mst@redhat.com> | 8 | virtio_scsi_handle_ctrl_req -> virtio_scsi_do_tmf -> device_code_reset |
9 | -> scsi_disk_reset -> scsi_device_purge_requests -> blk_drain | ||
10 | |||
11 | ../block/block-backend.c:1780: void blk_drain(BlockBackend *): Assertion `qemu_in_main_thread()' failed. | ||
12 | |||
13 | The blk_drain() function is not designed to be called from an IOThread | ||
14 | because it needs the Big QEMU Lock (BQL). | ||
15 | |||
16 | This patch defers TMFs that reset SCSI devices to a Bottom Half (BH) | ||
17 | that runs in the main loop thread under the BQL. This way it's safe to | ||
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> | ||
9 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> | 36 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> |
10 | Message-Id: <20211102163342.31162-1-stefanha@redhat.com> | 37 | Message-Id: <20230221212218.1378734-4-stefanha@redhat.com> |
11 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
12 | Reviewed-by: Michael S. Tsirkin <mst@redhat.com> | ||
13 | Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> | ||
14 | Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com> | ||
15 | Reviewed-by: Damien Hedde <damien.hedde@greensocs.com> | ||
16 | Reviewed-by: Markus Armbruster <armbru@redhat.com> | ||
17 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 38 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
18 | --- | 39 | --- |
19 | softmmu/qdev-monitor.c | 2 +- | 40 | include/hw/virtio/virtio-scsi.h | 11 ++- |
20 | 1 file changed, 1 insertion(+), 1 deletion(-) | 41 | hw/scsi/virtio-scsi.c | 169 +++++++++++++++++++++++++------- |
21 | 42 | 2 files changed, 143 insertions(+), 37 deletions(-) | |
22 | diff --git a/softmmu/qdev-monitor.c b/softmmu/qdev-monitor.c | 43 | |
44 | diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h | ||
23 | index XXXXXXX..XXXXXXX 100644 | 45 | index XXXXXXX..XXXXXXX 100644 |
24 | --- a/softmmu/qdev-monitor.c | 46 | --- a/include/hw/virtio/virtio-scsi.h |
25 | +++ b/softmmu/qdev-monitor.c | 47 | +++ b/include/hw/virtio/virtio-scsi.h |
26 | @@ -XXX,XX +XXX,XX @@ const char *qdev_set_id(DeviceState *dev, char *id, Error **errp) | 48 | @@ -XXX,XX +XXX,XX @@ struct VirtIOSCSICommon { |
27 | if (prop) { | 49 | VirtQueue **cmd_vqs; |
28 | dev->id = id; | 50 | }; |
29 | } else { | 51 | |
30 | - g_free(id); | 52 | +struct VirtIOSCSIReq; |
31 | error_setg(errp, "Duplicate device ID '%s'", id); | 53 | + |
32 | + g_free(id); | 54 | struct VirtIOSCSI { |
33 | return NULL; | 55 | VirtIOSCSICommon parent_obj; |
56 | |||
57 | SCSIBus bus; | ||
58 | - int resetting; | ||
59 | + int resetting; /* written from main loop thread, read from any thread */ | ||
60 | bool events_dropped; | ||
61 | |||
62 | + /* | ||
63 | + * TMFs deferred to main loop BH. These fields are protected by | ||
64 | + * virtio_scsi_acquire(). | ||
65 | + */ | ||
66 | + QEMUBH *tmf_bh; | ||
67 | + QTAILQ_HEAD(, VirtIOSCSIReq) tmf_bh_list; | ||
68 | + | ||
69 | /* Fields for dataplane below */ | ||
70 | AioContext *ctx; /* one iothread per virtio-scsi-pci for now */ | ||
71 | |||
72 | diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c | ||
73 | index XXXXXXX..XXXXXXX 100644 | ||
74 | --- a/hw/scsi/virtio-scsi.c | ||
75 | +++ b/hw/scsi/virtio-scsi.c | ||
76 | @@ -XXX,XX +XXX,XX @@ typedef struct VirtIOSCSIReq { | ||
77 | QEMUSGList qsgl; | ||
78 | QEMUIOVector resp_iov; | ||
79 | |||
80 | - union { | ||
81 | - /* Used for two-stage request submission */ | ||
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 | - } | ||
233 | - if (d->lun != virtio_scsi_get_lun(req->req.tmf.lun)) { | ||
234 | - goto incorrect_lun; | ||
235 | - } | ||
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) | ||
34 | } | 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; | ||
35 | } else { | 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 | } | ||
36 | -- | 310 | -- |
37 | 2.31.1 | 311 | 2.39.2 |
38 | |||
39 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Or Ozeri <oro@il.ibm.com> | ||
1 | 2 | ||
3 | Signed-off-by: Or Ozeri <oro@il.ibm.com> | ||
4 | Message-Id: <20230129113120.722708-2-oro@oro.sl.cloud9.ibm.com> | ||
5 | Reviewed-by: Ilya Dryomov <idryomov@gmail.com> | ||
6 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
8 | --- | ||
9 | block/rbd.c | 16 ++++++---------- | ||
10 | 1 file changed, 6 insertions(+), 10 deletions(-) | ||
11 | |||
12 | diff --git a/block/rbd.c b/block/rbd.c | ||
13 | index XXXXXXX..XXXXXXX 100644 | ||
14 | --- a/block/rbd.c | ||
15 | +++ b/block/rbd.c | ||
16 | @@ -XXX,XX +XXX,XX @@ static int qemu_rbd_encryption_format(rbd_image_t image, | ||
17 | { | ||
18 | int r = 0; | ||
19 | g_autofree char *passphrase = NULL; | ||
20 | - size_t passphrase_len; | ||
21 | rbd_encryption_format_t format; | ||
22 | rbd_encryption_options_t opts; | ||
23 | rbd_encryption_luks1_format_options_t luks_opts; | ||
24 | @@ -XXX,XX +XXX,XX @@ static int qemu_rbd_encryption_format(rbd_image_t image, | ||
25 | opts_size = sizeof(luks_opts); | ||
26 | r = qemu_rbd_convert_luks_create_options( | ||
27 | qapi_RbdEncryptionCreateOptionsLUKS_base(&encrypt->u.luks), | ||
28 | - &luks_opts.alg, &passphrase, &passphrase_len, errp); | ||
29 | + &luks_opts.alg, &passphrase, &luks_opts.passphrase_size, | ||
30 | + errp); | ||
31 | if (r < 0) { | ||
32 | return r; | ||
33 | } | ||
34 | luks_opts.passphrase = passphrase; | ||
35 | - luks_opts.passphrase_size = passphrase_len; | ||
36 | break; | ||
37 | } | ||
38 | case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS2: { | ||
39 | @@ -XXX,XX +XXX,XX @@ static int qemu_rbd_encryption_format(rbd_image_t image, | ||
40 | r = qemu_rbd_convert_luks_create_options( | ||
41 | qapi_RbdEncryptionCreateOptionsLUKS2_base( | ||
42 | &encrypt->u.luks2), | ||
43 | - &luks2_opts.alg, &passphrase, &passphrase_len, errp); | ||
44 | + &luks2_opts.alg, &passphrase, &luks2_opts.passphrase_size, | ||
45 | + errp); | ||
46 | if (r < 0) { | ||
47 | return r; | ||
48 | } | ||
49 | luks2_opts.passphrase = passphrase; | ||
50 | - luks2_opts.passphrase_size = passphrase_len; | ||
51 | break; | ||
52 | } | ||
53 | default: { | ||
54 | @@ -XXX,XX +XXX,XX @@ static int qemu_rbd_encryption_load(rbd_image_t image, | ||
55 | { | ||
56 | int r = 0; | ||
57 | g_autofree char *passphrase = NULL; | ||
58 | - size_t passphrase_len; | ||
59 | rbd_encryption_luks1_format_options_t luks_opts; | ||
60 | rbd_encryption_luks2_format_options_t luks2_opts; | ||
61 | rbd_encryption_format_t format; | ||
62 | @@ -XXX,XX +XXX,XX @@ static int qemu_rbd_encryption_load(rbd_image_t image, | ||
63 | opts_size = sizeof(luks_opts); | ||
64 | r = qemu_rbd_convert_luks_options( | ||
65 | qapi_RbdEncryptionOptionsLUKS_base(&encrypt->u.luks), | ||
66 | - &passphrase, &passphrase_len, errp); | ||
67 | + &passphrase, &luks_opts.passphrase_size, errp); | ||
68 | if (r < 0) { | ||
69 | return r; | ||
70 | } | ||
71 | luks_opts.passphrase = passphrase; | ||
72 | - luks_opts.passphrase_size = passphrase_len; | ||
73 | break; | ||
74 | } | ||
75 | case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS2: { | ||
76 | @@ -XXX,XX +XXX,XX @@ static int qemu_rbd_encryption_load(rbd_image_t image, | ||
77 | opts_size = sizeof(luks2_opts); | ||
78 | r = qemu_rbd_convert_luks_options( | ||
79 | qapi_RbdEncryptionOptionsLUKS2_base(&encrypt->u.luks2), | ||
80 | - &passphrase, &passphrase_len, errp); | ||
81 | + &passphrase, &luks2_opts.passphrase_size, errp); | ||
82 | if (r < 0) { | ||
83 | return r; | ||
84 | } | ||
85 | luks2_opts.passphrase = passphrase; | ||
86 | - luks2_opts.passphrase_size = passphrase_len; | ||
87 | break; | ||
88 | } | ||
89 | default: { | ||
90 | -- | ||
91 | 2.39.2 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Or Ozeri <oro@il.ibm.com> | ||
1 | 2 | ||
3 | Ceph RBD encryption API required specifying the encryption format | ||
4 | for loading encryption. The supported formats were LUKS (v1) and LUKS2. | ||
5 | |||
6 | Starting from Reef release, RBD also supports loading with "luks-any" format, | ||
7 | which works for both versions of LUKS. | ||
8 | |||
9 | This commit extends the qemu rbd driver API to enable qemu users to use | ||
10 | this luks-any wildcard format. | ||
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> | ||
17 | --- | ||
18 | qapi/block-core.json | 16 ++++++++++++++-- | ||
19 | block/rbd.c | 19 +++++++++++++++++++ | ||
20 | 2 files changed, 33 insertions(+), 2 deletions(-) | ||
21 | |||
22 | diff --git a/qapi/block-core.json b/qapi/block-core.json | ||
23 | index XXXXXXX..XXXXXXX 100644 | ||
24 | --- a/qapi/block-core.json | ||
25 | +++ b/qapi/block-core.json | ||
26 | @@ -XXX,XX +XXX,XX @@ | ||
27 | ## | ||
28 | # @RbdImageEncryptionFormat: | ||
29 | # | ||
30 | +# @luks-any: Used for opening either luks or luks2 (Since 8.0) | ||
31 | +# | ||
32 | # Since: 6.1 | ||
33 | ## | ||
34 | { 'enum': 'RbdImageEncryptionFormat', | ||
35 | - 'data': [ 'luks', 'luks2' ] } | ||
36 | + 'data': [ 'luks', 'luks2', 'luks-any' ] } | ||
37 | |||
38 | ## | ||
39 | # @RbdEncryptionOptionsLUKSBase: | ||
40 | @@ -XXX,XX +XXX,XX @@ | ||
41 | 'base': 'RbdEncryptionOptionsLUKSBase', | ||
42 | 'data': { } } | ||
43 | |||
44 | +## | ||
45 | +# @RbdEncryptionOptionsLUKSAny: | ||
46 | +# | ||
47 | +# Since: 8.0 | ||
48 | +## | ||
49 | +{ 'struct': 'RbdEncryptionOptionsLUKSAny', | ||
50 | + 'base': 'RbdEncryptionOptionsLUKSBase', | ||
51 | + 'data': { } } | ||
52 | + | ||
53 | ## | ||
54 | # @RbdEncryptionCreateOptionsLUKS: | ||
55 | # | ||
56 | @@ -XXX,XX +XXX,XX @@ | ||
57 | 'base': { 'format': 'RbdImageEncryptionFormat' }, | ||
58 | 'discriminator': 'format', | ||
59 | 'data': { 'luks': 'RbdEncryptionOptionsLUKS', | ||
60 | - 'luks2': 'RbdEncryptionOptionsLUKS2' } } | ||
61 | + 'luks2': 'RbdEncryptionOptionsLUKS2', | ||
62 | + 'luks-any': 'RbdEncryptionOptionsLUKSAny'} } | ||
63 | |||
64 | ## | ||
65 | # @RbdEncryptionCreateOptions: | ||
66 | diff --git a/block/rbd.c b/block/rbd.c | ||
67 | index XXXXXXX..XXXXXXX 100644 | ||
68 | --- a/block/rbd.c | ||
69 | +++ b/block/rbd.c | ||
70 | @@ -XXX,XX +XXX,XX @@ static int qemu_rbd_encryption_load(rbd_image_t image, | ||
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 | -- | ||
104 | 2.39.2 | diff view generated by jsdifflib |
1 | From: Hanna Reitz <hreitz@redhat.com> | 1 | From: Or Ozeri <oro@il.ibm.com> |
---|---|---|---|
2 | 2 | ||
3 | See the comment for why this is necessary. | 3 | Starting from ceph Reef, RBD has built-in support for layered encryption, |
4 | 4 | where each ancestor image (in a cloned image setting) can be possibly | |
5 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | 5 | encrypted using a unique passphrase. |
6 | Message-Id: <20211111120829.81329-11-hreitz@redhat.com> | 6 | |
7 | A new function, rbd_encryption_load2, was added to librbd API. | ||
8 | This new function supports an array of passphrases (via "spec" structs). | ||
9 | |||
10 | This commit extends the qemu rbd driver API to use this new librbd API, | ||
11 | in order to support this new layered encryption feature. | ||
12 | |||
13 | Signed-off-by: Or Ozeri <oro@il.ibm.com> | ||
14 | Message-Id: <20230129113120.722708-4-oro@oro.sl.cloud9.ibm.com> | ||
15 | Reviewed-by: Ilya Dryomov <idryomov@gmail.com> | ||
16 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 17 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
8 | --- | 18 | --- |
9 | tests/qemu-iotests/030 | 11 ++++++++++- | 19 | qapi/block-core.json | 11 +++- |
10 | 1 file changed, 10 insertions(+), 1 deletion(-) | 20 | block/rbd.c | 153 ++++++++++++++++++++++++++++++++++++++++++- |
11 | 21 | 2 files changed, 162 insertions(+), 2 deletions(-) | |
12 | diff --git a/tests/qemu-iotests/030 b/tests/qemu-iotests/030 | 22 | |
13 | index XXXXXXX..XXXXXXX 100755 | 23 | diff --git a/qapi/block-core.json b/qapi/block-core.json |
14 | --- a/tests/qemu-iotests/030 | 24 | index XXXXXXX..XXXXXXX 100644 |
15 | +++ b/tests/qemu-iotests/030 | 25 | --- a/qapi/block-core.json |
16 | @@ -XXX,XX +XXX,XX @@ class TestParallelOps(iotests.QMPTestCase): | 26 | +++ b/qapi/block-core.json |
17 | speed=1024) | 27 | @@ -XXX,XX +XXX,XX @@ |
18 | self.assert_qmp(result, 'return', {}) | 28 | ## |
19 | 29 | # @RbdEncryptionOptions: | |
20 | - for job in pending_jobs: | 30 | # |
21 | + # Do this in reverse: After unthrottling them, some jobs may finish | 31 | +# @format: Encryption format. |
22 | + # before we have unthrottled all of them. This will drain their | 32 | +# |
23 | + # subgraph, and this will make jobs above them advance (despite those | 33 | +# @parent: Parent image encryption options (for cloned images). |
24 | + # jobs on top being throttled). In the worst case, all jobs below the | 34 | +# Can be left unspecified if this cloned image is encrypted |
25 | + # top one are finished before we can unthrottle it, and this makes it | 35 | +# using the same format and secret as its parent image (i.e. |
26 | + # advance so far that it completes before we can unthrottle it - which | 36 | +# not explicitly formatted) or if its parent image is not |
27 | + # results in an error. | 37 | +# encrypted. (Since 8.0) |
28 | + # Starting from the top (i.e. in reverse) does not have this problem: | 38 | +# |
29 | + # When a job finishes, the ones below it are not advanced. | 39 | # Since: 6.1 |
30 | + for job in reversed(pending_jobs): | 40 | ## |
31 | result = self.vm.qmp('block-job-set-speed', device=job, speed=0) | 41 | { 'union': 'RbdEncryptionOptions', |
32 | self.assert_qmp(result, 'return', {}) | 42 | - 'base': { 'format': 'RbdImageEncryptionFormat' }, |
33 | 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 | ||
50 | --- a/block/rbd.c | ||
51 | +++ b/block/rbd.c | ||
52 | @@ -XXX,XX +XXX,XX @@ static const char rbd_luks2_header_verification[ | ||
53 | 'L', 'U', 'K', 'S', 0xBA, 0xBE, 0, 2 | ||
54 | }; | ||
55 | |||
56 | +static const char rbd_layered_luks_header_verification[ | ||
57 | + RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN] = { | ||
58 | + 'R', 'B', 'D', 'L', 0xBA, 0xBE, 0, 1 | ||
59 | +}; | ||
60 | + | ||
61 | +static const char rbd_layered_luks2_header_verification[ | ||
62 | + RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN] = { | ||
63 | + 'R', 'B', 'D', 'L', 0xBA, 0xBE, 0, 2 | ||
64 | +}; | ||
65 | + | ||
66 | typedef enum { | ||
67 | RBD_AIO_READ, | ||
68 | RBD_AIO_WRITE, | ||
69 | @@ -XXX,XX +XXX,XX @@ static int qemu_rbd_encryption_load(rbd_image_t image, | ||
70 | |||
71 | return 0; | ||
72 | } | ||
73 | + | ||
74 | +#ifdef LIBRBD_SUPPORTS_ENCRYPTION_LOAD2 | ||
75 | +static int qemu_rbd_encryption_load2(rbd_image_t image, | ||
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 | + | ||
88 | + /* count encryption options */ | ||
89 | + for (curr_encrypt = encrypt->parent; curr_encrypt; | ||
90 | + curr_encrypt = curr_encrypt->parent) { | ||
91 | + ++encrypt_count; | ||
92 | + } | ||
93 | + | ||
94 | + specs = g_new0(rbd_encryption_spec_t, encrypt_count); | ||
95 | + | ||
96 | + curr_encrypt = encrypt; | ||
97 | + for (i = 0; i < encrypt_count; ++i) { | ||
98 | + switch (curr_encrypt->format) { | ||
99 | + case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS: { | ||
100 | + specs[i].format = RBD_ENCRYPTION_FORMAT_LUKS1; | ||
101 | + | ||
102 | + luks_opts = g_new0(rbd_encryption_luks1_format_options_t, 1); | ||
103 | + specs[i].opts = luks_opts; | ||
104 | + specs[i].opts_size = sizeof(*luks_opts); | ||
105 | + | ||
106 | + r = qemu_rbd_convert_luks_options( | ||
107 | + qapi_RbdEncryptionOptionsLUKS_base( | ||
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 | + | ||
117 | + luks2_opts = g_new0(rbd_encryption_luks2_format_options_t, 1); | ||
118 | + specs[i].opts = luks2_opts; | ||
119 | + specs[i].opts_size = sizeof(*luks2_opts); | ||
120 | + | ||
121 | + r = qemu_rbd_convert_luks_options( | ||
122 | + qapi_RbdEncryptionOptionsLUKS2_base( | ||
123 | + &curr_encrypt->u.luks2), | ||
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 | + } | ||
151 | + | ||
152 | + if (r < 0) { | ||
153 | + goto exit; | ||
154 | + } | ||
155 | + | ||
156 | + curr_encrypt = curr_encrypt->parent; | ||
157 | + } | ||
158 | + | ||
159 | + r = rbd_encryption_load2(image, specs, encrypt_count); | ||
160 | + if (r < 0) { | ||
161 | + error_setg_errno(errp, -r, "layered encryption load fail"); | ||
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 | } | ||
34 | -- | 233 | -- |
35 | 2.31.1 | 234 | 2.39.2 |
36 | |||
37 | diff view generated by jsdifflib |