block: Include filters when freezing backing chain
In order to make filters work in backing chains, the associated
functions must be able to deal with them and freeze both COW and filter
child links.
While at it, add some comments that note which functions require their
caller to ensure that a given child link is not frozen, and how the
callers do so.
Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
diff --git a/block.c b/block.c
index e8d09d4..edef627 100644
--- a/block.c
+++ b/block.c
@@ -2612,12 +2612,15 @@
* If @new_bs is not NULL, bdrv_check_perm() must be called beforehand, as this
* function uses bdrv_set_perm() to update the permissions according to the new
* reference that @new_bs gets.
+ *
+ * Callers must ensure that child->frozen is false.
*/
static void bdrv_replace_child(BdrvChild *child, BlockDriverState *new_bs)
{
BlockDriverState *old_bs = child->bs;
uint64_t perm, shared_perm;
+ /* Asserts that child->frozen == false */
bdrv_replace_child_noperm(child, new_bs);
/*
@@ -2778,6 +2781,7 @@
g_free(child);
}
+/* Callers must ensure that child->frozen is false. */
void bdrv_root_unref_child(BdrvChild *child)
{
BlockDriverState *child_bs;
@@ -2815,6 +2819,7 @@
}
}
+/* Callers must ensure that child->frozen is false. */
void bdrv_unref_child(BlockDriverState *parent, BdrvChild *child)
{
if (child == NULL) {
@@ -2881,6 +2886,7 @@
}
if (bs->backing) {
+ /* Cannot be frozen, we checked that above */
bdrv_unref_child(bs, bs->backing);
bs->backing = NULL;
}
@@ -4387,6 +4393,7 @@
if (bs->drv) {
if (bs->drv->bdrv_close) {
+ /* Must unfreeze all children, so bdrv_unref_child() works */
bs->drv->bdrv_close(bs);
}
bs->drv = NULL;
@@ -4762,20 +4769,22 @@
}
/*
- * Return true if at least one of the backing links between @bs and
- * @base is frozen. @errp is set if that's the case.
+ * Return true if at least one of the COW (backing) and filter links
+ * between @bs and @base is frozen. @errp is set if that's the case.
* @base must be reachable from @bs, or NULL.
*/
bool bdrv_is_backing_chain_frozen(BlockDriverState *bs, BlockDriverState *base,
Error **errp)
{
BlockDriverState *i;
+ BdrvChild *child;
- for (i = bs; i != base; i = backing_bs(i)) {
- if (i->backing && i->backing->frozen) {
+ for (i = bs; i != base; i = child_bs(child)) {
+ child = bdrv_filter_or_cow_child(i);
+
+ if (child && child->frozen) {
error_setg(errp, "Cannot change '%s' link from '%s' to '%s'",
- i->backing->name, i->node_name,
- backing_bs(i)->node_name);
+ child->name, i->node_name, child->bs->node_name);
return true;
}
}
@@ -4784,7 +4793,7 @@
}
/*
- * Freeze all backing links between @bs and @base.
+ * Freeze all COW (backing) and filter links between @bs and @base.
* If any of the links is already frozen the operation is aborted and
* none of the links are modified.
* @base must be reachable from @bs, or NULL.
@@ -4794,22 +4803,25 @@
Error **errp)
{
BlockDriverState *i;
+ BdrvChild *child;
if (bdrv_is_backing_chain_frozen(bs, base, errp)) {
return -EPERM;
}
- for (i = bs; i != base; i = backing_bs(i)) {
- if (i->backing && backing_bs(i)->never_freeze) {
+ for (i = bs; i != base; i = child_bs(child)) {
+ child = bdrv_filter_or_cow_child(i);
+ if (child && child->bs->never_freeze) {
error_setg(errp, "Cannot freeze '%s' link to '%s'",
- i->backing->name, backing_bs(i)->node_name);
+ child->name, child->bs->node_name);
return -EPERM;
}
}
- for (i = bs; i != base; i = backing_bs(i)) {
- if (i->backing) {
- i->backing->frozen = true;
+ for (i = bs; i != base; i = child_bs(child)) {
+ child = bdrv_filter_or_cow_child(i);
+ if (child) {
+ child->frozen = true;
}
}
@@ -4817,18 +4829,21 @@
}
/*
- * Unfreeze all backing links between @bs and @base. The caller must
- * ensure that all links are frozen before using this function.
+ * Unfreeze all COW (backing) and filter links between @bs and @base.
+ * The caller must ensure that all links are frozen before using this
+ * function.
* @base must be reachable from @bs, or NULL.
*/
void bdrv_unfreeze_backing_chain(BlockDriverState *bs, BlockDriverState *base)
{
BlockDriverState *i;
+ BdrvChild *child;
- for (i = bs; i != base; i = backing_bs(i)) {
- if (i->backing) {
- assert(i->backing->frozen);
- i->backing->frozen = false;
+ for (i = bs; i != base; i = child_bs(child)) {
+ child = bdrv_filter_or_cow_child(i);
+ if (child) {
+ assert(child->frozen);
+ child->frozen = false;
}
}
}
@@ -4931,8 +4946,11 @@
}
}
- /* Do the actual switch in the in-memory graph.
- * Completes bdrv_check_update_perm() transaction internally. */
+ /*
+ * Do the actual switch in the in-memory graph.
+ * Completes bdrv_check_update_perm() transaction internally.
+ * c->frozen is false, we have checked that above.
+ */
bdrv_ref(base);
bdrv_replace_child(c, base);
bdrv_unref(top);