aboutsummaryrefslogtreecommitdiff
path: root/block
diff options
context:
space:
mode:
authorKevin Wolf <kwolf@redhat.com>2023-10-27 17:53:17 +0200
committerKevin Wolf <kwolf@redhat.com>2023-11-07 19:14:19 +0100
commitad74751fc0ffdad7678224df0e752689ebb3f4b7 (patch)
tree55eccd2af361e2a81f427b6db77106ebbb53cf3f /block
parent430da832afb6a6eebb7c1726991c60fb06322d3e (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.c1
-rw-r--r--block/block-copy.c9
-rw-r--r--block/commit.c5
-rw-r--r--block/mirror.c34
-rw-r--r--block/stream.c22
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;