From 4da26f138db06c9c6d7199d42bd3c2be552cb956 Mon Sep 17 00:00:00 2001 From: John Snow Date: Mon, 13 May 2019 11:06:38 -0400 Subject: blockdev: fix missed target unref for drive-backup If the bitmap can't be used for whatever reason, we skip putting down the reference. Fix that. In practice, this means that if you attempt to gracefully exit QEMU after a backup command being rejected, bdrv_close_all will fail and tell you some unpleasant things via assert(). Reported-by: aihua liang Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1703916 Signed-off-by: John Snow Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- blockdev.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'blockdev.c') diff --git a/blockdev.c b/blockdev.c index 17c2d801d7..d88dc115f2 100644 --- a/blockdev.c +++ b/blockdev.c @@ -3546,8 +3546,7 @@ static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn, if (set_backing_hd) { bdrv_set_backing_hd(target_bs, source, &local_err); if (local_err) { - bdrv_unref(target_bs); - goto out; + goto unref; } } @@ -3555,11 +3554,10 @@ static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn, bmap = bdrv_find_dirty_bitmap(bs, backup->bitmap); if (!bmap) { error_setg(errp, "Bitmap '%s' could not be found", backup->bitmap); - bdrv_unref(target_bs); - goto out; + goto unref; } if (bdrv_dirty_bitmap_check(bmap, BDRV_BITMAP_DEFAULT, errp)) { - goto out; + goto unref; } } if (!backup->auto_finalize) { @@ -3573,12 +3571,13 @@ static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn, backup->sync, bmap, backup->compress, backup->on_source_error, backup->on_target_error, job_flags, NULL, NULL, txn, &local_err); - bdrv_unref(target_bs); if (local_err != NULL) { error_propagate(errp, local_err); - goto out; + goto unref; } +unref: + bdrv_unref(target_bs); out: aio_context_release(aio_context); return job; -- cgit v1.2.3 From d861ab3acf8dcf817e0c2335979b258847b69564 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 25 Apr 2019 14:25:10 +0200 Subject: block: Add BlockBackend.ctx This adds a new parameter to blk_new() which requires its callers to declare from which AioContext this BlockBackend is going to be used (or the locks of which AioContext need to be taken anyway). The given context is only stored and kept up to date when changing AioContexts. Actually applying the stored AioContext to the root node is saved for another commit. Signed-off-by: Kevin Wolf --- blockdev.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'blockdev.c') diff --git a/blockdev.c b/blockdev.c index d88dc115f2..e1ad92c559 100644 --- a/blockdev.c +++ b/blockdev.c @@ -574,7 +574,7 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts, if ((!file || !*file) && !qdict_size(bs_opts)) { BlockBackendRootState *blk_rs; - blk = blk_new(0, BLK_PERM_ALL); + blk = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL); blk_rs = blk_get_root_state(blk); blk_rs->open_flags = bdrv_flags; blk_rs->read_only = read_only; @@ -3154,7 +3154,7 @@ void qmp_block_resize(bool has_device, const char *device, goto out; } - blk = blk_new(BLK_PERM_RESIZE, BLK_PERM_ALL); + blk = blk_new(bdrv_get_aio_context(bs), BLK_PERM_RESIZE, BLK_PERM_ALL); ret = blk_insert_bs(blk, bs, errp); if (ret < 0) { goto out; -- cgit v1.2.3 From 8ed7d42fb528d380bb0fda1e91aa1770a1b05cf6 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 26 Apr 2019 16:12:27 +0200 Subject: blockdev: Use bdrv_try_set_aio_context() for monitor commands Monitor commands can handle errors, so they can easily be converted to using the safer bdrv_try_set_aio_context() function. Signed-off-by: Kevin Wolf --- blockdev.c | 44 ++++++++++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 16 deletions(-) (limited to 'blockdev.c') diff --git a/blockdev.c b/blockdev.c index e1ad92c559..3f44b891eb 100644 --- a/blockdev.c +++ b/blockdev.c @@ -1535,6 +1535,7 @@ static void external_snapshot_prepare(BlkActionState *common, DO_UPCAST(ExternalSnapshotState, common, common); TransactionAction *action = common->action; AioContext *aio_context; + int ret; /* 'blockdev-snapshot' and 'blockdev-snapshot-sync' have similar * purpose but a different set of parameters */ @@ -1674,7 +1675,10 @@ static void external_snapshot_prepare(BlkActionState *common, goto out; } - bdrv_set_aio_context(state->new_bs, aio_context); + ret = bdrv_try_set_aio_context(state->new_bs, aio_context, errp); + if (ret < 0) { + goto out; + } /* This removes our old bs and adds the new bs. This is an operation that * can fail, so we need to do it in .prepare; undoing it for abort is @@ -3440,6 +3444,7 @@ static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn, int flags, job_flags = JOB_DEFAULT; int64_t size; bool set_backing_hd = false; + int ret; if (!backup->has_speed) { backup->speed = 0; @@ -3541,7 +3546,11 @@ static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn, goto out; } - bdrv_set_aio_context(target_bs, aio_context); + ret = bdrv_try_set_aio_context(target_bs, aio_context, errp); + if (ret < 0) { + bdrv_unref(target_bs); + goto out; + } if (set_backing_hd) { bdrv_set_backing_hd(target_bs, source, &local_err); @@ -3613,6 +3622,7 @@ BlockJob *do_blockdev_backup(BlockdevBackup *backup, JobTxn *txn, AioContext *aio_context; BlockJob *job = NULL; int job_flags = JOB_DEFAULT; + int ret; if (!backup->has_speed) { backup->speed = 0; @@ -3649,16 +3659,9 @@ BlockJob *do_blockdev_backup(BlockdevBackup *backup, JobTxn *txn, goto out; } - if (bdrv_get_aio_context(target_bs) != aio_context) { - if (!bdrv_has_blk(target_bs)) { - /* The target BDS is not attached, we can safely move it to another - * AioContext. */ - bdrv_set_aio_context(target_bs, aio_context); - } else { - error_setg(errp, "Target is attached to a different thread from " - "source."); - goto out; - } + ret = bdrv_try_set_aio_context(target_bs, aio_context, errp); + if (ret < 0) { + goto out; } if (backup->has_bitmap) { @@ -3831,6 +3834,7 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp) int flags; int64_t size; const char *format = arg->format; + int ret; bs = qmp_get_root_bs(arg->device, errp); if (!bs) { @@ -3931,7 +3935,11 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp) goto out; } - bdrv_set_aio_context(target_bs, aio_context); + ret = bdrv_try_set_aio_context(target_bs, aio_context, errp); + if (ret < 0) { + bdrv_unref(target_bs); + goto out; + } blockdev_mirror_common(arg->has_job_id ? arg->job_id : NULL, bs, target_bs, arg->has_replaces, arg->replaces, arg->sync, @@ -3975,6 +3983,7 @@ void qmp_blockdev_mirror(bool has_job_id, const char *job_id, AioContext *aio_context; BlockMirrorBackingMode backing_mode = MIRROR_LEAVE_BACKING_CHAIN; Error *local_err = NULL; + int ret; bs = qmp_get_root_bs(device, errp); if (!bs) { @@ -3989,7 +3998,10 @@ void qmp_blockdev_mirror(bool has_job_id, const char *job_id, aio_context = bdrv_get_aio_context(bs); aio_context_acquire(aio_context); - bdrv_set_aio_context(target_bs, aio_context); + ret = bdrv_try_set_aio_context(target_bs, aio_context, errp); + if (ret < 0) { + goto out; + } blockdev_mirror_common(has_job_id ? job_id : NULL, bs, target_bs, has_replaces, replaces, sync, backing_mode, @@ -4005,7 +4017,7 @@ void qmp_blockdev_mirror(bool has_job_id, const char *job_id, has_auto_dismiss, auto_dismiss, &local_err); error_propagate(errp, local_err); - +out: aio_context_release(aio_context); } @@ -4495,7 +4507,7 @@ void qmp_x_blockdev_set_iothread(const char *node_name, StrOrNull *iothread, old_context = bdrv_get_aio_context(bs); aio_context_acquire(old_context); - bdrv_set_aio_context(bs, new_context); + bdrv_try_set_aio_context(bs, new_context, errp); aio_context_release(old_context); } -- cgit v1.2.3