From: Paolo Bonzini <pbonzini@redhat.com>
To: qemu-devel@nongnu.org
Cc: famz@redhat.com, qemu-block@nongnu.org, stefanha@redhat.com
Subject: [Qemu-devel] [PATCH 11/11] block/snapshot: do not take AioContext lock
Date: Thu, 6 Jul 2017 18:38:28 +0200 [thread overview]
Message-ID: <20170706163828.24082-12-pbonzini@redhat.com> (raw)
In-Reply-To: <20170706163828.24082-1-pbonzini@redhat.com>
Snapshots are only created/destroyed/loaded under the BQL, while no
other I/O is happening. Snapshot information could be accessed while
other I/O is happening, but also under the BQL so they cannot be
modified concurrently. The AioContext lock is overkill. If needed,
in the future the BQL could be split to a separate lock covering all
snapshot operations, and the create/destroy/goto callbacks changed
to run in a coroutine (so the driver can do mutual exclusion as usual).
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
block/snapshot.c | 28 +---------------------------
blockdev.c | 43 ++++++++++++-------------------------------
hmp.c | 7 -------
include/block/block_int.h | 5 +++++
include/block/snapshot.h | 4 +---
migration/savevm.c | 22 ----------------------
monitor.c | 10 ++--------
7 files changed, 21 insertions(+), 98 deletions(-)
diff --git a/block/snapshot.c b/block/snapshot.c
index a46564e7b7..08c59d6166 100644
--- a/block/snapshot.c
+++ b/block/snapshot.c
@@ -384,9 +384,7 @@ int bdrv_snapshot_load_tmp_by_id_or_name(BlockDriverState *bs,
}
-/* Group operations. All block drivers are involved.
- * These functions will properly handle dataplane (take aio_context_acquire
- * when appropriate for appropriate block drivers) */
+/* Group operations. All block drivers are involved. */
bool bdrv_all_can_snapshot(BlockDriverState **first_bad_bs)
{
@@ -395,13 +393,9 @@ bool bdrv_all_can_snapshot(BlockDriverState **first_bad_bs)
BdrvNextIterator it;
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
- AioContext *ctx = bdrv_get_aio_context(bs);
-
- aio_context_acquire(ctx);
if (bdrv_is_inserted(bs) && !bdrv_is_read_only(bs)) {
ok = bdrv_can_snapshot(bs);
}
- aio_context_release(ctx);
if (!ok) {
goto fail;
}
@@ -421,14 +415,10 @@ int bdrv_all_delete_snapshot(const char *name, BlockDriverState **first_bad_bs,
QEMUSnapshotInfo sn1, *snapshot = &sn1;
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
- AioContext *ctx = bdrv_get_aio_context(bs);
-
- aio_context_acquire(ctx);
if (bdrv_can_snapshot(bs) &&
bdrv_snapshot_find(bs, snapshot, name) >= 0) {
ret = bdrv_snapshot_delete_by_id_or_name(bs, name, err);
}
- aio_context_release(ctx);
if (ret < 0) {
goto fail;
}
@@ -447,13 +437,9 @@ int bdrv_all_goto_snapshot(const char *name, BlockDriverState **first_bad_bs)
BdrvNextIterator it;
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
- AioContext *ctx = bdrv_get_aio_context(bs);
-
- aio_context_acquire(ctx);
if (bdrv_can_snapshot(bs)) {
err = bdrv_snapshot_goto(bs, name);
}
- aio_context_release(ctx);
if (err < 0) {
goto fail;
}
@@ -472,13 +458,9 @@ int bdrv_all_find_snapshot(const char *name, BlockDriverState **first_bad_bs)
BdrvNextIterator it;
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
- AioContext *ctx = bdrv_get_aio_context(bs);
-
- aio_context_acquire(ctx);
if (bdrv_can_snapshot(bs)) {
err = bdrv_snapshot_find(bs, &sn, name);
}
- aio_context_release(ctx);
if (err < 0) {
goto fail;
}
@@ -499,9 +481,6 @@ int bdrv_all_create_snapshot(QEMUSnapshotInfo *sn,
BdrvNextIterator it;
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
- AioContext *ctx = bdrv_get_aio_context(bs);
-
- aio_context_acquire(ctx);
if (bs == vm_state_bs) {
sn->vm_state_size = vm_state_size;
err = bdrv_snapshot_create(bs, sn);
@@ -509,7 +488,6 @@ int bdrv_all_create_snapshot(QEMUSnapshotInfo *sn,
sn->vm_state_size = 0;
err = bdrv_snapshot_create(bs, sn);
}
- aio_context_release(ctx);
if (err < 0) {
goto fail;
}
@@ -526,13 +504,9 @@ BlockDriverState *bdrv_all_find_vmstate_bs(void)
BdrvNextIterator it;
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
- AioContext *ctx = bdrv_get_aio_context(bs);
bool found;
- aio_context_acquire(ctx);
found = bdrv_can_snapshot(bs);
- aio_context_release(ctx);
-
if (found) {
break;
}
diff --git a/blockdev.c b/blockdev.c
index 88ab606949..56ef9c41a3 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1280,7 +1280,6 @@ SnapshotInfo *qmp_blockdev_snapshot_delete_internal_sync(const char *device,
Error **errp)
{
BlockDriverState *bs;
- AioContext *aio_context;
QEMUSnapshotInfo sn;
Error *local_err = NULL;
SnapshotInfo *info = NULL;
@@ -1290,8 +1289,6 @@ SnapshotInfo *qmp_blockdev_snapshot_delete_internal_sync(const char *device,
if (!bs) {
return NULL;
}
- aio_context = bdrv_get_aio_context(bs);
- aio_context_acquire(aio_context);
if (!has_id) {
id = NULL;
@@ -1303,34 +1300,32 @@ SnapshotInfo *qmp_blockdev_snapshot_delete_internal_sync(const char *device,
if (!id && !name) {
error_setg(errp, "Name or id must be provided");
- goto out_aio_context;
+ return NULL;
}
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_INTERNAL_SNAPSHOT_DELETE, errp)) {
- goto out_aio_context;
+ return NULL;
}
ret = bdrv_snapshot_find_by_id_and_name(bs, id, name, &sn, &local_err);
if (local_err) {
error_propagate(errp, local_err);
- goto out_aio_context;
+ return NULL;
}
if (!ret) {
error_setg(errp,
"Snapshot with id '%s' and name '%s' does not exist on "
"device '%s'",
STR_OR_NULL(id), STR_OR_NULL(name), device);
- goto out_aio_context;
+ return NULL;
}
bdrv_snapshot_delete(bs, id, name, &local_err);
if (local_err) {
error_propagate(errp, local_err);
- goto out_aio_context;
+ return NULL;
}
- aio_context_release(aio_context);
-
info = g_new0(SnapshotInfo, 1);
info->id = g_strdup(sn.id_str);
info->name = g_strdup(sn.name);
@@ -1341,10 +1336,6 @@ SnapshotInfo *qmp_blockdev_snapshot_delete_internal_sync(const char *device,
info->vm_clock_sec = sn.vm_clock_nsec / 1000000000;
return info;
-
-out_aio_context:
- aio_context_release(aio_context);
- return NULL;
}
/**
@@ -1446,7 +1437,6 @@ struct BlkActionState {
typedef struct InternalSnapshotState {
BlkActionState common;
BlockDriverState *bs;
- AioContext *aio_context;
QEMUSnapshotInfo sn;
bool created;
} InternalSnapshotState;
@@ -1498,10 +1488,6 @@ static void internal_snapshot_prepare(BlkActionState *common,
return;
}
- /* AioContext is released in .clean() */
- state->aio_context = bdrv_get_aio_context(bs);
- aio_context_acquire(state->aio_context);
-
state->bs = bs;
bdrv_drained_begin(bs);
@@ -1585,11 +1571,8 @@ static void internal_snapshot_clean(BlkActionState *common)
InternalSnapshotState *state = DO_UPCAST(InternalSnapshotState,
common, common);
- if (state->aio_context) {
- if (state->bs) {
- bdrv_drained_end(state->bs);
- }
- aio_context_release(state->aio_context);
+ if (state->bs) {
+ bdrv_drained_end(state->bs);
}
}
@@ -1598,7 +1581,6 @@ typedef struct ExternalSnapshotState {
BlkActionState common;
BlockDriverState *old_bs;
BlockDriverState *new_bs;
- AioContext *aio_context;
bool overlay_appended;
} ExternalSnapshotState;
@@ -1654,9 +1636,7 @@ static void external_snapshot_prepare(BlkActionState *common,
return;
}
- /* Acquire AioContext now so any threads operating on old_bs stop */
- state->aio_context = bdrv_get_aio_context(state->old_bs);
- aio_context_acquire(state->aio_context);
+ /* Make any threads operating on old_bs stop */
bdrv_drained_begin(state->old_bs);
if (!bdrv_is_inserted(state->old_bs)) {
@@ -1756,7 +1736,7 @@ static void external_snapshot_prepare(BlkActionState *common,
return;
}
- bdrv_set_aio_context(state->new_bs, state->aio_context);
+ bdrv_set_aio_context(state->new_bs, bdrv_get_aio_context(state->old_bs));
/* 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
@@ -1775,6 +1755,8 @@ static void external_snapshot_commit(BlkActionState *common)
ExternalSnapshotState *state =
DO_UPCAST(ExternalSnapshotState, common, common);
+ bdrv_set_aio_context(state->new_bs, bdrv_get_aio_context(state->old_bs));
+
/* We don't need (or want) to use the transactional
* bdrv_reopen_multiple() across all the entries at once, because we
* don't want to abort all of them if one of them fails the reopen */
@@ -1803,9 +1785,8 @@ static void external_snapshot_clean(BlkActionState *common)
{
ExternalSnapshotState *state =
DO_UPCAST(ExternalSnapshotState, common, common);
- if (state->aio_context) {
+ if (state->old_bs) {
bdrv_drained_end(state->old_bs);
- aio_context_release(state->aio_context);
bdrv_unref(state->new_bs);
}
}
diff --git a/hmp.c b/hmp.c
index 8c72c58b20..3c63ea7a72 100644
--- a/hmp.c
+++ b/hmp.c
@@ -1321,7 +1321,6 @@ void hmp_info_snapshots(Monitor *mon, const QDict *qdict)
int nb_sns, i;
int total;
int *global_snapshots;
- AioContext *aio_context;
typedef struct SnapshotEntry {
QEMUSnapshotInfo sn;
@@ -1345,11 +1344,8 @@ void hmp_info_snapshots(Monitor *mon, const QDict *qdict)
monitor_printf(mon, "No available block device supports snapshots\n");
return;
}
- aio_context = bdrv_get_aio_context(bs);
- aio_context_acquire(aio_context);
nb_sns = bdrv_snapshot_list(bs, &sn_tab);
- aio_context_release(aio_context);
if (nb_sns < 0) {
monitor_printf(mon, "bdrv_snapshot_list: error %d\n", nb_sns);
@@ -1360,9 +1356,7 @@ void hmp_info_snapshots(Monitor *mon, const QDict *qdict)
int bs1_nb_sns = 0;
ImageEntry *ie;
SnapshotEntry *se;
- AioContext *ctx = bdrv_get_aio_context(bs1);
- aio_context_acquire(ctx);
if (bdrv_can_snapshot(bs1)) {
sn = NULL;
bs1_nb_sns = bdrv_snapshot_list(bs1, &sn);
@@ -1380,7 +1374,6 @@ void hmp_info_snapshots(Monitor *mon, const QDict *qdict)
}
g_free(sn);
}
- aio_context_release(ctx);
}
if (no_snapshot) {
diff --git a/include/block/block_int.h b/include/block/block_int.h
index 43c9f4fcae..38d1067fa8 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -217,6 +217,11 @@ struct BlockDriver {
int coroutine_fn (*bdrv_co_pwritev_compressed)(BlockDriverState *bs,
uint64_t offset, uint64_t bytes, QEMUIOVector *qiov);
+ /*
+ * Snapshots are only created/destroyed/loaded under the BQL, while no
+ * other I/O is happening. snapshots/nb_snapshots is read while other
+ * I/O is happening, but also under the BQL.
+ */
int (*bdrv_snapshot_create)(BlockDriverState *bs,
QEMUSnapshotInfo *sn_info);
int (*bdrv_snapshot_goto)(BlockDriverState *bs,
diff --git a/include/block/snapshot.h b/include/block/snapshot.h
index e5c0553115..735d0f694c 100644
--- a/include/block/snapshot.h
+++ b/include/block/snapshot.h
@@ -76,9 +76,7 @@ int bdrv_snapshot_load_tmp_by_id_or_name(BlockDriverState *bs,
Error **errp);
-/* Group operations. All block drivers are involved.
- * These functions will properly handle dataplane (take aio_context_acquire
- * when appropriate for appropriate block drivers */
+/* Group operations. All block drivers are involved. */
bool bdrv_all_can_snapshot(BlockDriverState **first_bad_bs);
int bdrv_all_delete_snapshot(const char *name, BlockDriverState **first_bsd_bs,
diff --git a/migration/savevm.c b/migration/savevm.c
index c7a49c93c5..1b168c3ba8 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -2073,7 +2073,6 @@ int save_snapshot(const char *name, Error **errp)
uint64_t vm_state_size;
qemu_timeval tv;
struct tm tm;
- AioContext *aio_context;
if (!bdrv_all_can_snapshot(&bs)) {
error_setg(errp, "Device '%s' is writable but does not support "
@@ -2096,7 +2095,6 @@ int save_snapshot(const char *name, Error **errp)
error_setg(errp, "No block device can accept snapshots");
return ret;
}
- aio_context = bdrv_get_aio_context(bs);
saved_vm_running = runstate_is_running();
@@ -2109,8 +2107,6 @@ int save_snapshot(const char *name, Error **errp)
bdrv_drain_all_begin();
- aio_context_acquire(aio_context);
-
memset(sn, 0, sizeof(*sn));
/* fill auxiliary fields */
@@ -2146,14 +2142,6 @@ int save_snapshot(const char *name, Error **errp)
goto the_end;
}
- /* The bdrv_all_create_snapshot() call that follows acquires the AioContext
- * for itself. BDRV_POLL_WHILE() does not support nested locking because
- * it only releases the lock once. Therefore synchronous I/O will deadlock
- * unless we release the AioContext before bdrv_all_create_snapshot().
- */
- aio_context_release(aio_context);
- aio_context = NULL;
-
ret = bdrv_all_create_snapshot(sn, bs, vm_state_size, &bs);
if (ret < 0) {
error_setg(errp, "Error while creating snapshot on '%s'",
@@ -2164,10 +2152,6 @@ int save_snapshot(const char *name, Error **errp)
ret = 0;
the_end:
- if (aio_context) {
- aio_context_release(aio_context);
- }
-
bdrv_drain_all_end();
if (saved_vm_running) {
@@ -2241,7 +2225,6 @@ int load_snapshot(const char *name, Error **errp)
QEMUSnapshotInfo sn;
QEMUFile *f;
int ret;
- AioContext *aio_context;
MigrationIncomingState *mis = migration_incoming_get_current();
if (!bdrv_all_can_snapshot(&bs)) {
@@ -2263,12 +2246,9 @@ int load_snapshot(const char *name, Error **errp)
error_setg(errp, "No block device supports snapshots");
return -ENOTSUP;
}
- aio_context = bdrv_get_aio_context(bs_vm_state);
/* Don't even try to load empty VM states */
- aio_context_acquire(aio_context);
ret = bdrv_snapshot_find(bs_vm_state, &sn, name);
- aio_context_release(aio_context);
if (ret < 0) {
return ret;
} else if (sn.vm_state_size == 0) {
@@ -2298,10 +2278,8 @@ int load_snapshot(const char *name, Error **errp)
qemu_system_reset(SHUTDOWN_CAUSE_NONE);
mis->from_src_file = f;
- aio_context_acquire(aio_context);
ret = qemu_loadvm_state(f);
migration_incoming_state_destroy();
- aio_context_release(aio_context);
bdrv_drain_all_end();
diff --git a/monitor.c b/monitor.c
index 3c369f4dd5..48687aa94d 100644
--- a/monitor.c
+++ b/monitor.c
@@ -3639,15 +3639,9 @@ static void vm_completion(ReadLineState *rs, const char *str)
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
SnapshotInfoList *snapshots, *snapshot;
- AioContext *ctx = bdrv_get_aio_context(bs);
- bool ok = false;
- aio_context_acquire(ctx);
- if (bdrv_can_snapshot(bs)) {
- ok = bdrv_query_snapshot_info_list(bs, &snapshots, NULL) == 0;
- }
- aio_context_release(ctx);
- if (!ok) {
+ if (!bdrv_can_snapshot(bs) ||
+ bdrv_query_snapshot_info_list(bs, &snapshots, NULL) != 0) {
continue;
}
--
2.13.0
next prev parent reply other threads:[~2017-07-06 16:39 UTC|newest]
Thread overview: 34+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-07-06 16:38 [Qemu-devel] [RFC PATCH 00/11] Block layer thread-safety, next part Paolo Bonzini
2017-07-06 16:38 ` [Qemu-devel] [PATCH 01/11] block: prepare write threshold code for thread safety Paolo Bonzini
2017-07-06 16:51 ` Eric Blake
2017-07-10 13:21 ` Stefan Hajnoczi
2017-07-10 16:16 ` Paolo Bonzini
2017-07-10 16:22 ` Eric Blake
2017-07-06 16:38 ` [Qemu-devel] [PATCH 02/11] block: make write-threshold thread-safe Paolo Bonzini
2017-07-06 16:52 ` Eric Blake
2017-07-10 15:42 ` Stefan Hajnoczi
2017-07-06 16:38 ` [Qemu-devel] [PATCH 03/11] util: use RCU accessors for notifiers Paolo Bonzini
2017-07-10 15:52 ` Stefan Hajnoczi
2017-07-10 16:06 ` Paolo Bonzini
2017-07-11 9:45 ` [Qemu-devel] [Qemu-block] " Stefan Hajnoczi
2017-07-06 16:38 ` [Qemu-devel] [PATCH 04/11] block: make before-write notifiers thread-safe Paolo Bonzini
2017-07-10 15:50 ` Stefan Hajnoczi
2017-07-06 16:38 ` [Qemu-devel] [PATCH 05/11] block-backup: add reqs_lock Paolo Bonzini
2017-07-10 15:57 ` Stefan Hajnoczi
2017-07-06 16:38 ` [Qemu-devel] [PATCH 06/11] block: add a few more notes on locking Paolo Bonzini
2017-07-10 15:57 ` Stefan Hajnoczi
2017-07-06 16:38 ` [Qemu-devel] [PATCH 07/11] block: do not acquire AioContext in check_to_replace_node Paolo Bonzini
2017-07-10 15:58 ` Stefan Hajnoczi
2017-07-06 16:38 ` [Qemu-devel] [PATCH 08/11] block: drain I/O around key management Paolo Bonzini
2017-07-10 16:01 ` Stefan Hajnoczi
2017-07-06 16:38 ` [Qemu-devel] [PATCH 09/11] block/replication: do not acquire AioContext Paolo Bonzini
2017-07-06 16:38 ` [Qemu-devel] [PATCH 10/11] block: do not take AioContext around reopen Paolo Bonzini
2017-07-06 16:38 ` Paolo Bonzini [this message]
2017-07-10 16:24 ` [Qemu-devel] [PATCH 11/11] block/snapshot: do not take AioContext lock Stefan Hajnoczi
2017-07-10 16:27 ` Paolo Bonzini
2017-07-11 9:43 ` [Qemu-devel] [Qemu-block] " Stefan Hajnoczi
2017-07-11 9:48 ` Paolo Bonzini
2017-07-12 10:42 ` Stefan Hajnoczi
2017-07-06 23:48 ` [Qemu-devel] [RFC PATCH 00/11] Block layer thread-safety, next part no-reply
2017-07-07 0:06 ` Fam Zheng
2017-07-10 16:25 ` Stefan Hajnoczi
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20170706163828.24082-12-pbonzini@redhat.com \
--to=pbonzini@redhat.com \
--cc=famz@redhat.com \
--cc=qemu-block@nongnu.org \
--cc=qemu-devel@nongnu.org \
--cc=stefanha@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).