Skip to content

Commit

Permalink
qemu-img: add compression option to rebase subcommand
Browse files Browse the repository at this point in the history
If we rebase an image whose backing file has compressed clusters, we
might end up wasting disk space since the copied clusters are now
uncompressed.  In order to have better control over this, let's add
"--compress" option to the "qemu-img rebase" command.

Note that this option affects only the clusters which are actually being
copied from the original backing file.  The clusters which were
uncompressed in the target image will remain so.

Signed-off-by: Andrey Drobyshev <andrey.drobyshev@virtuozzo.com>
Reviewed-by: Denis V. Lunev <den@openvz.org>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-ID: <20230919165804.439110-8-andrey.drobyshev@virtuozzo.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
  • Loading branch information
Andrey Drobyshev authored and kevmw committed Oct 31, 2023
1 parent f93e65e commit 26ea278
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 10 deletions.
6 changes: 4 additions & 2 deletions docs/tools/qemu-img.rst
Original file line number Diff line number Diff line change
Expand Up @@ -667,7 +667,7 @@ Command description:

List, apply, create or delete snapshots in image *FILENAME*.

.. option:: rebase [--object OBJECTDEF] [--image-opts] [-U] [-q] [-f FMT] [-t CACHE] [-T SRC_CACHE] [-p] [-u] -b BACKING_FILE [-F BACKING_FMT] FILENAME
.. option:: rebase [--object OBJECTDEF] [--image-opts] [-U] [-q] [-f FMT] [-t CACHE] [-T SRC_CACHE] [-p] [-u] [-c] -b BACKING_FILE [-F BACKING_FMT] FILENAME

Changes the backing file of an image. Only the formats ``qcow2`` and
``qed`` support changing the backing file.
Expand All @@ -694,7 +694,9 @@ Command description:

In order to achieve this, any clusters that differ between
*BACKING_FILE* and the old backing file of *FILENAME* are merged
into *FILENAME* before actually changing the backing file.
into *FILENAME* before actually changing the backing file. With the
``-c`` option specified, the clusters which are being merged (but not
the entire *FILENAME* image) are compressed when written.

Note that the safe mode is an expensive operation, comparable to
converting an image. It only works if the old backing file still
Expand Down
4 changes: 2 additions & 2 deletions qemu-img-cmds.hx
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,9 @@ SRST
ERST

DEF("rebase", img_rebase,
"rebase [--object objectdef] [--image-opts] [-U] [-q] [-f fmt] [-t cache] [-T src_cache] [-p] [-u] -b backing_file [-F backing_fmt] filename")
"rebase [--object objectdef] [--image-opts] [-U] [-q] [-f fmt] [-t cache] [-T src_cache] [-p] [-u] [-c] -b backing_file [-F backing_fmt] filename")
SRST
.. option:: rebase [--object OBJECTDEF] [--image-opts] [-U] [-q] [-f FMT] [-t CACHE] [-T SRC_CACHE] [-p] [-u] -b BACKING_FILE [-F BACKING_FMT] FILENAME
.. option:: rebase [--object OBJECTDEF] [--image-opts] [-U] [-q] [-f FMT] [-t CACHE] [-T SRC_CACHE] [-p] [-u] [-c] -b BACKING_FILE [-F BACKING_FMT] FILENAME
ERST

DEF("resize", img_resize,
Expand Down
26 changes: 20 additions & 6 deletions qemu-img.c
Original file line number Diff line number Diff line change
Expand Up @@ -3534,11 +3534,13 @@ static int img_rebase(int argc, char **argv)
char *filename;
const char *fmt, *cache, *src_cache, *out_basefmt, *out_baseimg;
int c, flags, src_flags, ret;
BdrvRequestFlags write_flags = 0;
bool writethrough, src_writethrough;
int unsafe = 0;
bool force_share = false;
int progress = 0;
bool quiet = false;
bool compress = false;
Error *local_err = NULL;
bool image_opts = false;
int64_t write_align;
Expand All @@ -3555,9 +3557,10 @@ static int img_rebase(int argc, char **argv)
{"object", required_argument, 0, OPTION_OBJECT},
{"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
{"force-share", no_argument, 0, 'U'},
{"compress", no_argument, 0, 'c'},
{0, 0, 0, 0}
};
c = getopt_long(argc, argv, ":hf:F:b:upt:T:qU",
c = getopt_long(argc, argv, ":hf:F:b:upt:T:qUc",
long_options, NULL);
if (c == -1) {
break;
Expand Down Expand Up @@ -3605,6 +3608,9 @@ static int img_rebase(int argc, char **argv)
case 'U':
force_share = true;
break;
case 'c':
compress = true;
break;
}
}

Expand Down Expand Up @@ -3657,6 +3663,14 @@ static int img_rebase(int argc, char **argv)

unfiltered_bs = bdrv_skip_filters(bs);

if (compress && !block_driver_can_compress(unfiltered_bs->drv)) {
error_report("Compression not supported for this file format");
ret = -1;
goto out;
} else if (compress) {
write_flags |= BDRV_REQ_WRITE_COMPRESSED;
}

if (out_basefmt != NULL) {
if (bdrv_find_format(out_basefmt) == NULL) {
error_report("Invalid format name: '%s'", out_basefmt);
Expand All @@ -3666,18 +3680,18 @@ static int img_rebase(int argc, char **argv)
}

/*
* We need overlay subcluster size to make sure write requests are
* aligned.
* We need overlay subcluster size (or cluster size in case writes are
* compressed) to make sure write requests are aligned.
*/
ret = bdrv_get_info(unfiltered_bs, &bdi);
if (ret < 0) {
error_report("could not get block driver info");
goto out;
} else if (bdi.subcluster_size == 0) {
bdi.subcluster_size = 1;
bdi.cluster_size = bdi.subcluster_size = 1;
}

write_align = bdi.subcluster_size;
write_align = compress ? bdi.cluster_size : bdi.subcluster_size;

/* For safe rebasing we need to compare old and new backing file */
if (!unsafe) {
Expand Down Expand Up @@ -3930,7 +3944,7 @@ static int img_rebase(int argc, char **argv)
} else {
assert(written + pnum <= IO_BUF_SIZE);
ret = blk_pwrite(blk, offset + written, pnum,
buf_old + written, 0);
buf_old + written, write_flags);
}
if (ret < 0) {
error_report("Error while writing to COW image: %s",
Expand Down

0 comments on commit 26ea278

Please sign in to comment.