From 5fe5b2adf33815428e87bb2cbde549f8a0187c1e Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 26 Aug 2014 17:01:41 -0500 Subject: [CHANGE 2/3] qemu-img: Allow source cache mode specification To: rhvirt-patches@redhat.com, jen@redhat.com RH-Author: Stefan Hajnoczi Message-id: <1409072501-28240-3-git-send-email-stefanha@redhat.com> Patchwork-id: 60710 O-Subject: [PATCH v2 2/2] qemu-img: Allow source cache mode specification Bugzilla: 1116558 RH-Acked-by: John Snow RH-Acked-by: Markus Armbruster RH-Acked-by: Jeffrey Cody From: Max Reitz Many qemu-img subcommands only read the source file(s) once. For these use cases, a full write-back cache is unnecessary and mainly clutters host cache memory. Though this is generally no concern as cache memory is freely available and can be scaled by the host OS, it may become a concern with thin provisioning. For these cases, it makes sense to allow users to freely specify the source cache mode (e.g. use no cache at all). This commit adds a new switch (-T) for the qemu-img subcommands check, compare, convert and rebase to specify the cache to be used for source images (the backing file in case of rebase). Signed-off-by: Max Reitz Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf (cherry picked from commit 40055951a7afbfc037c6c7351d72a5c5d83ed99b) Signed-off-by: Stefan Hajnoczi Signed-off-by: Jeff E. Nelson Conflicts: qemu-img-cmds.hx qemu-img.c qemu-img.texi Upstream has additional command-line options which were not backported. This causes conflicts in documentation and getopt parsing. Upstream has a different qemu-img.c:bdrv_new_open() signature that causes conflicts. Upstream parses img_compare() source cache flags before qemu_progress_init() so that goto out3 would call qemu_progress_end(). This is incorrect, I have sent a fix upstream and included the small ordering change in this backport. --- qemu-img-cmds.hx | 16 ++++++------ qemu-img.c | 76 +++++++++++++++++++++++++++++++++++++++++++++----------- qemu-img.texi | 14 ++++++++--- 3 files changed, 79 insertions(+), 27 deletions(-) Signed-off-by: Jeff E. Nelson --- qemu-img-cmds.hx | 16 ++++++------ qemu-img.c | 76 +++++++++++++++++++++++++++++++++++++++++++++----------- qemu-img.texi | 14 ++++++++--- 3 files changed, 79 insertions(+), 27 deletions(-) diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx index 05af6ed..6435095 100644 --- a/qemu-img-cmds.hx +++ b/qemu-img-cmds.hx @@ -10,9 +10,9 @@ STEXI ETEXI DEF("check", img_check, - "check [-f fmt] [--output=ofmt] [-r [leaks | all]] filename") + "check [-f fmt] [--output=ofmt] [-r [leaks | all]] [-T src_cache] filename") STEXI -@item check [-f @var{fmt}] [--output=@var{ofmt}] [-r [leaks | all]] @var{filename} +@item check [-f @var{fmt}] [--output=@var{ofmt}] [-r [leaks | all]] [-T @var{src_cache}] @var{filename} ETEXI DEF("create", img_create, @@ -28,15 +28,15 @@ STEXI ETEXI DEF("compare", img_compare, - "compare [-f fmt] [-F fmt] [-p] [-s] filename1 filename2") + "compare [-f fmt] [-F fmt] [-T src_cache] [-p] [-s] filename1 filename2") STEXI -@item compare [-f @var{fmt}] [-F @var{fmt}] [-p] [-s] @var{filename1} @var{filename2} +@item compare [-f @var{fmt}] [-F @var{fmt}] [-T @var{src_cache}] [-p] [-s] @var{filename1} @var{filename2} ETEXI DEF("convert", img_convert, - "convert [-c] [-p] [-f fmt] [-t cache] [-O output_fmt] [-o options] [-S sparse_size] filename [filename2 [...]] output_filename") + "convert [-c] [-p] [-f fmt] [-t cache] [-T src_cache] [-O output_fmt] [-o options] [-S sparse_size] filename [filename2 [...]] output_filename") STEXI -@item convert [-c] [-p] [-f @var{fmt}] [-t @var{cache}] [-O @var{output_fmt}] [-o @var{options}] [-S @var{sparse_size}] @var{filename} [@var{filename2} [...]] @var{output_filename} +@item convert [-c] [-p] [-f @var{fmt}] [-t @var{cache}] [-T @var{src_cache}] [-O @var{output_fmt}] [-o @var{options}] [-S @var{sparse_size}] @var{filename} [@var{filename2} [...]] @var{output_filename} ETEXI DEF("info", img_info, @@ -58,9 +58,9 @@ STEXI ETEXI DEF("rebase", img_rebase, - "rebase [-f fmt] [-t cache] [-p] [-u] -b backing_file [-F backing_fmt] filename") + "rebase [-f fmt] [-t cache] [-T src_cache] [-p] [-u] -b backing_file [-F backing_fmt] filename") STEXI -@item rebase [-f @var{fmt}] [-t @var{cache}] [-p] [-u] -b @var{backing_file} [-F @var{backing_fmt}] @var{filename} +@item rebase [-f @var{fmt}] [-t @var{cache}] [-T @var{src_cache}] [-p] [-u] -b @var{backing_file} [-F @var{backing_fmt}] @var{filename} ETEXI DEF("resize", img_resize, diff --git a/qemu-img.c b/qemu-img.c index 31be4bd..bc31cf2 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -79,6 +79,7 @@ static void help(void) " 'fmt' is the disk image format. It is guessed automatically in most cases\n" " 'cache' is the cache mode used to write the output disk image, the valid\n" " options are: 'none', 'writeback' (default), 'writethrough' and 'unsafe'\n" + " 'src_cache' in contrast is the cache mode used to read input disk images\n" " 'size' is the disk image size in bytes. Optional suffixes\n" " 'k' or 'K' (kilobyte, 1024), 'M' (megabyte, 1024k), 'G' (gigabyte, 1024M)\n" " and T (terabyte, 1024G) are supported. 'b' is ignored.\n" @@ -485,7 +486,7 @@ static int img_check(int argc, char **argv) { int c, ret; OutputFormat output_format = OFORMAT_HUMAN; - const char *filename, *fmt, *output; + const char *filename, *fmt, *output, *cache; BlockDriverState *bs; int fix = 0; int flags = BDRV_O_FLAGS | BDRV_O_CHECK; @@ -493,6 +494,7 @@ static int img_check(int argc, char **argv) fmt = NULL; output = NULL; + cache = BDRV_DEFAULT_CACHE; for(;;) { int option_index = 0; static const struct option long_options[] = { @@ -502,7 +504,7 @@ static int img_check(int argc, char **argv) {"output", required_argument, 0, OPTION_OUTPUT}, {0, 0, 0, 0} }; - c = getopt_long(argc, argv, "f:hr:", + c = getopt_long(argc, argv, "hf:r:T:", long_options, &option_index); if (c == -1) { break; @@ -529,6 +531,9 @@ static int img_check(int argc, char **argv) case OPTION_OUTPUT: output = optarg; break; + case 'T': + cache = optarg; + break; } } if (optind >= argc) { @@ -545,6 +550,12 @@ static int img_check(int argc, char **argv) return 1; } + ret = bdrv_parse_cache_flags(cache, &flags); + if (ret < 0) { + error_report("Invalid source cache option: %s", cache); + return 1; + } + bs = bdrv_new_open(filename, fmt, flags, true); if (!bs) { return 1; @@ -831,7 +842,7 @@ static int check_empty_sectors(BlockDriverState *bs, int64_t sect_num, */ static int img_compare(int argc, char **argv) { - const char *fmt1 = NULL, *fmt2 = NULL, *filename1, *filename2; + const char *fmt1 = NULL, *fmt2 = NULL, *cache, *filename1, *filename2; BlockDriverState *bs1, *bs2; int64_t total_sectors1, total_sectors2; uint8_t *buf1 = NULL, *buf2 = NULL; @@ -839,6 +850,7 @@ static int img_compare(int argc, char **argv) int allocated1, allocated2; int ret = 0; /* return value - 0 Ident, 1 Different, >1 Error */ bool progress = false, strict = false; + int flags; int64_t total_sectors; int64_t sector_num = 0; int64_t nb_sectors; @@ -846,8 +858,9 @@ static int img_compare(int argc, char **argv) uint64_t bs_sectors; uint64_t progress_base; + cache = BDRV_DEFAULT_CACHE; for (;;) { - c = getopt(argc, argv, "hpf:F:s"); + c = getopt(argc, argv, "hf:F:T:ps"); if (c == -1) { break; } @@ -862,6 +875,9 @@ static int img_compare(int argc, char **argv) case 'F': fmt2 = optarg; break; + case 'T': + cache = optarg; + break; case 'p': progress = true; break; @@ -880,14 +896,22 @@ static int img_compare(int argc, char **argv) /* Initialize before goto out */ qemu_progress_init(progress, 2.0); - bs1 = bdrv_new_open(filename1, fmt1, BDRV_O_FLAGS, true); + flags = BDRV_O_FLAGS; + ret = bdrv_parse_cache_flags(cache, &flags); + if (ret < 0) { + error_report("Invalid source cache option: %s", cache); + ret = 2; + goto out3; + } + + bs1 = bdrv_new_open(filename1, fmt1, flags, true); if (!bs1) { error_report("Can't open file %s", filename1); ret = 2; goto out3; } - bs2 = bdrv_new_open(filename2, fmt2, BDRV_O_FLAGS, true); + bs2 = bdrv_new_open(filename2, fmt2, flags, true); if (!bs2) { error_report("Can't open file %s", filename2); ret = 2; @@ -1055,8 +1079,8 @@ out3: static int img_convert(int argc, char **argv) { int c, ret = 0, n, n1, bs_n, bs_i, compress, cluster_size, cluster_sectors; - int progress = 0, flags; - const char *fmt, *out_fmt, *cache, *out_baseimg, *out_filename; + int progress = 0, flags, src_flags; + const char *fmt, *out_fmt, *cache, *src_cache, *out_baseimg, *out_filename; BlockDriver *drv, *proto_drv; BlockDriverState **bs = NULL, *out_bs = NULL; int64_t total_sectors, nb_sectors, sector_num, bs_offset; @@ -1073,10 +1097,11 @@ static int img_convert(int argc, char **argv) fmt = NULL; out_fmt = "raw"; cache = "unsafe"; + src_cache = BDRV_DEFAULT_CACHE; out_baseimg = NULL; compress = 0; for(;;) { - c = getopt(argc, argv, "f:O:B:hce6o:pS:t:"); + c = getopt(argc, argv, "hf:O:B:ce6o:S:pt:T:"); if (c == -1) { break; } @@ -1126,6 +1151,9 @@ static int img_convert(int argc, char **argv) case 't': cache = optarg; break; + case 'T': + src_cache = optarg; + break; } } @@ -1151,13 +1179,20 @@ static int img_convert(int argc, char **argv) goto out; } + src_flags = BDRV_O_FLAGS; + ret = bdrv_parse_cache_flags(src_cache, &src_flags); + if (ret < 0) { + error_report("Invalid source cache option: %s", src_cache); + goto out; + } + qemu_progress_print(0, 100); bs = qemu_mallocz(bs_n * sizeof(BlockDriverState *)); total_sectors = 0; for (bs_i = 0; bs_i < bs_n; bs_i++) { - bs[bs_i] = bdrv_new_open(argv[optind + bs_i], fmt, BDRV_O_FLAGS, true); + bs[bs_i] = bdrv_new_open(argv[optind + bs_i], fmt, src_flags, true); if (!bs[bs_i]) { error_report("Could not open '%s'", argv[optind + bs_i]); ret = -1; @@ -2141,18 +2176,19 @@ static int img_rebase(int argc, char **argv) BlockDriverState *bs, *bs_old_backing = NULL, *bs_new_backing = NULL; BlockDriver *old_backing_drv, *new_backing_drv; char *filename; - const char *fmt, *cache, *out_basefmt, *out_baseimg; - int c, flags, ret; + const char *fmt, *cache, *src_cache, *out_basefmt, *out_baseimg; + int c, flags, src_flags, ret; int unsafe = 0; int progress = 0; /* Parse commandline parameters */ fmt = NULL; cache = BDRV_DEFAULT_CACHE; + src_cache = BDRV_DEFAULT_CACHE; out_baseimg = NULL; out_basefmt = NULL; for(;;) { - c = getopt(argc, argv, "uhf:F:b:pt:"); + c = getopt(argc, argv, "hf:F:b:upt:T:"); if (c == -1) { break; } @@ -2179,6 +2215,9 @@ static int img_rebase(int argc, char **argv) case 't': cache = optarg; break; + case 'T': + src_cache = optarg; + break; } } @@ -2197,6 +2236,13 @@ static int img_rebase(int argc, char **argv) return -1; } + src_flags = BDRV_O_FLAGS; + ret = bdrv_parse_cache_flags(src_cache, &src_flags); + if (ret < 0) { + error_report("Invalid source cache option: %s", src_cache); + return -1; + } + /* * Open the images. * @@ -2240,7 +2286,7 @@ static int img_rebase(int argc, char **argv) bs_old_backing = bdrv_new("old_backing"); bdrv_get_backing_filename(bs, backing_name, sizeof(backing_name)); - ret = bdrv_open(bs_old_backing, backing_name, BDRV_O_FLAGS, + ret = bdrv_open(bs_old_backing, backing_name, src_flags, old_backing_drv); if (ret) { error_report("Could not open old backing file '%s'", backing_name); @@ -2248,7 +2294,7 @@ static int img_rebase(int argc, char **argv) } if (out_baseimg[0]) { bs_new_backing = bdrv_new("new_backing"); - ret = bdrv_open(bs_new_backing, out_baseimg, BDRV_O_FLAGS, + ret = bdrv_open(bs_new_backing, out_baseimg, src_flags, new_backing_drv); if (ret) { error_report("Could not open new backing file '%s'", diff --git a/qemu-img.texi b/qemu-img.texi index 3ed69cb..c7042ed 100644 --- a/qemu-img.texi +++ b/qemu-img.texi @@ -51,6 +51,9 @@ down to the nearest 512 bytes. You may use the common size suffixes like specifies the cache mode that should be used with the (destination) file. See the documentation of the emulator's @code{-drive cache=...} option for allowed values. +@item -T @var{src_cache} +in contrast specifies the cache mode that should be used with the source +file(s). @end table Parameters to snapshot subcommand: @@ -84,7 +87,7 @@ Strict mode - fail on on different image size or sector allocation Command description: @table @option -@item check [-f @var{fmt}] [--output=@var{ofmt}] [-r [leaks | all]] @var{filename} +@item check [-f @var{fmt}] [--output=@var{ofmt}] [-r [leaks | all]] [-T @var{src_cache}] @var{filename} Perform a consistency check on the disk image @var{filename}. The command can output in the format @var{ofmt} which is either @code{human} or @code{json}. @@ -138,7 +141,7 @@ it doesn't need to be specified separately in this case. Commit the changes recorded in @var{filename} in its base image. -@item compare [-f @var{fmt}] [-F @var{fmt}] [-p] [-s] @var{filename1} @var{filename2} +@item compare [-f @var{fmt}] [-F @var{fmt}] [-T @var{src_cache}] [-p] [-s] @var{filename1} @var{filename2} Check if two images have the same content. You can compare images with different format or settings. @@ -179,7 +182,7 @@ Error on reading data @end table -@item convert [-c] [-p] [-f @var{fmt}] [-t @var{cache}] [-O @var{output_fmt}] [-o @var{options}] [-S @var{sparse_size}] @var{filename} [@var{filename2} [...]] @var{output_filename} +@item convert [-c] [-p] [-f @var{fmt}] [-t @var{cache}] [-T @var{src_cache}] [-O @var{output_fmt}] [-o @var{options}] [-S @var{sparse_size}] @var{filename} [@var{filename2} [...]] @var{output_filename} Convert the disk image @var{filename} to disk image @var{output_filename} using format @var{output_fmt}. It can be optionally compressed (@code{-c} @@ -265,7 +268,7 @@ source code. List, apply, create or delete snapshots in image @var{filename}. -@item rebase [-f @var{fmt}] [-t @var{cache}] [-p] [-u] -b @var{backing_file} [-F @var{backing_fmt}] @var{filename} +@item rebase [-f @var{fmt}] [-t @var{cache}] [-T @var{src_cache}] [-p] [-u] -b @var{backing_file} [-F @var{backing_fmt}] @var{filename} Changes the backing file of an image. Only the formats @code{qcow2} and @code{qed} support changing the backing file. @@ -276,6 +279,9 @@ The backing file is changed to @var{backing_file} and (if the image format of string), then the image is rebased onto no backing file (i.e. it will exist independently of any backing file). +@var{cache} specifies the cache mode to be used for @var{filename}, whereas +@var{src_cache} specifies the cache mode for reading the new backing file. + There are two different modes in which @code{rebase} can operate: @table @option @item Safe mode -- 1.9.3