aboutsummaryrefslogtreecommitdiff
path: root/block.c
diff options
context:
space:
mode:
authorVladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>2021-04-28 18:17:50 +0300
committerKevin Wolf <kwolf@redhat.com>2021-04-30 12:27:48 +0200
commit46541ee579b134485376bf51cf85250877ca69ec (patch)
tree67f02503be2b24991f8077cfc22503382e2bef75 /block.c
parent2272edcfffba659d0b49b98a9d5e65783b2c4e53 (diff)
block: add bdrv_remove_filter_or_cow transaction action
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> Reviewed-by: Kevin Wolf <kwolf@redhat.com> Message-Id: <20210428151804.439460-23-vsementsov@virtuozzo.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Diffstat (limited to 'block.c')
-rw-r--r--block.c84
1 files changed, 82 insertions, 2 deletions
diff --git a/block.c b/block.c
index 5bb6a2bef9..2ea9cc110d 100644
--- a/block.c
+++ b/block.c
@@ -2963,12 +2963,19 @@ static void bdrv_replace_child(BdrvChild *child, BlockDriverState *new_bs)
}
}
+static void bdrv_child_free(void *opaque)
+{
+ BdrvChild *c = opaque;
+
+ g_free(c->name);
+ g_free(c);
+}
+
static void bdrv_remove_empty_child(BdrvChild *child)
{
assert(!child->bs);
QLIST_SAFE_REMOVE(child, next);
- g_free(child->name);
- g_free(child);
+ bdrv_child_free(child);
}
typedef struct BdrvAttachChildCommonState {
@@ -4991,6 +4998,79 @@ static bool should_update_child(BdrvChild *c, BlockDriverState *to)
return ret;
}
+typedef struct BdrvRemoveFilterOrCowChild {
+ BdrvChild *child;
+ bool is_backing;
+} BdrvRemoveFilterOrCowChild;
+
+static void bdrv_remove_filter_or_cow_child_abort(void *opaque)
+{
+ BdrvRemoveFilterOrCowChild *s = opaque;
+ BlockDriverState *parent_bs = s->child->opaque;
+
+ QLIST_INSERT_HEAD(&parent_bs->children, s->child, next);
+ if (s->is_backing) {
+ parent_bs->backing = s->child;
+ } else {
+ parent_bs->file = s->child;
+ }
+
+ /*
+ * We don't have to restore child->bs here to undo bdrv_replace_child()
+ * because that function is transactionable and it registered own completion
+ * entries in @tran, so .abort() for bdrv_replace_child_safe() will be
+ * called automatically.
+ */
+}
+
+static void bdrv_remove_filter_or_cow_child_commit(void *opaque)
+{
+ BdrvRemoveFilterOrCowChild *s = opaque;
+
+ bdrv_child_free(s->child);
+}
+
+static TransactionActionDrv bdrv_remove_filter_or_cow_child_drv = {
+ .abort = bdrv_remove_filter_or_cow_child_abort,
+ .commit = bdrv_remove_filter_or_cow_child_commit,
+ .clean = g_free,
+};
+
+/*
+ * A function to remove backing-chain child of @bs if exists: cow child for
+ * format nodes (always .backing) and filter child for filters (may be .file or
+ * .backing)
+ */
+__attribute__((unused))
+static void bdrv_remove_filter_or_cow_child(BlockDriverState *bs,
+ Transaction *tran)
+{
+ BdrvRemoveFilterOrCowChild *s;
+ BdrvChild *child = bdrv_filter_or_cow_child(bs);
+
+ if (!child) {
+ return;
+ }
+
+ if (child->bs) {
+ bdrv_replace_child_safe(child, NULL, tran);
+ }
+
+ s = g_new(BdrvRemoveFilterOrCowChild, 1);
+ *s = (BdrvRemoveFilterOrCowChild) {
+ .child = child,
+ .is_backing = (child == bs->backing),
+ };
+ tran_add(tran, &bdrv_remove_filter_or_cow_child_drv, s);
+
+ QLIST_SAFE_REMOVE(child, next);
+ if (s->is_backing) {
+ bs->backing = NULL;
+ } else {
+ bs->file = NULL;
+ }
+}
+
static int bdrv_replace_node_noperm(BlockDriverState *from,
BlockDriverState *to,
bool auto_skip, Transaction *tran,