Merge tag 'for-upstream' of https://repo.or.cz/qemu/kevin into staging

Block layer patches

- file-posix: Fix aio=threads performance regression after enablign FUA
- QMP query-block/query-named-block-nodes: Include child references
- Graph locking cleanups and fixes around making drain GRAPH_UNLOCKED
- qemu-img: Overhaul option handling and --help
- iotests: add test for changing the 'drive' property via 'qom-set'

# -----BEGIN PGP SIGNATURE-----
#
# iQJFBAABCgAvFiEE3D3rFZqa+V09dFb+fwmycsiPL9YFAmh2pZkRHGt3b2xmQHJl
# ZGhhdC5jb20ACgkQfwmycsiPL9aloBAAkbT2DpdcPb5v6Jc02bDTjBBi//R03cTy
# 0jjU3zvEEjukeA8d7lsQnvD2YwQgvIoOgH/MeNjdYizYh6sLIofTKukbKWMWiBpt
# ygs67IrlsmEqrb+i/xeLdRA1o7jzpJCutU/cQeWV/fUur9ovhjnIJvwiw2Z3uhBR
# QajjPAZcGALwNMauweMhqTX7U1+EpAe/OdtAfc2UgyJIFCyLN9onuQleZ1lCbxSt
# PCAUT/M8zcId2Tcb9Bw3p0mzDNG2AI2FYqGIKNoaWwFfK/SgS8NCUvgpIWGghoxs
# bMbmKMqJpZamsbO7bmEEGjj1Vs14vYVMbqys6N2Gux74RXCBGDleGAR3HNvV+3jR
# 98AuoTOWZxb3Sfu0e+9xNE/+kWcJ0vmsy3sxkpZ6hkPz6fmrrJJYy8Kv2tcCAOCi
# qIJ4hwNx052f1tnyxvARHj+Hj1Q4PSeQl/MAISVeQNAQXoinxzCP/hGLF3PkdpgD
# 6m/xwQ+qMnnblgn4s2ICPXOJAaWLTeB6Y6F34MG+Wgi/7sfKGwxDgRSLMnlNICsm
# PpbSlRy3n7tBTUq4gF3kbknxKeEPGUGw3sakX8fc0DJshs6nz/nKL4Ftwgiuuo3F
# HWR8icj1giifohJOF0KJEa1Q2H9jR6hYwcNpjd9d/OEz1q/3HtuYAiEM3CUygVad
# 2cyZBHjNWLE=
# =A4ZH
# -----END PGP SIGNATURE-----
# gpg: Signature made Tue 15 Jul 2025 15:01:45 EDT
# gpg:                using RSA key DC3DEB159A9AF95D3D7456FE7F09B272C88F2FD6
# gpg:                issuer "kwolf@redhat.com"
# gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>" [full]
# Primary key fingerprint: DC3D EB15 9A9A F95D 3D74  56FE 7F09 B272 C88F 2FD6

