summaryrefslogtreecommitdiff
path: root/block/io.c
diff options
context:
space:
mode:
authorKevin Wolf <kwolf@redhat.com>2017-12-18 16:05:48 +0100
committerKevin Wolf <kwolf@redhat.com>2017-12-22 15:05:32 +0100
commitd736f119dae6d292e8d60f2e02fa51a79524113e (patch)
treed43428b92070b16badcd30678dde7974e0be02ac /block/io.c
parent27e64474a384e68ca928fa875930b921b53d61f4 (diff)
downloadqemu-d736f119dae6d292e8d60f2e02fa51a79524113e.tar.gz
block: Allow graph changes in subtree drained section
We need to remember how many of the drain sections in which a node is were recursive (i.e. subtree drain rather than node drain), so that they can be correctly applied when children are added or removed during the drained section. With this change, it is safe to modify the graph even inside a bdrv_subtree_drained_begin/end() section. Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Diffstat (limited to 'block/io.c')
-rw-r--r--block/io.c28
1 files changed, 24 insertions, 4 deletions
diff --git a/block/io.c b/block/io.c
index 6befef166d..7ea402352e 100644
--- a/block/io.c
+++ b/block/io.c
@@ -270,8 +270,8 @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
assert(data.done);
}
-static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive,
- BdrvChild *parent)
+void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive,
+ BdrvChild *parent)
{
BdrvChild *child, *next;
@@ -290,6 +290,7 @@ static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive,
bdrv_drain_recurse(bs);
if (recursive) {
+ bs->recursive_quiesce_counter++;
QLIST_FOREACH_SAFE(child, &bs->children, next, next) {
bdrv_do_drained_begin(child->bs, true, child);
}
@@ -306,8 +307,8 @@ void bdrv_subtree_drained_begin(BlockDriverState *bs)
bdrv_do_drained_begin(bs, true, NULL);
}
-static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive,
- BdrvChild *parent)
+void bdrv_do_drained_end(BlockDriverState *bs, bool recursive,
+ BdrvChild *parent)
{
BdrvChild *child, *next;
int old_quiesce_counter;
@@ -327,6 +328,7 @@ static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive,
}
if (recursive) {
+ bs->recursive_quiesce_counter--;
QLIST_FOREACH_SAFE(child, &bs->children, next, next) {
bdrv_do_drained_end(child->bs, true, child);
}
@@ -343,6 +345,24 @@ void bdrv_subtree_drained_end(BlockDriverState *bs)
bdrv_do_drained_end(bs, true, NULL);
}
+void bdrv_apply_subtree_drain(BdrvChild *child, BlockDriverState *new_parent)
+{
+ int i;
+
+ for (i = 0; i < new_parent->recursive_quiesce_counter; i++) {
+ bdrv_do_drained_begin(child->bs, true, child);
+ }
+}
+
+void bdrv_unapply_subtree_drain(BdrvChild *child, BlockDriverState *old_parent)
+{
+ int i;
+
+ for (i = 0; i < old_parent->recursive_quiesce_counter; i++) {
+ bdrv_do_drained_end(child->bs, true, child);
+ }
+}
+
/*
* Wait for pending requests to complete on a single BlockDriverState subtree,
* and suspend block driver's internal I/O until next request arrives.