All of lore.kernel.org
 help / color / mirror / Atom feed
From: Max Reitz <mreitz@redhat.com>
To: qemu-block@nongnu.org
Cc: qemu-devel@nongnu.org, Max Reitz <mreitz@redhat.com>,
	Kevin Wolf <kwolf@redhat.com>, John Snow <jsnow@redhat.com>,
	Fam Zheng <famz@redhat.com>,
	Stefan Hajnoczi <stefanha@redhat.com>
Subject: [Qemu-devel] [PATCH v2 09/16] block: Generalize should_update_child() rule
Date: Mon, 22 Jan 2018 23:07:59 +0100	[thread overview]
Message-ID: <20180122220806.22154-10-mreitz@redhat.com> (raw)
In-Reply-To: <20180122220806.22154-1-mreitz@redhat.com>

Currently, bdrv_replace_node() refuses to create loops from one BDS to
itself if the BDS to be replaced is the backing node of the BDS to
replace it: Say there is a node A and a node B.  Replacing B by A means
making all references to B point to A.  If B is a child of A (i.e. A has
a reference to B), that would mean we would have to make this reference
point to A itself -- so we'd create a loop.

bdrv_replace_node() (through should_update_child()) refuses to do so if
B is the backing node of A.  There is no reason why we should create
loops if B is not the backing node of A, though.  The BDS graph should
never contain loops, so we should always refuse to create them.

If B is a child of A and B is to be replaced by A, we should simply
leave B in place there because it is the most sensible choice.

A more specific argument would be: Putting filter drivers into the BDS
graph is basically the same as appending an overlay to a backing chain.
But the main child BDS of a filter driver is not "backing" but "file",
so restricting the no-loop rule to backing nodes would fail here.

Signed-off-by: Max Reitz <mreitz@redhat.com>
---
 include/block/block_int.h |  2 ++
 block.c                   | 44 ++++++++++++++++++++++++++++++++++----------
 2 files changed, 36 insertions(+), 10 deletions(-)

diff --git a/include/block/block_int.h b/include/block/block_int.h
index 29cafa4236..03f3fdd129 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -587,6 +587,8 @@ struct BdrvChild {
     QLIST_ENTRY(BdrvChild) next_parent;
 };
 