* tag 'for-upstream' of https://repo.or.cz/qemu/kevin: (57 commits)
  qemu-img: extend cvtnum() and use it in more places
  qemu-img: implement short --help, remove global help() function
  qemu-img: measure: refresh options/--help
  qemu-img: dd: refresh options/--help
  qemu-img: bitmap: refresh options/--help
  qemu-img: bench: refresh options/--help
  qemu-img: amend: refresh options/--help
  qemu-img: resize: refresh options/--help
  qemu-img: resize: do not always eat last argument
  qemu-img: rebase: refresh options/--help (short option change)
  qemu-img: snapshot: refresh options/--help
  qemu-img: snapshot: make -l (list) the default, simplify option handling
  qemu-img: snapshot: allow specifying -f fmt
  qemu-img: map: refresh options/--help
  qemu-img: info: refresh options/--help
  qemu-img: convert: refresh options/--help (short option change)
  qemu-img: compare: refresh options/--help
  qemu-img: compare: use helper function for --object
  qemu-img: commit: refresh options/--help
  qemu-img: simplify --repair error message
  ...

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
Stefan Hajnoczi
2025-07-16 07:08:09 -04:00
43 changed files with 1547 additions and 1068 deletions
+25 -50
View File
@@ -431,7 +431,7 @@ BlockDriverState *bdrv_new(void)
bs->block_status_cache = g_new0(BdrvBlockStatusCache, 1);
for (i = 0; i < bdrv_drain_all_count; i++) {
bdrv_drained_begin(bs);
bdrv_do_drained_begin_quiesce(bs, NULL);
}
QTAILQ_INSERT_TAIL(&all_bdrv_states, bs, bs_list);
@@ -1721,14 +1721,12 @@ bdrv_open_driver(BlockDriverState *bs, BlockDriver *drv, const char *node_name,
open_failed:
bs->drv = NULL;
bdrv_drain_all_begin();
bdrv_graph_wrlock();
bdrv_graph_wrlock_drained();
if (bs->file != NULL) {
bdrv_unref_child(bs, bs->file);
assert(!bs->file);
}
bdrv_graph_wrunlock();
bdrv_drain_all_end();
g_free(bs->opaque);
bs->opaque = NULL;
@@ -3572,9 +3570,8 @@ out:
*
* All block nodes must be drained.
*/
int bdrv_set_backing_hd_drained(BlockDriverState *bs,
BlockDriverState *backing_hd,
Error **errp)
int bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
Error **errp)
{
int ret;
Transaction *tran = tran_new();
@@ -3596,21 +3593,6 @@ out:
return ret;
}
int bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
Error **errp)
{
int ret;
GLOBAL_STATE_CODE();
bdrv_drain_all_begin();
bdrv_graph_wrlock();
ret = bdrv_set_backing_hd_drained(bs, backing_hd, errp);
bdrv_graph_wrunlock();
bdrv_drain_all_end();
return ret;
}
/*
* Opens the backing file for a BlockDriverState if not yet open
*
@@ -3636,7 +3618,8 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
Error *local_err = NULL;
GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
bdrv_graph_rdlock_main_loop();
if (bs->backing != NULL) {
goto free_exit;
@@ -3717,7 +3700,11 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
/* Hook up the backing file link; drop our reference, bs owns the
* backing_hd reference now */
bdrv_graph_rdunlock_main_loop();
bdrv_graph_wrlock_drained();
ret = bdrv_set_backing_hd(bs, backing_hd, errp);
bdrv_graph_wrunlock();
bdrv_graph_rdlock_main_loop();
bdrv_unref(backing_hd);
if (ret < 0) {
@@ -3729,6 +3716,7 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
free_exit:
g_free(backing_filename);
qobject_unref(tmp_parent_options);
bdrv_graph_rdunlock_main_loop();
return ret;
}
@@ -3778,13 +3766,12 @@ done:
return bs;
}
static BdrvChild *bdrv_open_child_common(const char *filename,
QDict *options, const char *bdref_key,
BlockDriverState *parent,
const BdrvChildClass *child_class,
BdrvChildRole child_role,
bool allow_none, bool parse_filename,
Error **errp)
static BdrvChild * GRAPH_UNLOCKED
bdrv_open_child_common(const char *filename, QDict *options,
const char *bdref_key, BlockDriverState *parent,
const BdrvChildClass *child_class,
BdrvChildRole child_role, bool allow_none,
bool parse_filename, Error **errp)
{
BlockDriverState *bs;
BdrvChild *child;
@@ -3797,12 +3784,10 @@ static BdrvChild *bdrv_open_child_common(const char *filename,
return NULL;
}
bdrv_drain_all_begin();
bdrv_graph_wrlock();
bdrv_graph_wrlock_drained();
child = bdrv_attach_child(parent, bs, bdref_key, child_class, child_role,
errp);
bdrv_graph_wrunlock();
bdrv_drain_all_end();
return child;
}
@@ -5160,7 +5145,7 @@ static void GRAPH_UNLOCKED bdrv_reopen_abort(BDRVReopenState *reopen_state)
}
static void bdrv_close(BlockDriverState *bs)
static void GRAPH_UNLOCKED bdrv_close(BlockDriverState *bs)
{
BdrvAioNotifier *ban, *ban_next;
BdrvChild *child, *next;
@@ -5180,8 +5165,7 @@ static void bdrv_close(BlockDriverState *bs)
bs->drv = NULL;
}
bdrv_drain_all_begin();
bdrv_graph_wrlock();
bdrv_graph_wrlock_drained();
QLIST_FOREACH_SAFE(child, &bs->children, next, next) {
bdrv_unref_child(bs, child);
}
@@ -5189,7 +5173,6 @@ static void bdrv_close(BlockDriverState *bs)
assert(!bs->backing);
assert(!bs->file);
bdrv_graph_wrunlock();
bdrv_drain_all_end();
g_free(bs->opaque);
bs->opaque = NULL;
@@ -5515,8 +5498,7 @@ int bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top,
assert(!bs_new->backing);
bdrv_graph_rdunlock_main_loop();
bdrv_drain_all_begin();
bdrv_graph_wrlock();
bdrv_graph_wrlock_drained();
child = bdrv_attach_child_noperm(bs_new, bs_top, "backing",
&child_of_bds, bdrv_backing_role(bs_new),
@@ -5537,7 +5519,6 @@ out:
bdrv_refresh_limits(bs_top, NULL, NULL);
bdrv_graph_wrunlock();
bdrv_drain_all_end();
return ret;
}
@@ -7076,31 +7057,25 @@ bdrv_inactivate_recurse(BlockDriverState *bs, bool top_level)
return 0;
}
/* All block nodes must be drained. */
int bdrv_inactivate(BlockDriverState *bs, Error **errp)
{
int ret;
GLOBAL_STATE_CODE();
bdrv_drain_all_begin();
bdrv_graph_rdlock_main_loop();
if (bdrv_has_bds_parent(bs, true)) {
error_setg(errp, "Node has active parent node");
ret = -EPERM;
goto out;
return -EPERM;
}
ret = bdrv_inactivate_recurse(bs, true);
if (ret < 0) {
error_setg_errno(errp, -ret, "Failed to inactivate node");
goto out;
return ret;
}
out:
bdrv_graph_rdunlock_main_loop();
bdrv_drain_all_end();
return ret;
return 0;
}
int bdrv_inactivate_all(void)
+1 -3
View File
@@ -498,12 +498,10 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
block_copy_set_speed(bcs, speed);
/* Required permissions are taken by copy-before-write filter target */
bdrv_drain_all_begin();
bdrv_graph_wrlock();
bdrv_graph_wrlock_drained();
block_job_add_bdrv(&job->common, "target", target, 0, BLK_PERM_ALL,
&error_abort);
bdrv_graph_wrunlock();
bdrv_drain_all_end();
return &job->common;
+2 -6
View File
@@ -281,11 +281,9 @@ static int blk_log_writes_open(BlockDriverState *bs, QDict *options, int flags,
ret = 0;
fail_log:
if (ret < 0) {
bdrv_drain_all_begin();
bdrv_graph_wrlock();
bdrv_graph_wrlock_drained();
bdrv_unref_child(bs, s->log_file);
bdrv_graph_wrunlock();
bdrv_drain_all_end();
s->log_file = NULL;
qemu_mutex_destroy(&s->mutex);
}
@@ -298,12 +296,10 @@ static void blk_log_writes_close(BlockDriverState *bs)
{
BDRVBlkLogWritesState *s = bs->opaque;
bdrv_drain_all_begin();
bdrv_graph_wrlock();
bdrv_graph_wrlock_drained();
bdrv_unref_child(bs, s->log_file);
s->log_file = NULL;
bdrv_graph_wrunlock();
bdrv_drain_all_end();
qemu_mutex_destroy(&s->mutex);
}
+1 -3
View File
@@ -151,12 +151,10 @@ static void blkverify_close(BlockDriverState *bs)
{
BDRVBlkverifyState *s = bs->opaque;
bdrv_drain_all_begin();
bdrv_graph_wrlock();
bdrv_graph_wrlock_drained();
bdrv_unref_child(bs, s->test_file);
s->test_file = NULL;
bdrv_graph_wrunlock();
bdrv_drain_all_end();
}
static int64_t coroutine_fn GRAPH_RDLOCK
+2 -6
View File
@@ -889,11 +889,9 @@ void blk_remove_bs(BlockBackend *blk)
root = blk->root;
blk->root = NULL;
bdrv_drain_all_begin();
bdrv_graph_wrlock();
bdrv_graph_wrlock_drained();
bdrv_root_unref_child(root);
bdrv_graph_wrunlock();
bdrv_drain_all_end();
}
/*
@@ -906,8 +904,7 @@ int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, Error **errp)
GLOBAL_STATE_CODE();
bdrv_ref(bs);
bdrv_drain_all_begin();
bdrv_graph_wrlock();
bdrv_graph_wrlock_drained();
if ((bs->open_flags & BDRV_O_INACTIVE) && blk_can_inactivate(blk)) {
blk->disable_perm = true;
@@ -922,7 +919,6 @@ int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, Error **errp)
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
perm, shared_perm, blk, errp);
bdrv_graph_wrunlock();
bdrv_drain_all_end();
if (blk->root == NULL) {
return -EPERM;
}
+24 -10
View File
@@ -68,7 +68,7 @@ static int commit_prepare(Job *job)
s->backing_mask_protocol);
}
static void commit_abort(Job *job)
static void GRAPH_UNLOCKED commit_abort(Job *job)
{
CommitBlockJob *s = container_of(job, CommitBlockJob, common.job);
BlockDriverState *top_bs = blk_bs(s->top);
@@ -392,8 +392,7 @@ void commit_start(const char *job_id, BlockDriverState *bs,
* this is the responsibility of the interface (i.e. whoever calls
* commit_start()).
*/
bdrv_drain_all_begin();
bdrv_graph_wrlock();
bdrv_graph_wrlock_drained();
s->base_overlay = bdrv_find_overlay(top, base);
assert(s->base_overlay);
@@ -425,21 +424,18 @@ void commit_start(const char *job_id, BlockDriverState *bs,
iter_shared_perms, errp);
if (ret < 0) {
bdrv_graph_wrunlock();
bdrv_drain_all_end();
goto fail;
}
}
if (bdrv_freeze_backing_chain(commit_top_bs, base, errp) < 0) {
bdrv_graph_wrunlock();
bdrv_drain_all_end();
goto fail;
}
s->chain_frozen = true;
ret = block_job_add_bdrv(&s->common, "base", base, 0, BLK_PERM_ALL, errp);
bdrv_graph_wrunlock();
bdrv_drain_all_end();
if (ret < 0) {
goto fail;
@@ -518,28 +514,32 @@ int bdrv_commit(BlockDriverState *bs)
Error *local_err = NULL;
GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
if (!drv)
return -ENOMEDIUM;
bdrv_graph_rdlock_main_loop();
backing_file_bs = bdrv_cow_bs(bs);
if (!backing_file_bs) {
return -ENOTSUP;
ret = -ENOTSUP;
goto out;
}
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_COMMIT_SOURCE, NULL) ||
bdrv_op_is_blocked(backing_file_bs, BLOCK_OP_TYPE_COMMIT_TARGET, NULL))
{
return -EBUSY;
ret = -EBUSY;
goto out;
}
ro = bdrv_is_read_only(backing_file_bs);
if (ro) {
if (bdrv_reopen_set_read_only(backing_file_bs, false, NULL)) {
return -EACCES;
ret = -EACCES;
goto out;
}
}
@@ -563,8 +563,14 @@ int bdrv_commit(BlockDriverState *bs)
goto ro_cleanup;
}
bdrv_graph_rdunlock_main_loop();
bdrv_graph_wrlock_drained();
bdrv_set_backing_hd(commit_top_bs, backing_file_bs, &error_abort);
bdrv_set_backing_hd(bs, commit_top_bs, &error_abort);
bdrv_graph_wrunlock();
bdrv_graph_rdlock_main_loop();
ret = blk_insert_bs(backing, backing_file_bs, &local_err);
if (ret < 0) {
@@ -639,9 +645,14 @@ int bdrv_commit(BlockDriverState *bs)
ret = 0;
ro_cleanup:
blk_unref(backing);
bdrv_graph_rdunlock_main_loop();
bdrv_graph_wrlock_drained();
if (bdrv_cow_bs(bs) != backing_file_bs) {
bdrv_set_backing_hd(bs, backing_file_bs, &error_abort);
}
bdrv_graph_wrunlock();
bdrv_graph_rdlock_main_loop();
bdrv_unref(commit_top_bs);
blk_unref(src);
@@ -650,5 +661,8 @@ ro_cleanup:
bdrv_reopen_set_read_only(backing_file_bs, true, NULL);
}
out:
bdrv_graph_rdunlock_main_loop();
return ret;
}
+15 -14
View File
@@ -2564,9 +2564,9 @@ static inline bool raw_check_linux_aio(BDRVRawState *s)
}
#endif
static int coroutine_fn raw_co_prw(BlockDriverState *bs, int64_t *offset_ptr,
uint64_t bytes, QEMUIOVector *qiov, int type,
int flags)
static int coroutine_fn GRAPH_RDLOCK
raw_co_prw(BlockDriverState *bs, int64_t *offset_ptr, uint64_t bytes,
QEMUIOVector *qiov, int type, int flags)
{
BDRVRawState *s = bs->opaque;
RawPosixAIOData acb;
@@ -2625,7 +2625,7 @@ static int coroutine_fn raw_co_prw(BlockDriverState *bs, int64_t *offset_ptr,
ret = raw_thread_pool_submit(handle_aiocb_rw, &acb);
if (ret == 0 && (flags & BDRV_REQ_FUA)) {
/* TODO Use pwritev2() instead if it's available */
ret = raw_co_flush_to_disk(bs);
ret = bdrv_co_flush(bs);
}
goto out; /* Avoid the compiler err of unused label */
@@ -2660,16 +2660,16 @@ out:
return ret;
}
static int coroutine_fn raw_co_preadv(BlockDriverState *bs, int64_t offset,
int64_t bytes, QEMUIOVector *qiov,
BdrvRequestFlags flags)
static int coroutine_fn GRAPH_RDLOCK
raw_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
QEMUIOVector *qiov, BdrvRequestFlags flags)
{
return raw_co_prw(bs, &offset, bytes, qiov, QEMU_AIO_READ, flags);
}
static int coroutine_fn raw_co_pwritev(BlockDriverState *bs, int64_t offset,
int64_t bytes, QEMUIOVector *qiov,
BdrvRequestFlags flags)
static int coroutine_fn GRAPH_RDLOCK
raw_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes,
QEMUIOVector *qiov, BdrvRequestFlags flags)
{
return raw_co_prw(bs, &offset, bytes, qiov, QEMU_AIO_WRITE, flags);
}
@@ -3606,10 +3606,11 @@ static int coroutine_fn raw_co_zone_mgmt(BlockDriverState *bs, BlockZoneOp op,
#endif
#if defined(CONFIG_BLKZONED)
static int coroutine_fn raw_co_zone_append(BlockDriverState *bs,
int64_t *offset,
QEMUIOVector *qiov,
BdrvRequestFlags flags) {
static int coroutine_fn GRAPH_RDLOCK
raw_co_zone_append(BlockDriverState *bs,
int64_t *offset,
QEMUIOVector *qiov,
BdrvRequestFlags flags) {
assert(flags == 0);
int64_t zone_size_mask = bs->bl.zone_size - 1;
int64_t iov_len = 0;
+37 -3
View File
@@ -33,6 +33,17 @@ static QemuMutex aio_context_list_lock;
/* Written and read with atomic operations. */
static int has_writer;
/*
* Many write-locked sections are also drained sections. There is a convenience
* wrapper bdrv_graph_wrlock_drained() which begins a drained section before
* acquiring the lock. This variable here is used so bdrv_graph_wrunlock() knows
* if it also needs to end such a drained section. It needs to be a counter,
* because the aio_poll() call in bdrv_graph_wrlock() might re-enter
* bdrv_graph_wrlock_drained(). And note that aio_bh_poll() in
* bdrv_graph_wrunlock() might also re-enter a write-locked section.
*/
static int wrlock_quiesced_counter;
/*
* A reader coroutine could move from an AioContext to another.
* If this happens, there is no problem from the point of view of
@@ -112,8 +123,14 @@ void no_coroutine_fn bdrv_graph_wrlock(void)
assert(!qatomic_read(&has_writer));
assert(!qemu_in_coroutine());
/* Make sure that constantly arriving new I/O doesn't cause starvation */
bdrv_drain_all_begin_nopoll();
bool need_drain = wrlock_quiesced_counter == 0;
if (need_drain) {
/*
* Make sure that constantly arriving new I/O doesn't cause starvation
*/
bdrv_drain_all_begin_nopoll();
}
/*
* reader_count == 0: this means writer will read has_reader as 1
@@ -139,7 +156,18 @@ void no_coroutine_fn bdrv_graph_wrlock(void)
smp_mb();
} while (reader_count() >= 1);
bdrv_drain_all_end();
if (need_drain) {
bdrv_drain_all_end();
}
}
void no_coroutine_fn bdrv_graph_wrlock_drained(void)
{
GLOBAL_STATE_CODE();
bdrv_drain_all_begin();
wrlock_quiesced_counter++;
bdrv_graph_wrlock();
}
void no_coroutine_fn bdrv_graph_wrunlock(void)
@@ -168,6 +196,12 @@ void no_coroutine_fn bdrv_graph_wrunlock(void)
* progress.
*/
aio_bh_poll(qemu_get_aio_context());
if (wrlock_quiesced_counter > 0) {
bdrv_drain_all_end();
wrlock_quiesced_counter--;
}
}
void coroutine_fn bdrv_graph_co_rdlock(void)
+2 -5
View File
@@ -361,7 +361,7 @@ static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent,
GLOBAL_STATE_CODE();
/* Stop things in parent-to-child order */
if (qatomic_fetch_inc(&bs->quiesce_counter) == 0) {
if (bs->quiesce_counter++ == 0) {
GRAPH_RDLOCK_GUARD_MAINLOOP();
bdrv_parent_drained_begin(bs, parent);
if (bs->drv && bs->drv->bdrv_drain_begin) {
@@ -401,8 +401,6 @@ bdrv_drained_begin(BlockDriverState *bs)
*/
static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent)
{
int old_quiesce_counter;
IO_OR_GS_CODE();
if (qemu_in_coroutine()) {
@@ -415,8 +413,7 @@ static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent)
assert(bs->quiesce_counter > 0);
/* Re-enable things in child-to-parent order */
old_quiesce_counter = qatomic_fetch_dec(&bs->quiesce_counter);
if (old_quiesce_counter == 1) {
if (--bs->quiesce_counter == 0) {
GRAPH_RDLOCK_GUARD_MAINLOOP();
if (bs->drv && bs->drv->bdrv_drain_end) {
bs->drv->bdrv_drain_end(bs);
+9 -8
View File
@@ -761,10 +761,14 @@ 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;
BlockDriverState *unfiltered_target = bdrv_skip_filters(target_bs);
BlockDriverState *unfiltered_target;
bdrv_graph_wrlock_drained();
unfiltered_target = bdrv_skip_filters(target_bs);
backing = s->sync_mode == MIRROR_SYNC_MODE_NONE ? src : s->base;
if (bdrv_cow_bs(unfiltered_target) != backing) {
@@ -775,16 +779,18 @@ static int mirror_exit_common(Job *job)
ret = -EPERM;
}
}
bdrv_graph_wrunlock();
} else if (!abort && s->backing_mode == MIRROR_OPEN_BACKING_CHAIN) {
bdrv_graph_rdlock_main_loop();
assert(!bdrv_backing_chain_next(target_bs));
ret = bdrv_open_backing_file(bdrv_skip_filters(target_bs), NULL,
"backing", &local_err);
bdrv_graph_rdunlock_main_loop();
if (ret < 0) {
error_report_err(local_err);
local_err = NULL;
}
}
bdrv_graph_rdunlock_main_loop();
if (s->should_complete && !abort) {
BlockDriverState *to_replace = s->to_replace ?: src;
@@ -2014,15 +2020,13 @@ static BlockJob *mirror_start_job(
*/
bdrv_disable_dirty_bitmap(s->dirty_bitmap);
bdrv_drain_all_begin();
bdrv_graph_wrlock();
bdrv_graph_wrlock_drained();
ret = block_job_add_bdrv(&s->common, "source", bs, 0,
BLK_PERM_WRITE_UNCHANGED | BLK_PERM_WRITE |
BLK_PERM_CONSISTENT_READ,
errp);
if (ret < 0) {
bdrv_graph_wrunlock();
bdrv_drain_all_end();
goto fail;
}
@@ -2068,19 +2072,16 @@ static BlockJob *mirror_start_job(
iter_shared_perms, errp);
if (ret < 0) {
bdrv_graph_wrunlock();
bdrv_drain_all_end();
goto fail;
}
}
if (bdrv_freeze_backing_chain(mirror_top_bs, target, errp) < 0) {
bdrv_graph_wrunlock();
bdrv_drain_all_end();
goto fail;
}
}
bdrv_graph_wrunlock();
bdrv_drain_all_end();
QTAILQ_INIT(&s->ops_in_flight);
+10 -5
View File
@@ -144,7 +144,7 @@ void hmp_drive_del(Monitor *mon, const QDict *qdict)
Error *local_err = NULL;
GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
bdrv_graph_rdlock_main_loop();
bs = bdrv_find_node(id);
if (bs) {
@@ -152,29 +152,31 @@ void hmp_drive_del(Monitor *mon, const QDict *qdict)
if (local_err) {
error_report_err(local_err);
}
return;
goto unlock;
}
blk = blk_by_name(id);
if (!blk) {
error_report("Device '%s' not found", id);
return;
goto unlock;
}
if (!blk_legacy_dinfo(blk)) {
error_report("Deleting device added with blockdev-add"
" is not supported");
return;
goto unlock;
}
bs = blk_bs(blk);
if (bs) {
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_DRIVE_DEL, &local_err)) {
error_report_err(local_err);
return;
goto unlock;
}
bdrv_graph_rdunlock_main_loop();
blk_remove_bs(blk);
bdrv_graph_rdlock_main_loop();
}
/* Make the BlockBackend and the attached BlockDriverState anonymous */
@@ -191,6 +193,9 @@ void hmp_drive_del(Monitor *mon, const QDict *qdict)
} else {
blk_unref(blk);
}
unlock:
bdrv_graph_rdunlock_main_loop();
}
void hmp_commit(Monitor *mon, const QDict *qdict)
+10 -2
View File
@@ -51,6 +51,8 @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk,
ImageInfo *backing_info;
BlockDriverState *backing;
BlockDeviceInfo *info;
BlockdevChildList **children_list_tail;
BdrvChild *child;
if (!bs->drv) {
error_setg(errp, "Block device %s is ejected", bs->node_name);
@@ -73,8 +75,14 @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk,
.no_flush = !!(bs->open_flags & BDRV_O_NO_FLUSH),
};
if (bs->node_name[0]) {
info->node_name = g_strdup(bs->node_name);
info->node_name = g_strdup(bs->node_name);
children_list_tail = &info->children;
QLIST_FOREACH(child, &bs->children, next) {
BlockdevChild *child_ref = g_new0(BlockdevChild, 1);
child_ref->child = g_strdup(child->name);
child_ref->node_name = g_strdup(child->bs->node_name);
QAPI_LIST_APPEND(children_list_tail, child_ref);
}
backing = bdrv_cow_bs(bs);
+1 -3
View File
@@ -2823,11 +2823,9 @@ qcow2_do_close(BlockDriverState *bs, bool close_data_file)
if (close_data_file && has_data_file(bs)) {
GLOBAL_STATE_CODE();
bdrv_graph_rdunlock_main_loop();
bdrv_drain_all_begin();
bdrv_graph_wrlock();
bdrv_graph_wrlock_drained();
bdrv_unref_child(bs, s->data_file);
bdrv_graph_wrunlock();
bdrv_drain_all_end();
s->data_file = NULL;
bdrv_graph_rdlock_main_loop();
}
+2 -6
View File
@@ -1037,8 +1037,7 @@ static int quorum_open(BlockDriverState *bs, QDict *options, int flags,
close_exit:
/* cleanup on error */
bdrv_drain_all_begin();
bdrv_graph_wrlock();
bdrv_graph_wrlock_drained();
for (i = 0; i < s->num_children; i++) {
if (!opened[i]) {
continue;
@@ -1046,7 +1045,6 @@ close_exit:
bdrv_unref_child(bs, s->children[i]);
}
bdrv_graph_wrunlock();
bdrv_drain_all_end();
g_free(s->children);
g_free(opened);
exit:
@@ -1059,13 +1057,11 @@ static void quorum_close(BlockDriverState *bs)
BDRVQuorumState *s = bs->opaque;
int i;
bdrv_drain_all_begin();
bdrv_graph_wrlock();
bdrv_graph_wrlock_drained();
for (i = 0; i < s->num_children; i++) {
bdrv_unref_child(bs, s->children[i]);
}
bdrv_graph_wrunlock();
bdrv_drain_all_end();
g_free(s->children);
}
+4 -10
View File
@@ -364,14 +364,15 @@ static void reopen_backing_file(BlockDriverState *bs, bool writable,
BlockReopenQueue *reopen_queue = NULL;
GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
bdrv_graph_rdlock_main_loop();
/*
* s->hidden_disk and s->secondary_disk may not be set yet, as they will
* only be set after the children are writable.
*/
hidden_disk = bs->file->bs->backing;
secondary_disk = hidden_disk->bs->backing;
bdrv_graph_rdunlock_main_loop();
if (writable) {
s->orig_hidden_read_only = bdrv_is_read_only(hidden_disk->bs);
@@ -540,8 +541,7 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
return;
}
bdrv_drain_all_begin();
bdrv_graph_wrlock();
bdrv_graph_wrlock_drained();
bdrv_ref(hidden_disk->bs);
s->hidden_disk = bdrv_attach_child(bs, hidden_disk->bs, "hidden disk",
@@ -550,7 +550,6 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
if (local_err) {
error_propagate(errp, local_err);
bdrv_graph_wrunlock();
bdrv_drain_all_end();
return;
}
@@ -561,7 +560,6 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
if (local_err) {
error_propagate(errp, local_err);
bdrv_graph_wrunlock();
bdrv_drain_all_end();
return;
}
@@ -574,14 +572,12 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
!check_top_bs(top_bs, bs)) {
error_setg(errp, "No top_bs or it is invalid");
bdrv_graph_wrunlock();
bdrv_drain_all_end();
reopen_backing_file(bs, false, NULL);
return;
}
bdrv_op_block_all(top_bs, s->blocker);
bdrv_graph_wrunlock();
bdrv_drain_all_end();
s->backup_job = backup_job_create(
NULL, s->secondary_disk->bs, s->hidden_disk->bs,
@@ -656,14 +652,12 @@ static void replication_done(void *opaque, int ret)
if (ret == 0) {
s->stage = BLOCK_REPLICATION_DONE;
bdrv_drain_all_begin();
bdrv_graph_wrlock();
bdrv_graph_wrlock_drained();
bdrv_unref_child(bs, s->secondary_disk);
s->secondary_disk = NULL;
bdrv_unref_child(bs, s->hidden_disk);
s->hidden_disk = NULL;
bdrv_graph_wrunlock();
bdrv_drain_all_end();
s->error = 0;
} else {
+1 -3
View File
@@ -291,11 +291,9 @@ int bdrv_snapshot_goto(BlockDriverState *bs,
}
/* .bdrv_open() will re-attach it */
bdrv_drain_all_begin();
bdrv_graph_wrlock();
bdrv_graph_wrlock_drained();
bdrv_unref_child(bs, fallback);
bdrv_graph_wrunlock();
bdrv_drain_all_end();
ret = bdrv_snapshot_goto(fallback_bs, snapshot_id, errp);
memset(bs->opaque, 0, drv->instance_size);
+8 -13
View File
@@ -51,7 +51,7 @@ static int coroutine_fn stream_populate(BlockBackend *blk,
return blk_co_preadv(blk, offset, bytes, NULL, BDRV_REQ_PREFETCH);
}
static int stream_prepare(Job *job)
static int GRAPH_UNLOCKED stream_prepare(Job *job)
{
StreamBlockJob *s = container_of(job, StreamBlockJob, common.job);
BlockDriverState *unfiltered_bs;
@@ -73,12 +73,11 @@ static int stream_prepare(Job *job)
s->cor_filter_bs = NULL;
/*
* bdrv_set_backing_hd() requires that the unfiltered_bs and the COW child
* of unfiltered_bs is drained. Drain already here and use
* bdrv_set_backing_hd_drained() instead because the polling during
* drained_begin() might change the graph, and if we do this only later, we
* may end up working with the wrong base node (or it might even have gone
* away by the time we want to use it).
* bdrv_set_backing_hd() requires that all block nodes are drained. Drain
* already here, because the polling during drained_begin() might change the
* graph, and if we do this only later, we may end up working with the wrong
* base node (or it might even have gone away by the time we want to use
* it).
*/
if (unfiltered_bs_cow) {
bdrv_ref(unfiltered_bs_cow);
@@ -105,7 +104,7 @@ static int stream_prepare(Job *job)
}
bdrv_graph_wrlock();
bdrv_set_backing_hd_drained(unfiltered_bs, base, &local_err);
bdrv_set_backing_hd(unfiltered_bs, base, &local_err);
bdrv_graph_wrunlock();
/*
@@ -371,12 +370,10 @@ void stream_start(const char *job_id, BlockDriverState *bs,
* already have our own plans. Also don't allow resize as the image size is
* queried only at the job start and then cached.
*/
bdrv_drain_all_begin();
bdrv_graph_wrlock();
bdrv_graph_wrlock_drained();
if (block_job_add_bdrv(&s->common, "active node", bs, 0,
basic_flags | BLK_PERM_WRITE, errp)) {
bdrv_graph_wrunlock();
bdrv_drain_all_end();
goto fail;
}
@@ -397,12 +394,10 @@ void stream_start(const char *job_id, BlockDriverState *bs,
basic_flags, errp);
if (ret < 0) {
bdrv_graph_wrunlock();
bdrv_drain_all_end();
goto fail;
}
}
bdrv_graph_wrunlock();
bdrv_drain_all_end();
s->base_overlay = base_overlay;
s->above_base = above_base;
+9 -17
View File
@@ -271,8 +271,7 @@ static void vmdk_free_extents(BlockDriverState *bs)
BDRVVmdkState *s = bs->opaque;
VmdkExtent *e;
bdrv_drain_all_begin();
bdrv_graph_wrlock();
bdrv_graph_wrlock_drained();
for (i = 0; i < s->num_extents; i++) {
e = &s->extents[i];
g_free(e->l1_table);
@@ -284,7 +283,6 @@ static void vmdk_free_extents(BlockDriverState *bs)
}
}
bdrv_graph_wrunlock();
bdrv_drain_all_end();
g_free(s->extents);
}
@@ -1231,9 +1229,11 @@ vmdk_parse_extents(const char *desc, BlockDriverState *bs, QDict *options,
extent_role |= BDRV_CHILD_METADATA;
}
bdrv_graph_rdunlock_main_loop();
extent_file = bdrv_open_child(extent_path, options, extent_opt_prefix,
bs, &child_of_bds, extent_role, false,
&local_err);
bdrv_graph_rdlock_main_loop();
g_free(extent_path);
if (!extent_file) {
error_propagate(errp, local_err);
@@ -1249,11 +1249,9 @@ vmdk_parse_extents(const char *desc, BlockDriverState *bs, QDict *options,
0, 0, 0, 0, 0, &extent, errp);
if (ret < 0) {
bdrv_graph_rdunlock_main_loop();
bdrv_drain_all_begin();
bdrv_graph_wrlock();
bdrv_graph_wrlock_drained();
bdrv_unref_child(bs, extent_file);
bdrv_graph_wrunlock();
bdrv_drain_all_end();
bdrv_graph_rdlock_main_loop();
goto out;
}
@@ -1270,11 +1268,9 @@ vmdk_parse_extents(const char *desc, BlockDriverState *bs, QDict *options,
g_free(buf);
if (ret) {
bdrv_graph_rdunlock_main_loop();
bdrv_drain_all_begin();
bdrv_graph_wrlock();
bdrv_graph_wrlock_drained();
bdrv_unref_child(bs, extent_file);
bdrv_graph_wrunlock();
bdrv_drain_all_end();
bdrv_graph_rdlock_main_loop();
goto out;
}
@@ -1283,11 +1279,9 @@ vmdk_parse_extents(const char *desc, BlockDriverState *bs, QDict *options,
ret = vmdk_open_se_sparse(bs, extent_file, bs->open_flags, errp);
if (ret) {
bdrv_graph_rdunlock_main_loop();
bdrv_drain_all_begin();
bdrv_graph_wrlock();
bdrv_graph_wrlock_drained();
bdrv_unref_child(bs, extent_file);
bdrv_graph_wrunlock();
bdrv_drain_all_end();
bdrv_graph_rdlock_main_loop();
goto out;
}
@@ -1295,11 +1289,9 @@ vmdk_parse_extents(const char *desc, BlockDriverState *bs, QDict *options,
} else {
error_setg(errp, "Unsupported extent type '%s'", type);
bdrv_graph_rdunlock_main_loop();
bdrv_drain_all_begin();
bdrv_graph_wrlock();
bdrv_graph_wrlock_drained();
bdrv_unref_child(bs, extent_file);
bdrv_graph_wrunlock();
bdrv_drain_all_end();
bdrv_graph_rdlock_main_loop();
ret = -ENOTSUP;
goto out;
@@ -1362,13 +1354,13 @@ static int vmdk_open(BlockDriverState *bs, QDict *options, int flags,
BDRVVmdkState *s = bs->opaque;
uint32_t magic;
GRAPH_RDLOCK_GUARD_MAINLOOP();
ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
if (ret < 0) {
return ret;
}
GRAPH_RDLOCK_GUARD_MAINLOOP();
buf = vmdk_read_desc(bs->file, 0, errp);
if (!buf) {
return -EINVAL;
+64 -40
View File
@@ -1421,7 +1421,7 @@ static void external_snapshot_action(TransactionAction *action,
bdrv_graph_rdunlock_main_loop();
/* Paired with .clean() */
bdrv_drained_begin(state->old_bs);
GRAPH_RDLOCK_GUARD_MAINLOOP();
bdrv_graph_rdlock_main_loop();
/* Make sure the associated bs did not change with the drain. */
check_bs = bdrv_lookup_bs(device, node_name, errp);
@@ -1430,18 +1430,18 @@ static void external_snapshot_action(TransactionAction *action,
error_setg(errp, "Block node of device '%s' unexpectedly changed",
device);
} /* else errp is already set */
return;
goto unlock;
}
if (!bdrv_is_inserted(state->old_bs)) {
error_setg(errp, "Device '%s' has no medium",
bdrv_get_device_or_node_name(state->old_bs));
return;
goto unlock;
}
if (bdrv_op_is_blocked(state->old_bs,
BLOCK_OP_TYPE_EXTERNAL_SNAPSHOT, errp)) {
return;
goto unlock;
}
if (!bdrv_is_read_only(state->old_bs)) {
@@ -1449,7 +1449,7 @@ static void external_snapshot_action(TransactionAction *action,
if (ret < 0) {
error_setg_errno(errp, -ret, "Write to node '%s' failed",
bdrv_get_device_or_node_name(state->old_bs));
return;
goto unlock;
}
}
@@ -1461,13 +1461,13 @@ static void external_snapshot_action(TransactionAction *action,
if (node_name && !snapshot_node_name) {
error_setg(errp, "New overlay node-name missing");
return;
goto unlock;
}
if (snapshot_node_name &&
bdrv_lookup_bs(snapshot_node_name, snapshot_node_name, NULL)) {
error_setg(errp, "New overlay node-name already in use");
return;
goto unlock;
}
flags = state->old_bs->open_flags;
@@ -1480,7 +1480,7 @@ static void external_snapshot_action(TransactionAction *action,
int64_t size = bdrv_getlength(state->old_bs);
if (size < 0) {
error_setg_errno(errp, -size, "bdrv_getlength failed");
return;
goto unlock;
}
bdrv_refresh_filename(state->old_bs);
@@ -1491,7 +1491,7 @@ static void external_snapshot_action(TransactionAction *action,
if (local_err) {
error_propagate(errp, local_err);
return;
goto unlock;
}
}
@@ -1507,7 +1507,7 @@ static void external_snapshot_action(TransactionAction *action,
/* We will manually add the backing_hd field to the bs later */
if (!state->new_bs) {
return;
goto unlock;
}
/*
@@ -1518,22 +1518,22 @@ static void external_snapshot_action(TransactionAction *action,
bdrv_get_cumulative_perm(state->new_bs, &perm, &shared);
if (perm & BLK_PERM_CONSISTENT_READ) {
error_setg(errp, "The overlay is already in use");
return;
goto unlock;
}
if (state->new_bs->drv->is_filter) {
error_setg(errp, "Filters cannot be used as overlays");
return;
goto unlock;
}
if (bdrv_cow_child(state->new_bs)) {
error_setg(errp, "The overlay already has a backing image");
return;
goto unlock;
}
if (!state->new_bs->drv->supports_backing) {
error_setg(errp, "The overlay does not support backing images");
return;
goto unlock;
}
/*
@@ -1546,17 +1546,23 @@ static void external_snapshot_action(TransactionAction *action,
* to keep this working.
*/
if (bdrv_is_inactive(state->old_bs) && !bdrv_is_inactive(state->new_bs)) {
bdrv_graph_rdunlock_main_loop();
bdrv_drain_all_begin();
bdrv_graph_rdlock_main_loop();
ret = bdrv_inactivate(state->new_bs, errp);
bdrv_drain_all_end();
if (ret < 0) {
return;
goto unlock;
}
}
ret = bdrv_append(state->new_bs, state->old_bs, errp);
if (ret < 0) {
return;
goto unlock;
}
state->overlay_appended = true;
unlock:
bdrv_graph_rdunlock_main_loop();
}
static void external_snapshot_commit(void *opaque)
@@ -1580,10 +1586,18 @@ static void external_snapshot_abort(void *opaque)
AioContext *tmp_context;
int ret;
bdrv_graph_wrlock_drained();
aio_context = bdrv_get_aio_context(state->old_bs);
bdrv_ref(state->old_bs); /* we can't let bdrv_set_backind_hd()
close state->old_bs; we need it */
/*
* Note that state->old_bs would not disappear during the
* write-locked section, because the unref from
* bdrv_set_backing_hd() only happens at the end of the write-locked
* section. However, just be explicit about keeping a reference and
* don't rely on that implicit detail.
*/
bdrv_ref(state->old_bs);
bdrv_set_backing_hd(state->new_bs, NULL, &error_abort);
/*
@@ -1593,16 +1607,14 @@ static void external_snapshot_abort(void *opaque)
*/
tmp_context = bdrv_get_aio_context(state->old_bs);
if (aio_context != tmp_context) {
ret = bdrv_try_change_aio_context(state->old_bs,
aio_context, NULL, NULL);
ret = bdrv_try_change_aio_context_locked(state->old_bs,
aio_context, NULL,
NULL);
assert(ret == 0);
}
bdrv_drained_begin(state->new_bs);
bdrv_graph_wrlock();
bdrv_replace_node(state->new_bs, state->old_bs, &error_abort);
bdrv_graph_wrunlock();
bdrv_drained_end(state->new_bs);
bdrv_unref(state->old_bs); /* bdrv_replace_node() ref'ed old_bs */
}
@@ -1770,7 +1782,10 @@ static void drive_backup_action(DriveBackup *backup,
}
if (set_backing_hd) {
if (bdrv_set_backing_hd(target_bs, source, errp) < 0) {
bdrv_graph_wrlock_drained();
ret = bdrv_set_backing_hd(target_bs, source, errp);
bdrv_graph_wrunlock();
if (ret < 0) {
goto unref;
}
}
@@ -3511,10 +3526,10 @@ void qmp_blockdev_del(const char *node_name, Error **errp)
void qmp_blockdev_set_active(const char *node_name, bool active, Error **errp)
{
BlockDriverState *bs;
int ret;
GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
if (!node_name) {
if (active) {
@@ -3525,19 +3540,30 @@ void qmp_blockdev_set_active(const char *node_name, bool active, Error **errp)
error_setg_errno(errp, -ret, "Failed to inactivate all nodes");
}
}
} else {
BlockDriverState *bs = bdrv_find_node(node_name);
if (!bs) {
error_setg(errp, "Failed to find node with node-name='%s'",
node_name);
return;
}
return;
}
if (active) {
bdrv_activate(bs, errp);
} else {
bdrv_inactivate(bs, errp);
}
if (!active) {
bdrv_drain_all_begin();
}
bdrv_graph_rdlock_main_loop();
bs = bdrv_find_node(node_name);
if (!bs) {
error_setg(errp, "Failed to find node with node-name='%s'",
node_name);
goto unlock;
}
if (active) {
bdrv_activate(bs, errp);
} else {
bdrv_inactivate(bs, errp);
}
unlock:
bdrv_graph_rdunlock_main_loop();
if (!active) {
bdrv_drain_all_end();
}
}
@@ -3561,8 +3587,7 @@ void qmp_x_blockdev_change(const char *parent, const char *child,
BlockDriverState *parent_bs, *new_bs = NULL;
BdrvChild *p_child;
bdrv_drain_all_begin();
bdrv_graph_wrlock();
bdrv_graph_wrlock_drained();
parent_bs = bdrv_lookup_bs(parent, parent, errp);
if (!parent_bs) {
@@ -3599,7 +3624,6 @@ void qmp_x_blockdev_change(const char *parent, const char *child,
out:
bdrv_graph_wrunlock();
bdrv_drain_all_end();
}
BlockJobInfoList *qmp_query_block_jobs(Error **errp)
+2 -8
View File
@@ -198,8 +198,7 @@ void block_job_remove_all_bdrv(BlockJob *job)
* one to make sure that such a concurrent access does not attempt
* to process an already freed BdrvChild.
*/
bdrv_drain_all_begin();
bdrv_graph_wrlock();
bdrv_graph_wrlock_drained();
while (job->nodes) {
GSList *l = job->nodes;
BdrvChild *c = l->data;
@@ -212,7 +211,6 @@ void block_job_remove_all_bdrv(BlockJob *job)
g_slist_free_1(l);
}
bdrv_graph_wrunlock();
bdrv_drain_all_end();
}
bool block_job_has_bdrv(BlockJob *job, BlockDriverState *bs)
@@ -498,8 +496,7 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
int ret;
GLOBAL_STATE_CODE();
bdrv_drain_all_begin();
bdrv_graph_wrlock();
bdrv_graph_wrlock_drained();
if (job_id == NULL && !(flags & JOB_INTERNAL)) {
job_id = bdrv_get_device_name(bs);
@@ -509,7 +506,6 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
flags, cb, opaque, errp);
if (job == NULL) {
bdrv_graph_wrunlock();
bdrv_drain_all_end();
return NULL;
}
@@ -548,12 +544,10 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
}
bdrv_graph_wrunlock();
bdrv_drain_all_end();
return job;
fail:
bdrv_graph_wrunlock();
bdrv_drain_all_end();
job_early_fail(&job->job);
return NULL;
}

Some files were not shown because too many files have changed in this diff Show More