block: Take graph lock for most of .bdrv_open

Most implementations of .bdrv_open first open their file child (which is
an operation that internally takes the write lock and therefore we
shouldn't hold the graph lock while calling it), and afterwards many
operations that require holding the graph lock, e.g. for accessing
bs->file.

This changes block drivers that follow this pattern to take the graph
lock after opening the child node.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Message-ID: <20231027155333.420094-24-kwolf@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
master
Kevin Wolf 2023-10-27 17:53:32 +02:00
parent 65ff757df0
commit a4b740db5e
16 changed files with 60 additions and 20 deletions

View File

@ -508,6 +508,8 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
goto out; goto out;
} }
bdrv_graph_rdlock_main_loop();
bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED | bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED |
(BDRV_REQ_FUA & bs->file->bs->supported_write_flags); (BDRV_REQ_FUA & bs->file->bs->supported_write_flags);
bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED | bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED |
@ -520,7 +522,7 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
if (s->align && (s->align >= INT_MAX || !is_power_of_2(s->align))) { if (s->align && (s->align >= INT_MAX || !is_power_of_2(s->align))) {
error_setg(errp, "Cannot meet constraints with align %" PRIu64, error_setg(errp, "Cannot meet constraints with align %" PRIu64,
s->align); s->align);
goto out; goto out_rdlock;
} }
align = MAX(s->align, bs->file->bs->bl.request_alignment); align = MAX(s->align, bs->file->bs->bl.request_alignment);
@ -530,7 +532,7 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
!QEMU_IS_ALIGNED(s->max_transfer, align))) { !QEMU_IS_ALIGNED(s->max_transfer, align))) {
error_setg(errp, "Cannot meet constraints with max-transfer %" PRIu64, error_setg(errp, "Cannot meet constraints with max-transfer %" PRIu64,
s->max_transfer); s->max_transfer);
goto out; goto out_rdlock;
} }
s->opt_write_zero = qemu_opt_get_size(opts, "opt-write-zero", 0); s->opt_write_zero = qemu_opt_get_size(opts, "opt-write-zero", 0);
@ -539,7 +541,7 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
!QEMU_IS_ALIGNED(s->opt_write_zero, align))) { !QEMU_IS_ALIGNED(s->opt_write_zero, align))) {
error_setg(errp, "Cannot meet constraints with opt-write-zero %" PRIu64, error_setg(errp, "Cannot meet constraints with opt-write-zero %" PRIu64,
s->opt_write_zero); s->opt_write_zero);
goto out; goto out_rdlock;
} }
s->max_write_zero = qemu_opt_get_size(opts, "max-write-zero", 0); s->max_write_zero = qemu_opt_get_size(opts, "max-write-zero", 0);
@ -549,7 +551,7 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
MAX(s->opt_write_zero, align)))) { MAX(s->opt_write_zero, align)))) {
error_setg(errp, "Cannot meet constraints with max-write-zero %" PRIu64, error_setg(errp, "Cannot meet constraints with max-write-zero %" PRIu64,
s->max_write_zero); s->max_write_zero);
goto out; goto out_rdlock;
} }
s->opt_discard = qemu_opt_get_size(opts, "opt-discard", 0); s->opt_discard = qemu_opt_get_size(opts, "opt-discard", 0);
@ -558,7 +560,7 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
!QEMU_IS_ALIGNED(s->opt_discard, align))) { !QEMU_IS_ALIGNED(s->opt_discard, align))) {
error_setg(errp, "Cannot meet constraints with opt-discard %" PRIu64, error_setg(errp, "Cannot meet constraints with opt-discard %" PRIu64,
s->opt_discard); s->opt_discard);
goto out; goto out_rdlock;
} }
s->max_discard = qemu_opt_get_size(opts, "max-discard", 0); s->max_discard = qemu_opt_get_size(opts, "max-discard", 0);
@ -568,12 +570,14 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
MAX(s->opt_discard, align)))) { MAX(s->opt_discard, align)))) {
error_setg(errp, "Cannot meet constraints with max-discard %" PRIu64, error_setg(errp, "Cannot meet constraints with max-discard %" PRIu64,
s->max_discard); s->max_discard);
goto out; goto out_rdlock;
} }
bdrv_debug_event(bs, BLKDBG_NONE); bdrv_debug_event(bs, BLKDBG_NONE);
ret = 0; ret = 0;
out_rdlock:
bdrv_graph_rdunlock_main_loop();
out: out:
if (ret < 0) { if (ret < 0) {
qemu_mutex_destroy(&s->lock); qemu_mutex_destroy(&s->lock);

View File

@ -105,6 +105,8 @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags,
struct bochs_header bochs; struct bochs_header bochs;
int ret; int ret;
GLOBAL_STATE_CODE();
/* No write support yet */ /* No write support yet */
bdrv_graph_rdlock_main_loop(); bdrv_graph_rdlock_main_loop();
ret = bdrv_apply_auto_read_only(bs, NULL, errp); ret = bdrv_apply_auto_read_only(bs, NULL, errp);
@ -118,6 +120,8 @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags,
return ret; return ret;
} }
GRAPH_RDLOCK_GUARD_MAINLOOP();
ret = bdrv_pread(bs->file, 0, sizeof(bochs), &bochs, 0); ret = bdrv_pread(bs->file, 0, sizeof(bochs), &bochs, 0);
if (ret < 0) { if (ret < 0) {
return ret; return ret;

View File

@ -67,6 +67,8 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
uint32_t offsets_size, max_compressed_block_size = 1, i; uint32_t offsets_size, max_compressed_block_size = 1, i;
int ret; int ret;
GLOBAL_STATE_CODE();
bdrv_graph_rdlock_main_loop(); bdrv_graph_rdlock_main_loop();
ret = bdrv_apply_auto_read_only(bs, NULL, errp); ret = bdrv_apply_auto_read_only(bs, NULL, errp);
bdrv_graph_rdunlock_main_loop(); bdrv_graph_rdunlock_main_loop();
@ -79,6 +81,8 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
return ret; return ret;
} }
GRAPH_RDLOCK_GUARD_MAINLOOP();
/* read header */ /* read header */
ret = bdrv_pread(bs->file, 128, 4, &s->block_size, 0); ret = bdrv_pread(bs->file, 128, 4, &s->block_size, 0);
if (ret < 0) { if (ret < 0) {

View File

@ -433,6 +433,8 @@ static int cbw_open(BlockDriverState *bs, QDict *options, int flags,
return -EINVAL; return -EINVAL;
} }
GRAPH_RDLOCK_GUARD_MAINLOOP();
ctx = bdrv_get_aio_context(bs); ctx = bdrv_get_aio_context(bs);
aio_context_acquire(ctx); aio_context_acquire(ctx);

View File

@ -51,6 +51,8 @@ cor_open(BlockDriverState *bs, QDict *options, int flags, Error **errp)
return ret; return ret;
} }
GRAPH_RDLOCK_GUARD_MAINLOOP();
bs->supported_read_flags = BDRV_REQ_PREFETCH; bs->supported_read_flags = BDRV_REQ_PREFETCH;
bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED | bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED |
@ -61,8 +63,6 @@ cor_open(BlockDriverState *bs, QDict *options, int flags, Error **errp)
bs->file->bs->supported_zero_flags); bs->file->bs->supported_zero_flags);
if (bottom_node) { if (bottom_node) {
GRAPH_RDLOCK_GUARD_MAINLOOP();
bottom_bs = bdrv_find_node(bottom_node); bottom_bs = bdrv_find_node(bottom_node);
if (!bottom_bs) { if (!bottom_bs) {
error_setg(errp, "Bottom node '%s' not found", bottom_node); error_setg(errp, "Bottom node '%s' not found", bottom_node);

View File

@ -263,11 +263,15 @@ static int block_crypto_open_generic(QCryptoBlockFormat format,
unsigned int cflags = 0; unsigned int cflags = 0;
QDict *cryptoopts = NULL; QDict *cryptoopts = NULL;
GLOBAL_STATE_CODE();
ret = bdrv_open_file_child(NULL, options, "file", bs, errp); ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }
GRAPH_RDLOCK_GUARD_MAINLOOP();
bs->supported_write_flags = BDRV_REQ_FUA & bs->supported_write_flags = BDRV_REQ_FUA &
bs->file->bs->supported_write_flags; bs->file->bs->supported_write_flags;

View File

@ -452,6 +452,8 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
int64_t offset; int64_t offset;
int ret; int ret;
GLOBAL_STATE_CODE();
bdrv_graph_rdlock_main_loop(); bdrv_graph_rdlock_main_loop();
ret = bdrv_apply_auto_read_only(bs, NULL, errp); ret = bdrv_apply_auto_read_only(bs, NULL, errp);
bdrv_graph_rdunlock_main_loop(); bdrv_graph_rdunlock_main_loop();
@ -463,6 +465,9 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }
GRAPH_RDLOCK_GUARD_MAINLOOP();
/* /*
* NB: if uncompress submodules are absent, * NB: if uncompress submodules are absent,
* ie block_module_load return value == 0, the function pointers * ie block_module_load return value == 0, the function pointers

View File

@ -36,6 +36,8 @@ static int compress_open(BlockDriverState *bs, QDict *options, int flags,
return ret; return ret;
} }
GRAPH_RDLOCK_GUARD_MAINLOOP();
if (!bs->file->bs->drv || !block_driver_can_compress(bs->file->bs->drv)) { if (!bs->file->bs->drv || !block_driver_can_compress(bs->file->bs->drv)) {
error_setg(errp, error_setg(errp,
"Compression is not supported for underlying format: %s", "Compression is not supported for underlying format: %s",

View File

@ -1255,6 +1255,8 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
return ret; return ret;
} }
GRAPH_RDLOCK_GUARD_MAINLOOP();
file_nb_sectors = bdrv_nb_sectors(bs->file->bs); file_nb_sectors = bdrv_nb_sectors(bs->file->bs);
if (file_nb_sectors < 0) { if (file_nb_sectors < 0) {
return -EINVAL; return -EINVAL;
@ -1359,11 +1361,9 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
bitmap_new(DIV_ROUND_UP(s->header_size, s->bat_dirty_block)); bitmap_new(DIV_ROUND_UP(s->header_size, s->bat_dirty_block));
/* Disable migration until bdrv_activate method is added */ /* Disable migration until bdrv_activate method is added */
bdrv_graph_rdlock_main_loop();
error_setg(&s->migration_blocker, "The Parallels format used by node '%s' " error_setg(&s->migration_blocker, "The Parallels format used by node '%s' "
"does not support live migration", "does not support live migration",
bdrv_get_device_or_node_name(bs)); bdrv_get_device_or_node_name(bs));
bdrv_graph_rdunlock_main_loop();
ret = migrate_add_blocker_normal(&s->migration_blocker, errp); ret = migrate_add_blocker_normal(&s->migration_blocker, errp);
if (ret < 0) { if (ret < 0) {

View File

@ -143,6 +143,8 @@ static int preallocate_open(BlockDriverState *bs, QDict *options, int flags,
BDRVPreallocateState *s = bs->opaque; BDRVPreallocateState *s = bs->opaque;
int ret; int ret;
GLOBAL_STATE_CODE();
/* /*
* s->data_end and friends should be initialized on permission update. * s->data_end and friends should be initialized on permission update.
* For this to work, mark them invalid. * For this to work, mark them invalid.
@ -155,6 +157,8 @@ static int preallocate_open(BlockDriverState *bs, QDict *options, int flags,
return ret; return ret;
} }
GRAPH_RDLOCK_GUARD_MAINLOOP();
if (!preallocate_absorb_opts(&s->opts, options, bs->file->bs, errp)) { if (!preallocate_absorb_opts(&s->opts, options, bs->file->bs, errp)) {
return -EINVAL; return -EINVAL;
} }

View File

@ -124,9 +124,11 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
ret = bdrv_open_file_child(NULL, options, "file", bs, errp); ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
if (ret < 0) { if (ret < 0) {
goto fail; goto fail_unlocked;
} }
bdrv_graph_rdlock_main_loop();
ret = bdrv_pread(bs->file, 0, sizeof(header), &header, 0); ret = bdrv_pread(bs->file, 0, sizeof(header), &header, 0);
if (ret < 0) { if (ret < 0) {
goto fail; goto fail;
@ -301,11 +303,9 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
} }
/* Disable migration when qcow images are used */ /* Disable migration when qcow images are used */
bdrv_graph_rdlock_main_loop();
error_setg(&s->migration_blocker, "The qcow format used by node '%s' " error_setg(&s->migration_blocker, "The qcow format used by node '%s' "
"does not support live migration", "does not support live migration",
bdrv_get_device_or_node_name(bs)); bdrv_get_device_or_node_name(bs));
bdrv_graph_rdunlock_main_loop();
ret = migrate_add_blocker_normal(&s->migration_blocker, errp); ret = migrate_add_blocker_normal(&s->migration_blocker, errp);
if (ret < 0) { if (ret < 0) {
@ -315,9 +315,12 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
qobject_unref(encryptopts); qobject_unref(encryptopts);
qapi_free_QCryptoBlockOpenOptions(crypto_opts); qapi_free_QCryptoBlockOpenOptions(crypto_opts);
qemu_co_mutex_init(&s->lock); qemu_co_mutex_init(&s->lock);
bdrv_graph_rdunlock_main_loop();
return 0; return 0;
fail: fail:
bdrv_graph_rdunlock_main_loop();
fail_unlocked:
g_free(s->l1_table); g_free(s->l1_table);
qemu_vfree(s->l2_cache); qemu_vfree(s->l2_cache);
g_free(s->cluster_cache); g_free(s->cluster_cache);

View File

@ -473,6 +473,8 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
BdrvChildRole file_role; BdrvChildRole file_role;
int ret; int ret;
GLOBAL_STATE_CODE();
ret = raw_read_options(options, &offset, &has_size, &size, errp); ret = raw_read_options(options, &offset, &has_size, &size, errp);
if (ret < 0) { if (ret < 0) {
return ret; return ret;
@ -490,6 +492,8 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
bdrv_open_child(NULL, options, "file", bs, &child_of_bds, bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
file_role, false, errp); file_role, false, errp);
GRAPH_RDLOCK_GUARD_MAINLOOP();
if (!bs->file) { if (!bs->file) {
return -EINVAL; return -EINVAL;
} }
@ -504,9 +508,7 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
BDRV_REQ_ZERO_WRITE; BDRV_REQ_ZERO_WRITE;
if (bs->probed && !bdrv_is_read_only(bs)) { if (bs->probed && !bdrv_is_read_only(bs)) {
bdrv_graph_rdlock_main_loop();
bdrv_refresh_filename(bs->file->bs); bdrv_refresh_filename(bs->file->bs);
bdrv_graph_rdunlock_main_loop();
fprintf(stderr, fprintf(stderr,
"WARNING: Image format was not specified for '%s' and probing " "WARNING: Image format was not specified for '%s' and probing "
"guessed raw.\n" "guessed raw.\n"

View File

@ -85,6 +85,9 @@ static int snapshot_access_open(BlockDriverState *bs, QDict *options, int flags,
bdrv_open_child(NULL, options, "file", bs, &child_of_bds, bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
BDRV_CHILD_DATA | BDRV_CHILD_PRIMARY, BDRV_CHILD_DATA | BDRV_CHILD_PRIMARY,
false, errp); false, errp);
GRAPH_RDLOCK_GUARD_MAINLOOP();
if (!bs->file) { if (!bs->file) {
return -EINVAL; return -EINVAL;
} }

View File

@ -84,6 +84,9 @@ static int throttle_open(BlockDriverState *bs, QDict *options,
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }
GRAPH_RDLOCK_GUARD_MAINLOOP();
bs->supported_write_flags = bs->file->bs->supported_write_flags | bs->supported_write_flags = bs->file->bs->supported_write_flags |
BDRV_REQ_WRITE_UNCHANGED; BDRV_REQ_WRITE_UNCHANGED;
bs->supported_zero_flags = bs->file->bs->supported_zero_flags | bs->supported_zero_flags = bs->file->bs->supported_zero_flags |

View File

@ -383,6 +383,8 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
return ret; return ret;
} }
GRAPH_RDLOCK_GUARD_MAINLOOP();
logout("\n"); logout("\n");
ret = bdrv_pread(bs->file, 0, sizeof(header), &header, 0); ret = bdrv_pread(bs->file, 0, sizeof(header), &header, 0);
@ -492,11 +494,9 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
} }
/* Disable migration when vdi images are used */ /* Disable migration when vdi images are used */
bdrv_graph_rdlock_main_loop();
error_setg(&s->migration_blocker, "The vdi format used by node '%s' " error_setg(&s->migration_blocker, "The vdi format used by node '%s' "
"does not support live migration", "does not support live migration",
bdrv_get_device_or_node_name(bs)); bdrv_get_device_or_node_name(bs));
bdrv_graph_rdunlock_main_loop();
ret = migrate_add_blocker_normal(&s->migration_blocker, errp); ret = migrate_add_blocker_normal(&s->migration_blocker, errp);
if (ret < 0) { if (ret < 0) {

View File

@ -238,6 +238,8 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
return ret; return ret;
} }
GRAPH_RDLOCK_GUARD_MAINLOOP();
opts = qemu_opts_create(&vpc_runtime_opts, NULL, 0, &error_abort); opts = qemu_opts_create(&vpc_runtime_opts, NULL, 0, &error_abort);
if (!qemu_opts_absorb_qdict(opts, options, errp)) { if (!qemu_opts_absorb_qdict(opts, options, errp)) {
ret = -EINVAL; ret = -EINVAL;
@ -446,11 +448,9 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
} }
/* Disable migration when VHD images are used */ /* Disable migration when VHD images are used */
bdrv_graph_rdlock_main_loop();
error_setg(&s->migration_blocker, "The vpc format used by node '%s' " error_setg(&s->migration_blocker, "The vpc format used by node '%s' "
"does not support live migration", "does not support live migration",
bdrv_get_device_or_node_name(bs)); bdrv_get_device_or_node_name(bs));
bdrv_graph_rdunlock_main_loop();
ret = migrate_add_blocker_normal(&s->migration_blocker, errp); ret = migrate_add_blocker_normal(&s->migration_blocker, errp);
if (ret < 0) { if (ret < 0) {