diff options
Diffstat (limited to 'block.c')
-rw-r--r-- | block.c | 21 |
1 files changed, 21 insertions, 0 deletions
@@ -2260,6 +2260,18 @@ static void bdrv_parent_cb_change_media(BlockDriverState *bs, bool load) } } +/* Return true if you can reach parent going through child->inherits_from + * recursively. If parent or child are NULL, return false */ +static bool bdrv_inherits_from_recursive(BlockDriverState *child, + BlockDriverState *parent) +{ + while (child && child != parent) { + child = child->inherits_from; + } + + return child != NULL; +} + /* * Sets the backing file link of a BDS. A new reference is created; callers * which don't need their own reference any more must call bdrv_unref(). @@ -2267,6 +2279,9 @@ static void bdrv_parent_cb_change_media(BlockDriverState *bs, bool load) void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd, Error **errp) { + bool update_inherits_from = bdrv_chain_contains(bs, backing_hd) && + bdrv_inherits_from_recursive(backing_hd, bs); + if (backing_hd) { bdrv_ref(backing_hd); } @@ -2282,6 +2297,12 @@ void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd, bs->backing = bdrv_attach_child(bs, backing_hd, "backing", &child_backing, errp); + /* If backing_hd was already part of bs's backing chain, and + * inherits_from pointed recursively to bs then let's update it to + * point directly to bs (else it will become NULL). */ + if (update_inherits_from) { + backing_hd->inherits_from = bs; + } if (!bs->backing) { bdrv_unref(backing_hd); } |