[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [RFC PATCH 1/4] block: add support functions for live commi
From: |
Jeff Cody |
Subject: |
[Qemu-devel] [RFC PATCH 1/4] block: add support functions for live commit, to find and delete images. |
Date: |
Tue, 31 Jul 2012 01:16:10 -0400 |
Add bdrv_find_image(), bdrv_find_base(), and bdrv_delete_intermediate().
bdrv_find_image(): given a filename and a BDS, find the image in the chain
that matches the passed filename.
bdrv_find_base(): given a BDS, find the base image (parent-most image)
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.
Signed-off-by: Jeff Cody <address@hidden>
---
block.c | 136 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
block.h | 4 ++
2 files changed, 139 insertions(+), 1 deletion(-)
diff --git a/block.c b/block.c
index 522acd1..a3c8d33 100644
--- a/block.c
+++ b/block.c
@@ -1408,7 +1408,7 @@ int bdrv_commit(BlockDriverState *bs)
if (!drv)
return -ENOMEDIUM;
-
+
if (!bs->backing_hd) {
return -ENOTSUP;
}
@@ -1661,6 +1661,110 @@ int bdrv_change_backing_file(BlockDriverState *bs,
return ret;
}
+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.
+ */
+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;
+ }
+
+ /* special case of top->backing_hd already pointing to base - nothing
+ * to do, no intermediate images
+ */
+ if (top->backing_hd == base) {
+ ret = 0;
+ goto exit;
+ }
+
+ /* if the active bs layer is the same as the new top, then there
+ * is no image above the top, so it is also the new_top (and we must
+ * not delete it below, either)
+ */
+ if (active == top) {
+ new_top_bs = active;
+ } else {
+ intermediate = active;
+ while (intermediate->backing_hd) {
+ if (intermediate->backing_hd == top) {
+ new_top_bs = intermediate;
+ break;
+ }
+ intermediate = intermediate->backing_hd;
+ }
+ }
+
+ 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)
{
@@ -3128,6 +3232,36 @@ BlockDriverState
*bdrv_find_backing_image(BlockDriverState *bs,
return NULL;
}
+BlockDriverState *bdrv_find_image(BlockDriverState *bs,
+ const char *filename)
+{
+ if (!bs || !bs->drv) {
+ return NULL;
+ }
+
+ if (strcmp(bs->filename, filename) == 0) {
+ return bs;
+ } else {
+ return bdrv_find_image(bs->backing_hd, filename);
+ }
+}
+
+BlockDriverState *bdrv_find_base(BlockDriverState *bs)
+{
+ BlockDriverState *curr_bs = NULL;
+
+ if (!bs) {
+ return NULL;
+ }
+
+ curr_bs = bs;
+
+ while (curr_bs->backing_hd) {
+ curr_bs = curr_bs->backing_hd;
+ }
+ return curr_bs;
+}
+
#define NB_SUFFIXES 4
char *get_human_readable_size(char *buf, int buf_size, int64_t size)
diff --git a/block.h b/block.h
index 25e0230..70fa53c 100644
--- a/block.h
+++ b/block.h
@@ -183,6 +183,10 @@ int bdrv_change_backing_file(BlockDriverState *bs,
const char *backing_file, const char *backing_fmt);
void bdrv_register(BlockDriver *bdrv);
int bdrv_change_hostcache(BlockDriverState *bs, bool enable_host_cache);
+BlockDriverState *bdrv_find_image(BlockDriverState *bs, const char *filename);
+BlockDriverState *bdrv_find_base(BlockDriverState *bs);
+int bdrv_delete_intermediate(BlockDriverState *active, BlockDriverState *top,
+ BlockDriverState *base);
typedef struct BdrvCheckResult {
--
1.7.10.4
- [Qemu-devel] [RFC PATCH 0/4] Live block commit, Jeff Cody, 2012/07/31
- [Qemu-devel] [RFC PATCH 1/4] block: add support functions for live commit, to find and delete images.,
Jeff Cody <=
- [Qemu-devel] [RFC PATCH 3/4] qerror: new errors for live block commit, QERR_TOP_NOT_FOUND, Jeff Cody, 2012/07/31
- [Qemu-devel] [RFC PATCH 4/4] QAPI: add command for live block commit, 'block-commit', Jeff Cody, 2012/07/31
- [Qemu-devel] [RFC PATCH 2/4] block: add live block commit functionality, Jeff Cody, 2012/07/31