[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [RFC v2 PATCH 1/6] block: add support functions for live co
From: |
Jeff Cody |
Subject: |
[Qemu-devel] [RFC v2 PATCH 1/6] block: add support functions for live commit, to find and delete images. |
Date: |
Thu, 30 Aug 2012 14:47:39 -0400 |
Add bdrv_find_child(), and bdrv_delete_intermediate().
bdrv_find_child(): given 'bs' and the active (topmost) BDS of an image chain,
find the image that is the immediate top of 'bs'
bdrv_delete_intermediate():
Given 3 BDS (active, top, base), delete images above
base up to and including top, and set base to be the
parent of top's child node.
E.g., this converts:
bottom <- base <- intermediate <- top <- active
to
bottom <- base <- active
where top == active is permitted, although active
will not be deleted.
Signed-off-by: Jeff Cody <address@hidden>
---
block.c | 142 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
block.h | 5 ++-
2 files changed, 146 insertions(+), 1 deletion(-)
diff --git a/block.c b/block.c
index 9470319..11e275c 100644
--- a/block.c
+++ b/block.c
@@ -1752,6 +1752,148 @@ int bdrv_change_backing_file(BlockDriverState *bs,
return ret;
}
+/* Finds the image layer immediately to the 'top' of bs.
+ *
+ * active is the current topmost image.
+ */
+BlockDriverState *bdrv_find_child(BlockDriverState *active,
+ BlockDriverState *bs)
+{
+ BlockDriverState *child = NULL;
+ BlockDriverState *intermediate;
+
+ /* if the active bs layer is the same as the new top, then there
+ * is no image above the top, so it will be returned as the child
+ */
+ if (active == bs) {
+ child = active;
+ } else {
+ intermediate = active;
+ while (intermediate->backing_hd) {
+ if (intermediate->backing_hd == bs) {
+ child = intermediate;
+ break;
+ }
+ intermediate = intermediate->backing_hd;
+ }
+ }
+
+ return child;
+}
+
+typedef struct BlkIntermediateStates {
+ BlockDriverState *bs;
+ QSIMPLEQ_ENTRY(BlkIntermediateStates) entry;
+} BlkIntermediateStates;
+
+
+/* deletes images above 'base' up to and including 'top', and sets the image
+ * above 'top' to have base as its backing file.
+ *
+ * E.g., this will convert the following chain:
+ * bottom <- base <- intermediate <- top <- active
+ *
+ * to
+ *
+ * bottom <- base <- active
+ *
+ * It is allowed for bottom==base, in which case it converts:
+ *
+ * base <- intermediate <- top <- active
+ *
+ * to
+ *
+ * base <- active
+ *
+ * It is also allowed for top==active, except in that case active is not
+ * deleted:
+ *
+ * base <- intermediate <- top
+ *
+ * becomes
+ *
+ * base <- top
+ */
+int bdrv_delete_intermediate(BlockDriverState *active, BlockDriverState *top,
+ BlockDriverState *base)
+{
+ BlockDriverState *intermediate;
+ BlockDriverState *base_bs = NULL;
+ BlockDriverState *new_top_bs = NULL;
+ BlkIntermediateStates *intermediate_state, *next;
+ int ret = -1;
+
+ QSIMPLEQ_HEAD(states_to_delete, BlkIntermediateStates) states_to_delete;
+ QSIMPLEQ_INIT(&states_to_delete);
+
+ if (!top->drv || !base->drv) {
+ goto exit;
+ }
+
+ new_top_bs = bdrv_find_child(active, top);
+
+ /* special case of new_top_bs->backing_hd already pointing to base -
nothing
+ * to do, no intermediate images
+ */
+ if (new_top_bs->backing_hd == base) {
+ ret = 0;
+ goto exit;
+ }
+
+ if (new_top_bs == NULL) {
+ /* we could not find the image above 'top', this is an error */
+ goto exit;
+ }
+
+ /* if the active and top image passed in are the same, then we
+ * can't delete the active, so we start one below
+ */
+ intermediate = (active == top) ? active->backing_hd : top;
+
+ /* now we will go down through the list, and add each BDS we find
+ * into our deletion queue, until we hit the 'base'
+ */
+ while (intermediate) {
+ intermediate_state = g_malloc0(sizeof(BlkIntermediateStates));
+ intermediate_state->bs = intermediate;
+ QSIMPLEQ_INSERT_TAIL(&states_to_delete, intermediate_state, entry);
+
+ if (intermediate->backing_hd == base) {
+ base_bs = intermediate->backing_hd;
+ break;
+ }
+ intermediate = intermediate->backing_hd;
+ }
+ if (base_bs == NULL) {
+ /* something went wrong, we did not end at the base. safely
+ * unravel everything, and exit with error */
+ goto exit;
+ }
+
+ /* success - we can delete the intermediate states, and link top->base */
+ ret = bdrv_change_backing_file(new_top_bs, base_bs->filename,
+ base_bs->drv ? base_bs->drv->format_name :
"");
+ if (ret) {
+ goto exit;
+ }
+ new_top_bs->backing_hd = base_bs;
+
+
+ QSIMPLEQ_FOREACH_SAFE(intermediate_state, &states_to_delete, entry, next) {
+ /* so that bdrv_close() does not recursively close the chain */
+ intermediate_state->bs->backing_hd = NULL;
+ bdrv_delete(intermediate_state->bs);
+ }
+ ret = 0;
+
+exit:
+ QSIMPLEQ_FOREACH_SAFE(intermediate_state, &states_to_delete, entry, next) {
+ g_free(intermediate_state);
+ }
+ return ret;
+}
+
+
static int bdrv_check_byte_request(BlockDriverState *bs, int64_t offset,
size_t size)
{
diff --git a/block.h b/block.h
index db812b1..ee76869 100644
--- a/block.h
+++ b/block.h
@@ -201,7 +201,10 @@ int bdrv_commit_all(void);
int bdrv_change_backing_file(BlockDriverState *bs,
const char *backing_file, const char *backing_fmt);
void bdrv_register(BlockDriver *bdrv);
-
+int bdrv_delete_intermediate(BlockDriverState *active, BlockDriverState *top,
+ BlockDriverState *base);
+BlockDriverState *bdrv_find_child(BlockDriverState *active,
+ BlockDriverState *bs);
typedef struct BdrvCheckResult {
int corruptions;
--
1.7.11.2
- [Qemu-devel] [RFC v2 PATCH 0/6] Live block commit, Jeff Cody, 2012/08/30
- [Qemu-devel] [RFC v2 PATCH 1/6] block: add support functions for live commit, to find and delete images.,
Jeff Cody <=
- [Qemu-devel] [RFC v2 PATCH 2/6] block: add live block commit functionality, Jeff Cody, 2012/08/30
- [Qemu-devel] [RFC v2 PATCH 3/6] blockdev: rename block_stream_cb to a generic block_job_cb, Jeff Cody, 2012/08/30
- [Qemu-devel] [RFC v2 PATCH 5/6] block: helper function, to find the base image of a chain, Jeff Cody, 2012/08/30
- [Qemu-devel] [RFC v2 PATCH 6/6] QAPI: add command for live block commit, 'block-commit', Jeff Cody, 2012/08/30
- [Qemu-devel] [RFC v2 PATCH 4/6] qerror: new error for live block commit, QERR_TOP_NOT_FOUND, Jeff Cody, 2012/08/30
- Re: [Qemu-devel] [RFC v2 PATCH 0/6] Live block commit, Jeff Cody, 2012/08/30