diff options
author | Kevin Wolf <kwolf@redhat.com> | 2023-10-27 17:53:17 +0200 |
---|---|---|
committer | Kevin Wolf <kwolf@redhat.com> | 2023-11-07 19:14:19 +0100 |
commit | ad74751fc0ffdad7678224df0e752689ebb3f4b7 (patch) | |
tree | 55eccd2af361e2a81f427b6db77106ebbb53cf3f /block | |
parent | 430da832afb6a6eebb7c1726991c60fb06322d3e (diff) |
block: Mark bdrv_skip_filters() and callers GRAPH_RDLOCK
This adds GRAPH_RDLOCK annotations to declare that callers of
bdrv_skip_filters() need to hold a reader lock for the graph because it
calls bdrv_filter_child(), which accesses bs->file/backing.
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Message-ID: <20231027155333.420094-9-kwolf@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Diffstat (limited to 'block')
-rw-r--r-- | block/block-backend.c | 1 | ||||
-rw-r--r-- | block/block-copy.c | 9 | ||||
-rw-r--r-- | block/commit.c | 5 | ||||
-rw-r--r-- | block/mirror.c | 34 | ||||
-rw-r--r-- | block/stream.c | 22 |
5 files changed, 51 insertions, 20 deletions
diff --git a/block/block-backend.c b/block/block-backend.c index 075a0dfa95..4053134781 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -2730,6 +2730,7 @@ int blk_commit_all(void) { BlockBackend *blk = NULL; GLOBAL_STATE_CODE(); + GRAPH_RDLOCK_GUARD_MAINLOOP(); while ((blk = blk_all_next(blk)) != NULL) { AioContext *aio_context = blk_get_aio_context(blk); diff --git a/block/block-copy.c b/block/block-copy.c index 1c60368d72..6b2be3d204 100644 --- a/block/block-copy.c +++ b/block/block-copy.c @@ -313,7 +313,12 @@ static int64_t block_copy_calculate_cluster_size(BlockDriverState *target, { int ret; BlockDriverInfo bdi; - bool target_does_cow = bdrv_backing_chain_next(target); + bool target_does_cow; + + GLOBAL_STATE_CODE(); + GRAPH_RDLOCK_GUARD_MAINLOOP(); + + target_does_cow = bdrv_backing_chain_next(target); /* * If there is no backing file on the target, we cannot rely on COW if our @@ -355,6 +360,8 @@ BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target, BdrvDirtyBitmap *copy_bitmap; bool is_fleecing; + GLOBAL_STATE_CODE(); + cluster_size = block_copy_calculate_cluster_size(target->bs, errp); if (cluster_size < 0) { return NULL; diff --git a/block/commit.c b/block/commit.c index fc3ad79749..05eb57d9ea 100644 --- a/block/commit.c +++ b/block/commit.c @@ -255,10 +255,13 @@ void commit_start(const char *job_id, BlockDriverState *bs, GLOBAL_STATE_CODE(); assert(top != bs); + bdrv_graph_rdlock_main_loop(); if (bdrv_skip_filters(top) == bdrv_skip_filters(base)) { error_setg(errp, "Invalid files for merge: top and base are the same"); + bdrv_graph_rdunlock_main_loop(); return; } + bdrv_graph_rdunlock_main_loop(); base_size = bdrv_getlength(base); if (base_size < 0) { @@ -324,6 +327,7 @@ void commit_start(const char *job_id, BlockDriverState *bs, * this is the responsibility of the interface (i.e. whoever calls * commit_start()). */ + bdrv_graph_wrlock(top); s->base_overlay = bdrv_find_overlay(top, base); assert(s->base_overlay); @@ -342,7 +346,6 @@ void commit_start(const char *job_id, BlockDriverState *bs, */ iter_shared_perms = BLK_PERM_WRITE_UNCHANGED | BLK_PERM_WRITE; - bdrv_graph_wrlock(top); for (iter = top; iter != base; iter = bdrv_filter_or_cow_bs(iter)) { if (iter == filtered_base) { /* diff --git a/block/mirror.c b/block/mirror.c index a03247a31b..75e826dac8 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -714,7 +714,6 @@ static int mirror_exit_common(Job *job) bdrv_graph_rdlock_main_loop(); bdrv_child_refresh_perms(mirror_top_bs, mirror_top_bs->backing, &error_abort); - bdrv_graph_rdunlock_main_loop(); if (!abort && s->backing_mode == MIRROR_SOURCE_BACKING_CHAIN) { BlockDriverState *backing = s->is_none_mode ? src : s->base; @@ -737,6 +736,7 @@ static int mirror_exit_common(Job *job) local_err = NULL; } } + bdrv_graph_rdunlock_main_loop(); if (s->to_replace) { replace_aio_context = bdrv_get_aio_context(s->to_replace); @@ -992,13 +992,13 @@ static int coroutine_fn mirror_run(Job *job, Error **errp) } else { s->target_cluster_size = BDRV_SECTOR_SIZE; } - bdrv_graph_co_rdunlock(); if (backing_filename[0] && !bdrv_backing_chain_next(target_bs) && s->granularity < s->target_cluster_size) { s->buf_size = MAX(s->buf_size, s->target_cluster_size); s->cow_bitmap = bitmap_new(length); } s->max_iov = MIN(bs->bl.max_iov, target_bs->bl.max_iov); + bdrv_graph_co_rdunlock(); s->buf = qemu_try_blockalign(bs, s->buf_size); if (s->buf == NULL) { @@ -1744,12 +1744,15 @@ static BlockJob *mirror_start_job( buf_size = DEFAULT_MIRROR_BUF_SIZE; } + bdrv_graph_rdlock_main_loop(); if (bdrv_skip_filters(bs) == bdrv_skip_filters(target)) { error_setg(errp, "Can't mirror node into itself"); + bdrv_graph_rdunlock_main_loop(); return NULL; } target_is_backing = bdrv_chain_contains(bs, target); + bdrv_graph_rdunlock_main_loop(); /* In the case of active commit, add dummy driver to provide consistent * reads on the top, while disabling it in the intermediate nodes, and make @@ -1832,14 +1835,19 @@ static BlockJob *mirror_start_job( } target_shared_perms |= BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE; - } else if (bdrv_chain_contains(bs, bdrv_skip_filters(target))) { - /* - * We may want to allow this in the future, but it would - * require taking some extra care. - */ - error_setg(errp, "Cannot mirror to a filter on top of a node in the " - "source's backing chain"); - goto fail; + } else { + bdrv_graph_rdlock_main_loop(); + if (bdrv_chain_contains(bs, bdrv_skip_filters(target))) { + /* + * We may want to allow this in the future, but it would + * require taking some extra care. + */ + error_setg(errp, "Cannot mirror to a filter on top of a node in " + "the source's backing chain"); + bdrv_graph_rdunlock_main_loop(); + goto fail; + } + bdrv_graph_rdunlock_main_loop(); } s->target = blk_new(s->common.job.aio_context, @@ -1860,6 +1868,7 @@ static BlockJob *mirror_start_job( blk_set_allow_aio_context_change(s->target, true); blk_set_disable_request_queuing(s->target, true); + bdrv_graph_rdlock_main_loop(); s->replaces = g_strdup(replaces); s->on_source_error = on_source_error; s->on_target_error = on_target_error; @@ -1875,6 +1884,7 @@ static BlockJob *mirror_start_job( if (auto_complete) { s->should_complete = true; } + bdrv_graph_rdunlock_main_loop(); s->dirty_bitmap = bdrv_create_dirty_bitmap(s->mirror_top_bs, granularity, NULL, errp); @@ -2007,8 +2017,12 @@ void mirror_start(const char *job_id, BlockDriverState *bs, MirrorSyncMode_str(mode)); return; } + + bdrv_graph_rdlock_main_loop(); is_none_mode = mode == MIRROR_SYNC_MODE_NONE; base = mode == MIRROR_SYNC_MODE_TOP ? bdrv_backing_chain_next(bs) : NULL; + bdrv_graph_rdunlock_main_loop(); + mirror_start_job(job_id, bs, creation_flags, target, replaces, speed, granularity, buf_size, backing_mode, zero_target, on_source_error, on_target_error, unmap, NULL, NULL, diff --git a/block/stream.c b/block/stream.c index 2781441191..5323a9976d 100644 --- a/block/stream.c +++ b/block/stream.c @@ -53,8 +53,8 @@ static int coroutine_fn stream_populate(BlockBackend *blk, static int stream_prepare(Job *job) { StreamBlockJob *s = container_of(job, StreamBlockJob, common.job); - BlockDriverState *unfiltered_bs = bdrv_skip_filters(s->target_bs); - BlockDriverState *unfiltered_bs_cow = bdrv_cow_bs(unfiltered_bs); + BlockDriverState *unfiltered_bs; + BlockDriverState *unfiltered_bs_cow; BlockDriverState *base; BlockDriverState *unfiltered_base; Error *local_err = NULL; @@ -62,6 +62,11 @@ static int stream_prepare(Job *job) GLOBAL_STATE_CODE(); + bdrv_graph_rdlock_main_loop(); + unfiltered_bs = bdrv_skip_filters(s->target_bs); + unfiltered_bs_cow = bdrv_cow_bs(unfiltered_bs); + bdrv_graph_rdunlock_main_loop(); + /* We should drop filter at this point, as filter hold the backing chain */ bdrv_cor_filter_drop(s->cor_filter_bs); s->cor_filter_bs = NULL; @@ -142,18 +147,19 @@ static void stream_clean(Job *job) static int coroutine_fn stream_run(Job *job, Error **errp) { StreamBlockJob *s = container_of(job, StreamBlockJob, common.job); - BlockDriverState *unfiltered_bs = bdrv_skip_filters(s->target_bs); + BlockDriverState *unfiltered_bs; int64_t len; int64_t offset = 0; int error = 0; int64_t n = 0; /* bytes */ - if (unfiltered_bs == s->base_overlay) { - /* Nothing to stream */ - return 0; - } - WITH_GRAPH_RDLOCK_GUARD() { + unfiltered_bs = bdrv_skip_filters(s->target_bs); + if (unfiltered_bs == s->base_overlay) { + /* Nothing to stream */ + return 0; + } + len = bdrv_co_getlength(s->target_bs); if (len < 0) { return len; |