@@ -1536,6 +1536,72 @@ void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top)
bs_new->drv ? bs_new->drv->format_name : "");
}
+/*
+ * Remove top bs contents in the image backing chain while the chain is live.
+ * Required fields on the top layer will be kept to let qemu continue use
+ * @bs_top.
+ *
+ * This will modify the BlockDriverState fields, and swap contents between
+ * bs_top and bs_top->backing_hd. Both bs_top and bs_top->backing_hd are
+ * modified, and bs_top->backing_hd will be deleted.
+ *
+ * This function does not delete any image files. If @bs_top have no backing
+ * image, the function will do nothing.
+ *
+ * Warning: Caller must guarantee @bs_top have same contents with its backing
+ * image, that is, when @bs_top was just appended or committed to
+ * bs_top->backing_hd.
+ */
+void bdrv_deappend(BlockDriverState *bs_top)
+{
+ BlockDriverState tmp;
+ BlockDriverState *bs_backing = bs_top->backing_hd;
+
+ if (!bs_backing) {
+ return;
+ }
+
+ BlockDriverState *bs_bottom = bs_backing->backing_hd;
+ /* Now only support deappend when bs_top is in following conditions. */
+ g_assert(bs_top->device_name[0] != '\0');
+ g_assert(bs_top->dev != NULL);
+
+ g_assert(bs_top->dirty_bitmap == NULL);
+ g_assert(bs_top->job == NULL);
+ g_assert(bs_top->in_use == 0);
+ g_assert(bs_top->io_limits_enabled == false);
+ g_assert(bs_top->block_timer == NULL);
+
+
+ tmp = *bs_top;
+ *bs_top = *bs_backing;
+ *bs_backing = tmp;
+
+ /* there are some fields which should not be swapped, move them back */
+ bdrv_move_feature_fields(&tmp, bs_top);
+ bdrv_move_feature_fields(bs_top, bs_backing);
+ bdrv_move_feature_fields(bs_backing, &tmp);
+
+ /* bs_top should keep device attached */
+ g_assert(bs_top->device_name[0] != '\0');
+ g_assert(bs_top->dev != NULL);
+
+ /* check a few fields that should remain */
+ g_assert(bs_top->job == NULL);
+ g_assert(bs_top->in_use == 0);
+ g_assert(bs_top->io_limits_enabled == false);
+ g_assert(bs_top->block_timer == NULL);
+ g_assert(bs_top->backing_hd == bs_bottom);
+
+ /* delete bs_backing */
+ bs_backing->backing_hd = NULL;
+ bs_backing->backing_file[0] = 0;
+ bs_backing->backing_format[0] = 0;
+ bdrv_delete(bs_backing);
+
+ bdrv_rebind(bs_top);
+}
+
void bdrv_delete(BlockDriverState *bs)
{
assert(!bs->dev);
@@ -132,6 +132,7 @@ BlockDriverState *bdrv_new(const char *device_name);
void bdrv_make_anon(BlockDriverState *bs);
void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old);
void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top);
+void bdrv_deappend(BlockDriverState *bs_top);
void bdrv_delete(BlockDriverState *bs);
int bdrv_parse_cache_flags(const char *mode, int *flags);
int bdrv_parse_discard_flags(const char *mode, int *flags);
This function should be used to remove contents of active *bs on the top of backing chain, when top *bs was committed to bs->backing_hd or *bs was just appended. Signed-off-by: Wenchao Xia <xiawenc@linux.vnet.ibm.com> --- block.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++ include/block/block.h | 1 + 2 files changed, 67 insertions(+), 0 deletions(-)