Commit 9bd910e2 authored by Max Reitz's avatar Max Reitz
Browse files

block: Allow replacement of a BDS by its overlay



change_parent_backing_link() asserts that the BDS to be replaced is not
used as a backing file. However, we may want to replace a BDS by its
overlay in which case that very link should not be redirected.

For instance, when doing a sync=none drive-mirror operation, we may have
the following BDS/BB forest before block job completion:

  target

  base <- source <- BlockBackend

During job completion, we want to establish the source BDS as the
target's backing node:

          target
            |
            v
  base <- source <- BlockBackend

This makes the target a valid replacement for the source:

          target <- BlockBackend
            |
            v
  base <- source

Without this modification to change_parent_backing_link() we have to
inject the target into the graph before the source is its backing node,
thus temporarily creating a wrong graph:

  target <- BlockBackend

  base <- source

Signed-off-by: default avatarMax Reitz <mreitz@redhat.com>
Message-id: 20160610185750.30956-2-mreitz@redhat.com
Reviewed-by: default avatarKevin Wolf <kwolf@redhat.com>
Reviewed-by: default avatarFam Zheng <famz@redhat.com>
Signed-off-by: default avatarMax Reitz <mreitz@redhat.com>
parent 87cd3d20
Loading
Loading
Loading
Loading
+15 −1
Original line number Diff line number Diff line
@@ -2226,9 +2226,23 @@ void bdrv_close_all(void)
static void change_parent_backing_link(BlockDriverState *from,
                                       BlockDriverState *to)
{
    BdrvChild *c, *next;
    BdrvChild *c, *next, *to_c;

    QLIST_FOREACH_SAFE(c, &from->parents, next_parent, next) {
        if (c->role == &child_backing) {
            /* @from is generally not allowed to be a backing file, except for
             * when @to is the overlay. In that case, @from may not be replaced
             * by @to as @to's backing node. */
            QLIST_FOREACH(to_c, &to->children, next) {
                if (to_c == c) {
                    break;
                }
            }
            if (to_c) {
                continue;
            }
        }

        assert(c->role != &child_backing);
        bdrv_ref(to);
        bdrv_replace_child(c, to);