diff --git a/block.c b/block.c index c74e6e7cc1..9283c8d97b 100644 --- a/block.c +++ b/block.c @@ -4991,6 +4991,34 @@ static bool should_update_child(BdrvChild *c, BlockDriverState *to) return ret; } +static int bdrv_replace_node_noperm(BlockDriverState *from, + BlockDriverState *to, + bool auto_skip, Transaction *tran, + Error **errp) +{ + BdrvChild *c, *next; + + QLIST_FOREACH_SAFE(c, &from->parents, next_parent, next) { + assert(c->bs == from); + if (!should_update_child(c, to)) { + if (auto_skip) { + continue; + } + error_setg(errp, "Should not change '%s' link to '%s'", + c->name, from->node_name); + return -EINVAL; + } + if (c->frozen) { + error_setg(errp, "Cannot change '%s' link to '%s'", + c->name, from->node_name); + return -EPERM; + } + bdrv_replace_child_safe(c, to, tran); + } + + return 0; +} + /* * With auto_skip=true bdrv_replace_node_common skips updating from parents * if it creates a parent-child relation loop or if parent is block-job. @@ -5002,7 +5030,6 @@ static int bdrv_replace_node_common(BlockDriverState *from, BlockDriverState *to, bool auto_skip, Error **errp) { - BdrvChild *c, *next; Transaction *tran = tran_new(); g_autoptr(GHashTable) found = NULL; g_autoptr(GSList) refresh_list = NULL; @@ -5022,24 +5049,9 @@ static int bdrv_replace_node_common(BlockDriverState *from, * permissions based on new graph. If we fail, we'll roll-back the * replacement. */ - QLIST_FOREACH_SAFE(c, &from->parents, next_parent, next) { - assert(c->bs == from); - if (!should_update_child(c, to)) { - if (auto_skip) { - continue; - } - ret = -EINVAL; - error_setg(errp, "Should not change '%s' link to '%s'", - c->name, from->node_name); - goto out; - } - if (c->frozen) { - ret = -EPERM; - error_setg(errp, "Cannot change '%s' link to '%s'", - c->name, from->node_name); - goto out; - } - bdrv_replace_child_safe(c, to, tran); + ret = bdrv_replace_node_noperm(from, to, auto_skip, tran, errp); + if (ret < 0) { + goto out; } found = g_hash_table_new(NULL, NULL);