+typedef QLIST_HEAD(BdrvChildList, BdrvChild) BdrvChildList;
+
 /*
  * Note: the function bdrv_append() copies and swaps contents of
  * BlockDriverStates, so if you add new fields to this struct, please
diff --git a/block.c b/block.c
index a8da4f2b25..df50825d94 100644
--- a/block.c
+++ b/block.c
@@ -3320,16 +3320,39 @@ static bool should_update_child(BdrvChild *c, BlockDriverState *to)
         return false;
     }
 
-    if (c->role == &child_backing) {
-        /* If @from is a backing file of @to, ignore the child to avoid
-         * creating a loop. We only want to change the pointer of other
-         * parents. */
-        QLIST_FOREACH(to_c, &to->children, next) {
-            if (to_c == c) {
-                break;
-            }
-        }
-        if (to_c) {
+    /* If the child @c belongs to the BDS @to, replacing the current
+     * c->bs by @to would mean to create a loop.
+     *
+     * Such a case occurs when appending a BDS to a backing chain.
+     * For instance, imagine the following chain:
+     *
+     *   guest device -> node A -> further backing chain...
+     *
+     * Now we create a new BDS B which we want to put on top of this
+     * chain, so we first attach A as its backing node:
+     *
+     *                   node B
+     *                     |
+     *                     v
+     *   guest device -> node A -> further backing chain...
+     *
+     * Finally we want to replace A by B.  When doing that, we want to
+     * replace all pointers to A by pointers to B -- except for the
+     * pointer from B because (1) that would create a loop, and (2)
+     * that pointer should simply stay intact:
+     *
+     *   guest device -> node B
+     *                     |
+     *                     v
+     *                   node A -> further backing chain...
+     *
+     * In general, when replacing a node A (c->bs) by a node B (@to),
+     * if A is a child of B, that means we cannot replace A by B there
+     * because that would create a loop.  Silently detaching A from B
+     * is also not really an option.  So overall just leaving A in
+     * place there is the most sensible choice. */
+    QLIST_FOREACH(to_c, &to->children, next) {
+        if (to_c == c) {
             return false;
         }
     }
@@ -3355,6 +3378,7 @@ void bdrv_replace_node(BlockDriverState *from, BlockDriverState *to,
 
     /* Put all parents into @list and calculate their cumulative permissions */
     QLIST_FOREACH_SAFE(c, &from->parents, next_parent, next) {
+        assert(c->bs == from);
         if (!should_update_child(c, to)) {
             continue;
         }
-- 
2.14.3

  parent reply	other threads:[~2018-01-22 22:09 UTC|newest]

Thread overview: 35+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-01-22 22:07 [Qemu-devel] [PATCH v2 00/16] block/mirror: Add active-sync mirroring Max Reitz
2018-01-22 22:07 ` [Qemu-devel] [PATCH v2 01/16] block: BDS deletion during bdrv_drain_recurse Max Reitz
2018-01-22 22:07 ` [Qemu-devel] [PATCH v2 02/16] block: BDS deletion in bdrv_do_drained_begin() Max Reitz
2018-01-22 22:07 ` [Qemu-devel] [PATCH v2 03/16] tests: Add bdrv-drain test for node deletion Max Reitz
2018-01-22 22:07 ` [Qemu-devel] [PATCH v2 04/16] block/mirror: Pull out mirror_perform() Max Reitz
2018-01-22 22:07 ` [Qemu-devel] [PATCH v2 05/16] block/mirror: Convert to coroutines Max Reitz
2018-02-27  7:44   ` Fam Zheng
2018-02-28 14:13     ` Max Reitz
2018-02-28 17:07       ` Max Reitz
2018-03-01  2:50         ` Fam Zheng
2018-01-22 22:07 ` [Qemu-devel] [PATCH v2 06/16] block/mirror: Use CoQueue to wait on in-flight ops Max Reitz
2018-02-27  8:37   ` Fam Zheng
2018-01-22 22:07 ` [Qemu-devel] [PATCH v2 07/16] block/mirror: Wait for in-flight op conflicts Max Reitz
2018-01-22 22:07 ` [Qemu-devel] [PATCH v2 08/16] block/mirror: Use source as a BdrvChild Max Reitz
2018-01-22 22:07 ` Max Reitz [this message]
2018-01-22 22:08 ` [Qemu-devel] [PATCH v2 10/16] hbitmap: Add @advance param to hbitmap_iter_next() Max Reitz
2018-02-27  8:59   ` Fam Zheng
2018-02-28 14:28     ` Max Reitz
2018-01-22 22:08 ` [Qemu-devel] [PATCH v2 11/16] block/dirty-bitmap: Add bdrv_dirty_iter_next_area Max Reitz
2018-02-27  9:06   ` Fam Zheng
2018-02-28 14:57     ` Max Reitz
2018-01-22 22:08 ` [Qemu-devel] [PATCH v2 12/16] block/mirror: Distinguish active from passive ops Max Reitz
2018-02-27  9:12   ` Fam Zheng
2018-02-28 15:05     ` Max Reitz
2018-01-22 22:08 ` [Qemu-devel] [PATCH v2 13/16] block/mirror: Add MirrorBDSOpaque Max Reitz
2018-01-22 22:08 ` [Qemu-devel] [PATCH v2 14/16] block/mirror: Add active mirroring Max Reitz
2018-02-27  9:34   ` Fam Zheng
2018-02-27 14:25     ` Eric Blake
2018-02-28 15:06     ` Max Reitz
2018-01-22 22:08 ` [Qemu-devel] [PATCH v2 15/16] block/mirror: Add copy mode QAPI interface Max Reitz
2018-02-27  9:38   ` Fam Zheng
2018-02-28 15:55     ` Max Reitz
2018-01-22 22:08 ` [Qemu-devel] [PATCH v2 16/16] iotests: Add test for active mirroring Max Reitz
2018-02-24 15:42 ` [Qemu-devel] [PATCH v2 00/16] block/mirror: Add active-sync mirroring Max Reitz
2018-02-27  9:51   ` Fam Zheng

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=20180122220806.22154-10-mreitz@redhat.com \
    --to=mreitz@redhat.com \
    --cc=famz@redhat.com \
    --cc=jsnow@redhat.com \
    --cc=kwolf@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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.