[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH v5 07/12] qemu-img: Empty images after commit
From: |
Max Reitz |
Subject: |
[Qemu-devel] [PATCH v5 07/12] qemu-img: Empty images after commit |
Date: |
Thu, 17 Apr 2014 23:59:47 +0200 |
After the top image has been committed into an image in its backing
chain, all images above that base image should be emptied to restore the
old qemu-img commit behavior.
Signed-off-by: Max Reitz <address@hidden>
---
qemu-img.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 84 insertions(+), 3 deletions(-)
diff --git a/qemu-img.c b/qemu-img.c
index 7ee791f..42616da 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -49,6 +49,11 @@ typedef enum OutputFormat {
OFORMAT_HUMAN,
} OutputFormat;
+typedef struct BackingList {
+ BlockDriverState *bs;
+ QSIMPLEQ_ENTRY(BackingList) list;
+} BackingList;
+
/* Default to cache=writeback as data integrity is not important for qemu-tcg.
*/
#define BDRV_O_FLAGS BDRV_O_CACHE_WB
#define BDRV_DEFAULT_CACHE "writeback"
@@ -717,10 +722,13 @@ static int img_commit(int argc, char **argv)
{
int c, ret, flags;
const char *filename, *fmt, *cache;
- BlockDriverState *bs, *base_bs;
+ BlockDriverState *bs, *base_bs, *backing_bs;
bool quiet = false;
Error *local_err = NULL;
CommonBlockJobCBInfo cbi;
+ BackingList *bl_element, *bl_next;
+ QSIMPLEQ_HEAD(, BackingList) backing_list =
+ QSIMPLEQ_HEAD_INITIALIZER(backing_list);
fmt = NULL;
cache = BDRV_DEFAULT_CACHE;
@@ -750,7 +758,7 @@ static int img_commit(int argc, char **argv)
}
filename = argv[optind++];
- flags = BDRV_O_RDWR;
+ flags = BDRV_O_RDWR | BDRV_O_UNMAP;
ret = bdrv_parse_cache_flags(cache, &flags);
if (ret < 0) {
error_report("Invalid cache option: %s", cache);
@@ -771,6 +779,32 @@ static int img_commit(int argc, char **argv)
goto done;
}
+ /* Build a list of the intermediate backing images in order to be able to
+ * empty them later; note that base_bs is included in this list although we
+ * actually want to empty bs instead. As bdrv_swap() will be called on both
+ * by the commit block job, it is however correct to use the pointer to
+ * base_bs in order to clear bs. */
+ backing_bs = bs;
+
+ do {
+ backing_bs = backing_bs->backing_hd;
+ assert(backing_bs);
+
+ bl_element = g_new(BackingList, 1);
+ bl_element->bs = backing_bs;
+
+ if (backing_bs != base_bs) {
+ /* Generally, the images should be emptied from top to bottom in
+ * order to keep them consistent even if one make_empty operation
+ * fails because it could empty an image only partially */
+ QSIMPLEQ_INSERT_TAIL(&backing_list, bl_element, list);
+ } else {
+ /* The final pointer in the backing chain will however later point
+ * to the image at the very top, so put it at the front instead */
+ QSIMPLEQ_INSERT_HEAD(&backing_list, bl_element, list);
+ }
+ } while (backing_bs != base_bs);
+
cbi = (CommonBlockJobCBInfo){
.errp = &local_err,
.bs = bs,
@@ -779,10 +813,57 @@ static int img_commit(int argc, char **argv)
commit_active_start(bs, base_bs, 0, BLOCKDEV_ON_ERROR_REPORT,
common_block_job_cb, &cbi, &local_err);
if (local_err) {
- goto done;
+ goto free_backing_list;
+ }
+
+ /* The block job will swap base_bs and bs (which is not what we really want
+ * here, but okay) and unref bs (and subsequently all intermediate block
+ * devices). In order to be able to empty these images afterwards,
increment
+ * the reference counter here preemptively. */
+ QSIMPLEQ_FOREACH(bl_element, &backing_list, list) {
+ bdrv_ref(bl_element->bs);
}
run_block_job(bs->job, &local_err);
+ if (local_err) {
+ goto unref_backing;
+ }
+
+ QSIMPLEQ_FOREACH(bl_element, &backing_list, list) {
+ if (bl_element->bs->drv->bdrv_make_empty) {
+ if (bl_element->bs->read_only) {
+ /* If this is an intermediate file in the backing chain between
+ * the top and the bottom image, it has been opened implicitly
+ * read-only; reopen it R/W for emptying */
+ ret = bdrv_reopen(bl_element->bs, flags, &local_err);
+ if (ret < 0 || local_err) {
+ if (!local_err) {
+ error_setg_errno(&local_err, -ret,
+ "Could not write to %s",
+ bl_element->bs->filename);
+ }
+ goto unref_backing;
+ }
+ }
+
+ ret = bl_element->bs->drv->bdrv_make_empty(bl_element->bs);
+ if (ret) {
+ error_setg_errno(&local_err, -ret, "Could not empty %s",
+ bl_element->bs->filename);
+ goto unref_backing;
+ }
+ }
+ }
+
+unref_backing:
+ QSIMPLEQ_FOREACH(bl_element, &backing_list, list) {
+ bdrv_unref(bl_element->bs);
+ }
+
+free_backing_list:
+ QSIMPLEQ_FOREACH_SAFE(bl_element, &backing_list, list, bl_next) {
+ g_free(bl_element);
+ }
done:
bdrv_unref(bs);
--
1.9.2
- [Qemu-devel] [PATCH v5 01/12] qcow2: Allow "full" discard, (continued)
- [Qemu-devel] [PATCH v5 01/12] qcow2: Allow "full" discard, Max Reitz, 2014/04/17
- [Qemu-devel] [PATCH v5 04/12] blockjob: Add "ready" field, Max Reitz, 2014/04/17
- [Qemu-devel] [PATCH v5 03/12] blockjob: Introduce block_job_complete_sync(), Max Reitz, 2014/04/17
- [Qemu-devel] [PATCH v5 05/12] block/mirror: Improve progress report, Max Reitz, 2014/04/17
- [Qemu-devel] [PATCH v5 06/12] qemu-img: Implement commit like QMP, Max Reitz, 2014/04/17
- [Qemu-devel] [PATCH v5 07/12] qemu-img: Empty images after commit,
Max Reitz <=
- Re: [Qemu-devel] [PATCH v5 07/12] qemu-img: Empty images after commit, Eric Blake, 2014/04/22
- Re: [Qemu-devel] [PATCH v5 07/12] qemu-img: Empty images after commit, Max Reitz, 2014/04/22
- Re: [Qemu-devel] [PATCH v5 07/12] qemu-img: Empty images after commit, Max Reitz, 2014/04/22
- Re: [Qemu-devel] [PATCH v5 07/12] qemu-img: Empty images after commit, Eric Blake, 2014/04/22
- Re: [Qemu-devel] [PATCH v5 07/12] qemu-img: Empty images after commit, Max Reitz, 2014/04/22
- Re: [Qemu-devel] [PATCH v5 07/12] qemu-img: Empty images after commit, Eric Blake, 2014/04/22
- Re: [Qemu-devel] [PATCH v5 07/12] qemu-img: Empty images after commit, Kevin Wolf, 2014/04/23
- Re: [Qemu-devel] [PATCH v5 07/12] qemu-img: Empty images after commit, Max Reitz, 2014/04/24
- Re: [Qemu-devel] [PATCH v5 07/12] qemu-img: Empty images after commit, Kevin Wolf, 2014/04/24
[Qemu-devel] [PATCH v5 08/12] qemu-img: Enable progress output for commit, Max Reitz, 2014/04/17