aboutsummaryrefslogtreecommitdiff
path: root/qemu-img.c
diff options
context:
space:
mode:
Diffstat (limited to 'qemu-img.c')
-rw-r--r--qemu-img.c85
1 files changed, 55 insertions, 30 deletions
diff --git a/qemu-img.c b/qemu-img.c
index 28fba1e7a7..b0535919b1 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -3164,7 +3164,7 @@ static int img_rebase(int argc, char **argv)
BlockBackend *blk = NULL, *blk_old_backing = NULL, *blk_new_backing = NULL;
uint8_t *buf_old = NULL;
uint8_t *buf_new = NULL;
- BlockDriverState *bs = NULL;
+ BlockDriverState *bs = NULL, *prefix_chain_bs = NULL;
char *filename;
const char *fmt, *cache, *src_cache, *out_basefmt, *out_baseimg;
int c, flags, src_flags, ret;
@@ -3309,29 +3309,18 @@ static int img_rebase(int argc, char **argv)
/* For safe rebasing we need to compare old and new backing file */
if (!unsafe) {
- char backing_name[PATH_MAX];
QDict *options = NULL;
+ BlockDriverState *base_bs = backing_bs(bs);
- if (bs->backing) {
- if (bs->backing_format[0] != '\0') {
- options = qdict_new();
- qdict_put_str(options, "driver", bs->backing_format);
- }
-
- if (force_share) {
- if (!options) {
- options = qdict_new();
- }
- qdict_put_bool(options, BDRV_OPT_FORCE_SHARE, true);
- }
- bdrv_get_backing_filename(bs, backing_name, sizeof(backing_name));
- blk_old_backing = blk_new_open(backing_name, NULL,
- options, src_flags, &local_err);
- if (!blk_old_backing) {
+ if (base_bs) {
+ blk_old_backing = blk_new(BLK_PERM_CONSISTENT_READ,
+ BLK_PERM_ALL);
+ ret = blk_insert_bs(blk_old_backing, base_bs,
+ &local_err);
+ if (ret < 0) {
error_reportf_err(local_err,
- "Could not open old backing file '%s': ",
- backing_name);
- ret = -1;
+ "Could not reuse old backing file '%s': ",
+ base_bs->filename);
goto out;
}
} else {
@@ -3364,15 +3353,34 @@ static int img_rebase(int argc, char **argv)
goto out;
}
- blk_new_backing = blk_new_open(out_real_path, NULL,
- options, src_flags, &local_err);
- g_free(out_real_path);
- if (!blk_new_backing) {
- error_reportf_err(local_err,
- "Could not open new backing file '%s': ",
- out_baseimg);
- ret = -1;
- goto out;
+ /*
+ * Find out whether we rebase an image on top of a previous image
+ * in its chain.
+ */
+ prefix_chain_bs = bdrv_find_backing_image(bs, out_real_path);
+ if (prefix_chain_bs) {
+ g_free(out_real_path);
+ blk_new_backing = blk_new(BLK_PERM_CONSISTENT_READ,
+ BLK_PERM_ALL);
+ ret = blk_insert_bs(blk_new_backing, prefix_chain_bs,
+ &local_err);
+ if (ret < 0) {
+ error_reportf_err(local_err,
+ "Could not reuse backing file '%s': ",
+ out_baseimg);
+ goto out;
+ }
+ } else {
+ blk_new_backing = blk_new_open(out_real_path, NULL,
+ options, src_flags, &local_err);
+ g_free(out_real_path);
+ if (!blk_new_backing) {
+ error_reportf_err(local_err,
+ "Could not open new backing file '%s': ",
+ out_baseimg);
+ ret = -1;
+ goto out;
+ }
}
}
}
@@ -3448,6 +3456,23 @@ static int img_rebase(int argc, char **argv)
continue;
}
+ if (prefix_chain_bs) {
+ /*
+ * If cluster wasn't changed since prefix_chain, we don't need
+ * to take action
+ */
+ ret = bdrv_is_allocated_above(backing_bs(bs), prefix_chain_bs,
+ offset, n, &n);
+ if (ret < 0) {
+ error_report("error while reading image metadata: %s",
+ strerror(-ret));
+ goto out;
+ }
+ if (!ret) {
+ continue;
+ }
+ }
+
/*
* Read old and new backing file and take into consideration that
* backing files may be smaller than the COW image.