1ea2384d3Sbellard /*
2fb43f4ddSbellard * QEMU disk image utility
3ea2384d3Sbellard *
468d0f70eSbellard * Copyright (c) 2003-2008 Fabrice Bellard
5ea2384d3Sbellard *
6ea2384d3Sbellard * Permission is hereby granted, free of charge, to any person obtaining a copy
7ea2384d3Sbellard * of this software and associated documentation files (the "Software"), to deal
8ea2384d3Sbellard * in the Software without restriction, including without limitation the rights
9ea2384d3Sbellard * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10ea2384d3Sbellard * copies of the Software, and to permit persons to whom the Software is
11ea2384d3Sbellard * furnished to do so, subject to the following conditions:
12ea2384d3Sbellard *
13ea2384d3Sbellard * The above copyright notice and this permission notice shall be included in
14ea2384d3Sbellard * all copies or substantial portions of the Software.
15ea2384d3Sbellard *
16ea2384d3Sbellard * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17ea2384d3Sbellard * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18ea2384d3Sbellard * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19ea2384d3Sbellard * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20ea2384d3Sbellard * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21ea2384d3Sbellard * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22ea2384d3Sbellard * THE SOFTWARE.
23ea2384d3Sbellard */
24452fcdbcSMarkus Armbruster
2580c71a24SPeter Maydell #include "qemu/osdep.h"
26c2a3d7daSEric Blake #include <getopt.h>
27c2a3d7daSEric Blake
2849f95221SMarc-André Lureau #include "qemu/help-texts.h"
2916a18f26SMarc-André Lureau #include "qemu/qemu-progress.h"
3067a1de0dSFam Zheng #include "qemu-version.h"
31da34e65cSMarkus Armbruster #include "qapi/error.h"
323b51ab4bSEric Blake #include "qapi/qapi-commands-block-core.h"
339af23989SMarkus Armbruster #include "qapi/qapi-visit-block-core.h"
34b3db211fSDaniel P. Berrange #include "qapi/qobject-output-visitor.h"
357b1b5d19SPaolo Bonzini #include "qapi/qmp/qjson.h"
36452fcdbcSMarkus Armbruster #include "qapi/qmp/qdict.h"
37f348b6d1SVeronia Bahaa #include "qemu/cutils.h"
383babeb15SDaniel P. Berrange #include "qemu/config-file.h"
391de7afc9SPaolo Bonzini #include "qemu/option.h"
401de7afc9SPaolo Bonzini #include "qemu/error-report.h"
4106a1e0c1SDenis V. Lunev #include "qemu/log.h"
42db725815SMarkus Armbruster #include "qemu/main-loop.h"
430b8fa32fSMarkus Armbruster #include "qemu/module.h"
4498c5d2e7SDaniel P. Berrangé #include "qemu/sockets.h"
4597ede57aSStefano Garzarella #include "qemu/units.h"
465df022cfSPeter Maydell #include "qemu/memalign.h"
473babeb15SDaniel P. Berrange #include "qom/object_interfaces.h"
4826f54e9aSMarkus Armbruster #include "sysemu/block-backend.h"
49737e150eSPaolo Bonzini #include "block/block_int.h"
50d4a3238aSMax Reitz #include "block/blockjob.h"
51e2c1c34fSMarkus Armbruster #include "block/dirty-bitmap.h"
52f364ec65SWenchao Xia #include "block/qapi.h"
53c2297088SDaniel P. Berrange #include "crypto/init.h"
5406a1e0c1SDenis V. Lunev #include "trace/control.h"
550c8c4895SZhengui #include "qemu/throttle.h"
560c8c4895SZhengui #include "block/throttle-groups.h"
57e8445331Sbellard
587e563bfbSThomas Huth #define QEMU_IMG_VERSION "qemu-img version " QEMU_FULL_VERSION \
590781dd6eSThomas Huth "\n" QEMU_COPYRIGHT "\n"
605f6979cbSJeff Cody
61c227f099SAnthony Liguori typedef struct img_cmd_t {
62153859beSStuart Brady const char *name;
63153859beSStuart Brady int (*handler)(int argc, char **argv);
64c227f099SAnthony Liguori } img_cmd_t;
65153859beSStuart Brady
668599ea4cSFederico Simoncelli enum {
678599ea4cSFederico Simoncelli OPTION_OUTPUT = 256,
688599ea4cSFederico Simoncelli OPTION_BACKING_CHAIN = 257,
693babeb15SDaniel P. Berrange OPTION_OBJECT = 258,
70eb769f74SDaniel P. Berrange OPTION_IMAGE_OPTS = 259,
71b6495fa8SKevin Wolf OPTION_PATTERN = 260,
7255d539c8SKevin Wolf OPTION_FLUSH_INTERVAL = 261,
7355d539c8SKevin Wolf OPTION_NO_DRAIN = 262,
74305b4c60SDaniel P. Berrange OPTION_TARGET_IMAGE_OPTS = 263,
75fd03c2b8SStefan Hajnoczi OPTION_SIZE = 264,
76dc5f690bSMax Reitz OPTION_PREALLOCATION = 265,
774ffca890SPavel Butsykin OPTION_SHRINK = 266,
788eaac025SMax Reitz OPTION_SALVAGE = 267,
79168468feSDavid Edmondson OPTION_TARGET_IS_ZERO = 268,
803b51ab4bSEric Blake OPTION_ADD = 269,
813b51ab4bSEric Blake OPTION_REMOVE = 270,
823b51ab4bSEric Blake OPTION_CLEAR = 271,
833b51ab4bSEric Blake OPTION_ENABLE = 272,
843b51ab4bSEric Blake OPTION_DISABLE = 273,
853b51ab4bSEric Blake OPTION_MERGE = 274,
8615e39ad9SEric Blake OPTION_BITMAPS = 275,
87a3579bfaSMaxim Levitsky OPTION_FORCE = 276,
88955171e4SEric Blake OPTION_SKIP_BROKEN = 277,
898599ea4cSFederico Simoncelli };
908599ea4cSFederico Simoncelli
918599ea4cSFederico Simoncelli typedef enum OutputFormat {
928599ea4cSFederico Simoncelli OFORMAT_JSON,
938599ea4cSFederico Simoncelli OFORMAT_HUMAN,
948599ea4cSFederico Simoncelli } OutputFormat;
958599ea4cSFederico Simoncelli
96e6996143SKevin Wolf /* Default to cache=writeback as data integrity is not important for qemu-img */
97661a0f71SFederico Simoncelli #define BDRV_DEFAULT_CACHE "writeback"
98137519ceSaurel32
format_print(void * opaque,const char * name)9900c6d403SStefan Hajnoczi static void format_print(void *opaque, const char *name)
100ea2384d3Sbellard {
10100c6d403SStefan Hajnoczi printf(" %s", name);
1021a443c1bSMike Day }
103ea2384d3Sbellard
1048905770bSMarc-André Lureau static G_NORETURN G_GNUC_PRINTF(1, 2)
error_exit(const char * fmt,...)1058905770bSMarc-André Lureau void error_exit(const char *fmt, ...)
106ac1307abSFam Zheng {
107ac1307abSFam Zheng va_list ap;
108ac1307abSFam Zheng
109ac1307abSFam Zheng va_start(ap, fmt);
110e9e1d92dSMarkus Armbruster error_vreport(fmt, ap);
111ac1307abSFam Zheng va_end(ap);
112ac1307abSFam Zheng
113e9e1d92dSMarkus Armbruster error_printf("Try 'qemu-img --help' for more information\n");
114ac1307abSFam Zheng exit(EXIT_FAILURE);
115ac1307abSFam Zheng }
116ac1307abSFam Zheng
1178905770bSMarc-André Lureau static G_NORETURN
missing_argument(const char * option)1188905770bSMarc-André Lureau void missing_argument(const char *option)
119c9192973SStefan Hajnoczi {
120c9192973SStefan Hajnoczi error_exit("missing argument for option '%s'", option);
121c9192973SStefan Hajnoczi }
122c9192973SStefan Hajnoczi
1238905770bSMarc-André Lureau static G_NORETURN
unrecognized_option(const char * option)1248905770bSMarc-André Lureau void unrecognized_option(const char *option)
125c9192973SStefan Hajnoczi {
126c9192973SStefan Hajnoczi error_exit("unrecognized option '%s'", option);
127c9192973SStefan Hajnoczi }
128c9192973SStefan Hajnoczi
1290562adf5SEric Blake /* Please keep in synch with docs/tools/qemu-img.rst */
1308905770bSMarc-André Lureau static G_NORETURN
help(void)1318905770bSMarc-André Lureau void help(void)
132ea2384d3Sbellard {
133e00291c0SPaolo Bonzini const char *help_msg =
1345f6979cbSJeff Cody QEMU_IMG_VERSION
13510985131SDenis V. Lunev "usage: qemu-img [standard options] command [command options]\n"
136ea2384d3Sbellard "QEMU disk image utility\n"
137ea2384d3Sbellard "\n"
13810985131SDenis V. Lunev " '-h', '--help' display this help and exit\n"
13910985131SDenis V. Lunev " '-V', '--version' output version information and exit\n"
14006a1e0c1SDenis V. Lunev " '-T', '--trace' [[enable=]<pattern>][,events=<file>][,file=<file>]\n"
14106a1e0c1SDenis V. Lunev " specify tracing options\n"
14210985131SDenis V. Lunev "\n"
143ea2384d3Sbellard "Command syntax:\n"
144153859beSStuart Brady #define DEF(option, callback, arg_string) \
145153859beSStuart Brady " " arg_string "\n"
146153859beSStuart Brady #include "qemu-img-cmds.h"
147153859beSStuart Brady #undef DEF
148ea2384d3Sbellard "\n"
149ea2384d3Sbellard "Command parameters:\n"
150ea2384d3Sbellard " 'filename' is a disk image filename\n"
1513babeb15SDaniel P. Berrange " 'objectdef' is a QEMU user creatable object definition. See the qemu(1)\n"
1523babeb15SDaniel P. Berrange " manual page for a description of the object properties. The most common\n"
1533babeb15SDaniel P. Berrange " object type is a 'secret', which is used to supply passwords and/or\n"
1543babeb15SDaniel P. Berrange " encryption keys.\n"
155ea2384d3Sbellard " 'fmt' is the disk image format. It is guessed automatically in most cases\n"
156661a0f71SFederico Simoncelli " 'cache' is the cache mode used to write the output disk image, the valid\n"
15780ccf93bSLiu Yuan " options are: 'none', 'writeback' (default, except for convert), 'writethrough',\n"
15880ccf93bSLiu Yuan " 'directsync' and 'unsafe' (default for convert)\n"
159bb87fdf8SStefan Hajnoczi " 'src_cache' is the cache mode used to read input disk images, the valid\n"
160bb87fdf8SStefan Hajnoczi " options are the same as for the 'cache' option\n"
16121eb3a2bSPierre Riteau " 'size' is the disk image size in bytes. Optional suffixes\n"
1625e00984aSKevin Wolf " 'k' or 'K' (kilobyte, 1024), 'M' (megabyte, 1024k), 'G' (gigabyte, 1024M),\n"
1635e00984aSKevin Wolf " 'T' (terabyte, 1024G), 'P' (petabyte, 1024T) and 'E' (exabyte, 1024P) are\n"
1645e00984aSKevin Wolf " supported. 'b' is ignored.\n"
165ea2384d3Sbellard " 'output_filename' is the destination disk image filename\n"
166ea2384d3Sbellard " 'output_fmt' is the destination format\n"
167eff44266SKevin Wolf " 'options' is a comma separated list of format specific options in a\n"
1687f118b43SMarkus Armbruster " name=value format. Use -o help for an overview of the options supported by\n"
1697f118b43SMarkus Armbruster " the used format\n"
170ef80654dSWenchao Xia " 'snapshot_param' is param used for internal snapshot, format\n"
171ef80654dSWenchao Xia " is 'snapshot.id=[ID],snapshot.name=[NAME]', or\n"
172ef80654dSWenchao Xia " '[ID_OR_NAME]'\n"
173ea2384d3Sbellard " '-c' indicates that target image must be compressed (qcow format only)\n"
1746e6e55f5SJohn Snow " '-u' allows unsafe backing chains. For rebasing, it is assumed that old and\n"
1756e6e55f5SJohn Snow " new backing file match exactly. The image doesn't need a working\n"
1766e6e55f5SJohn Snow " backing file before rebasing in this case (useful for renaming the\n"
1776e6e55f5SJohn Snow " backing file). For image creation, allow creating without attempting\n"
1786e6e55f5SJohn Snow " to open the backing file.\n"
179d2c639d6Sblueswir1 " '-h' with or without a command shows this help and lists the supported formats\n"
1806b837bc4SJes Sorensen " '-p' show progress of command (only certain commands)\n"
181f382d43aSMiroslav Rezanina " '-q' use Quiet mode - do not print any output (except errors)\n"
18211b6699aSPeter Lieven " '-S' indicates the consecutive number of bytes (defaults to 4k) that must\n"
18311b6699aSPeter Lieven " contain only zeros for qemu-img to create a sparse image during\n"
18411b6699aSPeter Lieven " conversion. If the number of bytes is 0, the source will not be scanned for\n"
18511b6699aSPeter Lieven " unallocated or zero sectors, and the destination image will always be\n"
18611b6699aSPeter Lieven " fully allocated\n"
187c054b3fdSBenoît Canet " '--output' takes the format in which the output must be done (human or json)\n"
188b2e10493SAlexandre Derumier " '-n' skips the target volume creation (useful if the volume is created\n"
189b2e10493SAlexandre Derumier " prior to running qemu-img)\n"
190f7b4a940Saliguori "\n"
1913b51ab4bSEric Blake "Parameters to bitmap subcommand:\n"
1923b51ab4bSEric Blake " 'bitmap' is the name of the bitmap to manipulate, through one or more\n"
1933b51ab4bSEric Blake " actions from '--add', '--remove', '--clear', '--enable', '--disable',\n"
1943b51ab4bSEric Blake " or '--merge source'\n"
1953b51ab4bSEric Blake " '-g granularity' sets the granularity for '--add' actions\n"
1963b51ab4bSEric Blake " '-b source' and '-F src_fmt' tell '--merge' actions to find the source\n"
1973b51ab4bSEric Blake " bitmaps from an alternative file\n"
1983b51ab4bSEric Blake "\n"
1994534ff54SKevin Wolf "Parameters to check subcommand:\n"
2004534ff54SKevin Wolf " '-r' tries to repair any inconsistencies that are found during the check.\n"
2014534ff54SKevin Wolf " '-r leaks' repairs only cluster leaks, whereas '-r all' fixes all\n"
2024534ff54SKevin Wolf " kinds of errors, with a higher risk of choosing the wrong fix or\n"
2030546b8c2SStefan Weil " hiding corruption that has already occurred.\n"
2044534ff54SKevin Wolf "\n"
2052d9187bcSPeter Lieven "Parameters to convert subcommand:\n"
20615e39ad9SEric Blake " '--bitmaps' copies all top-level persistent bitmaps to destination\n"
2072d9187bcSPeter Lieven " '-m' specifies how many coroutines work in parallel during the convert\n"
2082d9187bcSPeter Lieven " process (defaults to 8)\n"
2092d9187bcSPeter Lieven " '-W' allow to write to the target out of order rather than sequential\n"
2102d9187bcSPeter Lieven "\n"
211f7b4a940Saliguori "Parameters to snapshot subcommand:\n"
212f7b4a940Saliguori " 'snapshot' is the name of the snapshot to create, apply or delete\n"
213f7b4a940Saliguori " '-a' applies a snapshot (revert disk to saved state)\n"
214f7b4a940Saliguori " '-c' creates a snapshot\n"
215f7b4a940Saliguori " '-d' deletes a snapshot\n"
216d14ed18cSMiroslav Rezanina " '-l' lists all snapshots in the given image\n"
217d14ed18cSMiroslav Rezanina "\n"
218d14ed18cSMiroslav Rezanina "Parameters to compare subcommand:\n"
219d14ed18cSMiroslav Rezanina " '-f' first image format\n"
220d14ed18cSMiroslav Rezanina " '-F' second image format\n"
22186ce1f6eSReda Sallahi " '-s' run in Strict mode - fail on different image size or sector allocation\n"
22286ce1f6eSReda Sallahi "\n"
22386ce1f6eSReda Sallahi "Parameters to dd subcommand:\n"
22486ce1f6eSReda Sallahi " 'bs=BYTES' read and write up to BYTES bytes at a time "
22586ce1f6eSReda Sallahi "(default: 512)\n"
22686ce1f6eSReda Sallahi " 'count=N' copy only N input blocks\n"
22786ce1f6eSReda Sallahi " 'if=FILE' read from FILE\n"
228f7c15533SReda Sallahi " 'of=FILE' write to FILE\n"
229f7c15533SReda Sallahi " 'skip=N' skip N bs-sized blocks at the start of input\n";
230e00291c0SPaolo Bonzini
231e00291c0SPaolo Bonzini printf("%s\nSupported formats:", help_msg);
2329ac404c5SAndrey Shinkevich bdrv_iterate_format(format_print, NULL, false);
233f5048cb7SEric Blake printf("\n\n" QEMU_HELP_BOTTOM "\n");
234ac1307abSFam Zheng exit(EXIT_SUCCESS);
235ea2384d3Sbellard }
236ea2384d3Sbellard
23780c710cbSMarkus Armbruster /*
23846bb944eSPhilippe Mathieu-Daudé * Is @list safe for accumulate_options()?
23980c710cbSMarkus Armbruster * It is when multiple of them can be joined together separated by ','.
24046bb944eSPhilippe Mathieu-Daudé * To make that work, @list must not start with ',' (or else a
24180c710cbSMarkus Armbruster * separating ',' preceding it gets escaped), and it must not end with
24280c710cbSMarkus Armbruster * an odd number of ',' (or else a separating ',' following it gets
243f62514b3SMarkus Armbruster * escaped), or be empty (or else a separating ',' preceding it can
244f62514b3SMarkus Armbruster * escape a separating ',' following it).
245f62514b3SMarkus Armbruster *
24680c710cbSMarkus Armbruster */
is_valid_option_list(const char * list)24746bb944eSPhilippe Mathieu-Daudé static bool is_valid_option_list(const char *list)
24880c710cbSMarkus Armbruster {
24946bb944eSPhilippe Mathieu-Daudé size_t len = strlen(list);
25080c710cbSMarkus Armbruster size_t i;
25180c710cbSMarkus Armbruster
25246bb944eSPhilippe Mathieu-Daudé if (!list[0] || list[0] == ',') {
25380c710cbSMarkus Armbruster return false;
25480c710cbSMarkus Armbruster }
25580c710cbSMarkus Armbruster
25646bb944eSPhilippe Mathieu-Daudé for (i = len; i > 0 && list[i - 1] == ','; i--) {
25780c710cbSMarkus Armbruster }
25880c710cbSMarkus Armbruster if ((len - i) % 2) {
25980c710cbSMarkus Armbruster return false;
26080c710cbSMarkus Armbruster }
26180c710cbSMarkus Armbruster
26280c710cbSMarkus Armbruster return true;
26380c710cbSMarkus Armbruster }
26480c710cbSMarkus Armbruster
accumulate_options(char ** options,char * list)26546bb944eSPhilippe Mathieu-Daudé static int accumulate_options(char **options, char *list)
2666d2b5cbaSMarkus Armbruster {
2676d2b5cbaSMarkus Armbruster char *new_options;
2686d2b5cbaSMarkus Armbruster
26946bb944eSPhilippe Mathieu-Daudé if (!is_valid_option_list(list)) {
27046bb944eSPhilippe Mathieu-Daudé error_report("Invalid option list: %s", list);
2716d2b5cbaSMarkus Armbruster return -1;
2726d2b5cbaSMarkus Armbruster }
2736d2b5cbaSMarkus Armbruster
2746d2b5cbaSMarkus Armbruster if (!*options) {
27546bb944eSPhilippe Mathieu-Daudé *options = g_strdup(list);
2766d2b5cbaSMarkus Armbruster } else {
27746bb944eSPhilippe Mathieu-Daudé new_options = g_strdup_printf("%s,%s", *options, list);
2786d2b5cbaSMarkus Armbruster g_free(*options);
2796d2b5cbaSMarkus Armbruster *options = new_options;
2806d2b5cbaSMarkus Armbruster }
2816d2b5cbaSMarkus Armbruster return 0;
2826d2b5cbaSMarkus Armbruster }
2836d2b5cbaSMarkus Armbruster
284eb769f74SDaniel P. Berrange static QemuOptsList qemu_source_opts = {
285eb769f74SDaniel P. Berrange .name = "source",
286eb769f74SDaniel P. Berrange .implied_opt_name = "file",
287eb769f74SDaniel P. Berrange .head = QTAILQ_HEAD_INITIALIZER(qemu_source_opts.head),
288eb769f74SDaniel P. Berrange .desc = {
289eb769f74SDaniel P. Berrange { }
290eb769f74SDaniel P. Berrange },
291eb769f74SDaniel P. Berrange };
292eb769f74SDaniel P. Berrange
qprintf(bool quiet,const char * fmt,...)2939edc6313SMarc-André Lureau static int G_GNUC_PRINTF(2, 3) qprintf(bool quiet, const char *fmt, ...)
294f382d43aSMiroslav Rezanina {
295f382d43aSMiroslav Rezanina int ret = 0;
296f382d43aSMiroslav Rezanina if (!quiet) {
297f382d43aSMiroslav Rezanina va_list args;
298f382d43aSMiroslav Rezanina va_start(args, fmt);
299f382d43aSMiroslav Rezanina ret = vprintf(fmt, args);
300f382d43aSMiroslav Rezanina va_end(args);
301f382d43aSMiroslav Rezanina }
302f382d43aSMiroslav Rezanina return ret;
303f382d43aSMiroslav Rezanina }
304f382d43aSMiroslav Rezanina
305ea2384d3Sbellard
print_block_option_help(const char * filename,const char * fmt)3064ac8aacdSJes Sorensen static int print_block_option_help(const char *filename, const char *fmt)
3074ac8aacdSJes Sorensen {
3084ac8aacdSJes Sorensen BlockDriver *drv, *proto_drv;
30983d0521aSChunyan Liu QemuOptsList *create_opts = NULL;
310b65a5e12SMax Reitz Error *local_err = NULL;
3114ac8aacdSJes Sorensen
3124ac8aacdSJes Sorensen /* Find driver and parse its options */
3134ac8aacdSJes Sorensen drv = bdrv_find_format(fmt);
3144ac8aacdSJes Sorensen if (!drv) {
31515654a6dSJes Sorensen error_report("Unknown file format '%s'", fmt);
3164ac8aacdSJes Sorensen return 1;
3174ac8aacdSJes Sorensen }
3184ac8aacdSJes Sorensen
319d402b6a2SMax Reitz if (!drv->create_opts) {
320d402b6a2SMax Reitz error_report("Format driver '%s' does not support image creation", fmt);
321d402b6a2SMax Reitz return 1;
322d402b6a2SMax Reitz }
323d402b6a2SMax Reitz
324c282e1fdSChunyan Liu create_opts = qemu_opts_append(create_opts, drv->create_opts);
325a283cb6eSKevin Wolf if (filename) {
326b65a5e12SMax Reitz proto_drv = bdrv_find_protocol(filename, true, &local_err);
3274ac8aacdSJes Sorensen if (!proto_drv) {
3282867ce4aSMarkus Armbruster error_report_err(local_err);
32983d0521aSChunyan Liu qemu_opts_free(create_opts);
3304ac8aacdSJes Sorensen return 1;
3314ac8aacdSJes Sorensen }
332d402b6a2SMax Reitz if (!proto_drv->create_opts) {
333f0998879SMax Reitz error_report("Protocol driver '%s' does not support image creation",
334d402b6a2SMax Reitz proto_drv->format_name);
3353ecd5a4fSMax Reitz qemu_opts_free(create_opts);
336d402b6a2SMax Reitz return 1;
337d402b6a2SMax Reitz }
338c282e1fdSChunyan Liu create_opts = qemu_opts_append(create_opts, proto_drv->create_opts);
339a283cb6eSKevin Wolf }
340a283cb6eSKevin Wolf
341f4619af0SMax Reitz if (filename) {
3427f3fb001SMax Reitz printf("Supported options:\n");
343f4619af0SMax Reitz } else {
344f4619af0SMax Reitz printf("Supported %s options:\n", fmt);
345f4619af0SMax Reitz }
34663898712SMax Reitz qemu_opts_print_help(create_opts, false);
34783d0521aSChunyan Liu qemu_opts_free(create_opts);
348f4619af0SMax Reitz
349f4619af0SMax Reitz if (!filename) {
350f4619af0SMax Reitz printf("\n"
351f4619af0SMax Reitz "The protocol level may support further options.\n"
352f4619af0SMax Reitz "Specify the target filename to include those options.\n");
353f4619af0SMax Reitz }
354f4619af0SMax Reitz
3554ac8aacdSJes Sorensen return 0;
3564ac8aacdSJes Sorensen }
3574ac8aacdSJes Sorensen
358eb769f74SDaniel P. Berrange
img_open_opts(const char * optstr,QemuOpts * opts,int flags,bool writethrough,bool quiet,bool force_share)359efaa7c4eSMax Reitz static BlockBackend *img_open_opts(const char *optstr,
360ce099547SKevin Wolf QemuOpts *opts, int flags, bool writethrough,
361335e9937SFam Zheng bool quiet, bool force_share)
362eb769f74SDaniel P. Berrange {
363eb769f74SDaniel P. Berrange QDict *options;
364eb769f74SDaniel P. Berrange Error *local_err = NULL;
365eb769f74SDaniel P. Berrange BlockBackend *blk;
366eb769f74SDaniel P. Berrange options = qemu_opts_to_qdict(opts, NULL);
367335e9937SFam Zheng if (force_share) {
368335e9937SFam Zheng if (qdict_haskey(options, BDRV_OPT_FORCE_SHARE)
3694615f878SMax Reitz && strcmp(qdict_get_str(options, BDRV_OPT_FORCE_SHARE), "on")) {
370335e9937SFam Zheng error_report("--force-share/-U conflicts with image options");
371cb3e7f08SMarc-André Lureau qobject_unref(options);
372335e9937SFam Zheng return NULL;
373335e9937SFam Zheng }
3744615f878SMax Reitz qdict_put_str(options, BDRV_OPT_FORCE_SHARE, "on");
375335e9937SFam Zheng }
376efaa7c4eSMax Reitz blk = blk_new_open(NULL, NULL, options, flags, &local_err);
377eb769f74SDaniel P. Berrange if (!blk) {
378143605a2SDaniel P. Berrange error_reportf_err(local_err, "Could not open '%s': ", optstr);
379eb769f74SDaniel P. Berrange return NULL;
380eb769f74SDaniel P. Berrange }
381ce099547SKevin Wolf blk_set_enable_write_cache(blk, !writethrough);
382eb769f74SDaniel P. Berrange
383eb769f74SDaniel P. Berrange return blk;
384eb769f74SDaniel P. Berrange }
385eb769f74SDaniel P. Berrange
img_open_file(const char * filename,QDict * options,const char * fmt,int flags,bool writethrough,bool quiet,bool force_share)386efaa7c4eSMax Reitz static BlockBackend *img_open_file(const char *filename,
38729cf9336SDaniel P. Berrange QDict *options,
3887e7d56d9SMarkus Armbruster const char *fmt, int flags,
389335e9937SFam Zheng bool writethrough, bool quiet,
390335e9937SFam Zheng bool force_share)
39175c23805Sbellard {
3927e7d56d9SMarkus Armbruster BlockBackend *blk;
39334b5d2c6SMax Reitz Error *local_err = NULL;
394ad717139SKevin Wolf
39529cf9336SDaniel P. Berrange if (!options) {
39629cf9336SDaniel P. Berrange options = qdict_new();
39729cf9336SDaniel P. Berrange }
39875c23805Sbellard if (fmt) {
39946f5ac20SEric Blake qdict_put_str(options, "driver", fmt);
40075c23805Sbellard }
401b9eaf9ecSKevin Wolf
402335e9937SFam Zheng if (force_share) {
403579cf1d1SEric Blake qdict_put_bool(options, BDRV_OPT_FORCE_SHARE, true);
404335e9937SFam Zheng }
405efaa7c4eSMax Reitz blk = blk_new_open(filename, NULL, options, flags, &local_err);
4065bd31326SMax Reitz if (!blk) {
407c29b77f9SMarkus Armbruster error_reportf_err(local_err, "Could not open '%s': ", filename);
408eb769f74SDaniel P. Berrange return NULL;
40975c23805Sbellard }
410ce099547SKevin Wolf blk_set_enable_write_cache(blk, !writethrough);
411b9eaf9ecSKevin Wolf
412eb769f74SDaniel P. Berrange return blk;
413eb769f74SDaniel P. Berrange }
414eb769f74SDaniel P. Berrange
415eb769f74SDaniel P. Berrange
img_add_key_secrets(void * opaque,const char * name,const char * value,Error ** errp)41629cf9336SDaniel P. Berrange static int img_add_key_secrets(void *opaque,
41729cf9336SDaniel P. Berrange const char *name, const char *value,
41829cf9336SDaniel P. Berrange Error **errp)
41929cf9336SDaniel P. Berrange {
42029cf9336SDaniel P. Berrange QDict *options = opaque;
42129cf9336SDaniel P. Berrange
42229cf9336SDaniel P. Berrange if (g_str_has_suffix(name, "key-secret")) {
423187f47e9SEric Blake qdict_put_str(options, name, value);
42429cf9336SDaniel P. Berrange }
42529cf9336SDaniel P. Berrange
42629cf9336SDaniel P. Berrange return 0;
42729cf9336SDaniel P. Berrange }
42829cf9336SDaniel P. Berrange
42929cf9336SDaniel P. Berrange
img_open(bool image_opts,const char * filename,const char * fmt,int flags,bool writethrough,bool quiet,bool force_share)430efaa7c4eSMax Reitz static BlockBackend *img_open(bool image_opts,
431eb769f74SDaniel P. Berrange const char *filename,
432ce099547SKevin Wolf const char *fmt, int flags, bool writethrough,
433335e9937SFam Zheng bool quiet, bool force_share)
434eb769f74SDaniel P. Berrange {
435eb769f74SDaniel P. Berrange BlockBackend *blk;
436eb769f74SDaniel P. Berrange if (image_opts) {
437eb769f74SDaniel P. Berrange QemuOpts *opts;
438eb769f74SDaniel P. Berrange if (fmt) {
439eb769f74SDaniel P. Berrange error_report("--image-opts and --format are mutually exclusive");
440eb769f74SDaniel P. Berrange return NULL;
441eb769f74SDaniel P. Berrange }
442eb769f74SDaniel P. Berrange opts = qemu_opts_parse_noisily(qemu_find_opts("source"),
443eb769f74SDaniel P. Berrange filename, true);
444eb769f74SDaniel P. Berrange if (!opts) {
445eb769f74SDaniel P. Berrange return NULL;
446eb769f74SDaniel P. Berrange }
447335e9937SFam Zheng blk = img_open_opts(filename, opts, flags, writethrough, quiet,
448335e9937SFam Zheng force_share);
449eb769f74SDaniel P. Berrange } else {
45029cf9336SDaniel P. Berrange blk = img_open_file(filename, NULL, fmt, flags, writethrough, quiet,
451335e9937SFam Zheng force_share);
452eb769f74SDaniel P. Berrange }
45344efba2dSKevin Wolf
45444efba2dSKevin Wolf if (blk) {
45544efba2dSKevin Wolf blk_set_force_allow_inactivate(blk);
45644efba2dSKevin Wolf }
45744efba2dSKevin Wolf
458eb769f74SDaniel P. Berrange return blk;
459eb769f74SDaniel P. Berrange }
460eb769f74SDaniel P. Berrange
46175c23805Sbellard
add_old_style_options(const char * fmt,QemuOpts * opts,const char * base_filename,const char * base_fmt)46283d0521aSChunyan Liu static int add_old_style_options(const char *fmt, QemuOpts *opts,
463eec77d9eSJes Sorensen const char *base_filename,
464eec77d9eSJes Sorensen const char *base_fmt)
465efa84d43SKevin Wolf {
466efa84d43SKevin Wolf if (base_filename) {
467235e59cfSMarkus Armbruster if (!qemu_opt_set(opts, BLOCK_OPT_BACKING_FILE, base_filename,
4689e194e06SMarkus Armbruster NULL)) {
46915654a6dSJes Sorensen error_report("Backing file not supported for file format '%s'",
47015654a6dSJes Sorensen fmt);
471c2abccecSMORITA Kazutaka return -1;
472efa84d43SKevin Wolf }
473efa84d43SKevin Wolf }
474efa84d43SKevin Wolf if (base_fmt) {
4759e194e06SMarkus Armbruster if (!qemu_opt_set(opts, BLOCK_OPT_BACKING_FMT, base_fmt, NULL)) {
47615654a6dSJes Sorensen error_report("Backing file format not supported for file "
47715654a6dSJes Sorensen "format '%s'", fmt);
478c2abccecSMORITA Kazutaka return -1;
479efa84d43SKevin Wolf }
480efa84d43SKevin Wolf }
481c2abccecSMORITA Kazutaka return 0;
482efa84d43SKevin Wolf }
483efa84d43SKevin Wolf
cvtnum_full(const char * name,const char * value,int64_t min,int64_t max)48443d589b0SEyal Moscovici static int64_t cvtnum_full(const char *name, const char *value, int64_t min,
48543d589b0SEyal Moscovici int64_t max)
486606caa0aSMarkus Armbruster {
487f17fd4fdSMarkus Armbruster int err;
48843d589b0SEyal Moscovici uint64_t res;
489606caa0aSMarkus Armbruster
49043d589b0SEyal Moscovici err = qemu_strtosz(value, NULL, &res);
49143d589b0SEyal Moscovici if (err < 0 && err != -ERANGE) {
49243d589b0SEyal Moscovici error_report("Invalid %s specified. You may use "
49343d589b0SEyal Moscovici "k, M, G, T, P or E suffixes for", name);
49443d589b0SEyal Moscovici error_report("kilobytes, megabytes, gigabytes, terabytes, "
49543d589b0SEyal Moscovici "petabytes and exabytes.");
496f17fd4fdSMarkus Armbruster return err;
497f17fd4fdSMarkus Armbruster }
49843d589b0SEyal Moscovici if (err == -ERANGE || res > max || res < min) {
49943d589b0SEyal Moscovici error_report("Invalid %s specified. Must be between %" PRId64
50043d589b0SEyal Moscovici " and %" PRId64 ".", name, min, max);
501f46bfdbfSMarkus Armbruster return -ERANGE;
502f46bfdbfSMarkus Armbruster }
50343d589b0SEyal Moscovici return res;
50443d589b0SEyal Moscovici }
50543d589b0SEyal Moscovici
cvtnum(const char * name,const char * value)50643d589b0SEyal Moscovici static int64_t cvtnum(const char *name, const char *value)
50743d589b0SEyal Moscovici {
50843d589b0SEyal Moscovici return cvtnum_full(name, value, 0, INT64_MAX);
509606caa0aSMarkus Armbruster }
510606caa0aSMarkus Armbruster
img_create(int argc,char ** argv)511ea2384d3Sbellard static int img_create(int argc, char **argv)
512ea2384d3Sbellard {
513a9300911SLuiz Capitulino int c;
5141da7cfbdSJes Sorensen uint64_t img_size = -1;
515ea2384d3Sbellard const char *fmt = "raw";
5169230eaf6Saliguori const char *base_fmt = NULL;
517ea2384d3Sbellard const char *filename;
518ea2384d3Sbellard const char *base_filename = NULL;
5199ea2ea71SKevin Wolf char *options = NULL;
5209b37525aSLuiz Capitulino Error *local_err = NULL;
521f382d43aSMiroslav Rezanina bool quiet = false;
5226e6e55f5SJohn Snow int flags = 0;
523ea2384d3Sbellard
524ea2384d3Sbellard for(;;) {
5253babeb15SDaniel P. Berrange static const struct option long_options[] = {
5263babeb15SDaniel P. Berrange {"help", no_argument, 0, 'h'},
5273babeb15SDaniel P. Berrange {"object", required_argument, 0, OPTION_OBJECT},
5283babeb15SDaniel P. Berrange {0, 0, 0, 0}
5293babeb15SDaniel P. Berrange };
5306e6e55f5SJohn Snow c = getopt_long(argc, argv, ":F:b:f:ho:qu",
5313babeb15SDaniel P. Berrange long_options, NULL);
532b8fb60daSJes Sorensen if (c == -1) {
533ea2384d3Sbellard break;
534b8fb60daSJes Sorensen }
535ea2384d3Sbellard switch(c) {
536c9192973SStefan Hajnoczi case ':':
537c9192973SStefan Hajnoczi missing_argument(argv[optind - 1]);
538c9192973SStefan Hajnoczi break;
539ef87394cSJes Sorensen case '?':
540c9192973SStefan Hajnoczi unrecognized_option(argv[optind - 1]);
541c9192973SStefan Hajnoczi break;
542ea2384d3Sbellard case 'h':
543ea2384d3Sbellard help();
544ea2384d3Sbellard break;
5459230eaf6Saliguori case 'F':
5469230eaf6Saliguori base_fmt = optarg;
5479230eaf6Saliguori break;
548ea2384d3Sbellard case 'b':
549ea2384d3Sbellard base_filename = optarg;
550ea2384d3Sbellard break;
551ea2384d3Sbellard case 'f':
552ea2384d3Sbellard fmt = optarg;
553ea2384d3Sbellard break;
5549ea2ea71SKevin Wolf case 'o':
5556d2b5cbaSMarkus Armbruster if (accumulate_options(&options, optarg) < 0) {
55677386bf6SKevin Wolf goto fail;
55777386bf6SKevin Wolf }
5589ea2ea71SKevin Wolf break;
559f382d43aSMiroslav Rezanina case 'q':
560f382d43aSMiroslav Rezanina quiet = true;
561f382d43aSMiroslav Rezanina break;
5626e6e55f5SJohn Snow case 'u':
5636e6e55f5SJohn Snow flags |= BDRV_O_NO_BACKING;
5646e6e55f5SJohn Snow break;
56599b1e646SKevin Wolf case OPTION_OBJECT:
56699b1e646SKevin Wolf user_creatable_process_cmdline(optarg);
56799b1e646SKevin Wolf break;
568ea2384d3Sbellard }
569ea2384d3Sbellard }
5709230eaf6Saliguori
571b50cbabcSMORITA Kazutaka /* Get the filename */
572a283cb6eSKevin Wolf filename = (optind < argc) ? argv[optind] : NULL;
573a283cb6eSKevin Wolf if (options && has_help_option(options)) {
574a283cb6eSKevin Wolf g_free(options);
575a283cb6eSKevin Wolf return print_block_option_help(filename, fmt);
576a283cb6eSKevin Wolf }
577a283cb6eSKevin Wolf
578b8fb60daSJes Sorensen if (optind >= argc) {
579ac1307abSFam Zheng error_exit("Expecting image file name");
580b8fb60daSJes Sorensen }
581a283cb6eSKevin Wolf optind++;
582b50cbabcSMORITA Kazutaka
5831da7cfbdSJes Sorensen /* Get image size, if specified */
5841da7cfbdSJes Sorensen if (optind < argc) {
58570b4f4bbSJes Sorensen int64_t sval;
586606caa0aSMarkus Armbruster
58743d589b0SEyal Moscovici sval = cvtnum("image size", argv[optind++]);
588606caa0aSMarkus Armbruster if (sval < 0) {
58977386bf6SKevin Wolf goto fail;
5901da7cfbdSJes Sorensen }
5911da7cfbdSJes Sorensen img_size = (uint64_t)sval;
5921da7cfbdSJes Sorensen }
593fc11eb26SKevin Wolf if (optind != argc) {
594ac1307abSFam Zheng error_exit("Unexpected argument: %s", argv[optind]);
595fc11eb26SKevin Wolf }
5961da7cfbdSJes Sorensen
5979b37525aSLuiz Capitulino bdrv_img_create(filename, fmt, base_filename, base_fmt,
5986e6e55f5SJohn Snow options, img_size, flags, quiet, &local_err);
59984d18f06SMarkus Armbruster if (local_err) {
600c29b77f9SMarkus Armbruster error_reportf_err(local_err, "%s: ", filename);
60177386bf6SKevin Wolf goto fail;
602c2abccecSMORITA Kazutaka }
603a9300911SLuiz Capitulino
60477386bf6SKevin Wolf g_free(options);
605ea2384d3Sbellard return 0;
60677386bf6SKevin Wolf
60777386bf6SKevin Wolf fail:
60877386bf6SKevin Wolf g_free(options);
60977386bf6SKevin Wolf return 1;
610ea2384d3Sbellard }
611ea2384d3Sbellard
dump_json_image_check(ImageCheck * check,bool quiet)612f382d43aSMiroslav Rezanina static void dump_json_image_check(ImageCheck *check, bool quiet)
6138599ea4cSFederico Simoncelli {
614eab3a467SMarkus Armbruster GString *str;
6158599ea4cSFederico Simoncelli QObject *obj;
6167d5e199aSDaniel P. Berrange Visitor *v = qobject_output_visitor_new(&obj);
6173b098d56SEric Blake
6183b098d56SEric Blake visit_type_ImageCheck(v, NULL, &check, &error_abort);
6193b098d56SEric Blake visit_complete(v, &obj);
6206589f459SMarkus Armbruster str = qobject_to_json_pretty(obj, true);
6218599ea4cSFederico Simoncelli assert(str != NULL);
622eab3a467SMarkus Armbruster qprintf(quiet, "%s\n", str->str);
623cb3e7f08SMarc-André Lureau qobject_unref(obj);
6243b098d56SEric Blake visit_free(v);
625eab3a467SMarkus Armbruster g_string_free(str, true);
6268599ea4cSFederico Simoncelli }
6278599ea4cSFederico Simoncelli
dump_human_image_check(ImageCheck * check,bool quiet)628f382d43aSMiroslav Rezanina static void dump_human_image_check(ImageCheck *check, bool quiet)
6298599ea4cSFederico Simoncelli {
6308599ea4cSFederico Simoncelli if (!(check->corruptions || check->leaks || check->check_errors)) {
631f382d43aSMiroslav Rezanina qprintf(quiet, "No errors were found on the image.\n");
6328599ea4cSFederico Simoncelli } else {
6338599ea4cSFederico Simoncelli if (check->corruptions) {
634f382d43aSMiroslav Rezanina qprintf(quiet, "\n%" PRId64 " errors were found on the image.\n"
6358599ea4cSFederico Simoncelli "Data may be corrupted, or further writes to the image "
6368599ea4cSFederico Simoncelli "may corrupt it.\n",
6378599ea4cSFederico Simoncelli check->corruptions);
6388599ea4cSFederico Simoncelli }
6398599ea4cSFederico Simoncelli
6408599ea4cSFederico Simoncelli if (check->leaks) {
641f382d43aSMiroslav Rezanina qprintf(quiet,
642f382d43aSMiroslav Rezanina "\n%" PRId64 " leaked clusters were found on the image.\n"
6438599ea4cSFederico Simoncelli "This means waste of disk space, but no harm to data.\n",
6448599ea4cSFederico Simoncelli check->leaks);
6458599ea4cSFederico Simoncelli }
6468599ea4cSFederico Simoncelli
6478599ea4cSFederico Simoncelli if (check->check_errors) {
648f382d43aSMiroslav Rezanina qprintf(quiet,
649f382d43aSMiroslav Rezanina "\n%" PRId64
650f382d43aSMiroslav Rezanina " internal errors have occurred during the check.\n",
6518599ea4cSFederico Simoncelli check->check_errors);
6528599ea4cSFederico Simoncelli }
6538599ea4cSFederico Simoncelli }
6548599ea4cSFederico Simoncelli
6558599ea4cSFederico Simoncelli if (check->total_clusters != 0 && check->allocated_clusters != 0) {
656f382d43aSMiroslav Rezanina qprintf(quiet, "%" PRId64 "/%" PRId64 " = %0.2f%% allocated, "
657e6439d78SStefan Hajnoczi "%0.2f%% fragmented, %0.2f%% compressed clusters\n",
6588599ea4cSFederico Simoncelli check->allocated_clusters, check->total_clusters,
6598599ea4cSFederico Simoncelli check->allocated_clusters * 100.0 / check->total_clusters,
660e6439d78SStefan Hajnoczi check->fragmented_clusters * 100.0 / check->allocated_clusters,
661f382d43aSMiroslav Rezanina check->compressed_clusters * 100.0 /
662f382d43aSMiroslav Rezanina check->allocated_clusters);
6638599ea4cSFederico Simoncelli }
6648599ea4cSFederico Simoncelli
6658599ea4cSFederico Simoncelli if (check->image_end_offset) {
666f382d43aSMiroslav Rezanina qprintf(quiet,
667f382d43aSMiroslav Rezanina "Image end offset: %" PRId64 "\n", check->image_end_offset);
6688599ea4cSFederico Simoncelli }
6698599ea4cSFederico Simoncelli }
6708599ea4cSFederico Simoncelli
collect_image_check(BlockDriverState * bs,ImageCheck * check,const char * filename,const char * fmt,int fix)6718599ea4cSFederico Simoncelli static int collect_image_check(BlockDriverState *bs,
6728599ea4cSFederico Simoncelli ImageCheck *check,
6738599ea4cSFederico Simoncelli const char *filename,
6748599ea4cSFederico Simoncelli const char *fmt,
6758599ea4cSFederico Simoncelli int fix)
6768599ea4cSFederico Simoncelli {
6778599ea4cSFederico Simoncelli int ret;
6788599ea4cSFederico Simoncelli BdrvCheckResult result;
6798599ea4cSFederico Simoncelli
6808599ea4cSFederico Simoncelli ret = bdrv_check(bs, &result, fix);
6818599ea4cSFederico Simoncelli if (ret < 0) {
6828599ea4cSFederico Simoncelli return ret;
6838599ea4cSFederico Simoncelli }
6848599ea4cSFederico Simoncelli
6858599ea4cSFederico Simoncelli check->filename = g_strdup(filename);
6868599ea4cSFederico Simoncelli check->format = g_strdup(bdrv_get_format_name(bs));
6878599ea4cSFederico Simoncelli check->check_errors = result.check_errors;
6888599ea4cSFederico Simoncelli check->corruptions = result.corruptions;
6898599ea4cSFederico Simoncelli check->has_corruptions = result.corruptions != 0;
6908599ea4cSFederico Simoncelli check->leaks = result.leaks;
6918599ea4cSFederico Simoncelli check->has_leaks = result.leaks != 0;
6928599ea4cSFederico Simoncelli check->corruptions_fixed = result.corruptions_fixed;
6931656324eSMax Reitz check->has_corruptions_fixed = result.corruptions_fixed != 0;
6948599ea4cSFederico Simoncelli check->leaks_fixed = result.leaks_fixed;
6951656324eSMax Reitz check->has_leaks_fixed = result.leaks_fixed != 0;
6968599ea4cSFederico Simoncelli check->image_end_offset = result.image_end_offset;
6978599ea4cSFederico Simoncelli check->has_image_end_offset = result.image_end_offset != 0;
6988599ea4cSFederico Simoncelli check->total_clusters = result.bfi.total_clusters;
6998599ea4cSFederico Simoncelli check->has_total_clusters = result.bfi.total_clusters != 0;
7008599ea4cSFederico Simoncelli check->allocated_clusters = result.bfi.allocated_clusters;
7018599ea4cSFederico Simoncelli check->has_allocated_clusters = result.bfi.allocated_clusters != 0;
7028599ea4cSFederico Simoncelli check->fragmented_clusters = result.bfi.fragmented_clusters;
7038599ea4cSFederico Simoncelli check->has_fragmented_clusters = result.bfi.fragmented_clusters != 0;
704e6439d78SStefan Hajnoczi check->compressed_clusters = result.bfi.compressed_clusters;
705e6439d78SStefan Hajnoczi check->has_compressed_clusters = result.bfi.compressed_clusters != 0;
7068599ea4cSFederico Simoncelli
7078599ea4cSFederico Simoncelli return 0;
7088599ea4cSFederico Simoncelli }
7098599ea4cSFederico Simoncelli
710e076f338SKevin Wolf /*
711e076f338SKevin Wolf * Checks an image for consistency. Exit codes:
712e076f338SKevin Wolf *
713e076f338SKevin Wolf * 0 - Check completed, image is good
714e076f338SKevin Wolf * 1 - Check not completed because of internal errors
715e076f338SKevin Wolf * 2 - Check completed, image is corrupted
716e076f338SKevin Wolf * 3 - Check completed, image has leaked clusters, but is good otherwise
717d6635c4dSMax Reitz * 63 - Checks are not supported by the image format
718e076f338SKevin Wolf */
img_check(int argc,char ** argv)7191585969cSaliguori static int img_check(int argc, char **argv)
7201585969cSaliguori {
7211585969cSaliguori int c, ret;
7228599ea4cSFederico Simoncelli OutputFormat output_format = OFORMAT_HUMAN;
72340055951SMax Reitz const char *filename, *fmt, *output, *cache;
72426f54e9aSMarkus Armbruster BlockBackend *blk;
7251585969cSaliguori BlockDriverState *bs;
7264534ff54SKevin Wolf int fix = 0;
727ce099547SKevin Wolf int flags = BDRV_O_CHECK;
728ce099547SKevin Wolf bool writethrough;
7297e7d56d9SMarkus Armbruster ImageCheck *check;
730f382d43aSMiroslav Rezanina bool quiet = false;
731eb769f74SDaniel P. Berrange bool image_opts = false;
732335e9937SFam Zheng bool force_share = false;
7331585969cSaliguori
7341585969cSaliguori fmt = NULL;
7358599ea4cSFederico Simoncelli output = NULL;
73640055951SMax Reitz cache = BDRV_DEFAULT_CACHE;
737ce099547SKevin Wolf
7381585969cSaliguori for(;;) {
7398599ea4cSFederico Simoncelli int option_index = 0;
7408599ea4cSFederico Simoncelli static const struct option long_options[] = {
7418599ea4cSFederico Simoncelli {"help", no_argument, 0, 'h'},
7428599ea4cSFederico Simoncelli {"format", required_argument, 0, 'f'},
7434fd6a984SPrasad Joshi {"repair", required_argument, 0, 'r'},
7448599ea4cSFederico Simoncelli {"output", required_argument, 0, OPTION_OUTPUT},
7453babeb15SDaniel P. Berrange {"object", required_argument, 0, OPTION_OBJECT},
746eb769f74SDaniel P. Berrange {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
747335e9937SFam Zheng {"force-share", no_argument, 0, 'U'},
7488599ea4cSFederico Simoncelli {0, 0, 0, 0}
7498599ea4cSFederico Simoncelli };
750335e9937SFam Zheng c = getopt_long(argc, argv, ":hf:r:T:qU",
7518599ea4cSFederico Simoncelli long_options, &option_index);
752b8fb60daSJes Sorensen if (c == -1) {
7531585969cSaliguori break;
754b8fb60daSJes Sorensen }
7551585969cSaliguori switch(c) {
756c9192973SStefan Hajnoczi case ':':
757c9192973SStefan Hajnoczi missing_argument(argv[optind - 1]);
758c9192973SStefan Hajnoczi break;
759ef87394cSJes Sorensen case '?':
760c9192973SStefan Hajnoczi unrecognized_option(argv[optind - 1]);
761c9192973SStefan Hajnoczi break;
7621585969cSaliguori case 'h':
7631585969cSaliguori help();
7641585969cSaliguori break;
7651585969cSaliguori case 'f':
7661585969cSaliguori fmt = optarg;
7671585969cSaliguori break;
7684534ff54SKevin Wolf case 'r':
7694534ff54SKevin Wolf flags |= BDRV_O_RDWR;
7704534ff54SKevin Wolf
7714534ff54SKevin Wolf if (!strcmp(optarg, "leaks")) {
7724534ff54SKevin Wolf fix = BDRV_FIX_LEAKS;
7734534ff54SKevin Wolf } else if (!strcmp(optarg, "all")) {
7744534ff54SKevin Wolf fix = BDRV_FIX_LEAKS | BDRV_FIX_ERRORS;
7754534ff54SKevin Wolf } else {
776ac1307abSFam Zheng error_exit("Unknown option value for -r "
777ac1307abSFam Zheng "(expecting 'leaks' or 'all'): %s", optarg);
7784534ff54SKevin Wolf }
7794534ff54SKevin Wolf break;
7808599ea4cSFederico Simoncelli case OPTION_OUTPUT:
7818599ea4cSFederico Simoncelli output = optarg;
7828599ea4cSFederico Simoncelli break;
78340055951SMax Reitz case 'T':
78440055951SMax Reitz cache = optarg;
78540055951SMax Reitz break;
786f382d43aSMiroslav Rezanina case 'q':
787f382d43aSMiroslav Rezanina quiet = true;
788f382d43aSMiroslav Rezanina break;
789335e9937SFam Zheng case 'U':
790335e9937SFam Zheng force_share = true;
791335e9937SFam Zheng break;
79299b1e646SKevin Wolf case OPTION_OBJECT:
79399b1e646SKevin Wolf user_creatable_process_cmdline(optarg);
79499b1e646SKevin Wolf break;
795eb769f74SDaniel P. Berrange case OPTION_IMAGE_OPTS:
796eb769f74SDaniel P. Berrange image_opts = true;
797eb769f74SDaniel P. Berrange break;
7981585969cSaliguori }
7991585969cSaliguori }
800fc11eb26SKevin Wolf if (optind != argc - 1) {
801ac1307abSFam Zheng error_exit("Expecting one image file name");
802b8fb60daSJes Sorensen }
8031585969cSaliguori filename = argv[optind++];
8041585969cSaliguori
8058599ea4cSFederico Simoncelli if (output && !strcmp(output, "json")) {
8068599ea4cSFederico Simoncelli output_format = OFORMAT_JSON;
8078599ea4cSFederico Simoncelli } else if (output && !strcmp(output, "human")) {
8088599ea4cSFederico Simoncelli output_format = OFORMAT_HUMAN;
8098599ea4cSFederico Simoncelli } else if (output) {
8108599ea4cSFederico Simoncelli error_report("--output must be used with human or json as argument.");
8118599ea4cSFederico Simoncelli return 1;
8128599ea4cSFederico Simoncelli }
8138599ea4cSFederico Simoncelli
814ce099547SKevin Wolf ret = bdrv_parse_cache_mode(cache, &flags, &writethrough);
81540055951SMax Reitz if (ret < 0) {
81640055951SMax Reitz error_report("Invalid source cache option: %s", cache);
81740055951SMax Reitz return 1;
81840055951SMax Reitz }
81940055951SMax Reitz
820335e9937SFam Zheng blk = img_open(image_opts, filename, fmt, flags, writethrough, quiet,
821335e9937SFam Zheng force_share);
8227e7d56d9SMarkus Armbruster if (!blk) {
8237e7d56d9SMarkus Armbruster return 1;
824c2abccecSMORITA Kazutaka }
8257e7d56d9SMarkus Armbruster bs = blk_bs(blk);
8268599ea4cSFederico Simoncelli
8278599ea4cSFederico Simoncelli check = g_new0(ImageCheck, 1);
8288599ea4cSFederico Simoncelli ret = collect_image_check(bs, check, filename, fmt, fix);
829e076f338SKevin Wolf
830e076f338SKevin Wolf if (ret == -ENOTSUP) {
83115654a6dSJes Sorensen error_report("This image format does not support checks");
832fefddf95SPeter Lieven ret = 63;
8338599ea4cSFederico Simoncelli goto fail;
8341585969cSaliguori }
835e076f338SKevin Wolf
8368599ea4cSFederico Simoncelli if (check->corruptions_fixed || check->leaks_fixed) {
8378599ea4cSFederico Simoncelli int corruptions_fixed, leaks_fixed;
8381656324eSMax Reitz bool has_leaks_fixed, has_corruptions_fixed;
8398599ea4cSFederico Simoncelli
8408599ea4cSFederico Simoncelli leaks_fixed = check->leaks_fixed;
8411656324eSMax Reitz has_leaks_fixed = check->has_leaks_fixed;
8428599ea4cSFederico Simoncelli corruptions_fixed = check->corruptions_fixed;
8431656324eSMax Reitz has_corruptions_fixed = check->has_corruptions_fixed;
8448599ea4cSFederico Simoncelli
8458599ea4cSFederico Simoncelli if (output_format == OFORMAT_HUMAN) {
846f382d43aSMiroslav Rezanina qprintf(quiet,
847f382d43aSMiroslav Rezanina "The following inconsistencies were found and repaired:\n\n"
8488599ea4cSFederico Simoncelli " %" PRId64 " leaked clusters\n"
8498599ea4cSFederico Simoncelli " %" PRId64 " corruptions\n\n"
850ccf34716SKevin Wolf "Double checking the fixed image now...\n",
8518599ea4cSFederico Simoncelli check->leaks_fixed,
8528599ea4cSFederico Simoncelli check->corruptions_fixed);
853ccf34716SKevin Wolf }
854ccf34716SKevin Wolf
855fc124ea1SPan Nengyuan qapi_free_ImageCheck(check);
856fc124ea1SPan Nengyuan check = g_new0(ImageCheck, 1);
8578599ea4cSFederico Simoncelli ret = collect_image_check(bs, check, filename, fmt, 0);
8588599ea4cSFederico Simoncelli
8598599ea4cSFederico Simoncelli check->leaks_fixed = leaks_fixed;
8601656324eSMax Reitz check->has_leaks_fixed = has_leaks_fixed;
8618599ea4cSFederico Simoncelli check->corruptions_fixed = corruptions_fixed;
8621656324eSMax Reitz check->has_corruptions_fixed = has_corruptions_fixed;
8638599ea4cSFederico Simoncelli }
8648599ea4cSFederico Simoncelli
865832390a5SMax Reitz if (!ret) {
8668599ea4cSFederico Simoncelli switch (output_format) {
8678599ea4cSFederico Simoncelli case OFORMAT_HUMAN:
868f382d43aSMiroslav Rezanina dump_human_image_check(check, quiet);
8698599ea4cSFederico Simoncelli break;
8708599ea4cSFederico Simoncelli case OFORMAT_JSON:
871f382d43aSMiroslav Rezanina dump_json_image_check(check, quiet);
8728599ea4cSFederico Simoncelli break;
8738599ea4cSFederico Simoncelli }
874832390a5SMax Reitz }
8758599ea4cSFederico Simoncelli
8768599ea4cSFederico Simoncelli if (ret || check->check_errors) {
877832390a5SMax Reitz if (ret) {
878832390a5SMax Reitz error_report("Check failed: %s", strerror(-ret));
879832390a5SMax Reitz } else {
880832390a5SMax Reitz error_report("Check failed");
881832390a5SMax Reitz }
8828599ea4cSFederico Simoncelli ret = 1;
8838599ea4cSFederico Simoncelli goto fail;
8848599ea4cSFederico Simoncelli }
8858599ea4cSFederico Simoncelli
8868599ea4cSFederico Simoncelli if (check->corruptions) {
8878599ea4cSFederico Simoncelli ret = 2;
8888599ea4cSFederico Simoncelli } else if (check->leaks) {
8898599ea4cSFederico Simoncelli ret = 3;
890e076f338SKevin Wolf } else {
8918599ea4cSFederico Simoncelli ret = 0;
892e076f338SKevin Wolf }
893e076f338SKevin Wolf
8948599ea4cSFederico Simoncelli fail:
8958599ea4cSFederico Simoncelli qapi_free_ImageCheck(check);
89626f54e9aSMarkus Armbruster blk_unref(blk);
8978599ea4cSFederico Simoncelli return ret;
898e076f338SKevin Wolf }
8991585969cSaliguori
900d4a3238aSMax Reitz typedef struct CommonBlockJobCBInfo {
901d4a3238aSMax Reitz BlockDriverState *bs;
902d4a3238aSMax Reitz Error **errp;
903d4a3238aSMax Reitz } CommonBlockJobCBInfo;
904d4a3238aSMax Reitz
common_block_job_cb(void * opaque,int ret)905d4a3238aSMax Reitz static void common_block_job_cb(void *opaque, int ret)
906d4a3238aSMax Reitz {
907d4a3238aSMax Reitz CommonBlockJobCBInfo *cbi = opaque;
908d4a3238aSMax Reitz
909d4a3238aSMax Reitz if (ret < 0) {
910d4a3238aSMax Reitz error_setg_errno(cbi->errp, -ret, "Block job failed");
911d4a3238aSMax Reitz }
912d4a3238aSMax Reitz }
913d4a3238aSMax Reitz
run_block_job(BlockJob * job,Error ** errp)914d4a3238aSMax Reitz static void run_block_job(BlockJob *job, Error **errp)
915d4a3238aSMax Reitz {
916a7b4f8fcSEmanuele Giuseppe Esposito uint64_t progress_current, progress_total;
917df9a3165SVladimir Sementsov-Ogievskiy AioContext *aio_context = block_job_get_aio_context(job);
9184172a003Ssochin.jiang int ret = 0;
919d4a3238aSMax Reitz
920880eeec6SEmanuele Giuseppe Esposito job_lock();
921880eeec6SEmanuele Giuseppe Esposito job_ref_locked(&job->job);
922d4a3238aSMax Reitz do {
92330a5c887SKevin Wolf float progress = 0.0f;
924880eeec6SEmanuele Giuseppe Esposito job_unlock();
925d4a3238aSMax Reitz aio_poll(aio_context, true);
926a7b4f8fcSEmanuele Giuseppe Esposito
927a7b4f8fcSEmanuele Giuseppe Esposito progress_get_snapshot(&job->job.progress, &progress_current,
928a7b4f8fcSEmanuele Giuseppe Esposito &progress_total);
929a7b4f8fcSEmanuele Giuseppe Esposito if (progress_total) {
930a7b4f8fcSEmanuele Giuseppe Esposito progress = (float)progress_current / progress_total * 100.f;
93130a5c887SKevin Wolf }
93230a5c887SKevin Wolf qemu_progress_print(progress, 0);
933880eeec6SEmanuele Giuseppe Esposito job_lock();
934880eeec6SEmanuele Giuseppe Esposito } while (!job_is_ready_locked(&job->job) &&
935880eeec6SEmanuele Giuseppe Esposito !job_is_completed_locked(&job->job));
936d4a3238aSMax Reitz
937880eeec6SEmanuele Giuseppe Esposito if (!job_is_completed_locked(&job->job)) {
938880eeec6SEmanuele Giuseppe Esposito ret = job_complete_sync_locked(&job->job, errp);
9394172a003Ssochin.jiang } else {
9404ad35181SKevin Wolf ret = job->job.ret;
9414172a003Ssochin.jiang }
942880eeec6SEmanuele Giuseppe Esposito job_unref_locked(&job->job);
943880eeec6SEmanuele Giuseppe Esposito job_unlock();
944687fa1d8SMax Reitz
9454172a003Ssochin.jiang /* publish completion progress only when success */
9464172a003Ssochin.jiang if (!ret) {
947687fa1d8SMax Reitz qemu_progress_print(100.f, 0);
948d4a3238aSMax Reitz }
9494172a003Ssochin.jiang }
950d4a3238aSMax Reitz
img_commit(int argc,char ** argv)951ea2384d3Sbellard static int img_commit(int argc, char **argv)
952ea2384d3Sbellard {
953661a0f71SFederico Simoncelli int c, ret, flags;
9541b22bffdSMax Reitz const char *filename, *fmt, *cache, *base;
95526f54e9aSMarkus Armbruster BlockBackend *blk;
956d4a3238aSMax Reitz BlockDriverState *bs, *base_bs;
9574ef85a9cSKevin Wolf BlockJob *job;
958687fa1d8SMax Reitz bool progress = false, quiet = false, drop = false;
959ce099547SKevin Wolf bool writethrough;
960d4a3238aSMax Reitz Error *local_err = NULL;
961d4a3238aSMax Reitz CommonBlockJobCBInfo cbi;
962eb769f74SDaniel P. Berrange bool image_opts = false;
963a0441b66SZhengui int64_t rate_limit = 0;
964ea2384d3Sbellard
965ea2384d3Sbellard fmt = NULL;
966661a0f71SFederico Simoncelli cache = BDRV_DEFAULT_CACHE;
9671b22bffdSMax Reitz base = NULL;
968ea2384d3Sbellard for(;;) {
9693babeb15SDaniel P. Berrange static const struct option long_options[] = {
9703babeb15SDaniel P. Berrange {"help", no_argument, 0, 'h'},
9713babeb15SDaniel P. Berrange {"object", required_argument, 0, OPTION_OBJECT},
972eb769f74SDaniel P. Berrange {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
9733babeb15SDaniel P. Berrange {0, 0, 0, 0}
9743babeb15SDaniel P. Berrange };
975a0441b66SZhengui c = getopt_long(argc, argv, ":f:ht:b:dpqr:",
9763babeb15SDaniel P. Berrange long_options, NULL);
977b8fb60daSJes Sorensen if (c == -1) {
978ea2384d3Sbellard break;
979b8fb60daSJes Sorensen }
980ea2384d3Sbellard switch(c) {
981c9192973SStefan Hajnoczi case ':':
982c9192973SStefan Hajnoczi missing_argument(argv[optind - 1]);
983c9192973SStefan Hajnoczi break;
984ef87394cSJes Sorensen case '?':
985c9192973SStefan Hajnoczi unrecognized_option(argv[optind - 1]);
986c9192973SStefan Hajnoczi break;
987ea2384d3Sbellard case 'h':
988ea2384d3Sbellard help();
989ea2384d3Sbellard break;
990ea2384d3Sbellard case 'f':
991ea2384d3Sbellard fmt = optarg;
992ea2384d3Sbellard break;
993661a0f71SFederico Simoncelli case 't':
994661a0f71SFederico Simoncelli cache = optarg;
995661a0f71SFederico Simoncelli break;
9961b22bffdSMax Reitz case 'b':
9971b22bffdSMax Reitz base = optarg;
9981b22bffdSMax Reitz /* -b implies -d */
9991b22bffdSMax Reitz drop = true;
10001b22bffdSMax Reitz break;
10019a86fe48SMax Reitz case 'd':
10029a86fe48SMax Reitz drop = true;
10039a86fe48SMax Reitz break;
1004687fa1d8SMax Reitz case 'p':
1005687fa1d8SMax Reitz progress = true;
1006687fa1d8SMax Reitz break;
1007f382d43aSMiroslav Rezanina case 'q':
1008f382d43aSMiroslav Rezanina quiet = true;
1009f382d43aSMiroslav Rezanina break;
1010a0441b66SZhengui case 'r':
1011a0441b66SZhengui rate_limit = cvtnum("rate limit", optarg);
1012a0441b66SZhengui if (rate_limit < 0) {
1013a0441b66SZhengui return 1;
1014a0441b66SZhengui }
1015a0441b66SZhengui break;
101699b1e646SKevin Wolf case OPTION_OBJECT:
101799b1e646SKevin Wolf user_creatable_process_cmdline(optarg);
101899b1e646SKevin Wolf break;
1019eb769f74SDaniel P. Berrange case OPTION_IMAGE_OPTS:
1020eb769f74SDaniel P. Berrange image_opts = true;
1021eb769f74SDaniel P. Berrange break;
1022ea2384d3Sbellard }
1023ea2384d3Sbellard }
1024687fa1d8SMax Reitz
1025687fa1d8SMax Reitz /* Progress is not shown in Quiet mode */
1026687fa1d8SMax Reitz if (quiet) {
1027687fa1d8SMax Reitz progress = false;
1028687fa1d8SMax Reitz }
1029687fa1d8SMax Reitz
1030fc11eb26SKevin Wolf if (optind != argc - 1) {
1031ac1307abSFam Zheng error_exit("Expecting one image file name");
1032b8fb60daSJes Sorensen }
1033ea2384d3Sbellard filename = argv[optind++];
1034ea2384d3Sbellard
10359a86fe48SMax Reitz flags = BDRV_O_RDWR | BDRV_O_UNMAP;
1036ce099547SKevin Wolf ret = bdrv_parse_cache_mode(cache, &flags, &writethrough);
1037661a0f71SFederico Simoncelli if (ret < 0) {
1038661a0f71SFederico Simoncelli error_report("Invalid cache option: %s", cache);
1039a3981eb9SStefan Hajnoczi return 1;
1040661a0f71SFederico Simoncelli }
1041661a0f71SFederico Simoncelli
1042335e9937SFam Zheng blk = img_open(image_opts, filename, fmt, flags, writethrough, quiet,
1043335e9937SFam Zheng false);
10447e7d56d9SMarkus Armbruster if (!blk) {
10457e7d56d9SMarkus Armbruster return 1;
1046c2abccecSMORITA Kazutaka }
10477e7d56d9SMarkus Armbruster bs = blk_bs(blk);
10487e7d56d9SMarkus Armbruster
1049687fa1d8SMax Reitz qemu_progress_init(progress, 1.f);
1050687fa1d8SMax Reitz qemu_progress_print(0.f, 100);
1051687fa1d8SMax Reitz
1052ad74751fSKevin Wolf bdrv_graph_rdlock_main_loop();
10531b22bffdSMax Reitz if (base) {
10541b22bffdSMax Reitz base_bs = bdrv_find_backing_image(bs, base);
10551b22bffdSMax Reitz if (!base_bs) {
10566b33f3aeSMax Reitz error_setg(&local_err,
10576b33f3aeSMax Reitz "Did not find '%s' in the backing chain of '%s'",
10586b33f3aeSMax Reitz base, filename);
1059ad74751fSKevin Wolf bdrv_graph_rdunlock_main_loop();
10601b22bffdSMax Reitz goto done;
10611b22bffdSMax Reitz }
10621b22bffdSMax Reitz } else {
10631b22bffdSMax Reitz /* This is different from QMP, which by default uses the deepest file in
10641b22bffdSMax Reitz * the backing chain (i.e., the very base); however, the traditional
10651b22bffdSMax Reitz * behavior of qemu-img commit is using the immediate backing file. */
10664a2061e6SMax Reitz base_bs = bdrv_backing_chain_next(bs);
1067d4a3238aSMax Reitz if (!base_bs) {
1068d4a3238aSMax Reitz error_setg(&local_err, "Image does not have a backing file");
1069ad74751fSKevin Wolf bdrv_graph_rdunlock_main_loop();
1070d4a3238aSMax Reitz goto done;
1071ea2384d3Sbellard }
10721b22bffdSMax Reitz }
1073ad74751fSKevin Wolf bdrv_graph_rdunlock_main_loop();
1074ea2384d3Sbellard
1075d4a3238aSMax Reitz cbi = (CommonBlockJobCBInfo){
1076d4a3238aSMax Reitz .errp = &local_err,
1077d4a3238aSMax Reitz .bs = bs,
1078d4a3238aSMax Reitz };
1079d4a3238aSMax Reitz
1080a0441b66SZhengui commit_active_start("commit", bs, base_bs, JOB_DEFAULT, rate_limit,
10810db832f4SKevin Wolf BLOCKDEV_ON_ERROR_REPORT, NULL, common_block_job_cb,
108278bbd910SFam Zheng &cbi, false, &local_err);
1083d4a3238aSMax Reitz if (local_err) {
1084d4a3238aSMax Reitz goto done;
1085d4a3238aSMax Reitz }
1086d4a3238aSMax Reitz
10873f09bfbcSKevin Wolf /* When the block job completes, the BlockBackend reference will point to
10883f09bfbcSKevin Wolf * the old backing file. In order to avoid that the top image is already
10893f09bfbcSKevin Wolf * deleted, so we can still empty it afterwards, increment the reference
10903f09bfbcSKevin Wolf * counter here preemptively. */
10919a86fe48SMax Reitz if (!drop) {
10923f09bfbcSKevin Wolf bdrv_ref(bs);
10939a86fe48SMax Reitz }
10949a86fe48SMax Reitz
10954ef85a9cSKevin Wolf job = block_job_get("commit");
10962e2db260SLiam Merwick assert(job);
10974ef85a9cSKevin Wolf run_block_job(job, &local_err);
10989a86fe48SMax Reitz if (local_err) {
10999a86fe48SMax Reitz goto unref_backing;
11009a86fe48SMax Reitz }
11019a86fe48SMax Reitz
11022d97fde4SMax Reitz if (!drop) {
11032d97fde4SMax Reitz BlockBackend *old_backing_blk;
11042d97fde4SMax Reitz
11052d97fde4SMax Reitz old_backing_blk = blk_new_with_bs(bs, BLK_PERM_WRITE, BLK_PERM_ALL,
11062d97fde4SMax Reitz &local_err);
11072d97fde4SMax Reitz if (!old_backing_blk) {
11082d97fde4SMax Reitz goto unref_backing;
11092d97fde4SMax Reitz }
11102d97fde4SMax Reitz ret = blk_make_empty(old_backing_blk, &local_err);
11112d97fde4SMax Reitz blk_unref(old_backing_blk);
11122d97fde4SMax Reitz if (ret == -ENOTSUP) {
11132d97fde4SMax Reitz error_free(local_err);
11142d97fde4SMax Reitz local_err = NULL;
11152d97fde4SMax Reitz } else if (ret < 0) {
11169a86fe48SMax Reitz goto unref_backing;
11179a86fe48SMax Reitz }
11189a86fe48SMax Reitz }
11199a86fe48SMax Reitz
11209a86fe48SMax Reitz unref_backing:
11219a86fe48SMax Reitz if (!drop) {
11223f09bfbcSKevin Wolf bdrv_unref(bs);
11239a86fe48SMax Reitz }
1124d4a3238aSMax Reitz
1125d4a3238aSMax Reitz done:
1126687fa1d8SMax Reitz qemu_progress_end();
1127687fa1d8SMax Reitz
112844efba2dSKevin Wolf /*
112944efba2dSKevin Wolf * Manually inactivate the image first because this way we can know whether
113044efba2dSKevin Wolf * an error occurred. blk_unref() doesn't tell us about failures.
113144efba2dSKevin Wolf */
113244efba2dSKevin Wolf ret = bdrv_inactivate_all();
113344efba2dSKevin Wolf if (ret < 0 && !local_err) {
113444efba2dSKevin Wolf error_setg_errno(&local_err, -ret, "Error while closing the image");
113544efba2dSKevin Wolf }
113626f54e9aSMarkus Armbruster blk_unref(blk);
1137d4a3238aSMax Reitz
1138d4a3238aSMax Reitz if (local_err) {
11396936f299SMarkus Armbruster error_report_err(local_err);
1140c2abccecSMORITA Kazutaka return 1;
1141c2abccecSMORITA Kazutaka }
1142d4a3238aSMax Reitz
1143d4a3238aSMax Reitz qprintf(quiet, "Image committed.\n");
1144ea2384d3Sbellard return 0;
1145ea2384d3Sbellard }
1146ea2384d3Sbellard
1147f6a00aa1SDmitry Konishchev /*
1148debb38a4SEric Blake * Returns -1 if 'buf' contains only zeroes, otherwise the byte index
1149debb38a4SEric Blake * of the first sector boundary within buf where the sector contains a
1150debb38a4SEric Blake * non-zero byte. This function is robust to a buffer that is not
1151debb38a4SEric Blake * sector-aligned.
1152debb38a4SEric Blake */
find_nonzero(const uint8_t * buf,int64_t n)1153debb38a4SEric Blake static int64_t find_nonzero(const uint8_t *buf, int64_t n)
1154debb38a4SEric Blake {
1155debb38a4SEric Blake int64_t i;
1156debb38a4SEric Blake int64_t end = QEMU_ALIGN_DOWN(n, BDRV_SECTOR_SIZE);
1157debb38a4SEric Blake
1158debb38a4SEric Blake for (i = 0; i < end; i += BDRV_SECTOR_SIZE) {
1159debb38a4SEric Blake if (!buffer_is_zero(buf + i, BDRV_SECTOR_SIZE)) {
1160debb38a4SEric Blake return i;
1161debb38a4SEric Blake }
1162debb38a4SEric Blake }
1163debb38a4SEric Blake if (i < n && !buffer_is_zero(buf + i, n - end)) {
1164debb38a4SEric Blake return i;
1165debb38a4SEric Blake }
1166debb38a4SEric Blake return -1;
1167debb38a4SEric Blake }
1168debb38a4SEric Blake
1169debb38a4SEric Blake /*
1170f58c7b35Sths * Returns true iff the first sector pointed to by 'buf' contains at least
1171f58c7b35Sths * a non-NUL byte.
1172f58c7b35Sths *
1173f58c7b35Sths * 'pnum' is set to the number of sectors (including and immediately following
1174f58c7b35Sths * the first one) that are known to be in the same allocated/unallocated state.
11758dcd3c9bSPeter Lieven * The function will try to align the end offset to alignment boundaries so
1176e3a6e0daSzhaolichang * that the request will at least end aligned and consecutive requests will
11778dcd3c9bSPeter Lieven * also start at an aligned offset.
1178f58c7b35Sths */
is_allocated_sectors(const uint8_t * buf,int n,int * pnum,int64_t sector_num,int alignment)11798dcd3c9bSPeter Lieven static int is_allocated_sectors(const uint8_t *buf, int n, int *pnum,
11808dcd3c9bSPeter Lieven int64_t sector_num, int alignment)
1181ea2384d3Sbellard {
11821a6d39fdSStefan Hajnoczi bool is_zero;
11838dcd3c9bSPeter Lieven int i, tail;
1184ea2384d3Sbellard
1185ea2384d3Sbellard if (n <= 0) {
1186ea2384d3Sbellard *pnum = 0;
1187ea2384d3Sbellard return 0;
1188ea2384d3Sbellard }
1189c075c42fSYi Li is_zero = buffer_is_zero(buf, BDRV_SECTOR_SIZE);
1190ea2384d3Sbellard for(i = 1; i < n; i++) {
1191c075c42fSYi Li buf += BDRV_SECTOR_SIZE;
1192c075c42fSYi Li if (is_zero != buffer_is_zero(buf, BDRV_SECTOR_SIZE)) {
1193ea2384d3Sbellard break;
1194ea2384d3Sbellard }
11951a6d39fdSStefan Hajnoczi }
11968dcd3c9bSPeter Lieven
119796054c76SVladimir Sementsov-Ogievskiy if (i == n) {
119896054c76SVladimir Sementsov-Ogievskiy /*
119996054c76SVladimir Sementsov-Ogievskiy * The whole buf is the same.
120096054c76SVladimir Sementsov-Ogievskiy * No reason to split it into chunks, so return now.
120196054c76SVladimir Sementsov-Ogievskiy */
120296054c76SVladimir Sementsov-Ogievskiy *pnum = i;
120396054c76SVladimir Sementsov-Ogievskiy return !is_zero;
120496054c76SVladimir Sementsov-Ogievskiy }
120596054c76SVladimir Sementsov-Ogievskiy
12068dcd3c9bSPeter Lieven tail = (sector_num + i) & (alignment - 1);
12078dcd3c9bSPeter Lieven if (tail) {
12088dcd3c9bSPeter Lieven if (is_zero && i <= tail) {
120996054c76SVladimir Sementsov-Ogievskiy /*
121096054c76SVladimir Sementsov-Ogievskiy * For sure next sector after i is data, and it will rewrite this
121196054c76SVladimir Sementsov-Ogievskiy * tail anyway due to RMW. So, let's just write data now.
121296054c76SVladimir Sementsov-Ogievskiy */
12138dcd3c9bSPeter Lieven is_zero = false;
12148dcd3c9bSPeter Lieven }
12158dcd3c9bSPeter Lieven if (!is_zero) {
121696054c76SVladimir Sementsov-Ogievskiy /* If possible, align up end offset of allocated areas. */
12178dcd3c9bSPeter Lieven i += alignment - tail;
12188dcd3c9bSPeter Lieven i = MIN(i, n);
12198dcd3c9bSPeter Lieven } else {
122096054c76SVladimir Sementsov-Ogievskiy /*
122196054c76SVladimir Sementsov-Ogievskiy * For sure next sector after i is data, and it will rewrite this
122296054c76SVladimir Sementsov-Ogievskiy * tail anyway due to RMW. Better is avoid RMW and write zeroes up
122396054c76SVladimir Sementsov-Ogievskiy * to aligned bound.
122496054c76SVladimir Sementsov-Ogievskiy */
12258dcd3c9bSPeter Lieven i -= tail;
12268dcd3c9bSPeter Lieven }
12278dcd3c9bSPeter Lieven }
1228ea2384d3Sbellard *pnum = i;
12291a6d39fdSStefan Hajnoczi return !is_zero;
1230ea2384d3Sbellard }
1231ea2384d3Sbellard
12323e85c6fdSKevin Wolf /*
1233a22f123cSKevin Wolf * Like is_allocated_sectors, but if the buffer starts with a used sector,
1234a22f123cSKevin Wolf * up to 'min' consecutive sectors containing zeros are ignored. This avoids
1235a22f123cSKevin Wolf * breaking up write requests for only small sparse areas.
1236a22f123cSKevin Wolf */
is_allocated_sectors_min(const uint8_t * buf,int n,int * pnum,int min,int64_t sector_num,int alignment)1237a22f123cSKevin Wolf static int is_allocated_sectors_min(const uint8_t *buf, int n, int *pnum,
12388dcd3c9bSPeter Lieven int min, int64_t sector_num, int alignment)
1239a22f123cSKevin Wolf {
1240a22f123cSKevin Wolf int ret;
1241a22f123cSKevin Wolf int num_checked, num_used;
1242a22f123cSKevin Wolf
1243a22f123cSKevin Wolf if (n < min) {
1244a22f123cSKevin Wolf min = n;
1245a22f123cSKevin Wolf }
1246a22f123cSKevin Wolf
12478dcd3c9bSPeter Lieven ret = is_allocated_sectors(buf, n, pnum, sector_num, alignment);
1248a22f123cSKevin Wolf if (!ret) {
1249a22f123cSKevin Wolf return ret;
1250a22f123cSKevin Wolf }
1251a22f123cSKevin Wolf
1252a22f123cSKevin Wolf num_used = *pnum;
1253a22f123cSKevin Wolf buf += BDRV_SECTOR_SIZE * *pnum;
1254a22f123cSKevin Wolf n -= *pnum;
12558dcd3c9bSPeter Lieven sector_num += *pnum;
1256a22f123cSKevin Wolf num_checked = num_used;
1257a22f123cSKevin Wolf
1258a22f123cSKevin Wolf while (n > 0) {
12598dcd3c9bSPeter Lieven ret = is_allocated_sectors(buf, n, pnum, sector_num, alignment);
1260a22f123cSKevin Wolf
1261a22f123cSKevin Wolf buf += BDRV_SECTOR_SIZE * *pnum;
1262a22f123cSKevin Wolf n -= *pnum;
12638dcd3c9bSPeter Lieven sector_num += *pnum;
1264a22f123cSKevin Wolf num_checked += *pnum;
1265a22f123cSKevin Wolf if (ret) {
1266a22f123cSKevin Wolf num_used = num_checked;
1267a22f123cSKevin Wolf } else if (*pnum >= min) {
1268a22f123cSKevin Wolf break;
1269a22f123cSKevin Wolf }
1270a22f123cSKevin Wolf }
1271a22f123cSKevin Wolf
1272a22f123cSKevin Wolf *pnum = num_used;
1273a22f123cSKevin Wolf return 1;
1274a22f123cSKevin Wolf }
1275a22f123cSKevin Wolf
1276a22f123cSKevin Wolf /*
1277c20c8ae7SAndrey Drobyshev * Compares two buffers chunk by chunk, where @chsize is the chunk size.
1278c20c8ae7SAndrey Drobyshev * If @chsize is 0, default chunk size of BDRV_SECTOR_SIZE is used.
1279c20c8ae7SAndrey Drobyshev * Returns 0 if the first chunk of each buffer matches, non-zero otherwise.
12803e85c6fdSKevin Wolf *
1281c20c8ae7SAndrey Drobyshev * @pnum is set to the size of the buffer prefix aligned to @chsize that
1282c20c8ae7SAndrey Drobyshev * has the same matching status as the first chunk.
12833e85c6fdSKevin Wolf */
compare_buffers(const uint8_t * buf1,const uint8_t * buf2,int64_t bytes,uint64_t chsize,int64_t * pnum)1284dc61cd3bSEric Blake static int compare_buffers(const uint8_t *buf1, const uint8_t *buf2,
1285c20c8ae7SAndrey Drobyshev int64_t bytes, uint64_t chsize, int64_t *pnum)
12863e85c6fdSKevin Wolf {
12878c1ac475SRadim Krčmář bool res;
1288c20c8ae7SAndrey Drobyshev int64_t i;
12893e85c6fdSKevin Wolf
1290dc61cd3bSEric Blake assert(bytes > 0);
12913e85c6fdSKevin Wolf
1292c20c8ae7SAndrey Drobyshev if (!chsize) {
1293c20c8ae7SAndrey Drobyshev chsize = BDRV_SECTOR_SIZE;
1294c20c8ae7SAndrey Drobyshev }
1295c20c8ae7SAndrey Drobyshev i = MIN(bytes, chsize);
1296c20c8ae7SAndrey Drobyshev
1297dc61cd3bSEric Blake res = !!memcmp(buf1, buf2, i);
1298dc61cd3bSEric Blake while (i < bytes) {
1299c20c8ae7SAndrey Drobyshev int64_t len = MIN(bytes - i, chsize);
13003e85c6fdSKevin Wolf
1301dc61cd3bSEric Blake if (!!memcmp(buf1 + i, buf2 + i, len) != res) {
13023e85c6fdSKevin Wolf break;
13033e85c6fdSKevin Wolf }
1304dc61cd3bSEric Blake i += len;
13053e85c6fdSKevin Wolf }
13063e85c6fdSKevin Wolf
13073e85c6fdSKevin Wolf *pnum = i;
13083e85c6fdSKevin Wolf return res;
13093e85c6fdSKevin Wolf }
13103e85c6fdSKevin Wolf
131197ede57aSStefano Garzarella #define IO_BUF_SIZE (2 * MiB)
1312ea2384d3Sbellard
1313d14ed18cSMiroslav Rezanina /*
1314d14ed18cSMiroslav Rezanina * Check if passed sectors are empty (not allocated or contain only 0 bytes)
1315d14ed18cSMiroslav Rezanina *
13160608e40eSEric Blake * Intended for use by 'qemu-img compare': Returns 0 in case sectors are
13170608e40eSEric Blake * filled with 0, 1 if sectors contain non-zero data (this is a comparison
13180608e40eSEric Blake * failure), and 4 on error (the exit status for read errors), after emitting
13190608e40eSEric Blake * an error message.
1320d14ed18cSMiroslav Rezanina *
1321f1d3cd79SMax Reitz * @param blk: BlockBackend for the image
1322c41508edSEric Blake * @param offset: Starting offset to check
1323c41508edSEric Blake * @param bytes: Number of bytes to check
1324d14ed18cSMiroslav Rezanina * @param filename: Name of disk file we are checking (logging purpose)
1325d14ed18cSMiroslav Rezanina * @param buffer: Allocated buffer for storing read data
1326d14ed18cSMiroslav Rezanina * @param quiet: Flag for quiet mode
1327d14ed18cSMiroslav Rezanina */
check_empty_sectors(BlockBackend * blk,int64_t offset,int64_t bytes,const char * filename,uint8_t * buffer,bool quiet)1328c41508edSEric Blake static int check_empty_sectors(BlockBackend *blk, int64_t offset,
1329c41508edSEric Blake int64_t bytes, const char *filename,
1330d14ed18cSMiroslav Rezanina uint8_t *buffer, bool quiet)
1331d14ed18cSMiroslav Rezanina {
1332debb38a4SEric Blake int ret = 0;
1333debb38a4SEric Blake int64_t idx;
1334debb38a4SEric Blake
1335a9262f55SAlberto Faria ret = blk_pread(blk, offset, bytes, buffer, 0);
1336d14ed18cSMiroslav Rezanina if (ret < 0) {
1337d14ed18cSMiroslav Rezanina error_report("Error while reading offset %" PRId64 " of %s: %s",
1338c41508edSEric Blake offset, filename, strerror(-ret));
13390608e40eSEric Blake return 4;
1340d14ed18cSMiroslav Rezanina }
1341c41508edSEric Blake idx = find_nonzero(buffer, bytes);
1342debb38a4SEric Blake if (idx >= 0) {
1343d14ed18cSMiroslav Rezanina qprintf(quiet, "Content mismatch at offset %" PRId64 "!\n",
1344c41508edSEric Blake offset + idx);
1345d14ed18cSMiroslav Rezanina return 1;
1346d14ed18cSMiroslav Rezanina }
1347d14ed18cSMiroslav Rezanina
1348d14ed18cSMiroslav Rezanina return 0;
1349d14ed18cSMiroslav Rezanina }
1350d14ed18cSMiroslav Rezanina
1351d14ed18cSMiroslav Rezanina /*
1352d14ed18cSMiroslav Rezanina * Compares two images. Exit codes:
1353d14ed18cSMiroslav Rezanina *
135499b1e646SKevin Wolf * 0 - Images are identical or the requested help was printed
1355d14ed18cSMiroslav Rezanina * 1 - Images differ
1356d14ed18cSMiroslav Rezanina * >1 - Error occurred
1357d14ed18cSMiroslav Rezanina */
img_compare(int argc,char ** argv)1358d14ed18cSMiroslav Rezanina static int img_compare(int argc, char **argv)
1359d14ed18cSMiroslav Rezanina {
136040055951SMax Reitz const char *fmt1 = NULL, *fmt2 = NULL, *cache, *filename1, *filename2;
136126f54e9aSMarkus Armbruster BlockBackend *blk1, *blk2;
1362d14ed18cSMiroslav Rezanina BlockDriverState *bs1, *bs2;
1363033d9fc2SEric Blake int64_t total_size1, total_size2;
1364d14ed18cSMiroslav Rezanina uint8_t *buf1 = NULL, *buf2 = NULL;
136531826642SEric Blake int64_t pnum1, pnum2;
1366d14ed18cSMiroslav Rezanina int allocated1, allocated2;
1367d14ed18cSMiroslav Rezanina int ret = 0; /* return value - 0 Ident, 1 Different, >1 Error */
1368d14ed18cSMiroslav Rezanina bool progress = false, quiet = false, strict = false;
136940055951SMax Reitz int flags;
1370ce099547SKevin Wolf bool writethrough;
1371033d9fc2SEric Blake int64_t total_size;
1372033d9fc2SEric Blake int64_t offset = 0;
1373033d9fc2SEric Blake int64_t chunk;
1374dc61cd3bSEric Blake int c;
1375d14ed18cSMiroslav Rezanina uint64_t progress_base;
1376eb769f74SDaniel P. Berrange bool image_opts = false;
1377335e9937SFam Zheng bool force_share = false;
1378d14ed18cSMiroslav Rezanina
137940055951SMax Reitz cache = BDRV_DEFAULT_CACHE;
1380d14ed18cSMiroslav Rezanina for (;;) {
13813babeb15SDaniel P. Berrange static const struct option long_options[] = {
13823babeb15SDaniel P. Berrange {"help", no_argument, 0, 'h'},
13833babeb15SDaniel P. Berrange {"object", required_argument, 0, OPTION_OBJECT},
1384eb769f74SDaniel P. Berrange {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
1385335e9937SFam Zheng {"force-share", no_argument, 0, 'U'},
13863babeb15SDaniel P. Berrange {0, 0, 0, 0}
13873babeb15SDaniel P. Berrange };
1388335e9937SFam Zheng c = getopt_long(argc, argv, ":hf:F:T:pqsU",
13893babeb15SDaniel P. Berrange long_options, NULL);
1390d14ed18cSMiroslav Rezanina if (c == -1) {
1391d14ed18cSMiroslav Rezanina break;
1392d14ed18cSMiroslav Rezanina }
1393d14ed18cSMiroslav Rezanina switch (c) {
1394c9192973SStefan Hajnoczi case ':':
1395c9192973SStefan Hajnoczi missing_argument(argv[optind - 1]);
1396c9192973SStefan Hajnoczi break;
1397d14ed18cSMiroslav Rezanina case '?':
1398c9192973SStefan Hajnoczi unrecognized_option(argv[optind - 1]);
1399c9192973SStefan Hajnoczi break;
1400d14ed18cSMiroslav Rezanina case 'h':
1401d14ed18cSMiroslav Rezanina help();
1402d14ed18cSMiroslav Rezanina break;
1403d14ed18cSMiroslav Rezanina case 'f':
1404d14ed18cSMiroslav Rezanina fmt1 = optarg;
1405d14ed18cSMiroslav Rezanina break;
1406d14ed18cSMiroslav Rezanina case 'F':
1407d14ed18cSMiroslav Rezanina fmt2 = optarg;
1408d14ed18cSMiroslav Rezanina break;
140940055951SMax Reitz case 'T':
141040055951SMax Reitz cache = optarg;
141140055951SMax Reitz break;
1412d14ed18cSMiroslav Rezanina case 'p':
1413d14ed18cSMiroslav Rezanina progress = true;
1414d14ed18cSMiroslav Rezanina break;
1415d14ed18cSMiroslav Rezanina case 'q':
1416d14ed18cSMiroslav Rezanina quiet = true;
1417d14ed18cSMiroslav Rezanina break;
1418d14ed18cSMiroslav Rezanina case 's':
1419d14ed18cSMiroslav Rezanina strict = true;
1420d14ed18cSMiroslav Rezanina break;
1421335e9937SFam Zheng case 'U':
1422335e9937SFam Zheng force_share = true;
1423335e9937SFam Zheng break;
142499b1e646SKevin Wolf case OPTION_OBJECT:
142599b1e646SKevin Wolf {
142699b1e646SKevin Wolf Error *local_err = NULL;
142799b1e646SKevin Wolf
142899b1e646SKevin Wolf if (!user_creatable_add_from_str(optarg, &local_err)) {
142999b1e646SKevin Wolf if (local_err) {
143099b1e646SKevin Wolf error_report_err(local_err);
143199b1e646SKevin Wolf exit(2);
143299b1e646SKevin Wolf } else {
143399b1e646SKevin Wolf /* Help was printed */
143499b1e646SKevin Wolf exit(EXIT_SUCCESS);
14353babeb15SDaniel P. Berrange }
143699b1e646SKevin Wolf }
143799b1e646SKevin Wolf break;
143899b1e646SKevin Wolf }
1439eb769f74SDaniel P. Berrange case OPTION_IMAGE_OPTS:
1440eb769f74SDaniel P. Berrange image_opts = true;
1441eb769f74SDaniel P. Berrange break;
1442d14ed18cSMiroslav Rezanina }
1443d14ed18cSMiroslav Rezanina }
1444d14ed18cSMiroslav Rezanina
1445d14ed18cSMiroslav Rezanina /* Progress is not shown in Quiet mode */
1446d14ed18cSMiroslav Rezanina if (quiet) {
1447d14ed18cSMiroslav Rezanina progress = false;
1448d14ed18cSMiroslav Rezanina }
1449d14ed18cSMiroslav Rezanina
1450d14ed18cSMiroslav Rezanina
1451fc11eb26SKevin Wolf if (optind != argc - 2) {
1452ac1307abSFam Zheng error_exit("Expecting two image file names");
1453d14ed18cSMiroslav Rezanina }
1454d14ed18cSMiroslav Rezanina filename1 = argv[optind++];
1455d14ed18cSMiroslav Rezanina filename2 = argv[optind++];
1456d14ed18cSMiroslav Rezanina
1457cbda016dSStefan Hajnoczi /* Initialize before goto out */
1458cbda016dSStefan Hajnoczi qemu_progress_init(progress, 2.0);
1459cbda016dSStefan Hajnoczi
1460ce099547SKevin Wolf flags = 0;
1461ce099547SKevin Wolf ret = bdrv_parse_cache_mode(cache, &flags, &writethrough);
146240055951SMax Reitz if (ret < 0) {
146340055951SMax Reitz error_report("Invalid source cache option: %s", cache);
146440055951SMax Reitz ret = 2;
146540055951SMax Reitz goto out3;
146640055951SMax Reitz }
146740055951SMax Reitz
1468335e9937SFam Zheng blk1 = img_open(image_opts, filename1, fmt1, flags, writethrough, quiet,
1469335e9937SFam Zheng force_share);
14707e7d56d9SMarkus Armbruster if (!blk1) {
1471d14ed18cSMiroslav Rezanina ret = 2;
14727e7d56d9SMarkus Armbruster goto out3;
14737e7d56d9SMarkus Armbruster }
14747e7d56d9SMarkus Armbruster
1475335e9937SFam Zheng blk2 = img_open(image_opts, filename2, fmt2, flags, writethrough, quiet,
1476335e9937SFam Zheng force_share);
14777e7d56d9SMarkus Armbruster if (!blk2) {
14787e7d56d9SMarkus Armbruster ret = 2;
147926f54e9aSMarkus Armbruster goto out2;
1480d14ed18cSMiroslav Rezanina }
1481eb769f74SDaniel P. Berrange bs1 = blk_bs(blk1);
14827e7d56d9SMarkus Armbruster bs2 = blk_bs(blk2);
1483d14ed18cSMiroslav Rezanina
1484f1d3cd79SMax Reitz buf1 = blk_blockalign(blk1, IO_BUF_SIZE);
1485f1d3cd79SMax Reitz buf2 = blk_blockalign(blk2, IO_BUF_SIZE);
1486033d9fc2SEric Blake total_size1 = blk_getlength(blk1);
1487033d9fc2SEric Blake if (total_size1 < 0) {
148852bf1e72SMarkus Armbruster error_report("Can't get size of %s: %s",
1489033d9fc2SEric Blake filename1, strerror(-total_size1));
149052bf1e72SMarkus Armbruster ret = 4;
149152bf1e72SMarkus Armbruster goto out;
149252bf1e72SMarkus Armbruster }
1493033d9fc2SEric Blake total_size2 = blk_getlength(blk2);
1494033d9fc2SEric Blake if (total_size2 < 0) {
149552bf1e72SMarkus Armbruster error_report("Can't get size of %s: %s",
1496033d9fc2SEric Blake filename2, strerror(-total_size2));
149752bf1e72SMarkus Armbruster ret = 4;
149852bf1e72SMarkus Armbruster goto out;
149952bf1e72SMarkus Armbruster }
1500033d9fc2SEric Blake total_size = MIN(total_size1, total_size2);
1501033d9fc2SEric Blake progress_base = MAX(total_size1, total_size2);
1502d14ed18cSMiroslav Rezanina
1503d14ed18cSMiroslav Rezanina qemu_progress_print(0, 100);
1504d14ed18cSMiroslav Rezanina
1505033d9fc2SEric Blake if (strict && total_size1 != total_size2) {
1506d14ed18cSMiroslav Rezanina ret = 1;
1507d14ed18cSMiroslav Rezanina qprintf(quiet, "Strict mode: Image size mismatch!\n");
1508d14ed18cSMiroslav Rezanina goto out;
1509d14ed18cSMiroslav Rezanina }
1510d14ed18cSMiroslav Rezanina
1511033d9fc2SEric Blake while (offset < total_size) {
151231826642SEric Blake int status1, status2;
151367a0fd2aSFam Zheng
1514033d9fc2SEric Blake status1 = bdrv_block_status_above(bs1, NULL, offset,
1515033d9fc2SEric Blake total_size1 - offset, &pnum1, NULL,
1516033d9fc2SEric Blake NULL);
151725ad8e6eSFam Zheng if (status1 < 0) {
1518d14ed18cSMiroslav Rezanina ret = 3;
1519d14ed18cSMiroslav Rezanina error_report("Sector allocation test failed for %s", filename1);
1520d14ed18cSMiroslav Rezanina goto out;
1521d14ed18cSMiroslav Rezanina }
152225ad8e6eSFam Zheng allocated1 = status1 & BDRV_BLOCK_ALLOCATED;
1523d14ed18cSMiroslav Rezanina
1524033d9fc2SEric Blake status2 = bdrv_block_status_above(bs2, NULL, offset,
1525033d9fc2SEric Blake total_size2 - offset, &pnum2, NULL,
1526033d9fc2SEric Blake NULL);
152725ad8e6eSFam Zheng if (status2 < 0) {
1528d14ed18cSMiroslav Rezanina ret = 3;
1529d14ed18cSMiroslav Rezanina error_report("Sector allocation test failed for %s", filename2);
1530d14ed18cSMiroslav Rezanina goto out;
1531d14ed18cSMiroslav Rezanina }
153225ad8e6eSFam Zheng allocated2 = status2 & BDRV_BLOCK_ALLOCATED;
15337daddc61SEric Blake
15347daddc61SEric Blake assert(pnum1 && pnum2);
1535033d9fc2SEric Blake chunk = MIN(pnum1, pnum2);
1536d14ed18cSMiroslav Rezanina
153725ad8e6eSFam Zheng if (strict) {
153831826642SEric Blake if (status1 != status2) {
153925ad8e6eSFam Zheng ret = 1;
154025ad8e6eSFam Zheng qprintf(quiet, "Strict mode: Offset %" PRId64
1541033d9fc2SEric Blake " block status mismatch!\n", offset);
154225ad8e6eSFam Zheng goto out;
154325ad8e6eSFam Zheng }
154425ad8e6eSFam Zheng }
154525ad8e6eSFam Zheng if ((status1 & BDRV_BLOCK_ZERO) && (status2 & BDRV_BLOCK_ZERO)) {
15467daddc61SEric Blake /* nothing to do */
154725ad8e6eSFam Zheng } else if (allocated1 == allocated2) {
1548d14ed18cSMiroslav Rezanina if (allocated1) {
1549dc61cd3bSEric Blake int64_t pnum;
1550dc61cd3bSEric Blake
1551033d9fc2SEric Blake chunk = MIN(chunk, IO_BUF_SIZE);
1552a9262f55SAlberto Faria ret = blk_pread(blk1, offset, chunk, buf1, 0);
1553d14ed18cSMiroslav Rezanina if (ret < 0) {
1554d14ed18cSMiroslav Rezanina error_report("Error while reading offset %" PRId64
1555033d9fc2SEric Blake " of %s: %s",
1556033d9fc2SEric Blake offset, filename1, strerror(-ret));
1557d14ed18cSMiroslav Rezanina ret = 4;
1558d14ed18cSMiroslav Rezanina goto out;
1559d14ed18cSMiroslav Rezanina }
1560a9262f55SAlberto Faria ret = blk_pread(blk2, offset, chunk, buf2, 0);
1561033d9fc2SEric Blake if (ret < 0) {
1562033d9fc2SEric Blake error_report("Error while reading offset %" PRId64
1563033d9fc2SEric Blake " of %s: %s",
1564033d9fc2SEric Blake offset, filename2, strerror(-ret));
1565033d9fc2SEric Blake ret = 4;
1566033d9fc2SEric Blake goto out;
1567033d9fc2SEric Blake }
1568c20c8ae7SAndrey Drobyshev ret = compare_buffers(buf1, buf2, chunk, 0, &pnum);
1569033d9fc2SEric Blake if (ret || pnum != chunk) {
1570d14ed18cSMiroslav Rezanina qprintf(quiet, "Content mismatch at offset %" PRId64 "!\n",
1571033d9fc2SEric Blake offset + (ret ? 0 : pnum));
157236452f12SFam Zheng ret = 1;
1573d14ed18cSMiroslav Rezanina goto out;
1574d14ed18cSMiroslav Rezanina }
1575d14ed18cSMiroslav Rezanina }
1576d14ed18cSMiroslav Rezanina } else {
1577033d9fc2SEric Blake chunk = MIN(chunk, IO_BUF_SIZE);
1578d14ed18cSMiroslav Rezanina if (allocated1) {
1579033d9fc2SEric Blake ret = check_empty_sectors(blk1, offset, chunk,
1580d14ed18cSMiroslav Rezanina filename1, buf1, quiet);
1581d14ed18cSMiroslav Rezanina } else {
1582033d9fc2SEric Blake ret = check_empty_sectors(blk2, offset, chunk,
1583d14ed18cSMiroslav Rezanina filename2, buf1, quiet);
1584d14ed18cSMiroslav Rezanina }
1585d14ed18cSMiroslav Rezanina if (ret) {
1586d14ed18cSMiroslav Rezanina goto out;
1587d14ed18cSMiroslav Rezanina }
1588d14ed18cSMiroslav Rezanina }
1589033d9fc2SEric Blake offset += chunk;
1590033d9fc2SEric Blake qemu_progress_print(((float) chunk / progress_base) * 100, 100);
1591d14ed18cSMiroslav Rezanina }
1592d14ed18cSMiroslav Rezanina
1593033d9fc2SEric Blake if (total_size1 != total_size2) {
1594f1d3cd79SMax Reitz BlockBackend *blk_over;
1595d14ed18cSMiroslav Rezanina const char *filename_over;
1596d14ed18cSMiroslav Rezanina
1597d14ed18cSMiroslav Rezanina qprintf(quiet, "Warning: Image size mismatch!\n");
1598033d9fc2SEric Blake if (total_size1 > total_size2) {
1599f1d3cd79SMax Reitz blk_over = blk1;
1600d14ed18cSMiroslav Rezanina filename_over = filename1;
1601d14ed18cSMiroslav Rezanina } else {
1602f1d3cd79SMax Reitz blk_over = blk2;
1603d14ed18cSMiroslav Rezanina filename_over = filename2;
1604d14ed18cSMiroslav Rezanina }
1605d14ed18cSMiroslav Rezanina
1606033d9fc2SEric Blake while (offset < progress_base) {
1607033d9fc2SEric Blake ret = bdrv_block_status_above(blk_bs(blk_over), NULL, offset,
1608033d9fc2SEric Blake progress_base - offset, &chunk,
1609033d9fc2SEric Blake NULL, NULL);
1610d14ed18cSMiroslav Rezanina if (ret < 0) {
1611d14ed18cSMiroslav Rezanina ret = 3;
1612d14ed18cSMiroslav Rezanina error_report("Sector allocation test failed for %s",
1613d14ed18cSMiroslav Rezanina filename_over);
1614d14ed18cSMiroslav Rezanina goto out;
1615d14ed18cSMiroslav Rezanina
1616d14ed18cSMiroslav Rezanina }
1617391cb1aaSEric Blake if (ret & BDRV_BLOCK_ALLOCATED && !(ret & BDRV_BLOCK_ZERO)) {
1618033d9fc2SEric Blake chunk = MIN(chunk, IO_BUF_SIZE);
1619033d9fc2SEric Blake ret = check_empty_sectors(blk_over, offset, chunk,
1620d14ed18cSMiroslav Rezanina filename_over, buf1, quiet);
1621d14ed18cSMiroslav Rezanina if (ret) {
1622d14ed18cSMiroslav Rezanina goto out;
1623d14ed18cSMiroslav Rezanina }
1624d14ed18cSMiroslav Rezanina }
1625033d9fc2SEric Blake offset += chunk;
1626033d9fc2SEric Blake qemu_progress_print(((float) chunk / progress_base) * 100, 100);
1627d14ed18cSMiroslav Rezanina }
1628d14ed18cSMiroslav Rezanina }
1629d14ed18cSMiroslav Rezanina
1630d14ed18cSMiroslav Rezanina qprintf(quiet, "Images are identical.\n");
1631d14ed18cSMiroslav Rezanina ret = 0;
1632d14ed18cSMiroslav Rezanina
1633d14ed18cSMiroslav Rezanina out:
1634d14ed18cSMiroslav Rezanina qemu_vfree(buf1);
1635d14ed18cSMiroslav Rezanina qemu_vfree(buf2);
163626f54e9aSMarkus Armbruster blk_unref(blk2);
1637d14ed18cSMiroslav Rezanina out2:
163826f54e9aSMarkus Armbruster blk_unref(blk1);
1639d14ed18cSMiroslav Rezanina out3:
1640d14ed18cSMiroslav Rezanina qemu_progress_end();
1641d14ed18cSMiroslav Rezanina return ret;
1642d14ed18cSMiroslav Rezanina }
1643d14ed18cSMiroslav Rezanina
16446c729dd8SEric Blake /* Convenience wrapper around qmp_block_dirty_bitmap_merge */
do_dirty_bitmap_merge(const char * dst_node,const char * dst_name,const char * src_node,const char * src_name,Error ** errp)16456c729dd8SEric Blake static void do_dirty_bitmap_merge(const char *dst_node, const char *dst_name,
16466c729dd8SEric Blake const char *src_node, const char *src_name,
16476c729dd8SEric Blake Error **errp)
16486c729dd8SEric Blake {
16491466ef6cSVladimir Sementsov-Ogievskiy BlockDirtyBitmapOrStr *merge_src;
16501466ef6cSVladimir Sementsov-Ogievskiy BlockDirtyBitmapOrStrList *list = NULL;
16516c729dd8SEric Blake
16521466ef6cSVladimir Sementsov-Ogievskiy merge_src = g_new0(BlockDirtyBitmapOrStr, 1);
16536c729dd8SEric Blake merge_src->type = QTYPE_QDICT;
16546c729dd8SEric Blake merge_src->u.external.node = g_strdup(src_node);
16556c729dd8SEric Blake merge_src->u.external.name = g_strdup(src_name);
165654aa3de7SEric Blake QAPI_LIST_PREPEND(list, merge_src);
16576c729dd8SEric Blake qmp_block_dirty_bitmap_merge(dst_node, dst_name, list, errp);
16581466ef6cSVladimir Sementsov-Ogievskiy qapi_free_BlockDirtyBitmapOrStrList(list);
16596c729dd8SEric Blake }
16606c729dd8SEric Blake
1661690c7301SKevin Wolf enum ImgConvertBlockStatus {
1662690c7301SKevin Wolf BLK_DATA,
1663690c7301SKevin Wolf BLK_ZERO,
1664690c7301SKevin Wolf BLK_BACKING_FILE,
1665690c7301SKevin Wolf };
1666690c7301SKevin Wolf
16672d9187bcSPeter Lieven #define MAX_COROUTINES 16
16680c8c4895SZhengui #define CONVERT_THROTTLE_GROUP "img_convert"
16692d9187bcSPeter Lieven
1670690c7301SKevin Wolf typedef struct ImgConvertState {
1671690c7301SKevin Wolf BlockBackend **src;
1672690c7301SKevin Wolf int64_t *src_sectors;
1673af8d43d3SPeter Lieven int *src_alignment;
16742d9187bcSPeter Lieven int src_num;
1675690c7301SKevin Wolf int64_t total_sectors;
1676690c7301SKevin Wolf int64_t allocated_sectors;
16772d9187bcSPeter Lieven int64_t allocated_done;
16782d9187bcSPeter Lieven int64_t sector_num;
16792d9187bcSPeter Lieven int64_t wr_offs;
1680690c7301SKevin Wolf enum ImgConvertBlockStatus status;
1681690c7301SKevin Wolf int64_t sector_next_status;
1682690c7301SKevin Wolf BlockBackend *target;
1683690c7301SKevin Wolf bool has_zero_init;
1684690c7301SKevin Wolf bool compressed;
16854d7c487eSMax Reitz bool target_is_new;
1686690c7301SKevin Wolf bool target_has_backing;
1687351c8effSMax Reitz int64_t target_backing_sectors; /* negative if unknown */
16882d9187bcSPeter Lieven bool wr_in_order;
1689ee5306d0SFam Zheng bool copy_range;
16908eaac025SMax Reitz bool salvage;
16913d96cb91SMax Reitz bool quiet;
1692690c7301SKevin Wolf int min_sparse;
16938dcd3c9bSPeter Lieven int alignment;
1694690c7301SKevin Wolf size_t cluster_sectors;
1695690c7301SKevin Wolf size_t buf_sectors;
16969fd77f99SPeter Lieven long num_coroutines;
16972d9187bcSPeter Lieven int running_coroutines;
16982d9187bcSPeter Lieven Coroutine *co[MAX_COROUTINES];
16992d9187bcSPeter Lieven int64_t wait_sector_num[MAX_COROUTINES];
17002d9187bcSPeter Lieven CoMutex lock;
17012d9187bcSPeter Lieven int ret;
1702690c7301SKevin Wolf } ImgConvertState;
1703690c7301SKevin Wolf
convert_select_part(ImgConvertState * s,int64_t sector_num,int * src_cur,int64_t * src_cur_offset)17042d9187bcSPeter Lieven static void convert_select_part(ImgConvertState *s, int64_t sector_num,
17052d9187bcSPeter Lieven int *src_cur, int64_t *src_cur_offset)
1706690c7301SKevin Wolf {
17072d9187bcSPeter Lieven *src_cur = 0;
17082d9187bcSPeter Lieven *src_cur_offset = 0;
17092d9187bcSPeter Lieven while (sector_num - *src_cur_offset >= s->src_sectors[*src_cur]) {
17102d9187bcSPeter Lieven *src_cur_offset += s->src_sectors[*src_cur];
17112d9187bcSPeter Lieven (*src_cur)++;
17122d9187bcSPeter Lieven assert(*src_cur < s->src_num);
1713690c7301SKevin Wolf }
1714690c7301SKevin Wolf }
1715690c7301SKevin Wolf
1716ad74751fSKevin Wolf static int coroutine_mixed_fn GRAPH_RDLOCK
convert_iteration_sectors(ImgConvertState * s,int64_t sector_num)1717ad74751fSKevin Wolf convert_iteration_sectors(ImgConvertState *s, int64_t sector_num)
1718690c7301SKevin Wolf {
171931826642SEric Blake int64_t src_cur_offset;
172031826642SEric Blake int ret, n, src_cur;
1721351c8effSMax Reitz bool post_backing_zero = false;
1722690c7301SKevin Wolf
17232d9187bcSPeter Lieven convert_select_part(s, sector_num, &src_cur, &src_cur_offset);
1724690c7301SKevin Wolf
1725690c7301SKevin Wolf assert(s->total_sectors > sector_num);
1726690c7301SKevin Wolf n = MIN(s->total_sectors - sector_num, BDRV_REQUEST_MAX_SECTORS);
1727690c7301SKevin Wolf
1728351c8effSMax Reitz if (s->target_backing_sectors >= 0) {
1729351c8effSMax Reitz if (sector_num >= s->target_backing_sectors) {
17302253d86eSVladimir Sementsov-Ogievskiy post_backing_zero = true;
1731351c8effSMax Reitz } else if (sector_num + n > s->target_backing_sectors) {
1732351c8effSMax Reitz /* Split requests around target_backing_sectors (because
1733351c8effSMax Reitz * starting from there, zeros are handled differently) */
1734351c8effSMax Reitz n = s->target_backing_sectors - sector_num;
1735351c8effSMax Reitz }
1736351c8effSMax Reitz }
1737351c8effSMax Reitz
1738690c7301SKevin Wolf if (s->sector_next_status <= sector_num) {
17398eaac025SMax Reitz uint64_t offset = (sector_num - src_cur_offset) * BDRV_SECTOR_SIZE;
17408eaac025SMax Reitz int64_t count;
1741af8d43d3SPeter Lieven int tail;
17424a2061e6SMax Reitz BlockDriverState *src_bs = blk_bs(s->src[src_cur]);
17434a2061e6SMax Reitz BlockDriverState *base;
17444a2061e6SMax Reitz
17454a2061e6SMax Reitz if (s->target_has_backing) {
17464a2061e6SMax Reitz base = bdrv_cow_bs(bdrv_skip_filters(src_bs));
17474a2061e6SMax Reitz } else {
17484a2061e6SMax Reitz base = NULL;
17494a2061e6SMax Reitz }
17508eaac025SMax Reitz
17518eaac025SMax Reitz do {
17528eaac025SMax Reitz count = n * BDRV_SECTOR_SIZE;
1753237d78f8SEric Blake
17544a2061e6SMax Reitz ret = bdrv_block_status_above(src_bs, base, offset, count, &count,
17554a2061e6SMax Reitz NULL, NULL);
17568eaac025SMax Reitz
1757690c7301SKevin Wolf if (ret < 0) {
17588eaac025SMax Reitz if (s->salvage) {
17598eaac025SMax Reitz if (n == 1) {
17608eaac025SMax Reitz if (!s->quiet) {
17618eaac025SMax Reitz warn_report("error while reading block status at "
17628eaac025SMax Reitz "offset %" PRIu64 ": %s", offset,
17638eaac025SMax Reitz strerror(-ret));
17648eaac025SMax Reitz }
17658eaac025SMax Reitz /* Just try to read the data, then */
17668eaac025SMax Reitz ret = BDRV_BLOCK_DATA;
17678eaac025SMax Reitz count = BDRV_SECTOR_SIZE;
17688eaac025SMax Reitz } else {
17698eaac025SMax Reitz /* Retry on a shorter range */
17708eaac025SMax Reitz n = DIV_ROUND_UP(n, 4);
17718eaac025SMax Reitz }
17728eaac025SMax Reitz } else {
17738eaac025SMax Reitz error_report("error while reading block status at offset "
17748eaac025SMax Reitz "%" PRIu64 ": %s", offset, strerror(-ret));
1775690c7301SKevin Wolf return ret;
1776690c7301SKevin Wolf }
17778eaac025SMax Reitz }
17788eaac025SMax Reitz } while (ret < 0);
17798eaac025SMax Reitz
178031826642SEric Blake n = DIV_ROUND_UP(count, BDRV_SECTOR_SIZE);
1781690c7301SKevin Wolf
1782af8d43d3SPeter Lieven /*
1783af8d43d3SPeter Lieven * Avoid that s->sector_next_status becomes unaligned to the source
1784af8d43d3SPeter Lieven * request alignment and/or cluster size to avoid unnecessary read
1785af8d43d3SPeter Lieven * cycles.
1786af8d43d3SPeter Lieven */
1787af8d43d3SPeter Lieven tail = (sector_num - src_cur_offset + n) % s->src_alignment[src_cur];
1788af8d43d3SPeter Lieven if (n > tail) {
1789af8d43d3SPeter Lieven n -= tail;
1790af8d43d3SPeter Lieven }
1791af8d43d3SPeter Lieven
1792690c7301SKevin Wolf if (ret & BDRV_BLOCK_ZERO) {
1793351c8effSMax Reitz s->status = post_backing_zero ? BLK_BACKING_FILE : BLK_ZERO;
1794690c7301SKevin Wolf } else if (ret & BDRV_BLOCK_DATA) {
1795690c7301SKevin Wolf s->status = BLK_DATA;
1796263a6f4cSRen Kimura } else {
17979f1b92adSVladimir Sementsov-Ogievskiy s->status = s->target_has_backing ? BLK_BACKING_FILE : BLK_DATA;
1798690c7301SKevin Wolf }
1799690c7301SKevin Wolf
1800690c7301SKevin Wolf s->sector_next_status = sector_num + n;
1801690c7301SKevin Wolf }
1802690c7301SKevin Wolf
1803690c7301SKevin Wolf n = MIN(n, s->sector_next_status - sector_num);
1804690c7301SKevin Wolf if (s->status == BLK_DATA) {
1805690c7301SKevin Wolf n = MIN(n, s->buf_sectors);
1806690c7301SKevin Wolf }
1807690c7301SKevin Wolf
1808690c7301SKevin Wolf /* We need to write complete clusters for compressed images, so if an
1809690c7301SKevin Wolf * unallocated area is shorter than that, we must consider the whole
1810690c7301SKevin Wolf * cluster allocated. */
1811690c7301SKevin Wolf if (s->compressed) {
1812690c7301SKevin Wolf if (n < s->cluster_sectors) {
1813690c7301SKevin Wolf n = MIN(s->cluster_sectors, s->total_sectors - sector_num);
1814690c7301SKevin Wolf s->status = BLK_DATA;
1815690c7301SKevin Wolf } else {
1816690c7301SKevin Wolf n = QEMU_ALIGN_DOWN(n, s->cluster_sectors);
1817690c7301SKevin Wolf }
1818690c7301SKevin Wolf }
1819690c7301SKevin Wolf
1820690c7301SKevin Wolf return n;
1821690c7301SKevin Wolf }
1822690c7301SKevin Wolf
convert_co_read(ImgConvertState * s,int64_t sector_num,int nb_sectors,uint8_t * buf)18232d9187bcSPeter Lieven static int coroutine_fn convert_co_read(ImgConvertState *s, int64_t sector_num,
18242d9187bcSPeter Lieven int nb_sectors, uint8_t *buf)
1825690c7301SKevin Wolf {
18268eaac025SMax Reitz uint64_t single_read_until = 0;
18272d9187bcSPeter Lieven int n, ret;
1828690c7301SKevin Wolf
1829690c7301SKevin Wolf assert(nb_sectors <= s->buf_sectors);
1830690c7301SKevin Wolf while (nb_sectors > 0) {
1831690c7301SKevin Wolf BlockBackend *blk;
18322d9187bcSPeter Lieven int src_cur;
18332d9187bcSPeter Lieven int64_t bs_sectors, src_cur_offset;
18348eaac025SMax Reitz uint64_t offset;
1835690c7301SKevin Wolf
1836690c7301SKevin Wolf /* In the case of compression with multiple source files, we can get a
1837690c7301SKevin Wolf * nb_sectors that spreads into the next part. So we must be able to
1838690c7301SKevin Wolf * read across multiple BDSes for one convert_read() call. */
18392d9187bcSPeter Lieven convert_select_part(s, sector_num, &src_cur, &src_cur_offset);
18402d9187bcSPeter Lieven blk = s->src[src_cur];
18412d9187bcSPeter Lieven bs_sectors = s->src_sectors[src_cur];
1842690c7301SKevin Wolf
18438eaac025SMax Reitz offset = (sector_num - src_cur_offset) << BDRV_SECTOR_BITS;
18442d9187bcSPeter Lieven
18458eaac025SMax Reitz n = MIN(nb_sectors, bs_sectors - (sector_num - src_cur_offset));
18468eaac025SMax Reitz if (single_read_until > offset) {
18478eaac025SMax Reitz n = 1;
18488eaac025SMax Reitz }
18498eaac025SMax Reitz
18508eaac025SMax Reitz ret = blk_co_pread(blk, offset, n << BDRV_SECTOR_BITS, buf, 0);
1851690c7301SKevin Wolf if (ret < 0) {
18528eaac025SMax Reitz if (s->salvage) {
18538eaac025SMax Reitz if (n > 1) {
18548eaac025SMax Reitz single_read_until = offset + (n << BDRV_SECTOR_BITS);
18558eaac025SMax Reitz continue;
18568eaac025SMax Reitz } else {
18578eaac025SMax Reitz if (!s->quiet) {
18588eaac025SMax Reitz warn_report("error while reading offset %" PRIu64
18598eaac025SMax Reitz ": %s", offset, strerror(-ret));
18608eaac025SMax Reitz }
18618eaac025SMax Reitz memset(buf, 0, BDRV_SECTOR_SIZE);
18628eaac025SMax Reitz }
18638eaac025SMax Reitz } else {
1864690c7301SKevin Wolf return ret;
1865690c7301SKevin Wolf }
18668eaac025SMax Reitz }
1867690c7301SKevin Wolf
1868690c7301SKevin Wolf sector_num += n;
1869690c7301SKevin Wolf nb_sectors -= n;
1870690c7301SKevin Wolf buf += n * BDRV_SECTOR_SIZE;
1871690c7301SKevin Wolf }
1872690c7301SKevin Wolf
1873690c7301SKevin Wolf return 0;
1874690c7301SKevin Wolf }
1875690c7301SKevin Wolf
18762d9187bcSPeter Lieven
convert_co_write(ImgConvertState * s,int64_t sector_num,int nb_sectors,uint8_t * buf,enum ImgConvertBlockStatus status)18772d9187bcSPeter Lieven static int coroutine_fn convert_co_write(ImgConvertState *s, int64_t sector_num,
18782d9187bcSPeter Lieven int nb_sectors, uint8_t *buf,
18792d9187bcSPeter Lieven enum ImgConvertBlockStatus status)
1880690c7301SKevin Wolf {
1881690c7301SKevin Wolf int ret;
1882690c7301SKevin Wolf
1883690c7301SKevin Wolf while (nb_sectors > 0) {
1884690c7301SKevin Wolf int n = nb_sectors;
1885db933fbeSLidong Chen BdrvRequestFlags flags = s->compressed ? BDRV_REQ_WRITE_COMPRESSED : 0;
1886db933fbeSLidong Chen
18872d9187bcSPeter Lieven switch (status) {
1888690c7301SKevin Wolf case BLK_BACKING_FILE:
1889690c7301SKevin Wolf /* If we have a backing file, leave clusters unallocated that are
1890690c7301SKevin Wolf * unallocated in the source image, so that the backing file is
1891690c7301SKevin Wolf * visible at the respective offset. */
1892690c7301SKevin Wolf assert(s->target_has_backing);
1893690c7301SKevin Wolf break;
1894690c7301SKevin Wolf
1895690c7301SKevin Wolf case BLK_DATA:
1896db933fbeSLidong Chen /* If we're told to keep the target fully allocated (-S 0) or there
1897db933fbeSLidong Chen * is real non-zero data, we must write it. Otherwise we can treat
1898db933fbeSLidong Chen * it as zero sectors.
1899db933fbeSLidong Chen * Compressed clusters need to be written as a whole, so in that
1900db933fbeSLidong Chen * case we can only save the write if the buffer is completely
1901db933fbeSLidong Chen * zeroed. */
1902690c7301SKevin Wolf if (!s->min_sparse ||
1903db933fbeSLidong Chen (!s->compressed &&
19048dcd3c9bSPeter Lieven is_allocated_sectors_min(buf, n, &n, s->min_sparse,
19058dcd3c9bSPeter Lieven sector_num, s->alignment)) ||
1906db933fbeSLidong Chen (s->compressed &&
1907db933fbeSLidong Chen !buffer_is_zero(buf, n * BDRV_SECTOR_SIZE)))
1908690c7301SKevin Wolf {
1909265a7e54SVladimir Sementsov-Ogievskiy ret = blk_co_pwrite(s->target, sector_num << BDRV_SECTOR_BITS,
1910265a7e54SVladimir Sementsov-Ogievskiy n << BDRV_SECTOR_BITS, buf, flags);
1911690c7301SKevin Wolf if (ret < 0) {
1912690c7301SKevin Wolf return ret;
1913690c7301SKevin Wolf }
1914690c7301SKevin Wolf break;
1915690c7301SKevin Wolf }
1916690c7301SKevin Wolf /* fall-through */
1917690c7301SKevin Wolf
1918690c7301SKevin Wolf case BLK_ZERO:
1919690c7301SKevin Wolf if (s->has_zero_init) {
1920db933fbeSLidong Chen assert(!s->target_has_backing);
1921690c7301SKevin Wolf break;
1922690c7301SKevin Wolf }
19232d9187bcSPeter Lieven ret = blk_co_pwrite_zeroes(s->target,
19242d9187bcSPeter Lieven sector_num << BDRV_SECTOR_BITS,
1925a3d6ae22SNir Soffer n << BDRV_SECTOR_BITS,
1926a3d6ae22SNir Soffer BDRV_REQ_MAY_UNMAP);
1927690c7301SKevin Wolf if (ret < 0) {
1928690c7301SKevin Wolf return ret;
1929690c7301SKevin Wolf }
1930690c7301SKevin Wolf break;
1931690c7301SKevin Wolf }
1932690c7301SKevin Wolf
1933690c7301SKevin Wolf sector_num += n;
1934690c7301SKevin Wolf nb_sectors -= n;
1935690c7301SKevin Wolf buf += n * BDRV_SECTOR_SIZE;
1936690c7301SKevin Wolf }
1937690c7301SKevin Wolf
1938690c7301SKevin Wolf return 0;
1939690c7301SKevin Wolf }
1940690c7301SKevin Wolf
convert_co_copy_range(ImgConvertState * s,int64_t sector_num,int nb_sectors)1941ee5306d0SFam Zheng static int coroutine_fn convert_co_copy_range(ImgConvertState *s, int64_t sector_num,
1942ee5306d0SFam Zheng int nb_sectors)
1943ee5306d0SFam Zheng {
1944ee5306d0SFam Zheng int n, ret;
1945ee5306d0SFam Zheng
1946ee5306d0SFam Zheng while (nb_sectors > 0) {
1947ee5306d0SFam Zheng BlockBackend *blk;
1948ee5306d0SFam Zheng int src_cur;
1949ee5306d0SFam Zheng int64_t bs_sectors, src_cur_offset;
1950ee5306d0SFam Zheng int64_t offset;
1951ee5306d0SFam Zheng
1952ee5306d0SFam Zheng convert_select_part(s, sector_num, &src_cur, &src_cur_offset);
1953ee5306d0SFam Zheng offset = (sector_num - src_cur_offset) << BDRV_SECTOR_BITS;
1954ee5306d0SFam Zheng blk = s->src[src_cur];
1955ee5306d0SFam Zheng bs_sectors = s->src_sectors[src_cur];
1956ee5306d0SFam Zheng
1957ee5306d0SFam Zheng n = MIN(nb_sectors, bs_sectors - (sector_num - src_cur_offset));
1958ee5306d0SFam Zheng
1959ee5306d0SFam Zheng ret = blk_co_copy_range(blk, offset, s->target,
1960ee5306d0SFam Zheng sector_num << BDRV_SECTOR_BITS,
196167b51fb9SVladimir Sementsov-Ogievskiy n << BDRV_SECTOR_BITS, 0, 0);
1962ee5306d0SFam Zheng if (ret < 0) {
1963ee5306d0SFam Zheng return ret;
1964ee5306d0SFam Zheng }
1965ee5306d0SFam Zheng
1966ee5306d0SFam Zheng sector_num += n;
1967ee5306d0SFam Zheng nb_sectors -= n;
1968ee5306d0SFam Zheng }
1969ee5306d0SFam Zheng return 0;
1970ee5306d0SFam Zheng }
1971ee5306d0SFam Zheng
convert_co_do_copy(void * opaque)19722d9187bcSPeter Lieven static void coroutine_fn convert_co_do_copy(void *opaque)
19732d9187bcSPeter Lieven {
19742d9187bcSPeter Lieven ImgConvertState *s = opaque;
19752d9187bcSPeter Lieven uint8_t *buf = NULL;
19762d9187bcSPeter Lieven int ret, i;
19772d9187bcSPeter Lieven int index = -1;
19782d9187bcSPeter Lieven
19792d9187bcSPeter Lieven for (i = 0; i < s->num_coroutines; i++) {
19802d9187bcSPeter Lieven if (s->co[i] == qemu_coroutine_self()) {
19812d9187bcSPeter Lieven index = i;
19822d9187bcSPeter Lieven break;
19832d9187bcSPeter Lieven }
19842d9187bcSPeter Lieven }
19852d9187bcSPeter Lieven assert(index >= 0);
19862d9187bcSPeter Lieven
19872d9187bcSPeter Lieven s->running_coroutines++;
19882d9187bcSPeter Lieven buf = blk_blockalign(s->target, s->buf_sectors * BDRV_SECTOR_SIZE);
19892d9187bcSPeter Lieven
19902d9187bcSPeter Lieven while (1) {
19912d9187bcSPeter Lieven int n;
19922d9187bcSPeter Lieven int64_t sector_num;
19932d9187bcSPeter Lieven enum ImgConvertBlockStatus status;
1994ee5306d0SFam Zheng bool copy_range;
19952d9187bcSPeter Lieven
19962d9187bcSPeter Lieven qemu_co_mutex_lock(&s->lock);
19972d9187bcSPeter Lieven if (s->ret != -EINPROGRESS || s->sector_num >= s->total_sectors) {
19982d9187bcSPeter Lieven qemu_co_mutex_unlock(&s->lock);
1999b91127edSAnton Nefedov break;
20002d9187bcSPeter Lieven }
20017ff9579eSKevin Wolf WITH_GRAPH_RDLOCK_GUARD() {
20022d9187bcSPeter Lieven n = convert_iteration_sectors(s, s->sector_num);
20037ff9579eSKevin Wolf }
20042d9187bcSPeter Lieven if (n < 0) {
20052d9187bcSPeter Lieven qemu_co_mutex_unlock(&s->lock);
20062d9187bcSPeter Lieven s->ret = n;
2007b91127edSAnton Nefedov break;
20082d9187bcSPeter Lieven }
20092d9187bcSPeter Lieven /* save current sector and allocation status to local variables */
20102d9187bcSPeter Lieven sector_num = s->sector_num;
20112d9187bcSPeter Lieven status = s->status;
20122d9187bcSPeter Lieven if (!s->min_sparse && s->status == BLK_ZERO) {
20132d9187bcSPeter Lieven n = MIN(n, s->buf_sectors);
20142d9187bcSPeter Lieven }
20152d9187bcSPeter Lieven /* increment global sector counter so that other coroutines can
20162d9187bcSPeter Lieven * already continue reading beyond this request */
20172d9187bcSPeter Lieven s->sector_num += n;
20182d9187bcSPeter Lieven qemu_co_mutex_unlock(&s->lock);
20192d9187bcSPeter Lieven
20202d9187bcSPeter Lieven if (status == BLK_DATA || (!s->min_sparse && status == BLK_ZERO)) {
20212d9187bcSPeter Lieven s->allocated_done += n;
20222d9187bcSPeter Lieven qemu_progress_print(100.0 * s->allocated_done /
20232d9187bcSPeter Lieven s->allocated_sectors, 0);
20242d9187bcSPeter Lieven }
20252d9187bcSPeter Lieven
2026ee5306d0SFam Zheng retry:
2027ee5306d0SFam Zheng copy_range = s->copy_range && s->status == BLK_DATA;
2028ee5306d0SFam Zheng if (status == BLK_DATA && !copy_range) {
20292d9187bcSPeter Lieven ret = convert_co_read(s, sector_num, n, buf);
20302d9187bcSPeter Lieven if (ret < 0) {
203139f77cb6SEric Blake error_report("error while reading at byte %lld: %s",
203239f77cb6SEric Blake sector_num * BDRV_SECTOR_SIZE, strerror(-ret));
20332d9187bcSPeter Lieven s->ret = ret;
20342d9187bcSPeter Lieven }
20352d9187bcSPeter Lieven } else if (!s->min_sparse && status == BLK_ZERO) {
20362d9187bcSPeter Lieven status = BLK_DATA;
20372d9187bcSPeter Lieven memset(buf, 0x00, n * BDRV_SECTOR_SIZE);
20382d9187bcSPeter Lieven }
20392d9187bcSPeter Lieven
20402d9187bcSPeter Lieven if (s->wr_in_order) {
20412d9187bcSPeter Lieven /* keep writes in order */
2042b91127edSAnton Nefedov while (s->wr_offs != sector_num && s->ret == -EINPROGRESS) {
20432d9187bcSPeter Lieven s->wait_sector_num[index] = sector_num;
20442d9187bcSPeter Lieven qemu_coroutine_yield();
20452d9187bcSPeter Lieven }
20462d9187bcSPeter Lieven s->wait_sector_num[index] = -1;
20472d9187bcSPeter Lieven }
20482d9187bcSPeter Lieven
2049b91127edSAnton Nefedov if (s->ret == -EINPROGRESS) {
2050ee5306d0SFam Zheng if (copy_range) {
2051742bf09bSEmanuele Giuseppe Esposito WITH_GRAPH_RDLOCK_GUARD() {
2052ee5306d0SFam Zheng ret = convert_co_copy_range(s, sector_num, n);
2053742bf09bSEmanuele Giuseppe Esposito }
2054ee5306d0SFam Zheng if (ret) {
2055ee5306d0SFam Zheng s->copy_range = false;
2056ee5306d0SFam Zheng goto retry;
2057ee5306d0SFam Zheng }
2058ee5306d0SFam Zheng } else {
20592d9187bcSPeter Lieven ret = convert_co_write(s, sector_num, n, buf, status);
2060ee5306d0SFam Zheng }
20612d9187bcSPeter Lieven if (ret < 0) {
206239f77cb6SEric Blake error_report("error while writing at byte %lld: %s",
206339f77cb6SEric Blake sector_num * BDRV_SECTOR_SIZE, strerror(-ret));
20642d9187bcSPeter Lieven s->ret = ret;
2065b91127edSAnton Nefedov }
20662d9187bcSPeter Lieven }
20672d9187bcSPeter Lieven
20682d9187bcSPeter Lieven if (s->wr_in_order) {
20692d9187bcSPeter Lieven /* reenter the coroutine that might have waited
20702d9187bcSPeter Lieven * for this write to complete */
20712d9187bcSPeter Lieven s->wr_offs = sector_num + n;
20722d9187bcSPeter Lieven for (i = 0; i < s->num_coroutines; i++) {
20732d9187bcSPeter Lieven if (s->co[i] && s->wait_sector_num[i] == s->wr_offs) {
20742d9187bcSPeter Lieven /*
20752d9187bcSPeter Lieven * A -> B -> A cannot occur because A has
20762d9187bcSPeter Lieven * s->wait_sector_num[i] == -1 during A -> B. Therefore
20772d9187bcSPeter Lieven * B will never enter A during this time window.
20782d9187bcSPeter Lieven */
20792d9187bcSPeter Lieven qemu_coroutine_enter(s->co[i]);
20802d9187bcSPeter Lieven break;
20812d9187bcSPeter Lieven }
20822d9187bcSPeter Lieven }
20832d9187bcSPeter Lieven }
20842d9187bcSPeter Lieven }
20852d9187bcSPeter Lieven
20862d9187bcSPeter Lieven qemu_vfree(buf);
20872d9187bcSPeter Lieven s->co[index] = NULL;
20882d9187bcSPeter Lieven s->running_coroutines--;
20892d9187bcSPeter Lieven if (!s->running_coroutines && s->ret == -EINPROGRESS) {
20902d9187bcSPeter Lieven /* the convert job finished successfully */
20912d9187bcSPeter Lieven s->ret = 0;
20922d9187bcSPeter Lieven }
20932d9187bcSPeter Lieven }
20942d9187bcSPeter Lieven
convert_do_copy(ImgConvertState * s)2095690c7301SKevin Wolf static int convert_do_copy(ImgConvertState *s)
2096690c7301SKevin Wolf {
20972d9187bcSPeter Lieven int ret, i, n;
20982d9187bcSPeter Lieven int64_t sector_num = 0;
2099690c7301SKevin Wolf
2100690c7301SKevin Wolf /* Check whether we have zero initialisation or can get it efficiently */
2101168468feSDavid Edmondson if (!s->has_zero_init && s->target_is_new && s->min_sparse &&
2102168468feSDavid Edmondson !s->target_has_backing) {
210306717986SKevin Wolf bdrv_graph_rdlock_main_loop();
21044d7c487eSMax Reitz s->has_zero_init = bdrv_has_zero_init(blk_bs(s->target));
210506717986SKevin Wolf bdrv_graph_rdunlock_main_loop();
21064d7c487eSMax Reitz }
2107690c7301SKevin Wolf
2108690c7301SKevin Wolf /* Allocate buffer for copied data. For compressed images, only one cluster
2109690c7301SKevin Wolf * can be copied at a time. */
2110690c7301SKevin Wolf if (s->compressed) {
2111690c7301SKevin Wolf if (s->cluster_sectors <= 0 || s->cluster_sectors > s->buf_sectors) {
2112690c7301SKevin Wolf error_report("invalid cluster size");
21132d9187bcSPeter Lieven return -EINVAL;
2114690c7301SKevin Wolf }
2115690c7301SKevin Wolf s->buf_sectors = s->cluster_sectors;
2116690c7301SKevin Wolf }
2117690c7301SKevin Wolf
2118690c7301SKevin Wolf while (sector_num < s->total_sectors) {
2119ad74751fSKevin Wolf bdrv_graph_rdlock_main_loop();
2120690c7301SKevin Wolf n = convert_iteration_sectors(s, sector_num);
2121ad74751fSKevin Wolf bdrv_graph_rdunlock_main_loop();
2122690c7301SKevin Wolf if (n < 0) {
21232d9187bcSPeter Lieven return n;
2124690c7301SKevin Wolf }
2125aad15de4SMax Reitz if (s->status == BLK_DATA || (!s->min_sparse && s->status == BLK_ZERO))
2126aad15de4SMax Reitz {
2127690c7301SKevin Wolf s->allocated_sectors += n;
2128690c7301SKevin Wolf }
2129690c7301SKevin Wolf sector_num += n;
2130690c7301SKevin Wolf }
2131690c7301SKevin Wolf
2132690c7301SKevin Wolf /* Do the copy */
2133690c7301SKevin Wolf s->sector_next_status = 0;
21342d9187bcSPeter Lieven s->ret = -EINPROGRESS;
2135690c7301SKevin Wolf
21362d9187bcSPeter Lieven qemu_co_mutex_init(&s->lock);
21372d9187bcSPeter Lieven for (i = 0; i < s->num_coroutines; i++) {
21382d9187bcSPeter Lieven s->co[i] = qemu_coroutine_create(convert_co_do_copy, s);
21392d9187bcSPeter Lieven s->wait_sector_num[i] = -1;
21402d9187bcSPeter Lieven qemu_coroutine_enter(s->co[i]);
2141690c7301SKevin Wolf }
2142690c7301SKevin Wolf
2143b91127edSAnton Nefedov while (s->running_coroutines) {
21442d9187bcSPeter Lieven main_loop_wait(false);
2145aad15de4SMax Reitz }
2146690c7301SKevin Wolf
21472d9187bcSPeter Lieven if (s->compressed && !s->ret) {
2148690c7301SKevin Wolf /* signal EOF to align */
21490cadf2c8SAlberto Faria ret = blk_pwrite_compressed(s->target, 0, 0, NULL);
2150690c7301SKevin Wolf if (ret < 0) {
21512d9187bcSPeter Lieven return ret;
2152690c7301SKevin Wolf }
2153690c7301SKevin Wolf }
2154690c7301SKevin Wolf
21552d9187bcSPeter Lieven return s->ret;
2156690c7301SKevin Wolf }
2157690c7301SKevin Wolf
215874a4320fSEric Blake /* Check that bitmaps can be copied, or output an error */
convert_check_bitmaps(BlockDriverState * src,bool skip_broken)2159955171e4SEric Blake static int convert_check_bitmaps(BlockDriverState *src, bool skip_broken)
216074a4320fSEric Blake {
216174a4320fSEric Blake BdrvDirtyBitmap *bm;
216274a4320fSEric Blake
216374a4320fSEric Blake if (!bdrv_supports_persistent_dirty_bitmap(src)) {
216474a4320fSEric Blake error_report("Source lacks bitmap support");
216574a4320fSEric Blake return -1;
216674a4320fSEric Blake }
216774a4320fSEric Blake FOR_EACH_DIRTY_BITMAP(src, bm) {
216874a4320fSEric Blake if (!bdrv_dirty_bitmap_get_persistence(bm)) {
216974a4320fSEric Blake continue;
217074a4320fSEric Blake }
2171955171e4SEric Blake if (!skip_broken && bdrv_dirty_bitmap_inconsistent(bm)) {
217274a4320fSEric Blake error_report("Cannot copy inconsistent bitmap '%s'",
217374a4320fSEric Blake bdrv_dirty_bitmap_name(bm));
2174955171e4SEric Blake error_printf("Try --skip-broken-bitmaps, or "
2175955171e4SEric Blake "use 'qemu-img bitmap --remove' to delete it\n");
217674a4320fSEric Blake return -1;
217774a4320fSEric Blake }
217874a4320fSEric Blake }
217974a4320fSEric Blake return 0;
218074a4320fSEric Blake }
218174a4320fSEric Blake
convert_copy_bitmaps(BlockDriverState * src,BlockDriverState * dst,bool skip_broken)2182955171e4SEric Blake static int convert_copy_bitmaps(BlockDriverState *src, BlockDriverState *dst,
2183955171e4SEric Blake bool skip_broken)
218415e39ad9SEric Blake {
218515e39ad9SEric Blake BdrvDirtyBitmap *bm;
218615e39ad9SEric Blake Error *err = NULL;
218715e39ad9SEric Blake
218815e39ad9SEric Blake FOR_EACH_DIRTY_BITMAP(src, bm) {
218915e39ad9SEric Blake const char *name;
219015e39ad9SEric Blake
219115e39ad9SEric Blake if (!bdrv_dirty_bitmap_get_persistence(bm)) {
219215e39ad9SEric Blake continue;
219315e39ad9SEric Blake }
219415e39ad9SEric Blake name = bdrv_dirty_bitmap_name(bm);
2195955171e4SEric Blake if (skip_broken && bdrv_dirty_bitmap_inconsistent(bm)) {
2196955171e4SEric Blake warn_report("Skipping inconsistent bitmap '%s'", name);
2197955171e4SEric Blake continue;
2198955171e4SEric Blake }
219915e39ad9SEric Blake qmp_block_dirty_bitmap_add(dst->node_name, name,
220015e39ad9SEric Blake true, bdrv_dirty_bitmap_granularity(bm),
220115e39ad9SEric Blake true, true,
220215e39ad9SEric Blake true, !bdrv_dirty_bitmap_enabled(bm),
220315e39ad9SEric Blake &err);
220415e39ad9SEric Blake if (err) {
220515e39ad9SEric Blake error_reportf_err(err, "Failed to create bitmap %s: ", name);
220615e39ad9SEric Blake return -1;
220715e39ad9SEric Blake }
220815e39ad9SEric Blake
220915e39ad9SEric Blake do_dirty_bitmap_merge(dst->node_name, name, src->node_name, name,
221015e39ad9SEric Blake &err);
221115e39ad9SEric Blake if (err) {
221215e39ad9SEric Blake error_reportf_err(err, "Failed to populate bitmap %s: ", name);
221374a4320fSEric Blake qmp_block_dirty_bitmap_remove(dst->node_name, name, NULL);
221415e39ad9SEric Blake return -1;
221515e39ad9SEric Blake }
221615e39ad9SEric Blake }
221715e39ad9SEric Blake
221815e39ad9SEric Blake return 0;
221915e39ad9SEric Blake }
222015e39ad9SEric Blake
22216360ab27SPeter Lieven #define MAX_BUF_SECTORS 32768
22226360ab27SPeter Lieven
set_rate_limit(BlockBackend * blk,int64_t rate_limit)22230c8c4895SZhengui static void set_rate_limit(BlockBackend *blk, int64_t rate_limit)
22240c8c4895SZhengui {
22250c8c4895SZhengui ThrottleConfig cfg;
22260c8c4895SZhengui
22270c8c4895SZhengui throttle_config_init(&cfg);
22280c8c4895SZhengui cfg.buckets[THROTTLE_BPS_WRITE].avg = rate_limit;
22290c8c4895SZhengui
22300c8c4895SZhengui blk_io_limits_enable(blk, CONVERT_THROTTLE_GROUP);
22310c8c4895SZhengui blk_set_io_limits(blk, &cfg);
22320c8c4895SZhengui }
22330c8c4895SZhengui
img_convert(int argc,char ** argv)2234ea2384d3Sbellard static int img_convert(int argc, char **argv)
2235ea2384d3Sbellard {
22360b8fb55cSKevin Wolf int c, bs_i, flags, src_flags = BDRV_O_NO_SHARE;
2237305b4c60SDaniel P. Berrange const char *fmt = NULL, *out_fmt = NULL, *cache = "unsafe",
22389fd77f99SPeter Lieven *src_cache = BDRV_DEFAULT_CACHE, *out_baseimg = NULL,
22391899bf47SEric Blake *out_filename, *out_baseimg_param, *snapshot_name = NULL,
22401899bf47SEric Blake *backing_fmt = NULL;
2241305b4c60SDaniel P. Berrange BlockDriver *drv = NULL, *proto_drv = NULL;
2242faea38e7Sbellard BlockDriverInfo bdi;
22439fd77f99SPeter Lieven BlockDriverState *out_bs;
22449fd77f99SPeter Lieven QemuOpts *opts = NULL, *sn_opts = NULL;
224583d0521aSChunyan Liu QemuOptsList *create_opts = NULL;
22468d65a3ccSDaniel P. Berrangé QDict *open_opts = NULL;
2247efa84d43SKevin Wolf char *options = NULL;
2248cc84d90fSMax Reitz Error *local_err = NULL;
22493d96cb91SMax Reitz bool writethrough, src_writethrough, image_opts = false,
2250305b4c60SDaniel P. Berrange skip_create = false, progress = false, tgt_image_opts = false;
22519fd77f99SPeter Lieven int64_t ret = -EINVAL;
2252335e9937SFam Zheng bool force_share = false;
2253e11ce12fSFam Zheng bool explict_min_sparse = false;
225415e39ad9SEric Blake bool bitmaps = false;
2255955171e4SEric Blake bool skip_broken = false;
22560c8c4895SZhengui int64_t rate_limit = 0;
2257ea2384d3Sbellard
22589fd77f99SPeter Lieven ImgConvertState s = (ImgConvertState) {
22599fd77f99SPeter Lieven /* Need at least 4k of zeros for sparse detection */
22609fd77f99SPeter Lieven .min_sparse = 8,
2261e11ce12fSFam Zheng .copy_range = false,
22629fd77f99SPeter Lieven .buf_sectors = IO_BUF_SIZE / BDRV_SECTOR_SIZE,
22639fd77f99SPeter Lieven .wr_in_order = true,
22649fd77f99SPeter Lieven .num_coroutines = 8,
22659fd77f99SPeter Lieven };
22669fd77f99SPeter Lieven
2267ea2384d3Sbellard for(;;) {
22683babeb15SDaniel P. Berrange static const struct option long_options[] = {
22693babeb15SDaniel P. Berrange {"help", no_argument, 0, 'h'},
22703babeb15SDaniel P. Berrange {"object", required_argument, 0, OPTION_OBJECT},
2271eb769f74SDaniel P. Berrange {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
2272335e9937SFam Zheng {"force-share", no_argument, 0, 'U'},
2273305b4c60SDaniel P. Berrange {"target-image-opts", no_argument, 0, OPTION_TARGET_IMAGE_OPTS},
22748eaac025SMax Reitz {"salvage", no_argument, 0, OPTION_SALVAGE},
2275168468feSDavid Edmondson {"target-is-zero", no_argument, 0, OPTION_TARGET_IS_ZERO},
227615e39ad9SEric Blake {"bitmaps", no_argument, 0, OPTION_BITMAPS},
2277955171e4SEric Blake {"skip-broken-bitmaps", no_argument, 0, OPTION_SKIP_BROKEN},
22783babeb15SDaniel P. Berrange {0, 0, 0, 0}
22793babeb15SDaniel P. Berrange };
22801899bf47SEric Blake c = getopt_long(argc, argv, ":hf:O:B:CcF:o:l:S:pt:T:qnm:WUr:",
22813babeb15SDaniel P. Berrange long_options, NULL);
2282b8fb60daSJes Sorensen if (c == -1) {
2283ea2384d3Sbellard break;
2284b8fb60daSJes Sorensen }
2285ea2384d3Sbellard switch(c) {
2286c9192973SStefan Hajnoczi case ':':
2287c9192973SStefan Hajnoczi missing_argument(argv[optind - 1]);
2288c9192973SStefan Hajnoczi break;
2289ef87394cSJes Sorensen case '?':
2290c9192973SStefan Hajnoczi unrecognized_option(argv[optind - 1]);
2291c9192973SStefan Hajnoczi break;
2292ea2384d3Sbellard case 'h':
2293ea2384d3Sbellard help();
2294ea2384d3Sbellard break;
2295ea2384d3Sbellard case 'f':
2296ea2384d3Sbellard fmt = optarg;
2297ea2384d3Sbellard break;
2298ea2384d3Sbellard case 'O':
2299ea2384d3Sbellard out_fmt = optarg;
2300ea2384d3Sbellard break;
2301f58c7b35Sths case 'B':
2302f58c7b35Sths out_baseimg = optarg;
2303f58c7b35Sths break;
2304e11ce12fSFam Zheng case 'C':
2305e11ce12fSFam Zheng s.copy_range = true;
2306e11ce12fSFam Zheng break;
2307ea2384d3Sbellard case 'c':
23089fd77f99SPeter Lieven s.compressed = true;
2309ea2384d3Sbellard break;
23101899bf47SEric Blake case 'F':
23111899bf47SEric Blake backing_fmt = optarg;
23121899bf47SEric Blake break;
2313efa84d43SKevin Wolf case 'o':
23146d2b5cbaSMarkus Armbruster if (accumulate_options(&options, optarg) < 0) {
231564bb01aaSKevin Wolf goto fail_getopt;
23162dc8328bSKevin Wolf }
2317efa84d43SKevin Wolf break;
2318ef80654dSWenchao Xia case 'l':
2319ef80654dSWenchao Xia if (strstart(optarg, SNAPSHOT_OPT_BASE, NULL)) {
232070b94331SMarkus Armbruster sn_opts = qemu_opts_parse_noisily(&internal_snapshot_opts,
232170b94331SMarkus Armbruster optarg, false);
2322ef80654dSWenchao Xia if (!sn_opts) {
2323ef80654dSWenchao Xia error_report("Failed in parsing snapshot param '%s'",
2324ef80654dSWenchao Xia optarg);
232564bb01aaSKevin Wolf goto fail_getopt;
2326ef80654dSWenchao Xia }
2327ef80654dSWenchao Xia } else {
2328ef80654dSWenchao Xia snapshot_name = optarg;
2329ef80654dSWenchao Xia }
2330ef80654dSWenchao Xia break;
2331a22f123cSKevin Wolf case 'S':
2332a22f123cSKevin Wolf {
2333a22f123cSKevin Wolf int64_t sval;
2334606caa0aSMarkus Armbruster
233543d589b0SEyal Moscovici sval = cvtnum("buffer size for sparse output", optarg);
233643d589b0SEyal Moscovici if (sval < 0) {
233743d589b0SEyal Moscovici goto fail_getopt;
233843d589b0SEyal Moscovici } else if (!QEMU_IS_ALIGNED(sval, BDRV_SECTOR_SIZE) ||
23396360ab27SPeter Lieven sval / BDRV_SECTOR_SIZE > MAX_BUF_SECTORS) {
23406360ab27SPeter Lieven error_report("Invalid buffer size for sparse output specified. "
23416360ab27SPeter Lieven "Valid sizes are multiples of %llu up to %llu. Select "
23426360ab27SPeter Lieven "0 to disable sparse detection (fully allocates output).",
23436360ab27SPeter Lieven BDRV_SECTOR_SIZE, MAX_BUF_SECTORS * BDRV_SECTOR_SIZE);
234464bb01aaSKevin Wolf goto fail_getopt;
2345a22f123cSKevin Wolf }
2346a22f123cSKevin Wolf
23479fd77f99SPeter Lieven s.min_sparse = sval / BDRV_SECTOR_SIZE;
2348e11ce12fSFam Zheng explict_min_sparse = true;
2349a22f123cSKevin Wolf break;
2350a22f123cSKevin Wolf }
23516b837bc4SJes Sorensen case 'p':
23529fd77f99SPeter Lieven progress = true;
23536b837bc4SJes Sorensen break;
2354661a0f71SFederico Simoncelli case 't':
2355661a0f71SFederico Simoncelli cache = optarg;
2356661a0f71SFederico Simoncelli break;
235740055951SMax Reitz case 'T':
235840055951SMax Reitz src_cache = optarg;
235940055951SMax Reitz break;
2360f382d43aSMiroslav Rezanina case 'q':
23613d96cb91SMax Reitz s.quiet = true;
2362f382d43aSMiroslav Rezanina break;
2363b2e10493SAlexandre Derumier case 'n':
23649fd77f99SPeter Lieven skip_create = true;
2365b2e10493SAlexandre Derumier break;
23662d9187bcSPeter Lieven case 'm':
23679fd77f99SPeter Lieven if (qemu_strtol(optarg, NULL, 0, &s.num_coroutines) ||
23689fd77f99SPeter Lieven s.num_coroutines < 1 || s.num_coroutines > MAX_COROUTINES) {
23692d9187bcSPeter Lieven error_report("Invalid number of coroutines. Allowed number of"
23702d9187bcSPeter Lieven " coroutines is between 1 and %d", MAX_COROUTINES);
23712d9187bcSPeter Lieven goto fail_getopt;
23722d9187bcSPeter Lieven }
23732d9187bcSPeter Lieven break;
23742d9187bcSPeter Lieven case 'W':
23759fd77f99SPeter Lieven s.wr_in_order = false;
23762d9187bcSPeter Lieven break;
2377335e9937SFam Zheng case 'U':
2378335e9937SFam Zheng force_share = true;
2379335e9937SFam Zheng break;
23800c8c4895SZhengui case 'r':
23810c8c4895SZhengui rate_limit = cvtnum("rate limit", optarg);
23820c8c4895SZhengui if (rate_limit < 0) {
23830c8c4895SZhengui goto fail_getopt;
23840c8c4895SZhengui }
23850c8c4895SZhengui break;
238699b1e646SKevin Wolf case OPTION_OBJECT:
238799b1e646SKevin Wolf user_creatable_process_cmdline(optarg);
23883babeb15SDaniel P. Berrange break;
2389eb769f74SDaniel P. Berrange case OPTION_IMAGE_OPTS:
2390eb769f74SDaniel P. Berrange image_opts = true;
2391eb769f74SDaniel P. Berrange break;
23928eaac025SMax Reitz case OPTION_SALVAGE:
23938eaac025SMax Reitz s.salvage = true;
23948eaac025SMax Reitz break;
2395305b4c60SDaniel P. Berrange case OPTION_TARGET_IMAGE_OPTS:
2396305b4c60SDaniel P. Berrange tgt_image_opts = true;
2397305b4c60SDaniel P. Berrange break;
2398168468feSDavid Edmondson case OPTION_TARGET_IS_ZERO:
2399168468feSDavid Edmondson /*
2400168468feSDavid Edmondson * The user asserting that the target is blank has the
2401168468feSDavid Edmondson * same effect as the target driver supporting zero
2402168468feSDavid Edmondson * initialisation.
2403168468feSDavid Edmondson */
2404168468feSDavid Edmondson s.has_zero_init = true;
2405168468feSDavid Edmondson break;
240615e39ad9SEric Blake case OPTION_BITMAPS:
240715e39ad9SEric Blake bitmaps = true;
240815e39ad9SEric Blake break;
2409955171e4SEric Blake case OPTION_SKIP_BROKEN:
2410955171e4SEric Blake skip_broken = true;
2411955171e4SEric Blake break;
24123babeb15SDaniel P. Berrange }
24133babeb15SDaniel P. Berrange }
24143babeb15SDaniel P. Berrange
2415305b4c60SDaniel P. Berrange if (!out_fmt && !tgt_image_opts) {
2416305b4c60SDaniel P. Berrange out_fmt = "raw";
2417305b4c60SDaniel P. Berrange }
2418305b4c60SDaniel P. Berrange
2419955171e4SEric Blake if (skip_broken && !bitmaps) {
2420955171e4SEric Blake error_report("Use of --skip-broken-bitmaps requires --bitmaps");
2421955171e4SEric Blake goto fail_getopt;
2422955171e4SEric Blake }
2423955171e4SEric Blake
2424e11ce12fSFam Zheng if (s.compressed && s.copy_range) {
2425e11ce12fSFam Zheng error_report("Cannot enable copy offloading when -c is used");
2426e11ce12fSFam Zheng goto fail_getopt;
2427e11ce12fSFam Zheng }
2428e11ce12fSFam Zheng
2429e11ce12fSFam Zheng if (explict_min_sparse && s.copy_range) {
2430e11ce12fSFam Zheng error_report("Cannot enable copy offloading when -S is used");
2431e11ce12fSFam Zheng goto fail_getopt;
2432e11ce12fSFam Zheng }
2433e11ce12fSFam Zheng
24348eaac025SMax Reitz if (s.copy_range && s.salvage) {
24358eaac025SMax Reitz error_report("Cannot use copy offloading in salvaging mode");
24368eaac025SMax Reitz goto fail_getopt;
24378eaac025SMax Reitz }
24388eaac025SMax Reitz
2439305b4c60SDaniel P. Berrange if (tgt_image_opts && !skip_create) {
2440305b4c60SDaniel P. Berrange error_report("--target-image-opts requires use of -n flag");
2441305b4c60SDaniel P. Berrange goto fail_getopt;
2442305b4c60SDaniel P. Berrange }
2443305b4c60SDaniel P. Berrange
2444ffd8e8ffSKevin Wolf if (skip_create && options) {
244525956af3SEric Blake error_report("-o has no effect when skipping image creation");
244625956af3SEric Blake goto fail_getopt;
2447ffd8e8ffSKevin Wolf }
2448ffd8e8ffSKevin Wolf
2449168468feSDavid Edmondson if (s.has_zero_init && !skip_create) {
2450168468feSDavid Edmondson error_report("--target-is-zero requires use of -n flag");
2451168468feSDavid Edmondson goto fail_getopt;
2452168468feSDavid Edmondson }
2453168468feSDavid Edmondson
24549fd77f99SPeter Lieven s.src_num = argc - optind - 1;
24559fd77f99SPeter Lieven out_filename = s.src_num >= 1 ? argv[argc - 1] : NULL;
24569fd77f99SPeter Lieven
24579fd77f99SPeter Lieven if (options && has_help_option(options)) {
2458305b4c60SDaniel P. Berrange if (out_fmt) {
24599fd77f99SPeter Lieven ret = print_block_option_help(out_filename, out_fmt);
24609fd77f99SPeter Lieven goto fail_getopt;
2461305b4c60SDaniel P. Berrange } else {
2462305b4c60SDaniel P. Berrange error_report("Option help requires a format be specified");
2463305b4c60SDaniel P. Berrange goto fail_getopt;
2464305b4c60SDaniel P. Berrange }
24659fd77f99SPeter Lieven }
24669fd77f99SPeter Lieven
24679fd77f99SPeter Lieven if (s.src_num < 1) {
24689fd77f99SPeter Lieven error_report("Must specify image file name");
24699fd77f99SPeter Lieven goto fail_getopt;
24709fd77f99SPeter Lieven }
24719fd77f99SPeter Lieven
24729fd77f99SPeter Lieven /* ret is still -EINVAL until here */
24739fd77f99SPeter Lieven ret = bdrv_parse_cache_mode(src_cache, &src_flags, &src_writethrough);
24749fd77f99SPeter Lieven if (ret < 0) {
24759fd77f99SPeter Lieven error_report("Invalid source cache option: %s", src_cache);
24762d9187bcSPeter Lieven goto fail_getopt;
24772d9187bcSPeter Lieven }
24782d9187bcSPeter Lieven
247964bb01aaSKevin Wolf /* Initialize before goto out */
24803d96cb91SMax Reitz if (s.quiet) {
24819fd77f99SPeter Lieven progress = false;
2482f382d43aSMiroslav Rezanina }
248364bb01aaSKevin Wolf qemu_progress_init(progress, 1.0);
24846b837bc4SJes Sorensen qemu_progress_print(0, 100);
24856b837bc4SJes Sorensen
24869fd77f99SPeter Lieven s.src = g_new0(BlockBackend *, s.src_num);
24879fd77f99SPeter Lieven s.src_sectors = g_new(int64_t, s.src_num);
2488af8d43d3SPeter Lieven s.src_alignment = g_new(int, s.src_num);
2489926c2d23Sbalrog
24909fd77f99SPeter Lieven for (bs_i = 0; bs_i < s.src_num; bs_i++) {
2491af8d43d3SPeter Lieven BlockDriverState *src_bs;
24929fd77f99SPeter Lieven s.src[bs_i] = img_open(image_opts, argv[optind + bs_i],
24933d96cb91SMax Reitz fmt, src_flags, src_writethrough, s.quiet,
2494335e9937SFam Zheng force_share);
24959fd77f99SPeter Lieven if (!s.src[bs_i]) {
2496c2abccecSMORITA Kazutaka ret = -1;
2497c2abccecSMORITA Kazutaka goto out;
2498c2abccecSMORITA Kazutaka }
24999fd77f99SPeter Lieven s.src_sectors[bs_i] = blk_nb_sectors(s.src[bs_i]);
25009fd77f99SPeter Lieven if (s.src_sectors[bs_i] < 0) {
250152bf1e72SMarkus Armbruster error_report("Could not get size of %s: %s",
25029fd77f99SPeter Lieven argv[optind + bs_i], strerror(-s.src_sectors[bs_i]));
250352bf1e72SMarkus Armbruster ret = -1;
250452bf1e72SMarkus Armbruster goto out;
250552bf1e72SMarkus Armbruster }
2506af8d43d3SPeter Lieven src_bs = blk_bs(s.src[bs_i]);
2507af8d43d3SPeter Lieven s.src_alignment[bs_i] = DIV_ROUND_UP(src_bs->bl.request_alignment,
2508af8d43d3SPeter Lieven BDRV_SECTOR_SIZE);
2509af8d43d3SPeter Lieven if (!bdrv_get_info(src_bs, &bdi)) {
2510af8d43d3SPeter Lieven s.src_alignment[bs_i] = MAX(s.src_alignment[bs_i],
2511af8d43d3SPeter Lieven bdi.cluster_size / BDRV_SECTOR_SIZE);
2512af8d43d3SPeter Lieven }
25139fd77f99SPeter Lieven s.total_sectors += s.src_sectors[bs_i];
2514926c2d23Sbalrog }
2515ea2384d3Sbellard
2516ef80654dSWenchao Xia if (sn_opts) {
25179fd77f99SPeter Lieven bdrv_snapshot_load_tmp(blk_bs(s.src[0]),
2518ef80654dSWenchao Xia qemu_opt_get(sn_opts, SNAPSHOT_OPT_ID),
2519ef80654dSWenchao Xia qemu_opt_get(sn_opts, SNAPSHOT_OPT_NAME),
2520ef80654dSWenchao Xia &local_err);
2521ef80654dSWenchao Xia } else if (snapshot_name != NULL) {
25229fd77f99SPeter Lieven if (s.src_num > 1) {
25236daf194dSMarkus Armbruster error_report("No support for concatenating multiple snapshot");
252451ef6727Sedison ret = -1;
252551ef6727Sedison goto out;
252651ef6727Sedison }
25277b4c4781SWenchao Xia
25289fd77f99SPeter Lieven bdrv_snapshot_load_tmp_by_id_or_name(blk_bs(s.src[0]), snapshot_name,
25299fd77f99SPeter Lieven &local_err);
2530ef80654dSWenchao Xia }
253184d18f06SMarkus Armbruster if (local_err) {
2532c29b77f9SMarkus Armbruster error_reportf_err(local_err, "Failed to load snapshot: ");
253351ef6727Sedison ret = -1;
253451ef6727Sedison goto out;
253551ef6727Sedison }
253651ef6727Sedison
2537305b4c60SDaniel P. Berrange if (!skip_create) {
2538efa84d43SKevin Wolf /* Find driver and parse its options */
2539ea2384d3Sbellard drv = bdrv_find_format(out_fmt);
2540c2abccecSMORITA Kazutaka if (!drv) {
254115654a6dSJes Sorensen error_report("Unknown file format '%s'", out_fmt);
2542c2abccecSMORITA Kazutaka ret = -1;
2543c2abccecSMORITA Kazutaka goto out;
2544c2abccecSMORITA Kazutaka }
2545926c2d23Sbalrog
2546b65a5e12SMax Reitz proto_drv = bdrv_find_protocol(out_filename, true, &local_err);
2547c2abccecSMORITA Kazutaka if (!proto_drv) {
25482867ce4aSMarkus Armbruster error_report_err(local_err);
2549c2abccecSMORITA Kazutaka ret = -1;
2550c2abccecSMORITA Kazutaka goto out;
2551c2abccecSMORITA Kazutaka }
2552b50cbabcSMORITA Kazutaka
2553f75613cfSMax Reitz if (!drv->create_opts) {
2554f75613cfSMax Reitz error_report("Format driver '%s' does not support image creation",
2555f75613cfSMax Reitz drv->format_name);
2556f75613cfSMax Reitz ret = -1;
2557f75613cfSMax Reitz goto out;
2558f75613cfSMax Reitz }
2559f75613cfSMax Reitz
2560f75613cfSMax Reitz if (!proto_drv->create_opts) {
2561f75613cfSMax Reitz error_report("Protocol driver '%s' does not support image creation",
2562f75613cfSMax Reitz proto_drv->format_name);
2563f75613cfSMax Reitz ret = -1;
2564f75613cfSMax Reitz goto out;
2565f75613cfSMax Reitz }
2566f75613cfSMax Reitz
2567c282e1fdSChunyan Liu create_opts = qemu_opts_append(create_opts, drv->create_opts);
2568c282e1fdSChunyan Liu create_opts = qemu_opts_append(create_opts, proto_drv->create_opts);
2569db08adf5SKevin Wolf
257083d0521aSChunyan Liu opts = qemu_opts_create(create_opts, NULL, 0, &error_abort);
2571dc523cd3SMarkus Armbruster if (options) {
2572235e59cfSMarkus Armbruster if (!qemu_opts_do_parse(opts, options, NULL, &local_err)) {
257397a2ca7aSMarkus Armbruster error_report_err(local_err);
2574c2abccecSMORITA Kazutaka ret = -1;
2575c2abccecSMORITA Kazutaka goto out;
2576efa84d43SKevin Wolf }
2577dc523cd3SMarkus Armbruster }
2578efa84d43SKevin Wolf
2579c075c42fSYi Li qemu_opt_set_number(opts, BLOCK_OPT_SIZE,
2580c075c42fSYi Li s.total_sectors * BDRV_SECTOR_SIZE, &error_abort);
25811899bf47SEric Blake ret = add_old_style_options(out_fmt, opts, out_baseimg, backing_fmt);
2582c2abccecSMORITA Kazutaka if (ret < 0) {
2583c2abccecSMORITA Kazutaka goto out;
2584c2abccecSMORITA Kazutaka }
25852e024cdeSMax Reitz }
2586efa84d43SKevin Wolf
2587a18953fbSKevin Wolf /* Get backing file name if -o backing_file was used */
258883d0521aSChunyan Liu out_baseimg_param = qemu_opt_get(opts, BLOCK_OPT_BACKING_FILE);
2589a18953fbSKevin Wolf if (out_baseimg_param) {
259083d0521aSChunyan Liu out_baseimg = out_baseimg_param;
2591a18953fbSKevin Wolf }
25929fd77f99SPeter Lieven s.target_has_backing = (bool) out_baseimg;
2593a18953fbSKevin Wolf
2594168468feSDavid Edmondson if (s.has_zero_init && s.target_has_backing) {
2595168468feSDavid Edmondson error_report("Cannot use --target-is-zero when the destination "
2596168468feSDavid Edmondson "image has a backing file");
2597168468feSDavid Edmondson goto out;
2598168468feSDavid Edmondson }
2599168468feSDavid Edmondson
260048758a84SMax Reitz if (s.src_num > 1 && out_baseimg) {
260148758a84SMax Reitz error_report("Having a backing file for the target makes no sense when "
260248758a84SMax Reitz "concatenating multiple input images");
260348758a84SMax Reitz ret = -1;
260448758a84SMax Reitz goto out;
260548758a84SMax Reitz }
260648758a84SMax Reitz
2607d9f059aaSEric Blake if (out_baseimg_param) {
2608d9f059aaSEric Blake if (!qemu_opt_get(opts, BLOCK_OPT_BACKING_FMT)) {
2609497a30dbSEric Blake error_report("Use of backing file requires explicit "
2610d9f059aaSEric Blake "backing format");
2611497a30dbSEric Blake ret = -1;
2612497a30dbSEric Blake goto out;
2613d9f059aaSEric Blake }
2614d9f059aaSEric Blake }
2615d9f059aaSEric Blake
2616efa84d43SKevin Wolf /* Check if compression is supported */
26179fd77f99SPeter Lieven if (s.compressed) {
261883d0521aSChunyan Liu bool encryption =
261983d0521aSChunyan Liu qemu_opt_get_bool(opts, BLOCK_OPT_ENCRYPT, false);
26200cb8d47bSDaniel P. Berrange const char *encryptfmt =
26210cb8d47bSDaniel P. Berrange qemu_opt_get(opts, BLOCK_OPT_ENCRYPT_FORMAT);
262283d0521aSChunyan Liu const char *preallocation =
262383d0521aSChunyan Liu qemu_opt_get(opts, BLOCK_OPT_PREALLOC);
2624efa84d43SKevin Wolf
2625ac850bf0SVladimir Sementsov-Ogievskiy if (drv && !block_driver_can_compress(drv)) {
262615654a6dSJes Sorensen error_report("Compression not supported for this file format");
2627c2abccecSMORITA Kazutaka ret = -1;
2628c2abccecSMORITA Kazutaka goto out;
2629efa84d43SKevin Wolf }
2630efa84d43SKevin Wolf
26310cb8d47bSDaniel P. Berrange if (encryption || encryptfmt) {
263215654a6dSJes Sorensen error_report("Compression and encryption not supported at "
263315654a6dSJes Sorensen "the same time");
2634c2abccecSMORITA Kazutaka ret = -1;
2635c2abccecSMORITA Kazutaka goto out;
2636efa84d43SKevin Wolf }
263741521fa4SKevin Wolf
263883d0521aSChunyan Liu if (preallocation
263983d0521aSChunyan Liu && strcmp(preallocation, "off"))
264041521fa4SKevin Wolf {
264141521fa4SKevin Wolf error_report("Compression and preallocation not supported at "
264241521fa4SKevin Wolf "the same time");
264341521fa4SKevin Wolf ret = -1;
264441521fa4SKevin Wolf goto out;
264541521fa4SKevin Wolf }
2646efa84d43SKevin Wolf }
2647efa84d43SKevin Wolf
264815e39ad9SEric Blake /* Determine if bitmaps need copying */
264915e39ad9SEric Blake if (bitmaps) {
265015e39ad9SEric Blake if (s.src_num > 1) {
265115e39ad9SEric Blake error_report("Copying bitmaps only possible with single source");
265215e39ad9SEric Blake ret = -1;
265315e39ad9SEric Blake goto out;
265415e39ad9SEric Blake }
2655955171e4SEric Blake ret = convert_check_bitmaps(blk_bs(s.src[0]), skip_broken);
265674a4320fSEric Blake if (ret < 0) {
265715e39ad9SEric Blake goto out;
265815e39ad9SEric Blake }
265915e39ad9SEric Blake }
266015e39ad9SEric Blake
26618d65a3ccSDaniel P. Berrangé /*
26628d65a3ccSDaniel P. Berrangé * The later open call will need any decryption secrets, and
26638d65a3ccSDaniel P. Berrangé * bdrv_create() will purge "opts", so extract them now before
26648d65a3ccSDaniel P. Berrangé * they are lost.
26658d65a3ccSDaniel P. Berrangé */
26668d65a3ccSDaniel P. Berrangé if (!skip_create) {
26678d65a3ccSDaniel P. Berrangé open_opts = qdict_new();
26688d65a3ccSDaniel P. Berrangé qemu_opt_foreach(opts, img_add_key_secrets, open_opts, &error_abort);
26698d65a3ccSDaniel P. Berrangé
2670efa84d43SKevin Wolf /* Create the new image */
2671c282e1fdSChunyan Liu ret = bdrv_create(drv, out_filename, opts, &local_err);
2672ea2384d3Sbellard if (ret < 0) {
2673c29b77f9SMarkus Armbruster error_reportf_err(local_err, "%s: error while converting %s: ",
2674c29b77f9SMarkus Armbruster out_filename, out_fmt);
2675c2abccecSMORITA Kazutaka goto out;
2676ea2384d3Sbellard }
2677b2e10493SAlexandre Derumier }
2678ea2384d3Sbellard
26794d7c487eSMax Reitz s.target_is_new = !skip_create;
26804d7c487eSMax Reitz
26819fd77f99SPeter Lieven flags = s.min_sparse ? (BDRV_O_RDWR | BDRV_O_UNMAP) : BDRV_O_RDWR;
2682ce099547SKevin Wolf ret = bdrv_parse_cache_mode(cache, &flags, &writethrough);
2683661a0f71SFederico Simoncelli if (ret < 0) {
2684661a0f71SFederico Simoncelli error_report("Invalid cache option: %s", cache);
2685bb9cd2eeSMarkus Armbruster goto out;
2686661a0f71SFederico Simoncelli }
2687661a0f71SFederico Simoncelli
2688a1c62436SHanna Reitz if (flags & BDRV_O_NOCACHE) {
2689a1c62436SHanna Reitz /*
2690a1c62436SHanna Reitz * If we open the target with O_DIRECT, it may be necessary to
2691a1c62436SHanna Reitz * extend its size to align to the physical sector size.
2692a1c62436SHanna Reitz */
2693a1c62436SHanna Reitz flags |= BDRV_O_RESIZE;
2694a1c62436SHanna Reitz }
2695a1c62436SHanna Reitz
2696305b4c60SDaniel P. Berrange if (skip_create) {
2697305b4c60SDaniel P. Berrange s.target = img_open(tgt_image_opts, out_filename, out_fmt,
26983d96cb91SMax Reitz flags, writethrough, s.quiet, false);
2699305b4c60SDaniel P. Berrange } else {
2700305b4c60SDaniel P. Berrange /* TODO ultimately we should allow --target-image-opts
2701305b4c60SDaniel P. Berrange * to be used even when -n is not given.
2702305b4c60SDaniel P. Berrange * That has to wait for bdrv_create to be improved
2703305b4c60SDaniel P. Berrange * to allow filenames in option syntax
2704eb769f74SDaniel P. Berrange */
27058d65a3ccSDaniel P. Berrangé s.target = img_open_file(out_filename, open_opts, out_fmt,
27063d96cb91SMax Reitz flags, writethrough, s.quiet, false);
27078d65a3ccSDaniel P. Berrangé open_opts = NULL; /* blk_new_open will have freed it */
2708305b4c60SDaniel P. Berrange }
27099fd77f99SPeter Lieven if (!s.target) {
2710c2abccecSMORITA Kazutaka ret = -1;
2711c2abccecSMORITA Kazutaka goto out;
2712c2abccecSMORITA Kazutaka }
27139fd77f99SPeter Lieven out_bs = blk_bs(s.target);
2714ea2384d3Sbellard
271515e39ad9SEric Blake if (bitmaps && !bdrv_supports_persistent_dirty_bitmap(out_bs)) {
271615e39ad9SEric Blake error_report("Format driver '%s' does not support bitmaps",
271715e39ad9SEric Blake out_bs->drv->format_name);
271815e39ad9SEric Blake ret = -1;
271915e39ad9SEric Blake goto out;
272015e39ad9SEric Blake }
272115e39ad9SEric Blake
2722ac850bf0SVladimir Sementsov-Ogievskiy if (s.compressed && !block_driver_can_compress(out_bs->drv)) {
2723305b4c60SDaniel P. Berrange error_report("Compression not supported for this file format");
2724305b4c60SDaniel P. Berrange ret = -1;
2725305b4c60SDaniel P. Berrange goto out;
2726305b4c60SDaniel P. Berrange }
2727305b4c60SDaniel P. Berrange
27285def6b80SEric Blake /* increase bufsectors from the default 4096 (2M) if opt_transfer
27296360ab27SPeter Lieven * or discard_alignment of the out_bs is greater. Limit to
27306360ab27SPeter Lieven * MAX_BUF_SECTORS as maximum which is currently 32768 (16MB). */
27316360ab27SPeter Lieven s.buf_sectors = MIN(MAX_BUF_SECTORS,
27329fd77f99SPeter Lieven MAX(s.buf_sectors,
27335def6b80SEric Blake MAX(out_bs->bl.opt_transfer >> BDRV_SECTOR_BITS,
2734b9f7855aSEric Blake out_bs->bl.pdiscard_alignment >>
2735b9f7855aSEric Blake BDRV_SECTOR_BITS)));
2736f2521c90SPeter Lieven
27378dcd3c9bSPeter Lieven /* try to align the write requests to the destination to avoid unnecessary
27388dcd3c9bSPeter Lieven * RMW cycles. */
27398dcd3c9bSPeter Lieven s.alignment = MAX(pow2floor(s.min_sparse),
27408dcd3c9bSPeter Lieven DIV_ROUND_UP(out_bs->bl.request_alignment,
27418dcd3c9bSPeter Lieven BDRV_SECTOR_SIZE));
27428dcd3c9bSPeter Lieven assert(is_power_of_2(s.alignment));
27438dcd3c9bSPeter Lieven
2744b2e10493SAlexandre Derumier if (skip_create) {
27459fd77f99SPeter Lieven int64_t output_sectors = blk_nb_sectors(s.target);
274643716fa8SMarkus Armbruster if (output_sectors < 0) {
2747eec5eb42SGonglei error_report("unable to get output image length: %s",
274843716fa8SMarkus Armbruster strerror(-output_sectors));
2749b2e10493SAlexandre Derumier ret = -1;
2750b2e10493SAlexandre Derumier goto out;
27519fd77f99SPeter Lieven } else if (output_sectors < s.total_sectors) {
2752b2e10493SAlexandre Derumier error_report("output file is smaller than input file");
2753b2e10493SAlexandre Derumier ret = -1;
2754b2e10493SAlexandre Derumier goto out;
2755b2e10493SAlexandre Derumier }
2756b2e10493SAlexandre Derumier }
2757b2e10493SAlexandre Derumier
2758c69291e7SMax Reitz if (s.target_has_backing && s.target_is_new) {
2759351c8effSMax Reitz /* Errors are treated as "backing length unknown" (which means
2760351c8effSMax Reitz * s.target_backing_sectors has to be negative, which it will
2761351c8effSMax Reitz * be automatically). The backing file length is used only
2762351c8effSMax Reitz * for optimizations, so such a case is not fatal. */
2763ad74751fSKevin Wolf bdrv_graph_rdlock_main_loop();
27644a2061e6SMax Reitz s.target_backing_sectors =
27654a2061e6SMax Reitz bdrv_nb_sectors(bdrv_backing_chain_next(out_bs));
2766ad74751fSKevin Wolf bdrv_graph_rdunlock_main_loop();
2767351c8effSMax Reitz } else {
2768351c8effSMax Reitz s.target_backing_sectors = -1;
2769351c8effSMax Reitz }
2770351c8effSMax Reitz
2771c2abccecSMORITA Kazutaka ret = bdrv_get_info(out_bs, &bdi);
2772c2abccecSMORITA Kazutaka if (ret < 0) {
27739fd77f99SPeter Lieven if (s.compressed) {
277415654a6dSJes Sorensen error_report("could not get block driver info");
2775c2abccecSMORITA Kazutaka goto out;
2776c2abccecSMORITA Kazutaka }
277724f833cdSPeter Lieven } else {
27789fd77f99SPeter Lieven s.compressed = s.compressed || bdi.needs_compressed_writes;
27799fd77f99SPeter Lieven s.cluster_sectors = bdi.cluster_size / BDRV_SECTOR_SIZE;
278024f833cdSPeter Lieven }
278124f833cdSPeter Lieven
27820c8c4895SZhengui if (rate_limit) {
27830c8c4895SZhengui set_rate_limit(s.target, rate_limit);
27840c8c4895SZhengui }
27850c8c4895SZhengui
27869fd77f99SPeter Lieven ret = convert_do_copy(&s);
278715e39ad9SEric Blake
278815e39ad9SEric Blake /* Now copy the bitmaps */
278915e39ad9SEric Blake if (bitmaps && ret == 0) {
2790955171e4SEric Blake ret = convert_copy_bitmaps(blk_bs(s.src[0]), out_bs, skip_broken);
279115e39ad9SEric Blake }
279215e39ad9SEric Blake
2793c2abccecSMORITA Kazutaka out:
279413c28af8SPeter Lieven if (!ret) {
279513c28af8SPeter Lieven qemu_progress_print(100, 0);
279613c28af8SPeter Lieven }
27976b837bc4SJes Sorensen qemu_progress_end();
279883d0521aSChunyan Liu qemu_opts_del(opts);
279983d0521aSChunyan Liu qemu_opts_free(create_opts);
28008d65a3ccSDaniel P. Berrangé qobject_unref(open_opts);
28019fd77f99SPeter Lieven blk_unref(s.target);
28029fd77f99SPeter Lieven if (s.src) {
28039fd77f99SPeter Lieven for (bs_i = 0; bs_i < s.src_num; bs_i++) {
28049fd77f99SPeter Lieven blk_unref(s.src[bs_i]);
280526f54e9aSMarkus Armbruster }
28069fd77f99SPeter Lieven g_free(s.src);
280726f54e9aSMarkus Armbruster }
28089fd77f99SPeter Lieven g_free(s.src_sectors);
2809af8d43d3SPeter Lieven g_free(s.src_alignment);
281064bb01aaSKevin Wolf fail_getopt:
28116aec830eSTuguoyi qemu_opts_del(sn_opts);
281264bb01aaSKevin Wolf g_free(options);
281364bb01aaSKevin Wolf
28149fd77f99SPeter Lieven return !!ret;
2815ea2384d3Sbellard }
2816ea2384d3Sbellard
281757d1a2b6Sbellard
dump_snapshots(BlockDriverState * bs)2818faea38e7Sbellard static void dump_snapshots(BlockDriverState *bs)
2819faea38e7Sbellard {
2820faea38e7Sbellard QEMUSnapshotInfo *sn_tab, *sn;
2821faea38e7Sbellard int nb_sns, i;
2822faea38e7Sbellard
2823faea38e7Sbellard nb_sns = bdrv_snapshot_list(bs, &sn_tab);
2824faea38e7Sbellard if (nb_sns <= 0)
2825faea38e7Sbellard return;
2826faea38e7Sbellard printf("Snapshot list:\n");
2827e1ce7d74SMarkus Armbruster bdrv_snapshot_dump(NULL);
28285b917044SWenchao Xia printf("\n");
2829faea38e7Sbellard for(i = 0; i < nb_sns; i++) {
2830faea38e7Sbellard sn = &sn_tab[i];
2831e1ce7d74SMarkus Armbruster bdrv_snapshot_dump(sn);
28325b917044SWenchao Xia printf("\n");
2833faea38e7Sbellard }
28347267c094SAnthony Liguori g_free(sn_tab);
2835faea38e7Sbellard }
2836faea38e7Sbellard
dump_json_block_graph_info_list(BlockGraphInfoList * list)2837c04d0ab0SHanna Reitz static void dump_json_block_graph_info_list(BlockGraphInfoList *list)
28389699bf0dSStefan Hajnoczi {
2839eab3a467SMarkus Armbruster GString *str;
28409699bf0dSStefan Hajnoczi QObject *obj;
28417d5e199aSDaniel P. Berrange Visitor *v = qobject_output_visitor_new(&obj);
28423b098d56SEric Blake
2843c04d0ab0SHanna Reitz visit_type_BlockGraphInfoList(v, NULL, &list, &error_abort);
28443b098d56SEric Blake visit_complete(v, &obj);
28456589f459SMarkus Armbruster str = qobject_to_json_pretty(obj, true);
28469699bf0dSStefan Hajnoczi assert(str != NULL);
2847eab3a467SMarkus Armbruster printf("%s\n", str->str);
2848cb3e7f08SMarc-André Lureau qobject_unref(obj);
28493b098d56SEric Blake visit_free(v);
2850eab3a467SMarkus Armbruster g_string_free(str, true);
28519699bf0dSStefan Hajnoczi }
28529699bf0dSStefan Hajnoczi
dump_json_block_graph_info(BlockGraphInfo * info)2853c04d0ab0SHanna Reitz static void dump_json_block_graph_info(BlockGraphInfo *info)
2854c054b3fdSBenoît Canet {
2855eab3a467SMarkus Armbruster GString *str;
2856c054b3fdSBenoît Canet QObject *obj;
28577d5e199aSDaniel P. Berrange Visitor *v = qobject_output_visitor_new(&obj);
28583b098d56SEric Blake
2859c04d0ab0SHanna Reitz visit_type_BlockGraphInfo(v, NULL, &info, &error_abort);
28603b098d56SEric Blake visit_complete(v, &obj);
28616589f459SMarkus Armbruster str = qobject_to_json_pretty(obj, true);
2862c054b3fdSBenoît Canet assert(str != NULL);
2863eab3a467SMarkus Armbruster printf("%s\n", str->str);
2864cb3e7f08SMarc-André Lureau qobject_unref(obj);
28653b098d56SEric Blake visit_free(v);
2866eab3a467SMarkus Armbruster g_string_free(str, true);
2867c054b3fdSBenoît Canet }
2868c054b3fdSBenoît Canet
dump_human_image_info(BlockGraphInfo * info,int indentation,const char * path)2869c04d0ab0SHanna Reitz static void dump_human_image_info(BlockGraphInfo *info, int indentation,
2870c04d0ab0SHanna Reitz const char *path)
28719699bf0dSStefan Hajnoczi {
2872c04d0ab0SHanna Reitz BlockChildInfoList *children_list;
2873c04d0ab0SHanna Reitz
2874d570177bSHanna Reitz bdrv_node_info_dump(qapi_BlockGraphInfo_base(info), indentation,
2875d570177bSHanna Reitz info->children == NULL);
2876c04d0ab0SHanna Reitz
2877c04d0ab0SHanna Reitz for (children_list = info->children; children_list;
2878c04d0ab0SHanna Reitz children_list = children_list->next)
2879c04d0ab0SHanna Reitz {
2880c04d0ab0SHanna Reitz BlockChildInfo *child = children_list->value;
2881c04d0ab0SHanna Reitz g_autofree char *child_path = NULL;
2882c04d0ab0SHanna Reitz
2883c04d0ab0SHanna Reitz printf("%*sChild node '%s%s':\n",
2884c04d0ab0SHanna Reitz indentation * 4, "", path, child->name);
2885c04d0ab0SHanna Reitz child_path = g_strdup_printf("%s%s/", path, child->name);
2886c04d0ab0SHanna Reitz dump_human_image_info(child->info, indentation + 1, child_path);
2887c04d0ab0SHanna Reitz }
2888c04d0ab0SHanna Reitz }
2889c04d0ab0SHanna Reitz
dump_human_image_info_list(BlockGraphInfoList * list)2890c04d0ab0SHanna Reitz static void dump_human_image_info_list(BlockGraphInfoList *list)
2891c04d0ab0SHanna Reitz {
2892c04d0ab0SHanna Reitz BlockGraphInfoList *elem;
28939699bf0dSStefan Hajnoczi bool delim = false;
28949699bf0dSStefan Hajnoczi
28959699bf0dSStefan Hajnoczi for (elem = list; elem; elem = elem->next) {
28969699bf0dSStefan Hajnoczi if (delim) {
28979699bf0dSStefan Hajnoczi printf("\n");
28989699bf0dSStefan Hajnoczi }
28999699bf0dSStefan Hajnoczi delim = true;
29009699bf0dSStefan Hajnoczi
2901c04d0ab0SHanna Reitz dump_human_image_info(elem->value, 0, "/");
29029699bf0dSStefan Hajnoczi }
29039699bf0dSStefan Hajnoczi }
29049699bf0dSStefan Hajnoczi
str_equal_func(gconstpointer a,gconstpointer b)29059699bf0dSStefan Hajnoczi static gboolean str_equal_func(gconstpointer a, gconstpointer b)
29069699bf0dSStefan Hajnoczi {
29079699bf0dSStefan Hajnoczi return strcmp(a, b) == 0;
29089699bf0dSStefan Hajnoczi }
29099699bf0dSStefan Hajnoczi
29109699bf0dSStefan Hajnoczi /**
2911c04d0ab0SHanna Reitz * Open an image file chain and return an BlockGraphInfoList
29129699bf0dSStefan Hajnoczi *
29139699bf0dSStefan Hajnoczi * @filename: topmost image filename
29149699bf0dSStefan Hajnoczi * @fmt: topmost image format (may be NULL to autodetect)
29159699bf0dSStefan Hajnoczi * @chain: true - enumerate entire backing file chain
29169699bf0dSStefan Hajnoczi * false - only topmost image file
29179699bf0dSStefan Hajnoczi *
2918b1f4cd15SHanna Reitz * Returns a list of BlockNodeInfo objects or NULL if there was an error
2919b1f4cd15SHanna Reitz * opening an image file. If there was an error a message will have been
2920b1f4cd15SHanna Reitz * printed to stderr.
29219699bf0dSStefan Hajnoczi */
collect_image_info_list(bool image_opts,const char * filename,const char * fmt,bool chain,bool force_share)2922c04d0ab0SHanna Reitz static BlockGraphInfoList *collect_image_info_list(bool image_opts,
2923eb769f74SDaniel P. Berrange const char *filename,
29249699bf0dSStefan Hajnoczi const char *fmt,
2925335e9937SFam Zheng bool chain, bool force_share)
29269699bf0dSStefan Hajnoczi {
2927c04d0ab0SHanna Reitz BlockGraphInfoList *head = NULL;
2928c04d0ab0SHanna Reitz BlockGraphInfoList **tail = &head;
29299699bf0dSStefan Hajnoczi GHashTable *filenames;
293043526ec8SWenchao Xia Error *err = NULL;
29319699bf0dSStefan Hajnoczi
29329699bf0dSStefan Hajnoczi filenames = g_hash_table_new_full(g_str_hash, str_equal_func, NULL, NULL);
29339699bf0dSStefan Hajnoczi
29349699bf0dSStefan Hajnoczi while (filename) {
293526f54e9aSMarkus Armbruster BlockBackend *blk;
29369699bf0dSStefan Hajnoczi BlockDriverState *bs;
2937c04d0ab0SHanna Reitz BlockGraphInfo *info;
29389699bf0dSStefan Hajnoczi
29399699bf0dSStefan Hajnoczi if (g_hash_table_lookup_extended(filenames, filename, NULL, NULL)) {
29409699bf0dSStefan Hajnoczi error_report("Backing file '%s' creates an infinite loop.",
29419699bf0dSStefan Hajnoczi filename);
29429699bf0dSStefan Hajnoczi goto err;
29439699bf0dSStefan Hajnoczi }
29449699bf0dSStefan Hajnoczi g_hash_table_insert(filenames, (gpointer)filename, NULL);
29459699bf0dSStefan Hajnoczi
2946efaa7c4eSMax Reitz blk = img_open(image_opts, filename, fmt,
2947335e9937SFam Zheng BDRV_O_NO_BACKING | BDRV_O_NO_IO, false, false,
2948335e9937SFam Zheng force_share);
29497e7d56d9SMarkus Armbruster if (!blk) {
29509699bf0dSStefan Hajnoczi goto err;
29519699bf0dSStefan Hajnoczi }
29527e7d56d9SMarkus Armbruster bs = blk_bs(blk);
29539699bf0dSStefan Hajnoczi
2954c04d0ab0SHanna Reitz /*
2955c04d0ab0SHanna Reitz * Note that the returned BlockGraphInfo object will not have
2956c04d0ab0SHanna Reitz * information about this image's backing node, because we have opened
2957c04d0ab0SHanna Reitz * it with BDRV_O_NO_BACKING. Printing this object will therefore not
2958c04d0ab0SHanna Reitz * duplicate the backing chain information that we obtain by walking
2959c04d0ab0SHanna Reitz * the chain manually here.
2960c04d0ab0SHanna Reitz */
29613db0c8b2SKevin Wolf bdrv_graph_rdlock_main_loop();
2962c04d0ab0SHanna Reitz bdrv_query_block_graph_info(bs, &info, &err);
29633db0c8b2SKevin Wolf bdrv_graph_rdunlock_main_loop();
29643db0c8b2SKevin Wolf
296584d18f06SMarkus Armbruster if (err) {
2966565f65d2SMarkus Armbruster error_report_err(err);
296726f54e9aSMarkus Armbruster blk_unref(blk);
296843526ec8SWenchao Xia goto err;
2969fb0ed453SWenchao Xia }
29709699bf0dSStefan Hajnoczi
2971c3033fd3SEric Blake QAPI_LIST_APPEND(tail, info);
29729699bf0dSStefan Hajnoczi
297326f54e9aSMarkus Armbruster blk_unref(blk);
29749699bf0dSStefan Hajnoczi
29750da7d13aSStefan Hajnoczi /* Clear parameters that only apply to the topmost image */
29769699bf0dSStefan Hajnoczi filename = fmt = NULL;
29770da7d13aSStefan Hajnoczi image_opts = false;
29780da7d13aSStefan Hajnoczi
29799699bf0dSStefan Hajnoczi if (chain) {
298054fde4ffSMarkus Armbruster if (info->full_backing_filename) {
29819699bf0dSStefan Hajnoczi filename = info->full_backing_filename;
298254fde4ffSMarkus Armbruster } else if (info->backing_filename) {
298392d617abSJohn Snow error_report("Could not determine absolute backing filename,"
298492d617abSJohn Snow " but backing filename '%s' present",
298592d617abSJohn Snow info->backing_filename);
298692d617abSJohn Snow goto err;
29879699bf0dSStefan Hajnoczi }
298854fde4ffSMarkus Armbruster if (info->backing_filename_format) {
29899699bf0dSStefan Hajnoczi fmt = info->backing_filename_format;
29909699bf0dSStefan Hajnoczi }
29919699bf0dSStefan Hajnoczi }
29929699bf0dSStefan Hajnoczi }
29939699bf0dSStefan Hajnoczi g_hash_table_destroy(filenames);
29949699bf0dSStefan Hajnoczi return head;
29959699bf0dSStefan Hajnoczi
29969699bf0dSStefan Hajnoczi err:
2997c04d0ab0SHanna Reitz qapi_free_BlockGraphInfoList(head);
29989699bf0dSStefan Hajnoczi g_hash_table_destroy(filenames);
29999699bf0dSStefan Hajnoczi return NULL;
30009699bf0dSStefan Hajnoczi }
30019699bf0dSStefan Hajnoczi
img_info(int argc,char ** argv)3002c054b3fdSBenoît Canet static int img_info(int argc, char **argv)
3003c054b3fdSBenoît Canet {
3004c054b3fdSBenoît Canet int c;
3005c054b3fdSBenoît Canet OutputFormat output_format = OFORMAT_HUMAN;
30069699bf0dSStefan Hajnoczi bool chain = false;
3007c054b3fdSBenoît Canet const char *filename, *fmt, *output;
3008c04d0ab0SHanna Reitz BlockGraphInfoList *list;
3009eb769f74SDaniel P. Berrange bool image_opts = false;
3010335e9937SFam Zheng bool force_share = false;
3011c054b3fdSBenoît Canet
3012ea2384d3Sbellard fmt = NULL;
3013c054b3fdSBenoît Canet output = NULL;
3014ea2384d3Sbellard for(;;) {
3015c054b3fdSBenoît Canet int option_index = 0;
3016c054b3fdSBenoît Canet static const struct option long_options[] = {
3017c054b3fdSBenoît Canet {"help", no_argument, 0, 'h'},
3018c054b3fdSBenoît Canet {"format", required_argument, 0, 'f'},
3019c054b3fdSBenoît Canet {"output", required_argument, 0, OPTION_OUTPUT},
30209699bf0dSStefan Hajnoczi {"backing-chain", no_argument, 0, OPTION_BACKING_CHAIN},
30213babeb15SDaniel P. Berrange {"object", required_argument, 0, OPTION_OBJECT},
3022eb769f74SDaniel P. Berrange {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
3023335e9937SFam Zheng {"force-share", no_argument, 0, 'U'},
3024c054b3fdSBenoît Canet {0, 0, 0, 0}
3025c054b3fdSBenoît Canet };
3026335e9937SFam Zheng c = getopt_long(argc, argv, ":f:hU",
3027c054b3fdSBenoît Canet long_options, &option_index);
3028b8fb60daSJes Sorensen if (c == -1) {
3029ea2384d3Sbellard break;
3030b8fb60daSJes Sorensen }
3031ea2384d3Sbellard switch(c) {
3032c9192973SStefan Hajnoczi case ':':
3033c9192973SStefan Hajnoczi missing_argument(argv[optind - 1]);
3034c9192973SStefan Hajnoczi break;
3035ef87394cSJes Sorensen case '?':
3036c9192973SStefan Hajnoczi unrecognized_option(argv[optind - 1]);
3037c9192973SStefan Hajnoczi break;
3038ea2384d3Sbellard case 'h':
3039ea2384d3Sbellard help();
3040ea2384d3Sbellard break;
3041ea2384d3Sbellard case 'f':
3042ea2384d3Sbellard fmt = optarg;
3043ea2384d3Sbellard break;
3044335e9937SFam Zheng case 'U':
3045335e9937SFam Zheng force_share = true;
3046335e9937SFam Zheng break;
3047c054b3fdSBenoît Canet case OPTION_OUTPUT:
3048c054b3fdSBenoît Canet output = optarg;
3049c054b3fdSBenoît Canet break;
30509699bf0dSStefan Hajnoczi case OPTION_BACKING_CHAIN:
30519699bf0dSStefan Hajnoczi chain = true;
30529699bf0dSStefan Hajnoczi break;
305399b1e646SKevin Wolf case OPTION_OBJECT:
305499b1e646SKevin Wolf user_creatable_process_cmdline(optarg);
305599b1e646SKevin Wolf break;
3056eb769f74SDaniel P. Berrange case OPTION_IMAGE_OPTS:
3057eb769f74SDaniel P. Berrange image_opts = true;
3058eb769f74SDaniel P. Berrange break;
3059ea2384d3Sbellard }
3060ea2384d3Sbellard }
3061fc11eb26SKevin Wolf if (optind != argc - 1) {
3062ac1307abSFam Zheng error_exit("Expecting one image file name");
3063b8fb60daSJes Sorensen }
3064ea2384d3Sbellard filename = argv[optind++];
3065ea2384d3Sbellard
3066c054b3fdSBenoît Canet if (output && !strcmp(output, "json")) {
3067c054b3fdSBenoît Canet output_format = OFORMAT_JSON;
3068c054b3fdSBenoît Canet } else if (output && !strcmp(output, "human")) {
3069c054b3fdSBenoît Canet output_format = OFORMAT_HUMAN;
3070c054b3fdSBenoît Canet } else if (output) {
3071c054b3fdSBenoît Canet error_report("--output must be used with human or json as argument.");
3072c054b3fdSBenoît Canet return 1;
3073c054b3fdSBenoît Canet }
3074c054b3fdSBenoît Canet
3075335e9937SFam Zheng list = collect_image_info_list(image_opts, filename, fmt, chain,
3076335e9937SFam Zheng force_share);
30779699bf0dSStefan Hajnoczi if (!list) {
3078c2abccecSMORITA Kazutaka return 1;
3079c2abccecSMORITA Kazutaka }
3080c054b3fdSBenoît Canet
3081c054b3fdSBenoît Canet switch (output_format) {
3082c054b3fdSBenoît Canet case OFORMAT_HUMAN:
30839699bf0dSStefan Hajnoczi dump_human_image_info_list(list);
3084c054b3fdSBenoît Canet break;
3085c054b3fdSBenoît Canet case OFORMAT_JSON:
30869699bf0dSStefan Hajnoczi if (chain) {
3087c04d0ab0SHanna Reitz dump_json_block_graph_info_list(list);
30889699bf0dSStefan Hajnoczi } else {
3089c04d0ab0SHanna Reitz dump_json_block_graph_info(list->value);
30909699bf0dSStefan Hajnoczi }
3091c054b3fdSBenoît Canet break;
3092c054b3fdSBenoît Canet }
3093c054b3fdSBenoît Canet
3094c04d0ab0SHanna Reitz qapi_free_BlockGraphInfoList(list);
3095ea2384d3Sbellard return 0;
3096ea2384d3Sbellard }
3097ea2384d3Sbellard
dump_map_entry(OutputFormat output_format,MapEntry * e,MapEntry * next)309830065d14SEric Blake static int dump_map_entry(OutputFormat output_format, MapEntry *e,
30994c93a13bSPaolo Bonzini MapEntry *next)
31004c93a13bSPaolo Bonzini {
31014c93a13bSPaolo Bonzini switch (output_format) {
31024c93a13bSPaolo Bonzini case OFORMAT_HUMAN:
310316b0d555SFam Zheng if (e->data && !e->has_offset) {
31044c93a13bSPaolo Bonzini error_report("File contains external, encrypted or compressed clusters.");
310530065d14SEric Blake return -1;
31064c93a13bSPaolo Bonzini }
310716b0d555SFam Zheng if (e->data && !e->zero) {
31084c93a13bSPaolo Bonzini printf("%#-16"PRIx64"%#-16"PRIx64"%#-16"PRIx64"%s\n",
310916b0d555SFam Zheng e->start, e->length,
311016b0d555SFam Zheng e->has_offset ? e->offset : 0,
311154fde4ffSMarkus Armbruster e->filename ?: "");
31124c93a13bSPaolo Bonzini }
31134c93a13bSPaolo Bonzini /* This format ignores the distinction between 0, ZERO and ZERO|DATA.
31144c93a13bSPaolo Bonzini * Modify the flags here to allow more coalescing.
31154c93a13bSPaolo Bonzini */
311616b0d555SFam Zheng if (next && (!next->data || next->zero)) {
311716b0d555SFam Zheng next->data = false;
311816b0d555SFam Zheng next->zero = true;
31194c93a13bSPaolo Bonzini }
31204c93a13bSPaolo Bonzini break;
31214c93a13bSPaolo Bonzini case OFORMAT_JSON:
3122e46c0b18SEyal Moscovici printf("{ \"start\": %"PRId64", \"length\": %"PRId64","
31238417e137SEric Blake " \"depth\": %"PRId64", \"present\": %s, \"zero\": %s,"
312452b10c9cSAndrey Drobyshev via " \"data\": %s, \"compressed\": %s",
312552b10c9cSAndrey Drobyshev via e->start, e->length, e->depth,
31268417e137SEric Blake e->present ? "true" : "false",
312716b0d555SFam Zheng e->zero ? "true" : "false",
312852b10c9cSAndrey Drobyshev via e->data ? "true" : "false",
312952b10c9cSAndrey Drobyshev via e->compressed ? "true" : "false");
313016b0d555SFam Zheng if (e->has_offset) {
3131c745bfb4SPaolo Bonzini printf(", \"offset\": %"PRId64"", e->offset);
31324c93a13bSPaolo Bonzini }
31334c93a13bSPaolo Bonzini putchar('}');
31344c93a13bSPaolo Bonzini
3135e46c0b18SEyal Moscovici if (next) {
3136e46c0b18SEyal Moscovici puts(",");
31374c93a13bSPaolo Bonzini }
31384c93a13bSPaolo Bonzini break;
31394c93a13bSPaolo Bonzini }
314030065d14SEric Blake return 0;
31414c93a13bSPaolo Bonzini }
31424c93a13bSPaolo Bonzini
get_block_status(BlockDriverState * bs,int64_t offset,int64_t bytes,MapEntry * e)31435e344dd8SEric Blake static int get_block_status(BlockDriverState *bs, int64_t offset,
31445e344dd8SEric Blake int64_t bytes, MapEntry *e)
31454c93a13bSPaolo Bonzini {
3146237d78f8SEric Blake int ret;
31474c93a13bSPaolo Bonzini int depth;
314867a0fd2aSFam Zheng BlockDriverState *file;
31492875645bSJohn Snow bool has_offset;
3150237d78f8SEric Blake int64_t map;
3151f30c66baSMax Reitz char *filename = NULL;
31524c93a13bSPaolo Bonzini
3153ad74751fSKevin Wolf GLOBAL_STATE_CODE();
3154ad74751fSKevin Wolf GRAPH_RDLOCK_GUARD_MAINLOOP();
3155ad74751fSKevin Wolf
31564c93a13bSPaolo Bonzini /* As an optimization, we could cache the current range of unallocated
31574c93a13bSPaolo Bonzini * clusters in each file of the chain, and avoid querying the same
31584c93a13bSPaolo Bonzini * range repeatedly.
31594c93a13bSPaolo Bonzini */
31604c93a13bSPaolo Bonzini
31614c93a13bSPaolo Bonzini depth = 0;
31624c93a13bSPaolo Bonzini for (;;) {
31634a2061e6SMax Reitz bs = bdrv_skip_filters(bs);
3164237d78f8SEric Blake ret = bdrv_block_status(bs, offset, bytes, &bytes, &map, &file);
31654c93a13bSPaolo Bonzini if (ret < 0) {
31664c93a13bSPaolo Bonzini return ret;
31674c93a13bSPaolo Bonzini }
3168237d78f8SEric Blake assert(bytes);
31694c93a13bSPaolo Bonzini if (ret & (BDRV_BLOCK_ZERO|BDRV_BLOCK_DATA)) {
31704c93a13bSPaolo Bonzini break;
31714c93a13bSPaolo Bonzini }
31724a2061e6SMax Reitz bs = bdrv_cow_bs(bs);
31734c93a13bSPaolo Bonzini if (bs == NULL) {
31744c93a13bSPaolo Bonzini ret = 0;
31754c93a13bSPaolo Bonzini break;
31764c93a13bSPaolo Bonzini }
31774c93a13bSPaolo Bonzini
31784c93a13bSPaolo Bonzini depth++;
31794c93a13bSPaolo Bonzini }
31804c93a13bSPaolo Bonzini
31812875645bSJohn Snow has_offset = !!(ret & BDRV_BLOCK_OFFSET_VALID);
31822875645bSJohn Snow
3183f30c66baSMax Reitz if (file && has_offset) {
3184f30c66baSMax Reitz bdrv_refresh_filename(file);
3185f30c66baSMax Reitz filename = file->filename;
3186f30c66baSMax Reitz }
3187f30c66baSMax Reitz
31882875645bSJohn Snow *e = (MapEntry) {
31895e344dd8SEric Blake .start = offset,
3190237d78f8SEric Blake .length = bytes,
31912875645bSJohn Snow .data = !!(ret & BDRV_BLOCK_DATA),
31922875645bSJohn Snow .zero = !!(ret & BDRV_BLOCK_ZERO),
319352b10c9cSAndrey Drobyshev via .compressed = !!(ret & BDRV_BLOCK_COMPRESSED),
3194237d78f8SEric Blake .offset = map,
31952875645bSJohn Snow .has_offset = has_offset,
31962875645bSJohn Snow .depth = depth,
31978417e137SEric Blake .present = !!(ret & BDRV_BLOCK_ALLOCATED),
3198f30c66baSMax Reitz .filename = filename,
31992875645bSJohn Snow };
32002875645bSJohn Snow
32014c93a13bSPaolo Bonzini return 0;
32024c93a13bSPaolo Bonzini }
32034c93a13bSPaolo Bonzini
entry_mergeable(const MapEntry * curr,const MapEntry * next)320416b0d555SFam Zheng static inline bool entry_mergeable(const MapEntry *curr, const MapEntry *next)
320516b0d555SFam Zheng {
320616b0d555SFam Zheng if (curr->length == 0) {
320716b0d555SFam Zheng return false;
320816b0d555SFam Zheng }
320916b0d555SFam Zheng if (curr->zero != next->zero ||
321016b0d555SFam Zheng curr->data != next->data ||
321152b10c9cSAndrey Drobyshev via curr->compressed != next->compressed ||
321216b0d555SFam Zheng curr->depth != next->depth ||
32138417e137SEric Blake curr->present != next->present ||
321454fde4ffSMarkus Armbruster !curr->filename != !next->filename ||
321516b0d555SFam Zheng curr->has_offset != next->has_offset) {
321616b0d555SFam Zheng return false;
321716b0d555SFam Zheng }
321854fde4ffSMarkus Armbruster if (curr->filename && strcmp(curr->filename, next->filename)) {
321916b0d555SFam Zheng return false;
322016b0d555SFam Zheng }
322116b0d555SFam Zheng if (curr->has_offset && curr->offset + curr->length != next->offset) {
322216b0d555SFam Zheng return false;
322316b0d555SFam Zheng }
322416b0d555SFam Zheng return true;
322516b0d555SFam Zheng }
322616b0d555SFam Zheng
img_map(int argc,char ** argv)32274c93a13bSPaolo Bonzini static int img_map(int argc, char **argv)
32284c93a13bSPaolo Bonzini {
32294c93a13bSPaolo Bonzini int c;
32304c93a13bSPaolo Bonzini OutputFormat output_format = OFORMAT_HUMAN;
323126f54e9aSMarkus Armbruster BlockBackend *blk;
32324c93a13bSPaolo Bonzini BlockDriverState *bs;
32334c93a13bSPaolo Bonzini const char *filename, *fmt, *output;
32344c93a13bSPaolo Bonzini int64_t length;
32354c93a13bSPaolo Bonzini MapEntry curr = { .length = 0 }, next;
32364c93a13bSPaolo Bonzini int ret = 0;
3237eb769f74SDaniel P. Berrange bool image_opts = false;
3238335e9937SFam Zheng bool force_share = false;
3239c0469496SEyal Moscovici int64_t start_offset = 0;
3240c0469496SEyal Moscovici int64_t max_length = -1;
32414c93a13bSPaolo Bonzini
32424c93a13bSPaolo Bonzini fmt = NULL;
32434c93a13bSPaolo Bonzini output = NULL;
32444c93a13bSPaolo Bonzini for (;;) {
32454c93a13bSPaolo Bonzini int option_index = 0;
32464c93a13bSPaolo Bonzini static const struct option long_options[] = {
32474c93a13bSPaolo Bonzini {"help", no_argument, 0, 'h'},
32484c93a13bSPaolo Bonzini {"format", required_argument, 0, 'f'},
32494c93a13bSPaolo Bonzini {"output", required_argument, 0, OPTION_OUTPUT},
32503babeb15SDaniel P. Berrange {"object", required_argument, 0, OPTION_OBJECT},
3251eb769f74SDaniel P. Berrange {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
3252335e9937SFam Zheng {"force-share", no_argument, 0, 'U'},
3253c0469496SEyal Moscovici {"start-offset", required_argument, 0, 's'},
3254c0469496SEyal Moscovici {"max-length", required_argument, 0, 'l'},
32554c93a13bSPaolo Bonzini {0, 0, 0, 0}
32564c93a13bSPaolo Bonzini };
3257c0469496SEyal Moscovici c = getopt_long(argc, argv, ":f:s:l:hU",
32584c93a13bSPaolo Bonzini long_options, &option_index);
32594c93a13bSPaolo Bonzini if (c == -1) {
32604c93a13bSPaolo Bonzini break;
32614c93a13bSPaolo Bonzini }
32624c93a13bSPaolo Bonzini switch (c) {
3263c9192973SStefan Hajnoczi case ':':
3264c9192973SStefan Hajnoczi missing_argument(argv[optind - 1]);
3265c9192973SStefan Hajnoczi break;
32664c93a13bSPaolo Bonzini case '?':
3267c9192973SStefan Hajnoczi unrecognized_option(argv[optind - 1]);
3268c9192973SStefan Hajnoczi break;
32694c93a13bSPaolo Bonzini case 'h':
32704c93a13bSPaolo Bonzini help();
32714c93a13bSPaolo Bonzini break;
32724c93a13bSPaolo Bonzini case 'f':
32734c93a13bSPaolo Bonzini fmt = optarg;
32744c93a13bSPaolo Bonzini break;
3275335e9937SFam Zheng case 'U':
3276335e9937SFam Zheng force_share = true;
3277335e9937SFam Zheng break;
32784c93a13bSPaolo Bonzini case OPTION_OUTPUT:
32794c93a13bSPaolo Bonzini output = optarg;
32804c93a13bSPaolo Bonzini break;
3281c0469496SEyal Moscovici case 's':
3282c0469496SEyal Moscovici start_offset = cvtnum("start offset", optarg);
3283c0469496SEyal Moscovici if (start_offset < 0) {
3284c0469496SEyal Moscovici return 1;
3285c0469496SEyal Moscovici }
3286c0469496SEyal Moscovici break;
3287c0469496SEyal Moscovici case 'l':
3288c0469496SEyal Moscovici max_length = cvtnum("max length", optarg);
3289c0469496SEyal Moscovici if (max_length < 0) {
3290c0469496SEyal Moscovici return 1;
3291c0469496SEyal Moscovici }
3292c0469496SEyal Moscovici break;
329399b1e646SKevin Wolf case OPTION_OBJECT:
329499b1e646SKevin Wolf user_creatable_process_cmdline(optarg);
329599b1e646SKevin Wolf break;
3296eb769f74SDaniel P. Berrange case OPTION_IMAGE_OPTS:
3297eb769f74SDaniel P. Berrange image_opts = true;
3298eb769f74SDaniel P. Berrange break;
32994c93a13bSPaolo Bonzini }
33004c93a13bSPaolo Bonzini }
3301ac1307abSFam Zheng if (optind != argc - 1) {
3302ac1307abSFam Zheng error_exit("Expecting one image file name");
33034c93a13bSPaolo Bonzini }
3304ac1307abSFam Zheng filename = argv[optind];
33054c93a13bSPaolo Bonzini
33064c93a13bSPaolo Bonzini if (output && !strcmp(output, "json")) {
33074c93a13bSPaolo Bonzini output_format = OFORMAT_JSON;
33084c93a13bSPaolo Bonzini } else if (output && !strcmp(output, "human")) {
33094c93a13bSPaolo Bonzini output_format = OFORMAT_HUMAN;
33104c93a13bSPaolo Bonzini } else if (output) {
33114c93a13bSPaolo Bonzini error_report("--output must be used with human or json as argument.");
33124c93a13bSPaolo Bonzini return 1;
33134c93a13bSPaolo Bonzini }
33144c93a13bSPaolo Bonzini
3315335e9937SFam Zheng blk = img_open(image_opts, filename, fmt, 0, false, false, force_share);
33167e7d56d9SMarkus Armbruster if (!blk) {
33177e7d56d9SMarkus Armbruster return 1;
33184c93a13bSPaolo Bonzini }
33197e7d56d9SMarkus Armbruster bs = blk_bs(blk);
33204c93a13bSPaolo Bonzini
33214c93a13bSPaolo Bonzini if (output_format == OFORMAT_HUMAN) {
33224c93a13bSPaolo Bonzini printf("%-16s%-16s%-16s%s\n", "Offset", "Length", "Mapped to", "File");
3323e46c0b18SEyal Moscovici } else if (output_format == OFORMAT_JSON) {
3324e46c0b18SEyal Moscovici putchar('[');
33254c93a13bSPaolo Bonzini }
33264c93a13bSPaolo Bonzini
3327f1d3cd79SMax Reitz length = blk_getlength(blk);
33288f282e83SEyal Moscovici if (length < 0) {
33298f282e83SEyal Moscovici error_report("Failed to get size for '%s'", filename);
33308f282e83SEyal Moscovici return 1;
33318f282e83SEyal Moscovici }
3332c0469496SEyal Moscovici if (max_length != -1) {
3333c0469496SEyal Moscovici length = MIN(start_offset + max_length, length);
3334c0469496SEyal Moscovici }
33358f282e83SEyal Moscovici
3336c0469496SEyal Moscovici curr.start = start_offset;
33374c93a13bSPaolo Bonzini while (curr.start + curr.length < length) {
33385e344dd8SEric Blake int64_t offset = curr.start + curr.length;
3339d0ceea88SKevin Wolf int64_t n = length - offset;
33404c93a13bSPaolo Bonzini
33415e344dd8SEric Blake ret = get_block_status(bs, offset, n, &next);
33424c93a13bSPaolo Bonzini if (ret < 0) {
33434c93a13bSPaolo Bonzini error_report("Could not read file metadata: %s", strerror(-ret));
33444c93a13bSPaolo Bonzini goto out;
33454c93a13bSPaolo Bonzini }
33464c93a13bSPaolo Bonzini
334716b0d555SFam Zheng if (entry_mergeable(&curr, &next)) {
33484c93a13bSPaolo Bonzini curr.length += next.length;
33494c93a13bSPaolo Bonzini continue;
33504c93a13bSPaolo Bonzini }
33514c93a13bSPaolo Bonzini
33524c93a13bSPaolo Bonzini if (curr.length > 0) {
335330065d14SEric Blake ret = dump_map_entry(output_format, &curr, &next);
335430065d14SEric Blake if (ret < 0) {
335530065d14SEric Blake goto out;
335630065d14SEric Blake }
33574c93a13bSPaolo Bonzini }
33584c93a13bSPaolo Bonzini curr = next;
33594c93a13bSPaolo Bonzini }
33604c93a13bSPaolo Bonzini
336130065d14SEric Blake ret = dump_map_entry(output_format, &curr, NULL);
3362e46c0b18SEyal Moscovici if (output_format == OFORMAT_JSON) {
3363e46c0b18SEyal Moscovici puts("]");
3364e46c0b18SEyal Moscovici }
33654c93a13bSPaolo Bonzini
33664c93a13bSPaolo Bonzini out:
336726f54e9aSMarkus Armbruster blk_unref(blk);
33684c93a13bSPaolo Bonzini return ret < 0;
33694c93a13bSPaolo Bonzini }
33704c93a13bSPaolo Bonzini
3371f7b4a940Saliguori #define SNAPSHOT_LIST 1
3372f7b4a940Saliguori #define SNAPSHOT_CREATE 2
3373f7b4a940Saliguori #define SNAPSHOT_APPLY 3
3374f7b4a940Saliguori #define SNAPSHOT_DELETE 4
3375f7b4a940Saliguori
img_snapshot(int argc,char ** argv)3376153859beSStuart Brady static int img_snapshot(int argc, char **argv)
3377f7b4a940Saliguori {
337826f54e9aSMarkus Armbruster BlockBackend *blk;
3379f7b4a940Saliguori BlockDriverState *bs;
3380f7b4a940Saliguori QEMUSnapshotInfo sn;
3381f7b4a940Saliguori char *filename, *snapshot_name = NULL;
3382c2abccecSMORITA Kazutaka int c, ret = 0, bdrv_oflags;
3383f7b4a940Saliguori int action = 0;
3384f382d43aSMiroslav Rezanina bool quiet = false;
3385a89d89d3SWenchao Xia Error *err = NULL;
3386eb769f74SDaniel P. Berrange bool image_opts = false;
3387335e9937SFam Zheng bool force_share = false;
3388f793dde0SMarc-André Lureau int64_t rt;
3389f7b4a940Saliguori
3390ce099547SKevin Wolf bdrv_oflags = BDRV_O_RDWR;
3391f7b4a940Saliguori /* Parse commandline parameters */
3392f7b4a940Saliguori for(;;) {
33933babeb15SDaniel P. Berrange static const struct option long_options[] = {
33943babeb15SDaniel P. Berrange {"help", no_argument, 0, 'h'},
33953babeb15SDaniel P. Berrange {"object", required_argument, 0, OPTION_OBJECT},
3396eb769f74SDaniel P. Berrange {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
3397335e9937SFam Zheng {"force-share", no_argument, 0, 'U'},
33983babeb15SDaniel P. Berrange {0, 0, 0, 0}
33993babeb15SDaniel P. Berrange };
3400335e9937SFam Zheng c = getopt_long(argc, argv, ":la:c:d:hqU",
34013babeb15SDaniel P. Berrange long_options, NULL);
3402b8fb60daSJes Sorensen if (c == -1) {
3403f7b4a940Saliguori break;
3404b8fb60daSJes Sorensen }
3405f7b4a940Saliguori switch(c) {
3406c9192973SStefan Hajnoczi case ':':
3407c9192973SStefan Hajnoczi missing_argument(argv[optind - 1]);
3408c9192973SStefan Hajnoczi break;
3409ef87394cSJes Sorensen case '?':
3410c9192973SStefan Hajnoczi unrecognized_option(argv[optind - 1]);
3411c9192973SStefan Hajnoczi break;
3412f7b4a940Saliguori case 'h':
3413f7b4a940Saliguori help();
3414153859beSStuart Brady return 0;
3415f7b4a940Saliguori case 'l':
3416f7b4a940Saliguori if (action) {
3417ac1307abSFam Zheng error_exit("Cannot mix '-l', '-a', '-c', '-d'");
3418153859beSStuart Brady return 0;
3419f7b4a940Saliguori }
3420f7b4a940Saliguori action = SNAPSHOT_LIST;
3421f5edb014SNaphtali Sprei bdrv_oflags &= ~BDRV_O_RDWR; /* no need for RW */
3422f7b4a940Saliguori break;
3423f7b4a940Saliguori case 'a':
3424f7b4a940Saliguori if (action) {
3425ac1307abSFam Zheng error_exit("Cannot mix '-l', '-a', '-c', '-d'");
3426153859beSStuart Brady return 0;
3427f7b4a940Saliguori }
3428f7b4a940Saliguori action = SNAPSHOT_APPLY;
3429f7b4a940Saliguori snapshot_name = optarg;
3430f7b4a940Saliguori break;
3431f7b4a940Saliguori case 'c':
3432f7b4a940Saliguori if (action) {
3433ac1307abSFam Zheng error_exit("Cannot mix '-l', '-a', '-c', '-d'");
3434153859beSStuart Brady return 0;
3435f7b4a940Saliguori }
3436f7b4a940Saliguori action = SNAPSHOT_CREATE;
3437f7b4a940Saliguori snapshot_name = optarg;
3438f7b4a940Saliguori break;
3439f7b4a940Saliguori case 'd':
3440f7b4a940Saliguori if (action) {
3441ac1307abSFam Zheng error_exit("Cannot mix '-l', '-a', '-c', '-d'");
3442153859beSStuart Brady return 0;
3443f7b4a940Saliguori }
3444f7b4a940Saliguori action = SNAPSHOT_DELETE;
3445f7b4a940Saliguori snapshot_name = optarg;
3446f7b4a940Saliguori break;
3447f382d43aSMiroslav Rezanina case 'q':
3448f382d43aSMiroslav Rezanina quiet = true;
3449f382d43aSMiroslav Rezanina break;
3450335e9937SFam Zheng case 'U':
3451335e9937SFam Zheng force_share = true;
3452335e9937SFam Zheng break;
345399b1e646SKevin Wolf case OPTION_OBJECT:
345499b1e646SKevin Wolf user_creatable_process_cmdline(optarg);
345599b1e646SKevin Wolf break;
3456eb769f74SDaniel P. Berrange case OPTION_IMAGE_OPTS:
3457eb769f74SDaniel P. Berrange image_opts = true;
3458eb769f74SDaniel P. Berrange break;
3459f7b4a940Saliguori }
3460f7b4a940Saliguori }
3461f7b4a940Saliguori
3462fc11eb26SKevin Wolf if (optind != argc - 1) {
3463ac1307abSFam Zheng error_exit("Expecting one image file name");
3464b8fb60daSJes Sorensen }
3465f7b4a940Saliguori filename = argv[optind++];
3466f7b4a940Saliguori
3467f7b4a940Saliguori /* Open the image */
3468335e9937SFam Zheng blk = img_open(image_opts, filename, NULL, bdrv_oflags, false, quiet,
3469335e9937SFam Zheng force_share);
34707e7d56d9SMarkus Armbruster if (!blk) {
34717e7d56d9SMarkus Armbruster return 1;
3472c2abccecSMORITA Kazutaka }
34737e7d56d9SMarkus Armbruster bs = blk_bs(blk);
3474f7b4a940Saliguori
3475f7b4a940Saliguori /* Perform the requested action */
3476f7b4a940Saliguori switch(action) {
3477f7b4a940Saliguori case SNAPSHOT_LIST:
3478f7b4a940Saliguori dump_snapshots(bs);
3479f7b4a940Saliguori break;
3480f7b4a940Saliguori
3481f7b4a940Saliguori case SNAPSHOT_CREATE:
3482f7b4a940Saliguori memset(&sn, 0, sizeof(sn));
3483f7b4a940Saliguori pstrcpy(sn.name, sizeof(sn.name), snapshot_name);
3484f7b4a940Saliguori
3485f793dde0SMarc-André Lureau rt = g_get_real_time();
3486f793dde0SMarc-André Lureau sn.date_sec = rt / G_USEC_PER_SEC;
3487f793dde0SMarc-André Lureau sn.date_nsec = (rt % G_USEC_PER_SEC) * 1000;
3488f7b4a940Saliguori
3489a32e7818SKevin Wolf bdrv_graph_rdlock_main_loop();
3490f7b4a940Saliguori ret = bdrv_snapshot_create(bs, &sn);
3491a32e7818SKevin Wolf bdrv_graph_rdunlock_main_loop();
3492a32e7818SKevin Wolf
3493b8fb60daSJes Sorensen if (ret) {
3494b0a6620aSMichael Tokarev error_report("Could not create snapshot '%s': %s",
3495b0a6620aSMichael Tokarev snapshot_name, strerror(-ret));
3496b8fb60daSJes Sorensen }
3497f7b4a940Saliguori break;
3498f7b4a940Saliguori
3499f7b4a940Saliguori case SNAPSHOT_APPLY:
35000b62bcbcSKevin Wolf ret = bdrv_snapshot_goto(bs, snapshot_name, &err);
3501b8fb60daSJes Sorensen if (ret) {
35020b62bcbcSKevin Wolf error_reportf_err(err, "Could not apply snapshot '%s': ",
35030b62bcbcSKevin Wolf snapshot_name);
3504b8fb60daSJes Sorensen }
3505f7b4a940Saliguori break;
3506f7b4a940Saliguori
3507f7b4a940Saliguori case SNAPSHOT_DELETE:
3508a32e7818SKevin Wolf bdrv_graph_rdlock_main_loop();
35098c04093cSDaniel Henrique Barboza ret = bdrv_snapshot_find(bs, &sn, snapshot_name);
35108c04093cSDaniel Henrique Barboza if (ret < 0) {
35118c04093cSDaniel Henrique Barboza error_report("Could not delete snapshot '%s': snapshot not "
35128c04093cSDaniel Henrique Barboza "found", snapshot_name);
35138c04093cSDaniel Henrique Barboza ret = 1;
35148c04093cSDaniel Henrique Barboza } else {
35158c04093cSDaniel Henrique Barboza ret = bdrv_snapshot_delete(bs, sn.id_str, sn.name, &err);
35168c04093cSDaniel Henrique Barboza if (ret < 0) {
3517c29b77f9SMarkus Armbruster error_reportf_err(err, "Could not delete snapshot '%s': ",
3518c29b77f9SMarkus Armbruster snapshot_name);
3519a89d89d3SWenchao Xia ret = 1;
3520b8fb60daSJes Sorensen }
35218c04093cSDaniel Henrique Barboza }
3522a32e7818SKevin Wolf bdrv_graph_rdunlock_main_loop();
3523f7b4a940Saliguori break;
3524f7b4a940Saliguori }
3525f7b4a940Saliguori
3526f7b4a940Saliguori /* Cleanup */
352726f54e9aSMarkus Armbruster blk_unref(blk);
3528c2abccecSMORITA Kazutaka if (ret) {
3529c2abccecSMORITA Kazutaka return 1;
3530c2abccecSMORITA Kazutaka }
3531153859beSStuart Brady return 0;
3532f7b4a940Saliguori }
3533f7b4a940Saliguori
img_rebase(int argc,char ** argv)35343e85c6fdSKevin Wolf static int img_rebase(int argc, char **argv)
35353e85c6fdSKevin Wolf {
353626f54e9aSMarkus Armbruster BlockBackend *blk = NULL, *blk_old_backing = NULL, *blk_new_backing = NULL;
3537396374caSPaolo Bonzini uint8_t *buf_old = NULL;
3538396374caSPaolo Bonzini uint8_t *buf_new = NULL;
3539863cc78fSSam Eiderman BlockDriverState *bs = NULL, *prefix_chain_bs = NULL;
3540*78a9c76eSKevin Wolf BlockDriverState *unfiltered_bs, *unfiltered_bs_cow;
354112df580bSAndrey Drobyshev BlockDriverInfo bdi = {0};
35423e85c6fdSKevin Wolf char *filename;
354340055951SMax Reitz const char *fmt, *cache, *src_cache, *out_basefmt, *out_baseimg;
354440055951SMax Reitz int c, flags, src_flags, ret;
354526ea2789SAndrey Drobyshev BdrvRequestFlags write_flags = 0;
3546ce099547SKevin Wolf bool writethrough, src_writethrough;
35473e85c6fdSKevin Wolf int unsafe = 0;
3548335e9937SFam Zheng bool force_share = false;
35496b837bc4SJes Sorensen int progress = 0;
3550f382d43aSMiroslav Rezanina bool quiet = false;
355126ea2789SAndrey Drobyshev bool compress = false;
355234b5d2c6SMax Reitz Error *local_err = NULL;
3553eb769f74SDaniel P. Berrange bool image_opts = false;
355412df580bSAndrey Drobyshev int64_t write_align;
35553e85c6fdSKevin Wolf
35563e85c6fdSKevin Wolf /* Parse commandline parameters */
3557e53dbee0SKevin Wolf fmt = NULL;
3558661a0f71SFederico Simoncelli cache = BDRV_DEFAULT_CACHE;
355940055951SMax Reitz src_cache = BDRV_DEFAULT_CACHE;
35603e85c6fdSKevin Wolf out_baseimg = NULL;
35613e85c6fdSKevin Wolf out_basefmt = NULL;
35623e85c6fdSKevin Wolf for(;;) {
35633babeb15SDaniel P. Berrange static const struct option long_options[] = {
35643babeb15SDaniel P. Berrange {"help", no_argument, 0, 'h'},
35653babeb15SDaniel P. Berrange {"object", required_argument, 0, OPTION_OBJECT},
3566eb769f74SDaniel P. Berrange {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
3567335e9937SFam Zheng {"force-share", no_argument, 0, 'U'},
356826ea2789SAndrey Drobyshev {"compress", no_argument, 0, 'c'},
35693babeb15SDaniel P. Berrange {0, 0, 0, 0}
35703babeb15SDaniel P. Berrange };
357126ea2789SAndrey Drobyshev c = getopt_long(argc, argv, ":hf:F:b:upt:T:qUc",
35723babeb15SDaniel P. Berrange long_options, NULL);
3573b8fb60daSJes Sorensen if (c == -1) {
35743e85c6fdSKevin Wolf break;
3575b8fb60daSJes Sorensen }
35763e85c6fdSKevin Wolf switch(c) {
3577c9192973SStefan Hajnoczi case ':':
3578c9192973SStefan Hajnoczi missing_argument(argv[optind - 1]);
3579c9192973SStefan Hajnoczi break;
3580ef87394cSJes Sorensen case '?':
3581c9192973SStefan Hajnoczi unrecognized_option(argv[optind - 1]);
3582c9192973SStefan Hajnoczi break;
35833e85c6fdSKevin Wolf case 'h':
35843e85c6fdSKevin Wolf help();
35853e85c6fdSKevin Wolf return 0;
3586e53dbee0SKevin Wolf case 'f':
3587e53dbee0SKevin Wolf fmt = optarg;
3588e53dbee0SKevin Wolf break;
35893e85c6fdSKevin Wolf case 'F':
35903e85c6fdSKevin Wolf out_basefmt = optarg;
35913e85c6fdSKevin Wolf break;
35923e85c6fdSKevin Wolf case 'b':
35933e85c6fdSKevin Wolf out_baseimg = optarg;
35943e85c6fdSKevin Wolf break;
35953e85c6fdSKevin Wolf case 'u':
35963e85c6fdSKevin Wolf unsafe = 1;
35973e85c6fdSKevin Wolf break;
35986b837bc4SJes Sorensen case 'p':
35996b837bc4SJes Sorensen progress = 1;
36006b837bc4SJes Sorensen break;
3601661a0f71SFederico Simoncelli case 't':
3602661a0f71SFederico Simoncelli cache = optarg;
3603661a0f71SFederico Simoncelli break;
360440055951SMax Reitz case 'T':
360540055951SMax Reitz src_cache = optarg;
360640055951SMax Reitz break;
3607f382d43aSMiroslav Rezanina case 'q':
3608f382d43aSMiroslav Rezanina quiet = true;
3609f382d43aSMiroslav Rezanina break;
361099b1e646SKevin Wolf case OPTION_OBJECT:
361199b1e646SKevin Wolf user_creatable_process_cmdline(optarg);
361299b1e646SKevin Wolf break;
3613eb769f74SDaniel P. Berrange case OPTION_IMAGE_OPTS:
3614eb769f74SDaniel P. Berrange image_opts = true;
3615eb769f74SDaniel P. Berrange break;
3616335e9937SFam Zheng case 'U':
3617335e9937SFam Zheng force_share = true;
3618335e9937SFam Zheng break;
361926ea2789SAndrey Drobyshev case 'c':
362026ea2789SAndrey Drobyshev compress = true;
362126ea2789SAndrey Drobyshev break;
36223e85c6fdSKevin Wolf }
36233e85c6fdSKevin Wolf }
36243e85c6fdSKevin Wolf
3625f382d43aSMiroslav Rezanina if (quiet) {
3626f382d43aSMiroslav Rezanina progress = 0;
3627f382d43aSMiroslav Rezanina }
3628f382d43aSMiroslav Rezanina
3629ac1307abSFam Zheng if (optind != argc - 1) {
3630ac1307abSFam Zheng error_exit("Expecting one image file name");
3631ac1307abSFam Zheng }
3632ac1307abSFam Zheng if (!unsafe && !out_baseimg) {
3633ac1307abSFam Zheng error_exit("Must specify backing file (-b) or use unsafe mode (-u)");
3634b8fb60daSJes Sorensen }
36353e85c6fdSKevin Wolf filename = argv[optind++];
36363e85c6fdSKevin Wolf
36376b837bc4SJes Sorensen qemu_progress_init(progress, 2.0);
36386b837bc4SJes Sorensen qemu_progress_print(0, 100);
36396b837bc4SJes Sorensen
3640661a0f71SFederico Simoncelli flags = BDRV_O_RDWR | (unsafe ? BDRV_O_NO_BACKING : 0);
3641ce099547SKevin Wolf ret = bdrv_parse_cache_mode(cache, &flags, &writethrough);
3642661a0f71SFederico Simoncelli if (ret < 0) {
3643661a0f71SFederico Simoncelli error_report("Invalid cache option: %s", cache);
364440ed35a3SStefan Hajnoczi goto out;
3645661a0f71SFederico Simoncelli }
3646661a0f71SFederico Simoncelli
3647ce099547SKevin Wolf src_flags = 0;
3648ce099547SKevin Wolf ret = bdrv_parse_cache_mode(src_cache, &src_flags, &src_writethrough);
364940055951SMax Reitz if (ret < 0) {
365040055951SMax Reitz error_report("Invalid source cache option: %s", src_cache);
365140ed35a3SStefan Hajnoczi goto out;
365240055951SMax Reitz }
365340055951SMax Reitz
3654ce099547SKevin Wolf /* The source files are opened read-only, don't care about WCE */
3655ce099547SKevin Wolf assert((src_flags & BDRV_O_RDWR) == 0);
3656ce099547SKevin Wolf (void) src_writethrough;
3657ce099547SKevin Wolf
36583e85c6fdSKevin Wolf /*
36593e85c6fdSKevin Wolf * Open the images.
36603e85c6fdSKevin Wolf *
36613e85c6fdSKevin Wolf * Ignore the old backing file for unsafe rebase in case we want to correct
36623e85c6fdSKevin Wolf * the reference to a renamed or moved backing file.
36633e85c6fdSKevin Wolf */
3664335e9937SFam Zheng blk = img_open(image_opts, filename, fmt, flags, writethrough, quiet,
3665335e9937SFam Zheng false);
36667e7d56d9SMarkus Armbruster if (!blk) {
366740ed35a3SStefan Hajnoczi ret = -1;
366840ed35a3SStefan Hajnoczi goto out;
3669c2abccecSMORITA Kazutaka }
36707e7d56d9SMarkus Armbruster bs = blk_bs(blk);
36713e85c6fdSKevin Wolf
3672ad74751fSKevin Wolf bdrv_graph_rdlock_main_loop();
36734a2061e6SMax Reitz unfiltered_bs = bdrv_skip_filters(bs);
3674*78a9c76eSKevin Wolf unfiltered_bs_cow = bdrv_cow_bs(unfiltered_bs);
3675ad74751fSKevin Wolf bdrv_graph_rdunlock_main_loop();
36764a2061e6SMax Reitz
367726ea2789SAndrey Drobyshev if (compress && !block_driver_can_compress(unfiltered_bs->drv)) {
367826ea2789SAndrey Drobyshev error_report("Compression not supported for this file format");
367926ea2789SAndrey Drobyshev ret = -1;
368026ea2789SAndrey Drobyshev goto out;
368126ea2789SAndrey Drobyshev } else if (compress) {
368226ea2789SAndrey Drobyshev write_flags |= BDRV_REQ_WRITE_COMPRESSED;
368326ea2789SAndrey Drobyshev }
368426ea2789SAndrey Drobyshev
36853e85c6fdSKevin Wolf if (out_basefmt != NULL) {
3686644483d9SMax Reitz if (bdrv_find_format(out_basefmt) == NULL) {
368715654a6dSJes Sorensen error_report("Invalid format name: '%s'", out_basefmt);
3688c2abccecSMORITA Kazutaka ret = -1;
3689c2abccecSMORITA Kazutaka goto out;
36903e85c6fdSKevin Wolf }
36913e85c6fdSKevin Wolf }
36923e85c6fdSKevin Wolf
369312df580bSAndrey Drobyshev /*
369426ea2789SAndrey Drobyshev * We need overlay subcluster size (or cluster size in case writes are
369526ea2789SAndrey Drobyshev * compressed) to make sure write requests are aligned.
369612df580bSAndrey Drobyshev */
369712df580bSAndrey Drobyshev ret = bdrv_get_info(unfiltered_bs, &bdi);
369812df580bSAndrey Drobyshev if (ret < 0) {
369912df580bSAndrey Drobyshev error_report("could not get block driver info");
370012df580bSAndrey Drobyshev goto out;
370112df580bSAndrey Drobyshev } else if (bdi.subcluster_size == 0) {
370226ea2789SAndrey Drobyshev bdi.cluster_size = bdi.subcluster_size = 1;
370312df580bSAndrey Drobyshev }
370412df580bSAndrey Drobyshev
370526ea2789SAndrey Drobyshev write_align = compress ? bdi.cluster_size : bdi.subcluster_size;
370612df580bSAndrey Drobyshev
37073e85c6fdSKevin Wolf /* For safe rebasing we need to compare old and new backing file */
370840ed35a3SStefan Hajnoczi if (!unsafe) {
3709644483d9SMax Reitz QDict *options = NULL;
3710*78a9c76eSKevin Wolf BlockDriverState *base_bs;
3711*78a9c76eSKevin Wolf
3712*78a9c76eSKevin Wolf bdrv_graph_rdlock_main_loop();
3713*78a9c76eSKevin Wolf base_bs = bdrv_cow_bs(unfiltered_bs);
3714*78a9c76eSKevin Wolf bdrv_graph_rdunlock_main_loop();
37153e85c6fdSKevin Wolf
37164ebe0617SSam Eiderman if (base_bs) {
3717d861ab3aSKevin Wolf blk_old_backing = blk_new(qemu_get_aio_context(),
3718d861ab3aSKevin Wolf BLK_PERM_CONSISTENT_READ,
37194ebe0617SSam Eiderman BLK_PERM_ALL);
37204ebe0617SSam Eiderman ret = blk_insert_bs(blk_old_backing, base_bs,
37214ebe0617SSam Eiderman &local_err);
37224ebe0617SSam Eiderman if (ret < 0) {
3723c29b77f9SMarkus Armbruster error_reportf_err(local_err,
37244ebe0617SSam Eiderman "Could not reuse old backing file '%s': ",
37254ebe0617SSam Eiderman base_bs->filename);
3726c2abccecSMORITA Kazutaka goto out;
37273e85c6fdSKevin Wolf }
372835ddd930SMax Reitz } else {
372935ddd930SMax Reitz blk_old_backing = NULL;
373035ddd930SMax Reitz }
3731644483d9SMax Reitz
3732a616673dSAlex Bligh if (out_baseimg[0]) {
3733d16699b6SMax Reitz const char *overlay_filename;
3734d16699b6SMax Reitz char *out_real_path;
3735d16699b6SMax Reitz
3736644483d9SMax Reitz options = qdict_new();
3737335e9937SFam Zheng if (out_basefmt) {
373846f5ac20SEric Blake qdict_put_str(options, "driver", out_basefmt);
3739335e9937SFam Zheng }
3740335e9937SFam Zheng if (force_share) {
3741335e9937SFam Zheng qdict_put_bool(options, BDRV_OPT_FORCE_SHARE, true);
3742644483d9SMax Reitz }
3743644483d9SMax Reitz
3744b7cfc7d5SKevin Wolf bdrv_graph_rdlock_main_loop();
3745f30c66baSMax Reitz bdrv_refresh_filename(bs);
3746b7cfc7d5SKevin Wolf bdrv_graph_rdunlock_main_loop();
3747d16699b6SMax Reitz overlay_filename = bs->exact_filename[0] ? bs->exact_filename
3748d16699b6SMax Reitz : bs->filename;
3749645ae7d8SMax Reitz out_real_path =
3750d16699b6SMax Reitz bdrv_get_full_backing_filename_from_filename(overlay_filename,
3751d16699b6SMax Reitz out_baseimg,
3752d16699b6SMax Reitz &local_err);
3753d16699b6SMax Reitz if (local_err) {
3754f22356d9SMax Reitz qobject_unref(options);
3755d16699b6SMax Reitz error_reportf_err(local_err,
3756d16699b6SMax Reitz "Could not resolve backing filename: ");
3757d16699b6SMax Reitz ret = -1;
3758d16699b6SMax Reitz goto out;
3759d16699b6SMax Reitz }
3760d16699b6SMax Reitz
3761863cc78fSSam Eiderman /*
3762863cc78fSSam Eiderman * Find out whether we rebase an image on top of a previous image
3763863cc78fSSam Eiderman * in its chain.
3764863cc78fSSam Eiderman */
3765863cc78fSSam Eiderman prefix_chain_bs = bdrv_find_backing_image(bs, out_real_path);
3766330c7295SSam Eiderman if (prefix_chain_bs) {
3767f22356d9SMax Reitz qobject_unref(options);
3768330c7295SSam Eiderman g_free(out_real_path);
3769f22356d9SMax Reitz
3770d861ab3aSKevin Wolf blk_new_backing = blk_new(qemu_get_aio_context(),
3771d861ab3aSKevin Wolf BLK_PERM_CONSISTENT_READ,
3772330c7295SSam Eiderman BLK_PERM_ALL);
3773330c7295SSam Eiderman ret = blk_insert_bs(blk_new_backing, prefix_chain_bs,
3774330c7295SSam Eiderman &local_err);
3775330c7295SSam Eiderman if (ret < 0) {
3776330c7295SSam Eiderman error_reportf_err(local_err,
3777330c7295SSam Eiderman "Could not reuse backing file '%s': ",
3778330c7295SSam Eiderman out_baseimg);
3779330c7295SSam Eiderman goto out;
3780330c7295SSam Eiderman }
3781330c7295SSam Eiderman } else {
3782d16699b6SMax Reitz blk_new_backing = blk_new_open(out_real_path, NULL,
3783644483d9SMax Reitz options, src_flags, &local_err);
3784d16699b6SMax Reitz g_free(out_real_path);
3785644483d9SMax Reitz if (!blk_new_backing) {
3786c29b77f9SMarkus Armbruster error_reportf_err(local_err,
3787c29b77f9SMarkus Armbruster "Could not open new backing file '%s': ",
3788c29b77f9SMarkus Armbruster out_baseimg);
3789e84a0dd5SXu Tian ret = -1;
3790c2abccecSMORITA Kazutaka goto out;
37913e85c6fdSKevin Wolf }
37923e85c6fdSKevin Wolf }
3793a616673dSAlex Bligh }
3794330c7295SSam Eiderman }
37953e85c6fdSKevin Wolf
37963e85c6fdSKevin Wolf /*
37973e85c6fdSKevin Wolf * Check each unallocated cluster in the COW file. If it is unallocated,
37983e85c6fdSKevin Wolf * accesses go to the backing file. We must therefore compare this cluster
37993e85c6fdSKevin Wolf * in the old and new backing file, and if they differ we need to copy it
38003e85c6fdSKevin Wolf * from the old backing file into the COW file.
38013e85c6fdSKevin Wolf *
38023e85c6fdSKevin Wolf * If qemu-img crashes during this step, no harm is done. The content of
38033e85c6fdSKevin Wolf * the image is the same as the original one at any time.
38043e85c6fdSKevin Wolf */
38053e85c6fdSKevin Wolf if (!unsafe) {
380641536287SEric Blake int64_t size;
380735ddd930SMax Reitz int64_t old_backing_size = 0;
380841536287SEric Blake int64_t new_backing_size = 0;
380941536287SEric Blake uint64_t offset;
381012df580bSAndrey Drobyshev int64_t n, n_old = 0, n_new = 0;
38111f710495SKevin Wolf float local_progress = 0;
3812d6771bfaSTeLeMan
3813ce8b8f9fSAndrey Drobyshev if (blk_old_backing && bdrv_opt_mem_align(blk_bs(blk_old_backing)) >
3814ce8b8f9fSAndrey Drobyshev bdrv_opt_mem_align(blk_bs(blk))) {
3815ce8b8f9fSAndrey Drobyshev buf_old = blk_blockalign(blk_old_backing, IO_BUF_SIZE);
3816ce8b8f9fSAndrey Drobyshev } else {
3817f1d3cd79SMax Reitz buf_old = blk_blockalign(blk, IO_BUF_SIZE);
3818ce8b8f9fSAndrey Drobyshev }
3819ce8b8f9fSAndrey Drobyshev buf_new = blk_blockalign(blk_new_backing, IO_BUF_SIZE);
38203e85c6fdSKevin Wolf
382141536287SEric Blake size = blk_getlength(blk);
382241536287SEric Blake if (size < 0) {
382352bf1e72SMarkus Armbruster error_report("Could not get size of '%s': %s",
382441536287SEric Blake filename, strerror(-size));
382552bf1e72SMarkus Armbruster ret = -1;
382652bf1e72SMarkus Armbruster goto out;
382752bf1e72SMarkus Armbruster }
382835ddd930SMax Reitz if (blk_old_backing) {
382941536287SEric Blake old_backing_size = blk_getlength(blk_old_backing);
383041536287SEric Blake if (old_backing_size < 0) {
38319a29e18fSJeff Cody char backing_name[PATH_MAX];
383252bf1e72SMarkus Armbruster
383335ddd930SMax Reitz bdrv_get_backing_filename(bs, backing_name,
383435ddd930SMax Reitz sizeof(backing_name));
383552bf1e72SMarkus Armbruster error_report("Could not get size of '%s': %s",
383641536287SEric Blake backing_name, strerror(-old_backing_size));
383752bf1e72SMarkus Armbruster ret = -1;
383852bf1e72SMarkus Armbruster goto out;
383952bf1e72SMarkus Armbruster }
384035ddd930SMax Reitz }
3841f1d3cd79SMax Reitz if (blk_new_backing) {
384241536287SEric Blake new_backing_size = blk_getlength(blk_new_backing);
384341536287SEric Blake if (new_backing_size < 0) {
384452bf1e72SMarkus Armbruster error_report("Could not get size of '%s': %s",
384541536287SEric Blake out_baseimg, strerror(-new_backing_size));
384652bf1e72SMarkus Armbruster ret = -1;
384752bf1e72SMarkus Armbruster goto out;
384852bf1e72SMarkus Armbruster }
3849a616673dSAlex Bligh }
38503e85c6fdSKevin Wolf
385141536287SEric Blake if (size != 0) {
385241536287SEric Blake local_progress = (float)100 / (size / MIN(size, IO_BUF_SIZE));
38531f710495SKevin Wolf }
38541f710495SKevin Wolf
385541536287SEric Blake for (offset = 0; offset < size; offset += n) {
385612df580bSAndrey Drobyshev bool old_backing_eof = false;
385712df580bSAndrey Drobyshev int64_t n_alloc;
38581c6e8779SMax Reitz
385941536287SEric Blake /* How many bytes can we handle with the next read? */
386041536287SEric Blake n = MIN(IO_BUF_SIZE, size - offset);
38613e85c6fdSKevin Wolf
38623e85c6fdSKevin Wolf /* If the cluster is allocated, we don't need to take action */
38634a2061e6SMax Reitz ret = bdrv_is_allocated(unfiltered_bs, offset, n, &n);
3864d663640cSPaolo Bonzini if (ret < 0) {
3865d663640cSPaolo Bonzini error_report("error while reading image metadata: %s",
3866d663640cSPaolo Bonzini strerror(-ret));
3867d663640cSPaolo Bonzini goto out;
3868d663640cSPaolo Bonzini }
3869cc60e327SKevin Wolf if (ret) {
38703e85c6fdSKevin Wolf continue;
38713e85c6fdSKevin Wolf }
38723e85c6fdSKevin Wolf
3873863cc78fSSam Eiderman if (prefix_chain_bs) {
38748b097fd6SAndrey Drobyshev uint64_t bytes = n;
38758b097fd6SAndrey Drobyshev
3876863cc78fSSam Eiderman /*
3877863cc78fSSam Eiderman * If cluster wasn't changed since prefix_chain, we don't need
3878863cc78fSSam Eiderman * to take action
3879863cc78fSSam Eiderman */
3880*78a9c76eSKevin Wolf ret = bdrv_is_allocated_above(unfiltered_bs_cow,
38814a2061e6SMax Reitz prefix_chain_bs, false,
38824a2061e6SMax Reitz offset, n, &n);
3883863cc78fSSam Eiderman if (ret < 0) {
3884863cc78fSSam Eiderman error_report("error while reading image metadata: %s",
3885863cc78fSSam Eiderman strerror(-ret));
3886863cc78fSSam Eiderman goto out;
3887863cc78fSSam Eiderman }
38888b097fd6SAndrey Drobyshev if (!ret && n) {
3889863cc78fSSam Eiderman continue;
3890863cc78fSSam Eiderman }
38918b097fd6SAndrey Drobyshev if (!n) {
38928b097fd6SAndrey Drobyshev /*
38938b097fd6SAndrey Drobyshev * If we've reached EOF of the old backing, it means that
38948b097fd6SAndrey Drobyshev * offsets beyond the old backing size were read as zeroes.
38958b097fd6SAndrey Drobyshev * Now we will need to explicitly zero the cluster in
38968b097fd6SAndrey Drobyshev * order to preserve that state after the rebase.
38978b097fd6SAndrey Drobyshev */
38988b097fd6SAndrey Drobyshev n = bytes;
38998b097fd6SAndrey Drobyshev }
3900863cc78fSSam Eiderman }
3901863cc78fSSam Eiderman
390287a1b3e3SKevin Wolf /*
390312df580bSAndrey Drobyshev * At this point we know that the region [offset; offset + n)
390412df580bSAndrey Drobyshev * is unallocated within the target image. This region might be
390512df580bSAndrey Drobyshev * unaligned to the target image's (sub)cluster boundaries, as
390612df580bSAndrey Drobyshev * old backing may have smaller clusters (or have subclusters).
390712df580bSAndrey Drobyshev * We extend it to the aligned boundaries to avoid CoW on
390812df580bSAndrey Drobyshev * partial writes in blk_pwrite(),
390912df580bSAndrey Drobyshev */
391012df580bSAndrey Drobyshev n += offset - QEMU_ALIGN_DOWN(offset, write_align);
391112df580bSAndrey Drobyshev offset = QEMU_ALIGN_DOWN(offset, write_align);
391212df580bSAndrey Drobyshev n += QEMU_ALIGN_UP(offset + n, write_align) - (offset + n);
391312df580bSAndrey Drobyshev n = MIN(n, size - offset);
391412df580bSAndrey Drobyshev assert(!bdrv_is_allocated(unfiltered_bs, offset, n, &n_alloc) &&
391512df580bSAndrey Drobyshev n_alloc == n);
391612df580bSAndrey Drobyshev
391712df580bSAndrey Drobyshev /*
391812df580bSAndrey Drobyshev * Much like with the target image, we'll try to read as much
391912df580bSAndrey Drobyshev * of the old and new backings as we can.
392012df580bSAndrey Drobyshev */
392112df580bSAndrey Drobyshev n_old = MIN(n, MAX(0, old_backing_size - (int64_t) offset));
392212df580bSAndrey Drobyshev n_new = MIN(n, MAX(0, new_backing_size - (int64_t) offset));
392312df580bSAndrey Drobyshev
392412df580bSAndrey Drobyshev /*
392587a1b3e3SKevin Wolf * Read old and new backing file and take into consideration that
392687a1b3e3SKevin Wolf * backing files may be smaller than the COW image.
392787a1b3e3SKevin Wolf */
392812df580bSAndrey Drobyshev memset(buf_old + n_old, 0, n - n_old);
392912df580bSAndrey Drobyshev if (!n_old) {
393012df580bSAndrey Drobyshev old_backing_eof = true;
393187a1b3e3SKevin Wolf } else {
393212df580bSAndrey Drobyshev ret = blk_pread(blk_old_backing, offset, n_old, buf_old, 0);
3933c2abccecSMORITA Kazutaka if (ret < 0) {
393415654a6dSJes Sorensen error_report("error while reading from old backing file");
3935c2abccecSMORITA Kazutaka goto out;
39363e85c6fdSKevin Wolf }
393787a1b3e3SKevin Wolf }
393887a1b3e3SKevin Wolf
393912df580bSAndrey Drobyshev memset(buf_new + n_new, 0, n - n_new);
394012df580bSAndrey Drobyshev if (n_new) {
394112df580bSAndrey Drobyshev ret = blk_pread(blk_new_backing, offset, n_new, buf_new, 0);
3942c2abccecSMORITA Kazutaka if (ret < 0) {
394315654a6dSJes Sorensen error_report("error while reading from new backing file");
3944c2abccecSMORITA Kazutaka goto out;
39453e85c6fdSKevin Wolf }
394687a1b3e3SKevin Wolf }
39473e85c6fdSKevin Wolf
39483e85c6fdSKevin Wolf /* If they differ, we need to write to the COW file */
39493e85c6fdSKevin Wolf uint64_t written = 0;
39503e85c6fdSKevin Wolf
395141536287SEric Blake while (written < n) {
3952dc61cd3bSEric Blake int64_t pnum;
39533e85c6fdSKevin Wolf
395441536287SEric Blake if (compare_buffers(buf_old + written, buf_new + written,
395512df580bSAndrey Drobyshev n - written, write_align, &pnum))
39563e85c6fdSKevin Wolf {
395712df580bSAndrey Drobyshev if (old_backing_eof) {
39581c6e8779SMax Reitz ret = blk_pwrite_zeroes(blk, offset + written, pnum, 0);
39591c6e8779SMax Reitz } else {
396012df580bSAndrey Drobyshev assert(written + pnum <= IO_BUF_SIZE);
3961a9262f55SAlberto Faria ret = blk_pwrite(blk, offset + written, pnum,
396226ea2789SAndrey Drobyshev buf_old + written, write_flags);
39631c6e8779SMax Reitz }
39643e85c6fdSKevin Wolf if (ret < 0) {
396515654a6dSJes Sorensen error_report("Error while writing to COW image: %s",
39663e85c6fdSKevin Wolf strerror(-ret));
3967c2abccecSMORITA Kazutaka goto out;
39683e85c6fdSKevin Wolf }
39693e85c6fdSKevin Wolf }
39703e85c6fdSKevin Wolf
39713e85c6fdSKevin Wolf written += pnum;
397212df580bSAndrey Drobyshev if (offset + written >= old_backing_size) {
397312df580bSAndrey Drobyshev old_backing_eof = true;
397412df580bSAndrey Drobyshev }
39753e85c6fdSKevin Wolf }
39766b837bc4SJes Sorensen qemu_progress_print(local_progress, 100);
39773e85c6fdSKevin Wolf }
39783e85c6fdSKevin Wolf }
39793e85c6fdSKevin Wolf
39803e85c6fdSKevin Wolf /*
39813e85c6fdSKevin Wolf * Change the backing file. All clusters that are different from the old
39823e85c6fdSKevin Wolf * backing file are overwritten in the COW file now, so the visible content
39833e85c6fdSKevin Wolf * doesn't change when we switch the backing file.
39843e85c6fdSKevin Wolf */
3985a616673dSAlex Bligh if (out_baseimg && *out_baseimg) {
39864a2061e6SMax Reitz ret = bdrv_change_backing_file(unfiltered_bs, out_baseimg, out_basefmt,
39874a2061e6SMax Reitz true);
3988a616673dSAlex Bligh } else {
39894a2061e6SMax Reitz ret = bdrv_change_backing_file(unfiltered_bs, NULL, NULL, false);
3990a616673dSAlex Bligh }
3991a616673dSAlex Bligh
39923e85c6fdSKevin Wolf if (ret == -ENOSPC) {
399315654a6dSJes Sorensen error_report("Could not change the backing file to '%s': No "
399415654a6dSJes Sorensen "space left in the file header", out_baseimg);
3995a7cd44beSEric Blake } else if (ret == -EINVAL && out_baseimg && !out_basefmt) {
3996a7cd44beSEric Blake error_report("Could not change the backing file to '%s': backing "
3997a7cd44beSEric Blake "format must be specified", out_baseimg);
39983e85c6fdSKevin Wolf } else if (ret < 0) {
399915654a6dSJes Sorensen error_report("Could not change the backing file to '%s': %s",
40003e85c6fdSKevin Wolf out_baseimg, strerror(-ret));
40013e85c6fdSKevin Wolf }
40023e85c6fdSKevin Wolf
40036b837bc4SJes Sorensen qemu_progress_print(100, 0);
40043e85c6fdSKevin Wolf /*
40053e85c6fdSKevin Wolf * TODO At this point it is possible to check if any clusters that are
40063e85c6fdSKevin Wolf * allocated in the COW file are the same in the backing file. If so, they
40073e85c6fdSKevin Wolf * could be dropped from the COW file. Don't do this before switching the
40083e85c6fdSKevin Wolf * backing file, in case of a crash this would lead to corruption.
40093e85c6fdSKevin Wolf */
4010c2abccecSMORITA Kazutaka out:
40116b837bc4SJes Sorensen qemu_progress_end();
40123e85c6fdSKevin Wolf /* Cleanup */
40133e85c6fdSKevin Wolf if (!unsafe) {
401426f54e9aSMarkus Armbruster blk_unref(blk_old_backing);
401526f54e9aSMarkus Armbruster blk_unref(blk_new_backing);
4016eb863addSKevin Wolf }
4017396374caSPaolo Bonzini qemu_vfree(buf_old);
4018396374caSPaolo Bonzini qemu_vfree(buf_new);
40193e85c6fdSKevin Wolf
402026f54e9aSMarkus Armbruster blk_unref(blk);
4021c2abccecSMORITA Kazutaka if (ret) {
4022c2abccecSMORITA Kazutaka return 1;
4023c2abccecSMORITA Kazutaka }
40243e85c6fdSKevin Wolf return 0;
40253e85c6fdSKevin Wolf }
40263e85c6fdSKevin Wolf
img_resize(int argc,char ** argv)4027ae6b0ed6SStefan Hajnoczi static int img_resize(int argc, char **argv)
4028ae6b0ed6SStefan Hajnoczi {
40296750e795SMarkus Armbruster Error *err = NULL;
4030ae6b0ed6SStefan Hajnoczi int c, ret, relative;
4031ae6b0ed6SStefan Hajnoczi const char *filename, *fmt, *size;
403209c5c6deSMax Reitz int64_t n, total_size, current_size;
4033f382d43aSMiroslav Rezanina bool quiet = false;
403426f54e9aSMarkus Armbruster BlockBackend *blk = NULL;
4035dc5f690bSMax Reitz PreallocMode prealloc = PREALLOC_MODE_OFF;
403620caf0f7SDong Xu Wang QemuOpts *param;
40373babeb15SDaniel P. Berrange
403820caf0f7SDong Xu Wang static QemuOptsList resize_options = {
403920caf0f7SDong Xu Wang .name = "resize_options",
404020caf0f7SDong Xu Wang .head = QTAILQ_HEAD_INITIALIZER(resize_options.head),
404120caf0f7SDong Xu Wang .desc = {
4042ae6b0ed6SStefan Hajnoczi {
4043ae6b0ed6SStefan Hajnoczi .name = BLOCK_OPT_SIZE,
404420caf0f7SDong Xu Wang .type = QEMU_OPT_SIZE,
4045ae6b0ed6SStefan Hajnoczi .help = "Virtual disk size"
404620caf0f7SDong Xu Wang }, {
404720caf0f7SDong Xu Wang /* end of list */
404820caf0f7SDong Xu Wang }
4049ae6b0ed6SStefan Hajnoczi },
4050ae6b0ed6SStefan Hajnoczi };
4051eb769f74SDaniel P. Berrange bool image_opts = false;
40524ffca890SPavel Butsykin bool shrink = false;
4053ae6b0ed6SStefan Hajnoczi
4054e80fec7fSKevin Wolf /* Remove size from argv manually so that negative numbers are not treated
4055e80fec7fSKevin Wolf * as options by getopt. */
4056e80fec7fSKevin Wolf if (argc < 3) {
4057ac1307abSFam Zheng error_exit("Not enough arguments");
4058e80fec7fSKevin Wolf return 1;
4059e80fec7fSKevin Wolf }
4060e80fec7fSKevin Wolf
4061e80fec7fSKevin Wolf size = argv[--argc];
4062e80fec7fSKevin Wolf
4063e80fec7fSKevin Wolf /* Parse getopt arguments */
4064ae6b0ed6SStefan Hajnoczi fmt = NULL;
4065ae6b0ed6SStefan Hajnoczi for(;;) {
40663babeb15SDaniel P. Berrange static const struct option long_options[] = {
40673babeb15SDaniel P. Berrange {"help", no_argument, 0, 'h'},
40683babeb15SDaniel P. Berrange {"object", required_argument, 0, OPTION_OBJECT},
4069eb769f74SDaniel P. Berrange {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
4070dc5f690bSMax Reitz {"preallocation", required_argument, 0, OPTION_PREALLOCATION},
40714ffca890SPavel Butsykin {"shrink", no_argument, 0, OPTION_SHRINK},
40723babeb15SDaniel P. Berrange {0, 0, 0, 0}
40733babeb15SDaniel P. Berrange };
4074c9192973SStefan Hajnoczi c = getopt_long(argc, argv, ":f:hq",
40753babeb15SDaniel P. Berrange long_options, NULL);
4076ae6b0ed6SStefan Hajnoczi if (c == -1) {
4077ae6b0ed6SStefan Hajnoczi break;
4078ae6b0ed6SStefan Hajnoczi }
4079ae6b0ed6SStefan Hajnoczi switch(c) {
4080c9192973SStefan Hajnoczi case ':':
4081c9192973SStefan Hajnoczi missing_argument(argv[optind - 1]);
4082c9192973SStefan Hajnoczi break;
4083ef87394cSJes Sorensen case '?':
4084c9192973SStefan Hajnoczi unrecognized_option(argv[optind - 1]);
4085c9192973SStefan Hajnoczi break;
4086ae6b0ed6SStefan Hajnoczi case 'h':
4087ae6b0ed6SStefan Hajnoczi help();
4088ae6b0ed6SStefan Hajnoczi break;
4089ae6b0ed6SStefan Hajnoczi case 'f':
4090ae6b0ed6SStefan Hajnoczi fmt = optarg;
4091ae6b0ed6SStefan Hajnoczi break;
4092f382d43aSMiroslav Rezanina case 'q':
4093f382d43aSMiroslav Rezanina quiet = true;
4094f382d43aSMiroslav Rezanina break;
409599b1e646SKevin Wolf case OPTION_OBJECT:
409699b1e646SKevin Wolf user_creatable_process_cmdline(optarg);
409799b1e646SKevin Wolf break;
4098eb769f74SDaniel P. Berrange case OPTION_IMAGE_OPTS:
4099eb769f74SDaniel P. Berrange image_opts = true;
4100eb769f74SDaniel P. Berrange break;
4101dc5f690bSMax Reitz case OPTION_PREALLOCATION:
4102f7abe0ecSMarc-André Lureau prealloc = qapi_enum_parse(&PreallocMode_lookup, optarg,
410306c60b6cSMarkus Armbruster PREALLOC_MODE__MAX, NULL);
4104dc5f690bSMax Reitz if (prealloc == PREALLOC_MODE__MAX) {
4105dc5f690bSMax Reitz error_report("Invalid preallocation mode '%s'", optarg);
4106dc5f690bSMax Reitz return 1;
4107dc5f690bSMax Reitz }
4108dc5f690bSMax Reitz break;
41094ffca890SPavel Butsykin case OPTION_SHRINK:
41104ffca890SPavel Butsykin shrink = true;
41114ffca890SPavel Butsykin break;
4112ae6b0ed6SStefan Hajnoczi }
4113ae6b0ed6SStefan Hajnoczi }
4114fc11eb26SKevin Wolf if (optind != argc - 1) {
4115be8fbd47SMax Reitz error_exit("Expecting image file name and size");
4116ae6b0ed6SStefan Hajnoczi }
4117ae6b0ed6SStefan Hajnoczi filename = argv[optind++];
4118ae6b0ed6SStefan Hajnoczi
4119ae6b0ed6SStefan Hajnoczi /* Choose grow, shrink, or absolute resize mode */
4120ae6b0ed6SStefan Hajnoczi switch (size[0]) {
4121ae6b0ed6SStefan Hajnoczi case '+':
4122ae6b0ed6SStefan Hajnoczi relative = 1;
4123ae6b0ed6SStefan Hajnoczi size++;
4124ae6b0ed6SStefan Hajnoczi break;
4125ae6b0ed6SStefan Hajnoczi case '-':
4126ae6b0ed6SStefan Hajnoczi relative = -1;
4127ae6b0ed6SStefan Hajnoczi size++;
4128ae6b0ed6SStefan Hajnoczi break;
4129ae6b0ed6SStefan Hajnoczi default:
4130ae6b0ed6SStefan Hajnoczi relative = 0;
4131ae6b0ed6SStefan Hajnoczi break;
4132ae6b0ed6SStefan Hajnoczi }
4133ae6b0ed6SStefan Hajnoczi
4134ae6b0ed6SStefan Hajnoczi /* Parse size */
413587ea75d5SPeter Crosthwaite param = qemu_opts_create(&resize_options, NULL, 0, &error_abort);
4136235e59cfSMarkus Armbruster if (!qemu_opt_set(param, BLOCK_OPT_SIZE, size, &err)) {
41376750e795SMarkus Armbruster error_report_err(err);
41382a81998aSJes Sorensen ret = -1;
413920caf0f7SDong Xu Wang qemu_opts_del(param);
41402a81998aSJes Sorensen goto out;
4141ae6b0ed6SStefan Hajnoczi }
414220caf0f7SDong Xu Wang n = qemu_opt_get_size(param, BLOCK_OPT_SIZE, 0);
414320caf0f7SDong Xu Wang qemu_opts_del(param);
4144ae6b0ed6SStefan Hajnoczi
4145efaa7c4eSMax Reitz blk = img_open(image_opts, filename, fmt,
4146335e9937SFam Zheng BDRV_O_RDWR | BDRV_O_RESIZE, false, quiet,
4147335e9937SFam Zheng false);
41487e7d56d9SMarkus Armbruster if (!blk) {
41492a81998aSJes Sorensen ret = -1;
41502a81998aSJes Sorensen goto out;
4151c2abccecSMORITA Kazutaka }
4152ae6b0ed6SStefan Hajnoczi
4153dc5f690bSMax Reitz current_size = blk_getlength(blk);
4154dc5f690bSMax Reitz if (current_size < 0) {
4155dc5f690bSMax Reitz error_report("Failed to inquire current image length: %s",
4156dc5f690bSMax Reitz strerror(-current_size));
4157dc5f690bSMax Reitz ret = -1;
4158dc5f690bSMax Reitz goto out;
4159dc5f690bSMax Reitz }
4160dc5f690bSMax Reitz
4161ae6b0ed6SStefan Hajnoczi if (relative) {
4162dc5f690bSMax Reitz total_size = current_size + n * relative;
4163ae6b0ed6SStefan Hajnoczi } else {
4164ae6b0ed6SStefan Hajnoczi total_size = n;
4165ae6b0ed6SStefan Hajnoczi }
4166ae6b0ed6SStefan Hajnoczi if (total_size <= 0) {
416715654a6dSJes Sorensen error_report("New image size must be positive");
4168c2abccecSMORITA Kazutaka ret = -1;
4169c2abccecSMORITA Kazutaka goto out;
4170ae6b0ed6SStefan Hajnoczi }
4171ae6b0ed6SStefan Hajnoczi
4172dc5f690bSMax Reitz if (total_size <= current_size && prealloc != PREALLOC_MODE_OFF) {
4173dc5f690bSMax Reitz error_report("Preallocation can only be used for growing images");
4174dc5f690bSMax Reitz ret = -1;
4175dc5f690bSMax Reitz goto out;
4176dc5f690bSMax Reitz }
4177dc5f690bSMax Reitz
41784ffca890SPavel Butsykin if (total_size < current_size && !shrink) {
41791c404d75SKevin Wolf error_report("Use the --shrink option to perform a shrink operation.");
41804ffca890SPavel Butsykin warn_report("Shrinking an image will delete all data beyond the "
41814ffca890SPavel Butsykin "shrunken image's end. Before performing such an "
41824ffca890SPavel Butsykin "operation, make sure there is no important data there.");
41834ffca890SPavel Butsykin ret = -1;
41844ffca890SPavel Butsykin goto out;
41854ffca890SPavel Butsykin }
41864ffca890SPavel Butsykin
4187e8d04f92SMax Reitz /*
4188e8d04f92SMax Reitz * The user expects the image to have the desired size after
4189e8d04f92SMax Reitz * resizing, so pass @exact=true. It is of no use to report
4190e8d04f92SMax Reitz * success when the image has not actually been resized.
4191e8d04f92SMax Reitz */
41928c6242b6SKevin Wolf ret = blk_truncate(blk, total_size, true, prealloc, 0, &err);
419309c5c6deSMax Reitz if (!ret) {
41945279b303SMax Reitz qprintf(quiet, "Image resized.\n");
419509c5c6deSMax Reitz } else {
419609c5c6deSMax Reitz error_report_err(err);
419709c5c6deSMax Reitz }
4198c2abccecSMORITA Kazutaka out:
419926f54e9aSMarkus Armbruster blk_unref(blk);
4200c2abccecSMORITA Kazutaka if (ret) {
4201c2abccecSMORITA Kazutaka return 1;
4202c2abccecSMORITA Kazutaka }
4203ae6b0ed6SStefan Hajnoczi return 0;
4204ae6b0ed6SStefan Hajnoczi }
4205ae6b0ed6SStefan Hajnoczi
amend_status_cb(BlockDriverState * bs,int64_t offset,int64_t total_work_size,void * opaque)420676a3a34dSMax Reitz static void amend_status_cb(BlockDriverState *bs,
42078b13976dSMax Reitz int64_t offset, int64_t total_work_size,
42088b13976dSMax Reitz void *opaque)
420976a3a34dSMax Reitz {
421076a3a34dSMax Reitz qemu_progress_print(100.f * offset / total_work_size, 0);
421176a3a34dSMax Reitz }
421276a3a34dSMax Reitz
print_amend_option_help(const char * format)421351641351SMax Reitz static int print_amend_option_help(const char *format)
421451641351SMax Reitz {
421551641351SMax Reitz BlockDriver *drv;
421651641351SMax Reitz
4217bd131d67SKevin Wolf GRAPH_RDLOCK_GUARD_MAINLOOP();
4218bd131d67SKevin Wolf
421951641351SMax Reitz /* Find driver and parse its options */
422051641351SMax Reitz drv = bdrv_find_format(format);
422151641351SMax Reitz if (!drv) {
422251641351SMax Reitz error_report("Unknown file format '%s'", format);
422351641351SMax Reitz return 1;
422451641351SMax Reitz }
422551641351SMax Reitz
422651641351SMax Reitz if (!drv->bdrv_amend_options) {
422751641351SMax Reitz error_report("Format driver '%s' does not support option amendment",
422851641351SMax Reitz format);
422951641351SMax Reitz return 1;
423051641351SMax Reitz }
423151641351SMax Reitz
4232df373fb0SMaxim Levitsky /* Every driver supporting amendment must have amend_opts */
4233df373fb0SMaxim Levitsky assert(drv->amend_opts);
423451641351SMax Reitz
42350b6786a9SMaxim Levitsky printf("Amend options for '%s':\n", format);
4236df373fb0SMaxim Levitsky qemu_opts_print_help(drv->amend_opts, false);
423751641351SMax Reitz return 0;
423851641351SMax Reitz }
423951641351SMax Reitz
img_amend(int argc,char ** argv)42406f176b48SMax Reitz static int img_amend(int argc, char **argv)
42416f176b48SMax Reitz {
4242dc523cd3SMarkus Armbruster Error *err = NULL;
42436f176b48SMax Reitz int c, ret = 0;
42446f176b48SMax Reitz char *options = NULL;
4245df373fb0SMaxim Levitsky QemuOptsList *amend_opts = NULL;
424683d0521aSChunyan Liu QemuOpts *opts = NULL;
4247bd39e6edSMax Reitz const char *fmt = NULL, *filename, *cache;
4248bd39e6edSMax Reitz int flags;
4249ce099547SKevin Wolf bool writethrough;
425076a3a34dSMax Reitz bool quiet = false, progress = false;
425126f54e9aSMarkus Armbruster BlockBackend *blk = NULL;
42526f176b48SMax Reitz BlockDriverState *bs = NULL;
4253eb769f74SDaniel P. Berrange bool image_opts = false;
4254a3579bfaSMaxim Levitsky bool force = false;
42556f176b48SMax Reitz
4256bd39e6edSMax Reitz cache = BDRV_DEFAULT_CACHE;
42576f176b48SMax Reitz for (;;) {
42583babeb15SDaniel P. Berrange static const struct option long_options[] = {
42593babeb15SDaniel P. Berrange {"help", no_argument, 0, 'h'},
42603babeb15SDaniel P. Berrange {"object", required_argument, 0, OPTION_OBJECT},
4261eb769f74SDaniel P. Berrange {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
4262a3579bfaSMaxim Levitsky {"force", no_argument, 0, OPTION_FORCE},
42633babeb15SDaniel P. Berrange {0, 0, 0, 0}
42643babeb15SDaniel P. Berrange };
4265c9192973SStefan Hajnoczi c = getopt_long(argc, argv, ":ho:f:t:pq",
42663babeb15SDaniel P. Berrange long_options, NULL);
42676f176b48SMax Reitz if (c == -1) {
42686f176b48SMax Reitz break;
42696f176b48SMax Reitz }
42706f176b48SMax Reitz
42716f176b48SMax Reitz switch (c) {
4272c9192973SStefan Hajnoczi case ':':
4273c9192973SStefan Hajnoczi missing_argument(argv[optind - 1]);
4274c9192973SStefan Hajnoczi break;
42756f176b48SMax Reitz case '?':
4276c9192973SStefan Hajnoczi unrecognized_option(argv[optind - 1]);
4277c9192973SStefan Hajnoczi break;
4278c9192973SStefan Hajnoczi case 'h':
42796f176b48SMax Reitz help();
42806f176b48SMax Reitz break;
42816f176b48SMax Reitz case 'o':
42826d2b5cbaSMarkus Armbruster if (accumulate_options(&options, optarg) < 0) {
4283626f84f3SKevin Wolf ret = -1;
4284e814dffcSMax Reitz goto out_no_progress;
4285626f84f3SKevin Wolf }
42866f176b48SMax Reitz break;
42876f176b48SMax Reitz case 'f':
42886f176b48SMax Reitz fmt = optarg;
42896f176b48SMax Reitz break;
4290bd39e6edSMax Reitz case 't':
4291bd39e6edSMax Reitz cache = optarg;
4292bd39e6edSMax Reitz break;
429376a3a34dSMax Reitz case 'p':
429476a3a34dSMax Reitz progress = true;
429576a3a34dSMax Reitz break;
42966f176b48SMax Reitz case 'q':
42976f176b48SMax Reitz quiet = true;
42986f176b48SMax Reitz break;
42993babeb15SDaniel P. Berrange case OPTION_OBJECT:
430099b1e646SKevin Wolf user_creatable_process_cmdline(optarg);
43013babeb15SDaniel P. Berrange break;
4302eb769f74SDaniel P. Berrange case OPTION_IMAGE_OPTS:
4303eb769f74SDaniel P. Berrange image_opts = true;
4304eb769f74SDaniel P. Berrange break;
4305a3579bfaSMaxim Levitsky case OPTION_FORCE:
4306a3579bfaSMaxim Levitsky force = true;
4307a3579bfaSMaxim Levitsky break;
43086f176b48SMax Reitz }
43096f176b48SMax Reitz }
43106f176b48SMax Reitz
43116f176b48SMax Reitz if (!options) {
4312ac1307abSFam Zheng error_exit("Must specify options (-o)");
43136f176b48SMax Reitz }
43146f176b48SMax Reitz
431576a3a34dSMax Reitz if (quiet) {
431676a3a34dSMax Reitz progress = false;
431776a3a34dSMax Reitz }
431876a3a34dSMax Reitz qemu_progress_init(progress, 1.0);
431976a3a34dSMax Reitz
4320a283cb6eSKevin Wolf filename = (optind == argc - 1) ? argv[argc - 1] : NULL;
4321a283cb6eSKevin Wolf if (fmt && has_help_option(options)) {
4322a283cb6eSKevin Wolf /* If a format is explicitly specified (and possibly no filename is
4323a283cb6eSKevin Wolf * given), print option help here */
432451641351SMax Reitz ret = print_amend_option_help(fmt);
4325a283cb6eSKevin Wolf goto out;
4326a283cb6eSKevin Wolf }
4327a283cb6eSKevin Wolf
4328a283cb6eSKevin Wolf if (optind != argc - 1) {
4329b2f27e44SMax Reitz error_report("Expecting one image file name");
4330b2f27e44SMax Reitz ret = -1;
4331b2f27e44SMax Reitz goto out;
4332a283cb6eSKevin Wolf }
43336f176b48SMax Reitz
4334ce099547SKevin Wolf flags = BDRV_O_RDWR;
4335ce099547SKevin Wolf ret = bdrv_parse_cache_mode(cache, &flags, &writethrough);
4336bd39e6edSMax Reitz if (ret < 0) {
4337bd39e6edSMax Reitz error_report("Invalid cache option: %s", cache);
4338bd39e6edSMax Reitz goto out;
4339bd39e6edSMax Reitz }
4340bd39e6edSMax Reitz
4341335e9937SFam Zheng blk = img_open(image_opts, filename, fmt, flags, writethrough, quiet,
4342335e9937SFam Zheng false);
43437e7d56d9SMarkus Armbruster if (!blk) {
43446f176b48SMax Reitz ret = -1;
43456f176b48SMax Reitz goto out;
43466f176b48SMax Reitz }
43477e7d56d9SMarkus Armbruster bs = blk_bs(blk);
43486f176b48SMax Reitz
43496f176b48SMax Reitz fmt = bs->drv->format_name;
43506f176b48SMax Reitz
4351626f84f3SKevin Wolf if (has_help_option(options)) {
4352a283cb6eSKevin Wolf /* If the format was auto-detected, print option help here */
435351641351SMax Reitz ret = print_amend_option_help(fmt);
43546f176b48SMax Reitz goto out;
43556f176b48SMax Reitz }
43566f176b48SMax Reitz
4357bd131d67SKevin Wolf bdrv_graph_rdlock_main_loop();
43581f996683SMax Reitz if (!bs->drv->bdrv_amend_options) {
43591f996683SMax Reitz error_report("Format driver '%s' does not support option amendment",
4360b2439d26SMax Reitz fmt);
4361bd131d67SKevin Wolf bdrv_graph_rdunlock_main_loop();
4362b2439d26SMax Reitz ret = -1;
4363b2439d26SMax Reitz goto out;
4364b2439d26SMax Reitz }
4365b2439d26SMax Reitz
4366df373fb0SMaxim Levitsky /* Every driver supporting amendment must have amend_opts */
4367df373fb0SMaxim Levitsky assert(bs->drv->amend_opts);
43681f996683SMax Reitz
4369df373fb0SMaxim Levitsky amend_opts = qemu_opts_append(amend_opts, bs->drv->amend_opts);
4370df373fb0SMaxim Levitsky opts = qemu_opts_create(amend_opts, NULL, 0, &error_abort);
4371235e59cfSMarkus Armbruster if (!qemu_opts_do_parse(opts, options, NULL, &err)) {
43720b6786a9SMaxim Levitsky /* Try to parse options using the create options */
43730b6786a9SMaxim Levitsky amend_opts = qemu_opts_append(amend_opts, bs->drv->create_opts);
43740b6786a9SMaxim Levitsky qemu_opts_del(opts);
43750b6786a9SMaxim Levitsky opts = qemu_opts_create(amend_opts, NULL, 0, &error_abort);
43769e194e06SMarkus Armbruster if (qemu_opts_do_parse(opts, options, NULL, NULL)) {
43770b6786a9SMaxim Levitsky error_append_hint(&err,
43780b6786a9SMaxim Levitsky "This option is only supported for image creation\n");
43790b6786a9SMaxim Levitsky }
43800b6786a9SMaxim Levitsky
4381bd131d67SKevin Wolf bdrv_graph_rdunlock_main_loop();
438297a2ca7aSMarkus Armbruster error_report_err(err);
43836f176b48SMax Reitz ret = -1;
43846f176b48SMax Reitz goto out;
43856f176b48SMax Reitz }
43866f176b48SMax Reitz
438776a3a34dSMax Reitz /* In case the driver does not call amend_status_cb() */
438876a3a34dSMax Reitz qemu_progress_print(0.f, 0);
4389a3579bfaSMaxim Levitsky ret = bdrv_amend_options(bs, opts, &amend_status_cb, NULL, force, &err);
439076a3a34dSMax Reitz qemu_progress_print(100.f, 0);
4391bd131d67SKevin Wolf bdrv_graph_rdunlock_main_loop();
4392bd131d67SKevin Wolf
43936f176b48SMax Reitz if (ret < 0) {
4394d1402b50SMax Reitz error_report_err(err);
43956f176b48SMax Reitz goto out;
43966f176b48SMax Reitz }
43976f176b48SMax Reitz
43986f176b48SMax Reitz out:
439976a3a34dSMax Reitz qemu_progress_end();
440076a3a34dSMax Reitz
4401e814dffcSMax Reitz out_no_progress:
440226f54e9aSMarkus Armbruster blk_unref(blk);
440383d0521aSChunyan Liu qemu_opts_del(opts);
4404df373fb0SMaxim Levitsky qemu_opts_free(amend_opts);
4405626f84f3SKevin Wolf g_free(options);
4406626f84f3SKevin Wolf
44076f176b48SMax Reitz if (ret) {
44086f176b48SMax Reitz return 1;
44096f176b48SMax Reitz }
44106f176b48SMax Reitz return 0;
44116f176b48SMax Reitz }
44126f176b48SMax Reitz
4413b6133b8cSKevin Wolf typedef struct BenchData {
4414b6133b8cSKevin Wolf BlockBackend *blk;
4415b6133b8cSKevin Wolf uint64_t image_size;
4416b6495fa8SKevin Wolf bool write;
4417b6133b8cSKevin Wolf int bufsize;
441883de9be0SKevin Wolf int step;
4419b6133b8cSKevin Wolf int nrreq;
4420b6133b8cSKevin Wolf int n;
442155d539c8SKevin Wolf int flush_interval;
442255d539c8SKevin Wolf bool drain_on_flush;
4423b6133b8cSKevin Wolf uint8_t *buf;
4424b6133b8cSKevin Wolf QEMUIOVector *qiov;
4425b6133b8cSKevin Wolf
4426b6133b8cSKevin Wolf int in_flight;
442755d539c8SKevin Wolf bool in_flush;
4428b6133b8cSKevin Wolf uint64_t offset;
4429b6133b8cSKevin Wolf } BenchData;
4430b6133b8cSKevin Wolf
bench_undrained_flush_cb(void * opaque,int ret)443155d539c8SKevin Wolf static void bench_undrained_flush_cb(void *opaque, int ret)
443255d539c8SKevin Wolf {
443355d539c8SKevin Wolf if (ret < 0) {
4434df3c286cSMarkus Armbruster error_report("Failed flush request: %s", strerror(-ret));
443555d539c8SKevin Wolf exit(EXIT_FAILURE);
443655d539c8SKevin Wolf }
443755d539c8SKevin Wolf }
443855d539c8SKevin Wolf
bench_cb(void * opaque,int ret)4439b6133b8cSKevin Wolf static void bench_cb(void *opaque, int ret)
4440b6133b8cSKevin Wolf {
4441b6133b8cSKevin Wolf BenchData *b = opaque;
4442b6133b8cSKevin Wolf BlockAIOCB *acb;
4443b6133b8cSKevin Wolf
4444b6133b8cSKevin Wolf if (ret < 0) {
4445df3c286cSMarkus Armbruster error_report("Failed request: %s", strerror(-ret));
4446b6133b8cSKevin Wolf exit(EXIT_FAILURE);
4447b6133b8cSKevin Wolf }
444855d539c8SKevin Wolf
444955d539c8SKevin Wolf if (b->in_flush) {
445055d539c8SKevin Wolf /* Just finished a flush with drained queue: Start next requests */
445155d539c8SKevin Wolf assert(b->in_flight == 0);
445255d539c8SKevin Wolf b->in_flush = false;
445355d539c8SKevin Wolf } else if (b->in_flight > 0) {
445455d539c8SKevin Wolf int remaining = b->n - b->in_flight;
445555d539c8SKevin Wolf
4456b6133b8cSKevin Wolf b->n--;
4457b6133b8cSKevin Wolf b->in_flight--;
445855d539c8SKevin Wolf
445955d539c8SKevin Wolf /* Time for flush? Drain queue if requested, then flush */
446055d539c8SKevin Wolf if (b->flush_interval && remaining % b->flush_interval == 0) {
446155d539c8SKevin Wolf if (!b->in_flight || !b->drain_on_flush) {
446255d539c8SKevin Wolf BlockCompletionFunc *cb;
446355d539c8SKevin Wolf
446455d539c8SKevin Wolf if (b->drain_on_flush) {
446555d539c8SKevin Wolf b->in_flush = true;
446655d539c8SKevin Wolf cb = bench_cb;
446755d539c8SKevin Wolf } else {
446855d539c8SKevin Wolf cb = bench_undrained_flush_cb;
446955d539c8SKevin Wolf }
447055d539c8SKevin Wolf
447155d539c8SKevin Wolf acb = blk_aio_flush(b->blk, cb, b);
447255d539c8SKevin Wolf if (!acb) {
447355d539c8SKevin Wolf error_report("Failed to issue flush request");
447455d539c8SKevin Wolf exit(EXIT_FAILURE);
447555d539c8SKevin Wolf }
447655d539c8SKevin Wolf }
447755d539c8SKevin Wolf if (b->drain_on_flush) {
447855d539c8SKevin Wolf return;
447955d539c8SKevin Wolf }
448055d539c8SKevin Wolf }
4481b6133b8cSKevin Wolf }
4482b6133b8cSKevin Wolf
4483b6133b8cSKevin Wolf while (b->n > b->in_flight && b->in_flight < b->nrreq) {
44844baaa8c3SPaolo Bonzini int64_t offset = b->offset;
44854baaa8c3SPaolo Bonzini /* blk_aio_* might look for completed I/Os and kick bench_cb
44864baaa8c3SPaolo Bonzini * again, so make sure this operation is counted by in_flight
44874baaa8c3SPaolo Bonzini * and b->offset is ready for the next submission.
44884baaa8c3SPaolo Bonzini */
44894baaa8c3SPaolo Bonzini b->in_flight++;
44904baaa8c3SPaolo Bonzini b->offset += b->step;
44914baaa8c3SPaolo Bonzini b->offset %= b->image_size;
4492b6495fa8SKevin Wolf if (b->write) {
44934baaa8c3SPaolo Bonzini acb = blk_aio_pwritev(b->blk, offset, b->qiov, 0, bench_cb, b);
4494b6495fa8SKevin Wolf } else {
44954baaa8c3SPaolo Bonzini acb = blk_aio_preadv(b->blk, offset, b->qiov, 0, bench_cb, b);
4496b6495fa8SKevin Wolf }
4497b6133b8cSKevin Wolf if (!acb) {
4498b6133b8cSKevin Wolf error_report("Failed to issue request");
4499b6133b8cSKevin Wolf exit(EXIT_FAILURE);
4500b6133b8cSKevin Wolf }
4501b6133b8cSKevin Wolf }
4502b6133b8cSKevin Wolf }
4503b6133b8cSKevin Wolf
img_bench(int argc,char ** argv)4504b6133b8cSKevin Wolf static int img_bench(int argc, char **argv)
4505b6133b8cSKevin Wolf {
4506b6133b8cSKevin Wolf int c, ret = 0;
4507b6133b8cSKevin Wolf const char *fmt = NULL, *filename;
4508b6133b8cSKevin Wolf bool quiet = false;
4509b6133b8cSKevin Wolf bool image_opts = false;
4510b6495fa8SKevin Wolf bool is_write = false;
4511b6133b8cSKevin Wolf int count = 75000;
4512b6133b8cSKevin Wolf int depth = 64;
4513d3199a31SKevin Wolf int64_t offset = 0;
4514b6133b8cSKevin Wolf size_t bufsize = 4096;
4515b6495fa8SKevin Wolf int pattern = 0;
451683de9be0SKevin Wolf size_t step = 0;
451755d539c8SKevin Wolf int flush_interval = 0;
451855d539c8SKevin Wolf bool drain_on_flush = true;
4519b6133b8cSKevin Wolf int64_t image_size;
4520b6133b8cSKevin Wolf BlockBackend *blk = NULL;
4521b6133b8cSKevin Wolf BenchData data = {};
4522b6133b8cSKevin Wolf int flags = 0;
4523604e8613SKevin Wolf bool writethrough = false;
4524b6133b8cSKevin Wolf struct timeval t1, t2;
4525b6133b8cSKevin Wolf int i;
4526335e9937SFam Zheng bool force_share = false;
45274f384011SStefan Hajnoczi size_t buf_size = 0;
4528b6133b8cSKevin Wolf
4529b6133b8cSKevin Wolf for (;;) {
4530b6133b8cSKevin Wolf static const struct option long_options[] = {
4531b6133b8cSKevin Wolf {"help", no_argument, 0, 'h'},
453255d539c8SKevin Wolf {"flush-interval", required_argument, 0, OPTION_FLUSH_INTERVAL},
4533b6133b8cSKevin Wolf {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
4534b6495fa8SKevin Wolf {"pattern", required_argument, 0, OPTION_PATTERN},
453555d539c8SKevin Wolf {"no-drain", no_argument, 0, OPTION_NO_DRAIN},
4536335e9937SFam Zheng {"force-share", no_argument, 0, 'U'},
4537b6133b8cSKevin Wolf {0, 0, 0, 0}
4538b6133b8cSKevin Wolf };
4539cdd26774SAarushi Mehta c = getopt_long(argc, argv, ":hc:d:f:ni:o:qs:S:t:wU", long_options,
4540cdd26774SAarushi Mehta NULL);
4541b6133b8cSKevin Wolf if (c == -1) {
4542b6133b8cSKevin Wolf break;
4543b6133b8cSKevin Wolf }
4544b6133b8cSKevin Wolf
4545b6133b8cSKevin Wolf switch (c) {
4546c9192973SStefan Hajnoczi case ':':
4547c9192973SStefan Hajnoczi missing_argument(argv[optind - 1]);
4548c9192973SStefan Hajnoczi break;
4549b6133b8cSKevin Wolf case '?':
4550c9192973SStefan Hajnoczi unrecognized_option(argv[optind - 1]);
4551c9192973SStefan Hajnoczi break;
4552c9192973SStefan Hajnoczi case 'h':
4553b6133b8cSKevin Wolf help();
4554b6133b8cSKevin Wolf break;
4555b6133b8cSKevin Wolf case 'c':
4556b6133b8cSKevin Wolf {
45578b3c6792SPeter Maydell unsigned long res;
45588b3c6792SPeter Maydell
45598b3c6792SPeter Maydell if (qemu_strtoul(optarg, NULL, 0, &res) < 0 || res > INT_MAX) {
4560b6133b8cSKevin Wolf error_report("Invalid request count specified");
4561b6133b8cSKevin Wolf return 1;
4562b6133b8cSKevin Wolf }
45638b3c6792SPeter Maydell count = res;
4564b6133b8cSKevin Wolf break;
4565b6133b8cSKevin Wolf }
4566b6133b8cSKevin Wolf case 'd':
4567b6133b8cSKevin Wolf {
45688b3c6792SPeter Maydell unsigned long res;
45698b3c6792SPeter Maydell
45708b3c6792SPeter Maydell if (qemu_strtoul(optarg, NULL, 0, &res) < 0 || res > INT_MAX) {
4571b6133b8cSKevin Wolf error_report("Invalid queue depth specified");
4572b6133b8cSKevin Wolf return 1;
4573b6133b8cSKevin Wolf }
45748b3c6792SPeter Maydell depth = res;
4575b6133b8cSKevin Wolf break;
4576b6133b8cSKevin Wolf }
4577b6133b8cSKevin Wolf case 'f':
4578b6133b8cSKevin Wolf fmt = optarg;
4579b6133b8cSKevin Wolf break;
4580b6133b8cSKevin Wolf case 'n':
4581b6133b8cSKevin Wolf flags |= BDRV_O_NATIVE_AIO;
4582b6133b8cSKevin Wolf break;
4583cdd26774SAarushi Mehta case 'i':
4584cdd26774SAarushi Mehta ret = bdrv_parse_aio(optarg, &flags);
4585cdd26774SAarushi Mehta if (ret < 0) {
4586cdd26774SAarushi Mehta error_report("Invalid aio option: %s", optarg);
4587cdd26774SAarushi Mehta ret = -1;
4588cdd26774SAarushi Mehta goto out;
4589cdd26774SAarushi Mehta }
4590cdd26774SAarushi Mehta break;
4591d3199a31SKevin Wolf case 'o':
4592d3199a31SKevin Wolf {
459343d589b0SEyal Moscovici offset = cvtnum("offset", optarg);
4594606caa0aSMarkus Armbruster if (offset < 0) {
4595d3199a31SKevin Wolf return 1;
4596d3199a31SKevin Wolf }
4597d3199a31SKevin Wolf break;
4598d3199a31SKevin Wolf }
4599d3199a31SKevin Wolf break;
4600b6133b8cSKevin Wolf case 'q':
4601b6133b8cSKevin Wolf quiet = true;
4602b6133b8cSKevin Wolf break;
4603b6133b8cSKevin Wolf case 's':
4604b6133b8cSKevin Wolf {
4605b6133b8cSKevin Wolf int64_t sval;
4606b6133b8cSKevin Wolf
460743d589b0SEyal Moscovici sval = cvtnum_full("buffer size", optarg, 0, INT_MAX);
460843d589b0SEyal Moscovici if (sval < 0) {
4609b6133b8cSKevin Wolf return 1;
4610b6133b8cSKevin Wolf }
4611b6133b8cSKevin Wolf
4612b6133b8cSKevin Wolf bufsize = sval;
4613b6133b8cSKevin Wolf break;
4614b6133b8cSKevin Wolf }
461583de9be0SKevin Wolf case 'S':
461683de9be0SKevin Wolf {
461783de9be0SKevin Wolf int64_t sval;
461883de9be0SKevin Wolf
461943d589b0SEyal Moscovici sval = cvtnum_full("step_size", optarg, 0, INT_MAX);
462043d589b0SEyal Moscovici if (sval < 0) {
462183de9be0SKevin Wolf return 1;
462283de9be0SKevin Wolf }
462383de9be0SKevin Wolf
462483de9be0SKevin Wolf step = sval;
462583de9be0SKevin Wolf break;
462683de9be0SKevin Wolf }
4627b6133b8cSKevin Wolf case 't':
4628b6133b8cSKevin Wolf ret = bdrv_parse_cache_mode(optarg, &flags, &writethrough);
4629b6133b8cSKevin Wolf if (ret < 0) {
4630b6133b8cSKevin Wolf error_report("Invalid cache mode");
4631b6133b8cSKevin Wolf ret = -1;
4632b6133b8cSKevin Wolf goto out;
4633b6133b8cSKevin Wolf }
4634b6133b8cSKevin Wolf break;
4635b6495fa8SKevin Wolf case 'w':
4636b6495fa8SKevin Wolf flags |= BDRV_O_RDWR;
4637b6495fa8SKevin Wolf is_write = true;
4638b6495fa8SKevin Wolf break;
4639335e9937SFam Zheng case 'U':
4640335e9937SFam Zheng force_share = true;
4641335e9937SFam Zheng break;
4642b6495fa8SKevin Wolf case OPTION_PATTERN:
4643b6495fa8SKevin Wolf {
46448b3c6792SPeter Maydell unsigned long res;
46458b3c6792SPeter Maydell
46468b3c6792SPeter Maydell if (qemu_strtoul(optarg, NULL, 0, &res) < 0 || res > 0xff) {
4647b6495fa8SKevin Wolf error_report("Invalid pattern byte specified");
4648b6495fa8SKevin Wolf return 1;
4649b6495fa8SKevin Wolf }
46508b3c6792SPeter Maydell pattern = res;
4651b6495fa8SKevin Wolf break;
4652b6495fa8SKevin Wolf }
465355d539c8SKevin Wolf case OPTION_FLUSH_INTERVAL:
465455d539c8SKevin Wolf {
46558b3c6792SPeter Maydell unsigned long res;
46568b3c6792SPeter Maydell
46578b3c6792SPeter Maydell if (qemu_strtoul(optarg, NULL, 0, &res) < 0 || res > INT_MAX) {
465855d539c8SKevin Wolf error_report("Invalid flush interval specified");
465955d539c8SKevin Wolf return 1;
466055d539c8SKevin Wolf }
46618b3c6792SPeter Maydell flush_interval = res;
466255d539c8SKevin Wolf break;
466355d539c8SKevin Wolf }
466455d539c8SKevin Wolf case OPTION_NO_DRAIN:
466555d539c8SKevin Wolf drain_on_flush = false;
466655d539c8SKevin Wolf break;
4667b6133b8cSKevin Wolf case OPTION_IMAGE_OPTS:
4668b6133b8cSKevin Wolf image_opts = true;
4669b6133b8cSKevin Wolf break;
4670b6133b8cSKevin Wolf }
4671b6133b8cSKevin Wolf }
4672b6133b8cSKevin Wolf
4673b6133b8cSKevin Wolf if (optind != argc - 1) {
4674b6133b8cSKevin Wolf error_exit("Expecting one image file name");
4675b6133b8cSKevin Wolf }
4676b6133b8cSKevin Wolf filename = argv[argc - 1];
4677b6133b8cSKevin Wolf
467855d539c8SKevin Wolf if (!is_write && flush_interval) {
467955d539c8SKevin Wolf error_report("--flush-interval is only available in write tests");
468055d539c8SKevin Wolf ret = -1;
468155d539c8SKevin Wolf goto out;
468255d539c8SKevin Wolf }
468355d539c8SKevin Wolf if (flush_interval && flush_interval < depth) {
468455d539c8SKevin Wolf error_report("Flush interval can't be smaller than depth");
468555d539c8SKevin Wolf ret = -1;
468655d539c8SKevin Wolf goto out;
468755d539c8SKevin Wolf }
468855d539c8SKevin Wolf
4689335e9937SFam Zheng blk = img_open(image_opts, filename, fmt, flags, writethrough, quiet,
4690335e9937SFam Zheng force_share);
4691b6133b8cSKevin Wolf if (!blk) {
4692b6133b8cSKevin Wolf ret = -1;
4693b6133b8cSKevin Wolf goto out;
4694b6133b8cSKevin Wolf }
4695b6133b8cSKevin Wolf
4696b6133b8cSKevin Wolf image_size = blk_getlength(blk);
4697b6133b8cSKevin Wolf if (image_size < 0) {
4698b6133b8cSKevin Wolf ret = image_size;
4699b6133b8cSKevin Wolf goto out;
4700b6133b8cSKevin Wolf }
4701b6133b8cSKevin Wolf
4702b6133b8cSKevin Wolf data = (BenchData) {
4703b6133b8cSKevin Wolf .blk = blk,
4704b6133b8cSKevin Wolf .image_size = image_size,
4705b6133b8cSKevin Wolf .bufsize = bufsize,
470683de9be0SKevin Wolf .step = step ?: bufsize,
4707b6133b8cSKevin Wolf .nrreq = depth,
4708b6133b8cSKevin Wolf .n = count,
4709d3199a31SKevin Wolf .offset = offset,
4710b6495fa8SKevin Wolf .write = is_write,
471155d539c8SKevin Wolf .flush_interval = flush_interval,
471255d539c8SKevin Wolf .drain_on_flush = drain_on_flush,
4713b6133b8cSKevin Wolf };
4714d3199a31SKevin Wolf printf("Sending %d %s requests, %d bytes each, %d in parallel "
471583de9be0SKevin Wolf "(starting at offset %" PRId64 ", step size %d)\n",
4716d3199a31SKevin Wolf data.n, data.write ? "write" : "read", data.bufsize, data.nrreq,
471783de9be0SKevin Wolf data.offset, data.step);
471855d539c8SKevin Wolf if (flush_interval) {
471955d539c8SKevin Wolf printf("Sending flush every %d requests\n", flush_interval);
472055d539c8SKevin Wolf }
4721b6133b8cSKevin Wolf
472279d46583SFam Zheng buf_size = data.nrreq * data.bufsize;
472379d46583SFam Zheng data.buf = blk_blockalign(blk, buf_size);
4724b6495fa8SKevin Wolf memset(data.buf, pattern, data.nrreq * data.bufsize);
4725b6495fa8SKevin Wolf
4726f4ec04baSStefan Hajnoczi blk_register_buf(blk, data.buf, buf_size, &error_fatal);
472779d46583SFam Zheng
4728b6133b8cSKevin Wolf data.qiov = g_new(QEMUIOVector, data.nrreq);
4729b6133b8cSKevin Wolf for (i = 0; i < data.nrreq; i++) {
4730b6133b8cSKevin Wolf qemu_iovec_init(&data.qiov[i], 1);
4731b6133b8cSKevin Wolf qemu_iovec_add(&data.qiov[i],
4732b6133b8cSKevin Wolf data.buf + i * data.bufsize, data.bufsize);
4733b6133b8cSKevin Wolf }
4734b6133b8cSKevin Wolf
4735b6133b8cSKevin Wolf gettimeofday(&t1, NULL);
4736b6133b8cSKevin Wolf bench_cb(&data, 0);
4737b6133b8cSKevin Wolf
4738b6133b8cSKevin Wolf while (data.n > 0) {
4739b6133b8cSKevin Wolf main_loop_wait(false);
4740b6133b8cSKevin Wolf }
4741b6133b8cSKevin Wolf gettimeofday(&t2, NULL);
4742b6133b8cSKevin Wolf
4743b6133b8cSKevin Wolf printf("Run completed in %3.3f seconds.\n",
4744b6133b8cSKevin Wolf (t2.tv_sec - t1.tv_sec)
4745b6133b8cSKevin Wolf + ((double)(t2.tv_usec - t1.tv_usec) / 1000000));
4746b6133b8cSKevin Wolf
4747b6133b8cSKevin Wolf out:
474879d46583SFam Zheng if (data.buf) {
47494f384011SStefan Hajnoczi blk_unregister_buf(blk, data.buf, buf_size);
475079d46583SFam Zheng }
4751b6133b8cSKevin Wolf qemu_vfree(data.buf);
4752b6133b8cSKevin Wolf blk_unref(blk);
4753b6133b8cSKevin Wolf
4754b6133b8cSKevin Wolf if (ret) {
4755b6133b8cSKevin Wolf return 1;
4756b6133b8cSKevin Wolf }
4757b6133b8cSKevin Wolf return 0;
4758b6133b8cSKevin Wolf }
4759b6133b8cSKevin Wolf
47603b51ab4bSEric Blake enum ImgBitmapAct {
47613b51ab4bSEric Blake BITMAP_ADD,
47623b51ab4bSEric Blake BITMAP_REMOVE,
47633b51ab4bSEric Blake BITMAP_CLEAR,
47643b51ab4bSEric Blake BITMAP_ENABLE,
47653b51ab4bSEric Blake BITMAP_DISABLE,
47663b51ab4bSEric Blake BITMAP_MERGE,
47673b51ab4bSEric Blake };
47683b51ab4bSEric Blake typedef struct ImgBitmapAction {
47693b51ab4bSEric Blake enum ImgBitmapAct act;
47703b51ab4bSEric Blake const char *src; /* only used for merge */
47713b51ab4bSEric Blake QSIMPLEQ_ENTRY(ImgBitmapAction) next;
47723b51ab4bSEric Blake } ImgBitmapAction;
47733b51ab4bSEric Blake
img_bitmap(int argc,char ** argv)47743b51ab4bSEric Blake static int img_bitmap(int argc, char **argv)
47753b51ab4bSEric Blake {
47763b51ab4bSEric Blake Error *err = NULL;
47773b51ab4bSEric Blake int c, ret = 1;
47783b51ab4bSEric Blake QemuOpts *opts = NULL;
47793b51ab4bSEric Blake const char *fmt = NULL, *src_fmt = NULL, *src_filename = NULL;
47803b51ab4bSEric Blake const char *filename, *bitmap;
47813b51ab4bSEric Blake BlockBackend *blk = NULL, *src = NULL;
47823b51ab4bSEric Blake BlockDriverState *bs = NULL, *src_bs = NULL;
47833b51ab4bSEric Blake bool image_opts = false;
47843b51ab4bSEric Blake int64_t granularity = 0;
47853b51ab4bSEric Blake bool add = false, merge = false;
47863b51ab4bSEric Blake QSIMPLEQ_HEAD(, ImgBitmapAction) actions;
47873b51ab4bSEric Blake ImgBitmapAction *act, *act_next;
47883b51ab4bSEric Blake const char *op;
4789c5e47711SKevin Wolf int inactivate_ret;
47903b51ab4bSEric Blake
47913b51ab4bSEric Blake QSIMPLEQ_INIT(&actions);
47923b51ab4bSEric Blake
47933b51ab4bSEric Blake for (;;) {
47943b51ab4bSEric Blake static const struct option long_options[] = {
47953b51ab4bSEric Blake {"help", no_argument, 0, 'h'},
47963b51ab4bSEric Blake {"object", required_argument, 0, OPTION_OBJECT},
47973b51ab4bSEric Blake {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
47983b51ab4bSEric Blake {"add", no_argument, 0, OPTION_ADD},
47993b51ab4bSEric Blake {"remove", no_argument, 0, OPTION_REMOVE},
48003b51ab4bSEric Blake {"clear", no_argument, 0, OPTION_CLEAR},
48013b51ab4bSEric Blake {"enable", no_argument, 0, OPTION_ENABLE},
48023b51ab4bSEric Blake {"disable", no_argument, 0, OPTION_DISABLE},
48033b51ab4bSEric Blake {"merge", required_argument, 0, OPTION_MERGE},
48043b51ab4bSEric Blake {"granularity", required_argument, 0, 'g'},
48053b51ab4bSEric Blake {"source-file", required_argument, 0, 'b'},
48063b51ab4bSEric Blake {"source-format", required_argument, 0, 'F'},
48073b51ab4bSEric Blake {0, 0, 0, 0}
48083b51ab4bSEric Blake };
48093b51ab4bSEric Blake c = getopt_long(argc, argv, ":b:f:F:g:h", long_options, NULL);
48103b51ab4bSEric Blake if (c == -1) {
48113b51ab4bSEric Blake break;
48123b51ab4bSEric Blake }
48133b51ab4bSEric Blake
48143b51ab4bSEric Blake switch (c) {
48153b51ab4bSEric Blake case ':':
48163b51ab4bSEric Blake missing_argument(argv[optind - 1]);
48173b51ab4bSEric Blake break;
48183b51ab4bSEric Blake case '?':
48193b51ab4bSEric Blake unrecognized_option(argv[optind - 1]);
48203b51ab4bSEric Blake break;
48213b51ab4bSEric Blake case 'h':
48223b51ab4bSEric Blake help();
48233b51ab4bSEric Blake break;
48243b51ab4bSEric Blake case 'b':
48253b51ab4bSEric Blake src_filename = optarg;
48263b51ab4bSEric Blake break;
48273b51ab4bSEric Blake case 'f':
48283b51ab4bSEric Blake fmt = optarg;
48293b51ab4bSEric Blake break;
48303b51ab4bSEric Blake case 'F':
48313b51ab4bSEric Blake src_fmt = optarg;
48323b51ab4bSEric Blake break;
48333b51ab4bSEric Blake case 'g':
48343b51ab4bSEric Blake granularity = cvtnum("granularity", optarg);
48353b51ab4bSEric Blake if (granularity < 0) {
48363b51ab4bSEric Blake return 1;
48373b51ab4bSEric Blake }
48383b51ab4bSEric Blake break;
48393b51ab4bSEric Blake case OPTION_ADD:
48403b51ab4bSEric Blake act = g_new0(ImgBitmapAction, 1);
48413b51ab4bSEric Blake act->act = BITMAP_ADD;
48423b51ab4bSEric Blake QSIMPLEQ_INSERT_TAIL(&actions, act, next);
48433b51ab4bSEric Blake add = true;
48443b51ab4bSEric Blake break;
48453b51ab4bSEric Blake case OPTION_REMOVE:
48463b51ab4bSEric Blake act = g_new0(ImgBitmapAction, 1);
48473b51ab4bSEric Blake act->act = BITMAP_REMOVE;
48483b51ab4bSEric Blake QSIMPLEQ_INSERT_TAIL(&actions, act, next);
48493b51ab4bSEric Blake break;
48503b51ab4bSEric Blake case OPTION_CLEAR:
48513b51ab4bSEric Blake act = g_new0(ImgBitmapAction, 1);
48523b51ab4bSEric Blake act->act = BITMAP_CLEAR;
48533b51ab4bSEric Blake QSIMPLEQ_INSERT_TAIL(&actions, act, next);
48543b51ab4bSEric Blake break;
48553b51ab4bSEric Blake case OPTION_ENABLE:
48563b51ab4bSEric Blake act = g_new0(ImgBitmapAction, 1);
48573b51ab4bSEric Blake act->act = BITMAP_ENABLE;
48583b51ab4bSEric Blake QSIMPLEQ_INSERT_TAIL(&actions, act, next);
48593b51ab4bSEric Blake break;
48603b51ab4bSEric Blake case OPTION_DISABLE:
48613b51ab4bSEric Blake act = g_new0(ImgBitmapAction, 1);
48623b51ab4bSEric Blake act->act = BITMAP_DISABLE;
48633b51ab4bSEric Blake QSIMPLEQ_INSERT_TAIL(&actions, act, next);
48643b51ab4bSEric Blake break;
48653b51ab4bSEric Blake case OPTION_MERGE:
48663b51ab4bSEric Blake act = g_new0(ImgBitmapAction, 1);
48673b51ab4bSEric Blake act->act = BITMAP_MERGE;
48683b51ab4bSEric Blake act->src = optarg;
48693b51ab4bSEric Blake QSIMPLEQ_INSERT_TAIL(&actions, act, next);
48703b51ab4bSEric Blake merge = true;
48713b51ab4bSEric Blake break;
48723b51ab4bSEric Blake case OPTION_OBJECT:
487399b1e646SKevin Wolf user_creatable_process_cmdline(optarg);
48743b51ab4bSEric Blake break;
48753b51ab4bSEric Blake case OPTION_IMAGE_OPTS:
48763b51ab4bSEric Blake image_opts = true;
48773b51ab4bSEric Blake break;
48783b51ab4bSEric Blake }
48793b51ab4bSEric Blake }
48803b51ab4bSEric Blake
48813b51ab4bSEric Blake if (QSIMPLEQ_EMPTY(&actions)) {
48823b51ab4bSEric Blake error_report("Need at least one of --add, --remove, --clear, "
48833b51ab4bSEric Blake "--enable, --disable, or --merge");
48843b51ab4bSEric Blake goto out;
48853b51ab4bSEric Blake }
48863b51ab4bSEric Blake
48873b51ab4bSEric Blake if (granularity && !add) {
48883b51ab4bSEric Blake error_report("granularity only supported with --add");
48893b51ab4bSEric Blake goto out;
48903b51ab4bSEric Blake }
48913b51ab4bSEric Blake if (src_fmt && !src_filename) {
48923b51ab4bSEric Blake error_report("-F only supported with -b");
48933b51ab4bSEric Blake goto out;
48943b51ab4bSEric Blake }
48953b51ab4bSEric Blake if (src_filename && !merge) {
48963b51ab4bSEric Blake error_report("Merge bitmap source file only supported with "
48973b51ab4bSEric Blake "--merge");
48983b51ab4bSEric Blake goto out;
48993b51ab4bSEric Blake }
49003b51ab4bSEric Blake
49013b51ab4bSEric Blake if (optind != argc - 2) {
49023b51ab4bSEric Blake error_report("Expecting filename and bitmap name");
49033b51ab4bSEric Blake goto out;
49043b51ab4bSEric Blake }
49053b51ab4bSEric Blake
49063b51ab4bSEric Blake filename = argv[optind];
49073b51ab4bSEric Blake bitmap = argv[optind + 1];
49083b51ab4bSEric Blake
490914f16bf9SEric Blake /*
491014f16bf9SEric Blake * No need to open backing chains; we will be manipulating bitmaps
491114f16bf9SEric Blake * directly in this image without reference to image contents.
491214f16bf9SEric Blake */
491314f16bf9SEric Blake blk = img_open(image_opts, filename, fmt, BDRV_O_RDWR | BDRV_O_NO_BACKING,
491414f16bf9SEric Blake false, false, false);
49153b51ab4bSEric Blake if (!blk) {
49163b51ab4bSEric Blake goto out;
49173b51ab4bSEric Blake }
49183b51ab4bSEric Blake bs = blk_bs(blk);
49193b51ab4bSEric Blake if (src_filename) {
492014f16bf9SEric Blake src = img_open(false, src_filename, src_fmt, BDRV_O_NO_BACKING,
492114f16bf9SEric Blake false, false, false);
49223b51ab4bSEric Blake if (!src) {
49233b51ab4bSEric Blake goto out;
49243b51ab4bSEric Blake }
49253b51ab4bSEric Blake src_bs = blk_bs(src);
49263b51ab4bSEric Blake } else {
49273b51ab4bSEric Blake src_bs = bs;
49283b51ab4bSEric Blake }
49293b51ab4bSEric Blake
49303b51ab4bSEric Blake QSIMPLEQ_FOREACH_SAFE(act, &actions, next, act_next) {
49313b51ab4bSEric Blake switch (act->act) {
49323b51ab4bSEric Blake case BITMAP_ADD:
49333b51ab4bSEric Blake qmp_block_dirty_bitmap_add(bs->node_name, bitmap,
49343b51ab4bSEric Blake !!granularity, granularity, true, true,
49353b51ab4bSEric Blake false, false, &err);
49363b51ab4bSEric Blake op = "add";
49373b51ab4bSEric Blake break;
49383b51ab4bSEric Blake case BITMAP_REMOVE:
49393b51ab4bSEric Blake qmp_block_dirty_bitmap_remove(bs->node_name, bitmap, &err);
49403b51ab4bSEric Blake op = "remove";
49413b51ab4bSEric Blake break;
49423b51ab4bSEric Blake case BITMAP_CLEAR:
49433b51ab4bSEric Blake qmp_block_dirty_bitmap_clear(bs->node_name, bitmap, &err);
49443b51ab4bSEric Blake op = "clear";
49453b51ab4bSEric Blake break;
49463b51ab4bSEric Blake case BITMAP_ENABLE:
49473b51ab4bSEric Blake qmp_block_dirty_bitmap_enable(bs->node_name, bitmap, &err);
49483b51ab4bSEric Blake op = "enable";
49493b51ab4bSEric Blake break;
49503b51ab4bSEric Blake case BITMAP_DISABLE:
49513b51ab4bSEric Blake qmp_block_dirty_bitmap_disable(bs->node_name, bitmap, &err);
49523b51ab4bSEric Blake op = "disable";
49533b51ab4bSEric Blake break;
49546c729dd8SEric Blake case BITMAP_MERGE:
49556c729dd8SEric Blake do_dirty_bitmap_merge(bs->node_name, bitmap, src_bs->node_name,
49566c729dd8SEric Blake act->src, &err);
49573b51ab4bSEric Blake op = "merge";
49583b51ab4bSEric Blake break;
49593b51ab4bSEric Blake default:
49603b51ab4bSEric Blake g_assert_not_reached();
49613b51ab4bSEric Blake }
49623b51ab4bSEric Blake
49633b51ab4bSEric Blake if (err) {
49643b51ab4bSEric Blake error_reportf_err(err, "Operation %s on bitmap %s failed: ",
49653b51ab4bSEric Blake op, bitmap);
49663b51ab4bSEric Blake goto out;
49673b51ab4bSEric Blake }
49683b51ab4bSEric Blake g_free(act);
49693b51ab4bSEric Blake }
49703b51ab4bSEric Blake
49713b51ab4bSEric Blake ret = 0;
49723b51ab4bSEric Blake
49733b51ab4bSEric Blake out:
4974c5e47711SKevin Wolf /*
4975c5e47711SKevin Wolf * Manually inactivate the images first because this way we can know whether
4976c5e47711SKevin Wolf * an error occurred. blk_unref() doesn't tell us about failures.
4977c5e47711SKevin Wolf */
4978c5e47711SKevin Wolf inactivate_ret = bdrv_inactivate_all();
4979c5e47711SKevin Wolf if (inactivate_ret < 0) {
4980c5e47711SKevin Wolf error_report("Error while closing the image: %s", strerror(-inactivate_ret));
4981c5e47711SKevin Wolf ret = 1;
4982c5e47711SKevin Wolf }
4983c5e47711SKevin Wolf
49843b51ab4bSEric Blake blk_unref(src);
49853b51ab4bSEric Blake blk_unref(blk);
49863b51ab4bSEric Blake qemu_opts_del(opts);
49873b51ab4bSEric Blake return ret;
49883b51ab4bSEric Blake }
49893b51ab4bSEric Blake
499086ce1f6eSReda Sallahi #define C_BS 01
499186ce1f6eSReda Sallahi #define C_COUNT 02
499286ce1f6eSReda Sallahi #define C_IF 04
499386ce1f6eSReda Sallahi #define C_OF 010
4994f7c15533SReda Sallahi #define C_SKIP 020
499586ce1f6eSReda Sallahi
499686ce1f6eSReda Sallahi struct DdInfo {
499786ce1f6eSReda Sallahi unsigned int flags;
499886ce1f6eSReda Sallahi int64_t count;
499986ce1f6eSReda Sallahi };
500086ce1f6eSReda Sallahi
500186ce1f6eSReda Sallahi struct DdIo {
500286ce1f6eSReda Sallahi int bsz; /* Block size */
500386ce1f6eSReda Sallahi char *filename;
500486ce1f6eSReda Sallahi uint8_t *buf;
5005f7c15533SReda Sallahi int64_t offset;
500686ce1f6eSReda Sallahi };
500786ce1f6eSReda Sallahi
500886ce1f6eSReda Sallahi struct DdOpts {
500986ce1f6eSReda Sallahi const char *name;
501086ce1f6eSReda Sallahi int (*f)(const char *, struct DdIo *, struct DdIo *, struct DdInfo *);
501186ce1f6eSReda Sallahi unsigned int flag;
501286ce1f6eSReda Sallahi };
501386ce1f6eSReda Sallahi
img_dd_bs(const char * arg,struct DdIo * in,struct DdIo * out,struct DdInfo * dd)501486ce1f6eSReda Sallahi static int img_dd_bs(const char *arg,
501586ce1f6eSReda Sallahi struct DdIo *in, struct DdIo *out,
501686ce1f6eSReda Sallahi struct DdInfo *dd)
501786ce1f6eSReda Sallahi {
501886ce1f6eSReda Sallahi int64_t res;
501986ce1f6eSReda Sallahi
502043d589b0SEyal Moscovici res = cvtnum_full("bs", arg, 1, INT_MAX);
502186ce1f6eSReda Sallahi
502243d589b0SEyal Moscovici if (res < 0) {
502386ce1f6eSReda Sallahi return 1;
502486ce1f6eSReda Sallahi }
502586ce1f6eSReda Sallahi in->bsz = out->bsz = res;
502686ce1f6eSReda Sallahi
502786ce1f6eSReda Sallahi return 0;
502886ce1f6eSReda Sallahi }
502986ce1f6eSReda Sallahi
img_dd_count(const char * arg,struct DdIo * in,struct DdIo * out,struct DdInfo * dd)503086ce1f6eSReda Sallahi static int img_dd_count(const char *arg,
503186ce1f6eSReda Sallahi struct DdIo *in, struct DdIo *out,
503286ce1f6eSReda Sallahi struct DdInfo *dd)
503386ce1f6eSReda Sallahi {
503443d589b0SEyal Moscovici dd->count = cvtnum("count", arg);
503586ce1f6eSReda Sallahi
5036606caa0aSMarkus Armbruster if (dd->count < 0) {
503786ce1f6eSReda Sallahi return 1;
503886ce1f6eSReda Sallahi }
503986ce1f6eSReda Sallahi
504086ce1f6eSReda Sallahi return 0;
504186ce1f6eSReda Sallahi }
504286ce1f6eSReda Sallahi
img_dd_if(const char * arg,struct DdIo * in,struct DdIo * out,struct DdInfo * dd)504386ce1f6eSReda Sallahi static int img_dd_if(const char *arg,
504486ce1f6eSReda Sallahi struct DdIo *in, struct DdIo *out,
504586ce1f6eSReda Sallahi struct DdInfo *dd)
504686ce1f6eSReda Sallahi {
504786ce1f6eSReda Sallahi in->filename = g_strdup(arg);
504886ce1f6eSReda Sallahi
504986ce1f6eSReda Sallahi return 0;
505086ce1f6eSReda Sallahi }
505186ce1f6eSReda Sallahi
img_dd_of(const char * arg,struct DdIo * in,struct DdIo * out,struct DdInfo * dd)505286ce1f6eSReda Sallahi static int img_dd_of(const char *arg,
505386ce1f6eSReda Sallahi struct DdIo *in, struct DdIo *out,
505486ce1f6eSReda Sallahi struct DdInfo *dd)
505586ce1f6eSReda Sallahi {
505686ce1f6eSReda Sallahi out->filename = g_strdup(arg);
505786ce1f6eSReda Sallahi
505886ce1f6eSReda Sallahi return 0;
505986ce1f6eSReda Sallahi }
506086ce1f6eSReda Sallahi
img_dd_skip(const char * arg,struct DdIo * in,struct DdIo * out,struct DdInfo * dd)5061f7c15533SReda Sallahi static int img_dd_skip(const char *arg,
5062f7c15533SReda Sallahi struct DdIo *in, struct DdIo *out,
5063f7c15533SReda Sallahi struct DdInfo *dd)
5064f7c15533SReda Sallahi {
506543d589b0SEyal Moscovici in->offset = cvtnum("skip", arg);
5066f7c15533SReda Sallahi
5067606caa0aSMarkus Armbruster if (in->offset < 0) {
5068f7c15533SReda Sallahi return 1;
5069f7c15533SReda Sallahi }
5070f7c15533SReda Sallahi
5071f7c15533SReda Sallahi return 0;
5072f7c15533SReda Sallahi }
5073f7c15533SReda Sallahi
img_dd(int argc,char ** argv)507486ce1f6eSReda Sallahi static int img_dd(int argc, char **argv)
507586ce1f6eSReda Sallahi {
507686ce1f6eSReda Sallahi int ret = 0;
507786ce1f6eSReda Sallahi char *arg = NULL;
507886ce1f6eSReda Sallahi char *tmp;
507986ce1f6eSReda Sallahi BlockDriver *drv = NULL, *proto_drv = NULL;
508086ce1f6eSReda Sallahi BlockBackend *blk1 = NULL, *blk2 = NULL;
508186ce1f6eSReda Sallahi QemuOpts *opts = NULL;
508286ce1f6eSReda Sallahi QemuOptsList *create_opts = NULL;
508386ce1f6eSReda Sallahi Error *local_err = NULL;
508486ce1f6eSReda Sallahi bool image_opts = false;
508586ce1f6eSReda Sallahi int c, i;
508686ce1f6eSReda Sallahi const char *out_fmt = "raw";
508786ce1f6eSReda Sallahi const char *fmt = NULL;
508886ce1f6eSReda Sallahi int64_t size = 0;
50890f48c47cSMiroslav Rezanina int64_t out_pos, in_pos;
5090335e9937SFam Zheng bool force_share = false;
509186ce1f6eSReda Sallahi struct DdInfo dd = {
509286ce1f6eSReda Sallahi .flags = 0,
509386ce1f6eSReda Sallahi .count = 0,
509486ce1f6eSReda Sallahi };
509586ce1f6eSReda Sallahi struct DdIo in = {
509686ce1f6eSReda Sallahi .bsz = 512, /* Block size is by default 512 bytes */
509786ce1f6eSReda Sallahi .filename = NULL,
5098f7c15533SReda Sallahi .buf = NULL,
5099f7c15533SReda Sallahi .offset = 0
510086ce1f6eSReda Sallahi };
510186ce1f6eSReda Sallahi struct DdIo out = {
510286ce1f6eSReda Sallahi .bsz = 512,
510386ce1f6eSReda Sallahi .filename = NULL,
5104f7c15533SReda Sallahi .buf = NULL,
5105f7c15533SReda Sallahi .offset = 0
510686ce1f6eSReda Sallahi };
510786ce1f6eSReda Sallahi
510886ce1f6eSReda Sallahi const struct DdOpts options[] = {
510986ce1f6eSReda Sallahi { "bs", img_dd_bs, C_BS },
511086ce1f6eSReda Sallahi { "count", img_dd_count, C_COUNT },
511186ce1f6eSReda Sallahi { "if", img_dd_if, C_IF },
511286ce1f6eSReda Sallahi { "of", img_dd_of, C_OF },
5113f7c15533SReda Sallahi { "skip", img_dd_skip, C_SKIP },
511486ce1f6eSReda Sallahi { NULL, NULL, 0 }
511586ce1f6eSReda Sallahi };
511686ce1f6eSReda Sallahi const struct option long_options[] = {
511786ce1f6eSReda Sallahi { "help", no_argument, 0, 'h'},
511883d4bf94SDaniel P. Berrange { "object", required_argument, 0, OPTION_OBJECT},
511986ce1f6eSReda Sallahi { "image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
5120335e9937SFam Zheng { "force-share", no_argument, 0, 'U'},
512186ce1f6eSReda Sallahi { 0, 0, 0, 0 }
512286ce1f6eSReda Sallahi };
512386ce1f6eSReda Sallahi
5124335e9937SFam Zheng while ((c = getopt_long(argc, argv, ":hf:O:U", long_options, NULL))) {
512586ce1f6eSReda Sallahi if (c == EOF) {
512686ce1f6eSReda Sallahi break;
512786ce1f6eSReda Sallahi }
512886ce1f6eSReda Sallahi switch (c) {
512986ce1f6eSReda Sallahi case 'O':
513086ce1f6eSReda Sallahi out_fmt = optarg;
513186ce1f6eSReda Sallahi break;
513286ce1f6eSReda Sallahi case 'f':
513386ce1f6eSReda Sallahi fmt = optarg;
513486ce1f6eSReda Sallahi break;
5135c9192973SStefan Hajnoczi case ':':
5136c9192973SStefan Hajnoczi missing_argument(argv[optind - 1]);
5137c9192973SStefan Hajnoczi break;
513886ce1f6eSReda Sallahi case '?':
5139c9192973SStefan Hajnoczi unrecognized_option(argv[optind - 1]);
5140c9192973SStefan Hajnoczi break;
514186ce1f6eSReda Sallahi case 'h':
514286ce1f6eSReda Sallahi help();
514386ce1f6eSReda Sallahi break;
5144335e9937SFam Zheng case 'U':
5145335e9937SFam Zheng force_share = true;
5146335e9937SFam Zheng break;
51472a245709SStefan Hajnoczi case OPTION_OBJECT:
514899b1e646SKevin Wolf user_creatable_process_cmdline(optarg);
51492a245709SStefan Hajnoczi break;
515086ce1f6eSReda Sallahi case OPTION_IMAGE_OPTS:
515186ce1f6eSReda Sallahi image_opts = true;
515286ce1f6eSReda Sallahi break;
515386ce1f6eSReda Sallahi }
515486ce1f6eSReda Sallahi }
515586ce1f6eSReda Sallahi
515686ce1f6eSReda Sallahi for (i = optind; i < argc; i++) {
515786ce1f6eSReda Sallahi int j;
515886ce1f6eSReda Sallahi arg = g_strdup(argv[i]);
515986ce1f6eSReda Sallahi
516086ce1f6eSReda Sallahi tmp = strchr(arg, '=');
516186ce1f6eSReda Sallahi if (tmp == NULL) {
516286ce1f6eSReda Sallahi error_report("unrecognized operand %s", arg);
516386ce1f6eSReda Sallahi ret = -1;
516486ce1f6eSReda Sallahi goto out;
516586ce1f6eSReda Sallahi }
516686ce1f6eSReda Sallahi
516786ce1f6eSReda Sallahi *tmp++ = '\0';
516886ce1f6eSReda Sallahi
516986ce1f6eSReda Sallahi for (j = 0; options[j].name != NULL; j++) {
517086ce1f6eSReda Sallahi if (!strcmp(arg, options[j].name)) {
517186ce1f6eSReda Sallahi break;
517286ce1f6eSReda Sallahi }
517386ce1f6eSReda Sallahi }
517486ce1f6eSReda Sallahi if (options[j].name == NULL) {
517586ce1f6eSReda Sallahi error_report("unrecognized operand %s", arg);
517686ce1f6eSReda Sallahi ret = -1;
517786ce1f6eSReda Sallahi goto out;
517886ce1f6eSReda Sallahi }
517986ce1f6eSReda Sallahi
518086ce1f6eSReda Sallahi if (options[j].f(tmp, &in, &out, &dd) != 0) {
518186ce1f6eSReda Sallahi ret = -1;
518286ce1f6eSReda Sallahi goto out;
518386ce1f6eSReda Sallahi }
518486ce1f6eSReda Sallahi dd.flags |= options[j].flag;
518586ce1f6eSReda Sallahi g_free(arg);
518686ce1f6eSReda Sallahi arg = NULL;
518786ce1f6eSReda Sallahi }
518886ce1f6eSReda Sallahi
518986ce1f6eSReda Sallahi if (!(dd.flags & C_IF && dd.flags & C_OF)) {
519086ce1f6eSReda Sallahi error_report("Must specify both input and output files");
519186ce1f6eSReda Sallahi ret = -1;
519286ce1f6eSReda Sallahi goto out;
519386ce1f6eSReda Sallahi }
519483d4bf94SDaniel P. Berrange
5195335e9937SFam Zheng blk1 = img_open(image_opts, in.filename, fmt, 0, false, false,
5196335e9937SFam Zheng force_share);
519786ce1f6eSReda Sallahi
519886ce1f6eSReda Sallahi if (!blk1) {
519986ce1f6eSReda Sallahi ret = -1;
520086ce1f6eSReda Sallahi goto out;
520186ce1f6eSReda Sallahi }
520286ce1f6eSReda Sallahi
520386ce1f6eSReda Sallahi drv = bdrv_find_format(out_fmt);
520486ce1f6eSReda Sallahi if (!drv) {
520586ce1f6eSReda Sallahi error_report("Unknown file format");
520686ce1f6eSReda Sallahi ret = -1;
520786ce1f6eSReda Sallahi goto out;
520886ce1f6eSReda Sallahi }
520986ce1f6eSReda Sallahi proto_drv = bdrv_find_protocol(out.filename, true, &local_err);
521086ce1f6eSReda Sallahi
521186ce1f6eSReda Sallahi if (!proto_drv) {
521286ce1f6eSReda Sallahi error_report_err(local_err);
521386ce1f6eSReda Sallahi ret = -1;
521486ce1f6eSReda Sallahi goto out;
521586ce1f6eSReda Sallahi }
521686ce1f6eSReda Sallahi if (!drv->create_opts) {
521786ce1f6eSReda Sallahi error_report("Format driver '%s' does not support image creation",
521886ce1f6eSReda Sallahi drv->format_name);
521986ce1f6eSReda Sallahi ret = -1;
522086ce1f6eSReda Sallahi goto out;
522186ce1f6eSReda Sallahi }
522286ce1f6eSReda Sallahi if (!proto_drv->create_opts) {
522386ce1f6eSReda Sallahi error_report("Protocol driver '%s' does not support image creation",
522486ce1f6eSReda Sallahi proto_drv->format_name);
522586ce1f6eSReda Sallahi ret = -1;
522686ce1f6eSReda Sallahi goto out;
522786ce1f6eSReda Sallahi }
522886ce1f6eSReda Sallahi create_opts = qemu_opts_append(create_opts, drv->create_opts);
522986ce1f6eSReda Sallahi create_opts = qemu_opts_append(create_opts, proto_drv->create_opts);
523086ce1f6eSReda Sallahi
523186ce1f6eSReda Sallahi opts = qemu_opts_create(create_opts, NULL, 0, &error_abort);
523286ce1f6eSReda Sallahi
523386ce1f6eSReda Sallahi size = blk_getlength(blk1);
523486ce1f6eSReda Sallahi if (size < 0) {
523586ce1f6eSReda Sallahi error_report("Failed to get size for '%s'", in.filename);
523686ce1f6eSReda Sallahi ret = -1;
523786ce1f6eSReda Sallahi goto out;
523886ce1f6eSReda Sallahi }
523986ce1f6eSReda Sallahi
524086ce1f6eSReda Sallahi if (dd.flags & C_COUNT && dd.count <= INT64_MAX / in.bsz &&
524186ce1f6eSReda Sallahi dd.count * in.bsz < size) {
524286ce1f6eSReda Sallahi size = dd.count * in.bsz;
524386ce1f6eSReda Sallahi }
524486ce1f6eSReda Sallahi
5245f7c15533SReda Sallahi /* Overflow means the specified offset is beyond input image's size */
5246f7c15533SReda Sallahi if (dd.flags & C_SKIP && (in.offset > INT64_MAX / in.bsz ||
5247f7c15533SReda Sallahi size < in.bsz * in.offset)) {
5248f7c15533SReda Sallahi qemu_opt_set_number(opts, BLOCK_OPT_SIZE, 0, &error_abort);
5249f7c15533SReda Sallahi } else {
5250f7c15533SReda Sallahi qemu_opt_set_number(opts, BLOCK_OPT_SIZE,
5251f7c15533SReda Sallahi size - in.bsz * in.offset, &error_abort);
5252f7c15533SReda Sallahi }
525386ce1f6eSReda Sallahi
525486ce1f6eSReda Sallahi ret = bdrv_create(drv, out.filename, opts, &local_err);
525586ce1f6eSReda Sallahi if (ret < 0) {
525686ce1f6eSReda Sallahi error_reportf_err(local_err,
525786ce1f6eSReda Sallahi "%s: error while creating output image: ",
525886ce1f6eSReda Sallahi out.filename);
525986ce1f6eSReda Sallahi ret = -1;
526086ce1f6eSReda Sallahi goto out;
526186ce1f6eSReda Sallahi }
526286ce1f6eSReda Sallahi
5263ea204ddaSDaniel P. Berrange /* TODO, we can't honour --image-opts for the target,
5264ea204ddaSDaniel P. Berrange * since it needs to be given in a format compatible
5265ea204ddaSDaniel P. Berrange * with the bdrv_create() call above which does not
5266ea204ddaSDaniel P. Berrange * support image-opts style.
5267ea204ddaSDaniel P. Berrange */
526829cf9336SDaniel P. Berrange blk2 = img_open_file(out.filename, NULL, out_fmt, BDRV_O_RDWR,
5269335e9937SFam Zheng false, false, false);
527086ce1f6eSReda Sallahi
527186ce1f6eSReda Sallahi if (!blk2) {
527286ce1f6eSReda Sallahi ret = -1;
527386ce1f6eSReda Sallahi goto out;
527486ce1f6eSReda Sallahi }
527586ce1f6eSReda Sallahi
5276f7c15533SReda Sallahi if (dd.flags & C_SKIP && (in.offset > INT64_MAX / in.bsz ||
5277f7c15533SReda Sallahi size < in.offset * in.bsz)) {
5278f7c15533SReda Sallahi /* We give a warning if the skip option is bigger than the input
5279f7c15533SReda Sallahi * size and create an empty output disk image (i.e. like dd(1)).
5280f7c15533SReda Sallahi */
5281f7c15533SReda Sallahi error_report("%s: cannot skip to specified offset", in.filename);
5282f7c15533SReda Sallahi in_pos = size;
5283f7c15533SReda Sallahi } else {
5284f7c15533SReda Sallahi in_pos = in.offset * in.bsz;
5285f7c15533SReda Sallahi }
5286f7c15533SReda Sallahi
528786ce1f6eSReda Sallahi in.buf = g_new(uint8_t, in.bsz);
528886ce1f6eSReda Sallahi
52890f48c47cSMiroslav Rezanina for (out_pos = 0; in_pos < size; ) {
5290bf5b16faSAlberto Faria int bytes = (in_pos + in.bsz > size) ? size - in_pos : in.bsz;
529186ce1f6eSReda Sallahi
5292a9262f55SAlberto Faria ret = blk_pread(blk1, in_pos, bytes, in.buf, 0);
5293bf5b16faSAlberto Faria if (ret < 0) {
529486ce1f6eSReda Sallahi error_report("error while reading from input image file: %s",
5295bf5b16faSAlberto Faria strerror(-ret));
529686ce1f6eSReda Sallahi goto out;
529786ce1f6eSReda Sallahi }
5298bf5b16faSAlberto Faria in_pos += bytes;
529986ce1f6eSReda Sallahi
5300a9262f55SAlberto Faria ret = blk_pwrite(blk2, out_pos, bytes, in.buf, 0);
5301bf5b16faSAlberto Faria if (ret < 0) {
530286ce1f6eSReda Sallahi error_report("error while writing to output image file: %s",
5303bf5b16faSAlberto Faria strerror(-ret));
530486ce1f6eSReda Sallahi goto out;
530586ce1f6eSReda Sallahi }
5306bf5b16faSAlberto Faria out_pos += bytes;
530786ce1f6eSReda Sallahi }
530886ce1f6eSReda Sallahi
530986ce1f6eSReda Sallahi out:
531086ce1f6eSReda Sallahi g_free(arg);
531186ce1f6eSReda Sallahi qemu_opts_del(opts);
531286ce1f6eSReda Sallahi qemu_opts_free(create_opts);
531386ce1f6eSReda Sallahi blk_unref(blk1);
531486ce1f6eSReda Sallahi blk_unref(blk2);
531586ce1f6eSReda Sallahi g_free(in.filename);
531686ce1f6eSReda Sallahi g_free(out.filename);
531786ce1f6eSReda Sallahi g_free(in.buf);
531886ce1f6eSReda Sallahi g_free(out.buf);
531986ce1f6eSReda Sallahi
532086ce1f6eSReda Sallahi if (ret) {
532186ce1f6eSReda Sallahi return 1;
532286ce1f6eSReda Sallahi }
532386ce1f6eSReda Sallahi return 0;
532486ce1f6eSReda Sallahi }
532586ce1f6eSReda Sallahi
dump_json_block_measure_info(BlockMeasureInfo * info)5326fd03c2b8SStefan Hajnoczi static void dump_json_block_measure_info(BlockMeasureInfo *info)
5327fd03c2b8SStefan Hajnoczi {
5328eab3a467SMarkus Armbruster GString *str;
5329fd03c2b8SStefan Hajnoczi QObject *obj;
5330fd03c2b8SStefan Hajnoczi Visitor *v = qobject_output_visitor_new(&obj);
5331fd03c2b8SStefan Hajnoczi
5332fd03c2b8SStefan Hajnoczi visit_type_BlockMeasureInfo(v, NULL, &info, &error_abort);
5333fd03c2b8SStefan Hajnoczi visit_complete(v, &obj);
53346589f459SMarkus Armbruster str = qobject_to_json_pretty(obj, true);
5335fd03c2b8SStefan Hajnoczi assert(str != NULL);
5336eab3a467SMarkus Armbruster printf("%s\n", str->str);
5337cb3e7f08SMarc-André Lureau qobject_unref(obj);
5338fd03c2b8SStefan Hajnoczi visit_free(v);
5339eab3a467SMarkus Armbruster g_string_free(str, true);
5340fd03c2b8SStefan Hajnoczi }
5341fd03c2b8SStefan Hajnoczi
img_measure(int argc,char ** argv)5342fd03c2b8SStefan Hajnoczi static int img_measure(int argc, char **argv)
5343fd03c2b8SStefan Hajnoczi {
5344fd03c2b8SStefan Hajnoczi static const struct option long_options[] = {
5345fd03c2b8SStefan Hajnoczi {"help", no_argument, 0, 'h'},
5346fd03c2b8SStefan Hajnoczi {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
5347fd03c2b8SStefan Hajnoczi {"object", required_argument, 0, OPTION_OBJECT},
5348fd03c2b8SStefan Hajnoczi {"output", required_argument, 0, OPTION_OUTPUT},
5349fd03c2b8SStefan Hajnoczi {"size", required_argument, 0, OPTION_SIZE},
5350fd03c2b8SStefan Hajnoczi {"force-share", no_argument, 0, 'U'},
5351fd03c2b8SStefan Hajnoczi {0, 0, 0, 0}
5352fd03c2b8SStefan Hajnoczi };
5353fd03c2b8SStefan Hajnoczi OutputFormat output_format = OFORMAT_HUMAN;
5354fd03c2b8SStefan Hajnoczi BlockBackend *in_blk = NULL;
5355fd03c2b8SStefan Hajnoczi BlockDriver *drv;
5356fd03c2b8SStefan Hajnoczi const char *filename = NULL;
5357fd03c2b8SStefan Hajnoczi const char *fmt = NULL;
5358fd03c2b8SStefan Hajnoczi const char *out_fmt = "raw";
5359fd03c2b8SStefan Hajnoczi char *options = NULL;
5360fd03c2b8SStefan Hajnoczi char *snapshot_name = NULL;
5361fd03c2b8SStefan Hajnoczi bool force_share = false;
5362fd03c2b8SStefan Hajnoczi QemuOpts *opts = NULL;
5363fd03c2b8SStefan Hajnoczi QemuOpts *object_opts = NULL;
5364fd03c2b8SStefan Hajnoczi QemuOpts *sn_opts = NULL;
5365fd03c2b8SStefan Hajnoczi QemuOptsList *create_opts = NULL;
5366fd03c2b8SStefan Hajnoczi bool image_opts = false;
5367fd03c2b8SStefan Hajnoczi uint64_t img_size = UINT64_MAX;
5368fd03c2b8SStefan Hajnoczi BlockMeasureInfo *info = NULL;
5369fd03c2b8SStefan Hajnoczi Error *local_err = NULL;
5370fd03c2b8SStefan Hajnoczi int ret = 1;
5371fd03c2b8SStefan Hajnoczi int c;
5372fd03c2b8SStefan Hajnoczi
5373fd03c2b8SStefan Hajnoczi while ((c = getopt_long(argc, argv, "hf:O:o:l:U",
5374fd03c2b8SStefan Hajnoczi long_options, NULL)) != -1) {
5375fd03c2b8SStefan Hajnoczi switch (c) {
5376fd03c2b8SStefan Hajnoczi case '?':
5377fd03c2b8SStefan Hajnoczi case 'h':
5378fd03c2b8SStefan Hajnoczi help();
5379fd03c2b8SStefan Hajnoczi break;
5380fd03c2b8SStefan Hajnoczi case 'f':
5381fd03c2b8SStefan Hajnoczi fmt = optarg;
5382fd03c2b8SStefan Hajnoczi break;
5383fd03c2b8SStefan Hajnoczi case 'O':
5384fd03c2b8SStefan Hajnoczi out_fmt = optarg;
5385fd03c2b8SStefan Hajnoczi break;
5386fd03c2b8SStefan Hajnoczi case 'o':
53876d2b5cbaSMarkus Armbruster if (accumulate_options(&options, optarg) < 0) {
5388fd03c2b8SStefan Hajnoczi goto out;
5389fd03c2b8SStefan Hajnoczi }
5390fd03c2b8SStefan Hajnoczi break;
5391fd03c2b8SStefan Hajnoczi case 'l':
5392fd03c2b8SStefan Hajnoczi if (strstart(optarg, SNAPSHOT_OPT_BASE, NULL)) {
5393fd03c2b8SStefan Hajnoczi sn_opts = qemu_opts_parse_noisily(&internal_snapshot_opts,
5394fd03c2b8SStefan Hajnoczi optarg, false);
5395fd03c2b8SStefan Hajnoczi if (!sn_opts) {
5396fd03c2b8SStefan Hajnoczi error_report("Failed in parsing snapshot param '%s'",
5397fd03c2b8SStefan Hajnoczi optarg);
5398fd03c2b8SStefan Hajnoczi goto out;
5399fd03c2b8SStefan Hajnoczi }
5400fd03c2b8SStefan Hajnoczi } else {
5401fd03c2b8SStefan Hajnoczi snapshot_name = optarg;
5402fd03c2b8SStefan Hajnoczi }
5403fd03c2b8SStefan Hajnoczi break;
5404fd03c2b8SStefan Hajnoczi case 'U':
5405fd03c2b8SStefan Hajnoczi force_share = true;
5406fd03c2b8SStefan Hajnoczi break;
5407fd03c2b8SStefan Hajnoczi case OPTION_OBJECT:
540899b1e646SKevin Wolf user_creatable_process_cmdline(optarg);
5409fd03c2b8SStefan Hajnoczi break;
5410fd03c2b8SStefan Hajnoczi case OPTION_IMAGE_OPTS:
5411fd03c2b8SStefan Hajnoczi image_opts = true;
5412fd03c2b8SStefan Hajnoczi break;
5413fd03c2b8SStefan Hajnoczi case OPTION_OUTPUT:
5414fd03c2b8SStefan Hajnoczi if (!strcmp(optarg, "json")) {
5415fd03c2b8SStefan Hajnoczi output_format = OFORMAT_JSON;
5416fd03c2b8SStefan Hajnoczi } else if (!strcmp(optarg, "human")) {
5417fd03c2b8SStefan Hajnoczi output_format = OFORMAT_HUMAN;
5418fd03c2b8SStefan Hajnoczi } else {
5419fd03c2b8SStefan Hajnoczi error_report("--output must be used with human or json "
5420fd03c2b8SStefan Hajnoczi "as argument.");
5421fd03c2b8SStefan Hajnoczi goto out;
5422fd03c2b8SStefan Hajnoczi }
5423fd03c2b8SStefan Hajnoczi break;
5424fd03c2b8SStefan Hajnoczi case OPTION_SIZE:
5425fd03c2b8SStefan Hajnoczi {
5426fd03c2b8SStefan Hajnoczi int64_t sval;
5427fd03c2b8SStefan Hajnoczi
542843d589b0SEyal Moscovici sval = cvtnum("image size", optarg);
5429fd03c2b8SStefan Hajnoczi if (sval < 0) {
5430fd03c2b8SStefan Hajnoczi goto out;
5431fd03c2b8SStefan Hajnoczi }
5432fd03c2b8SStefan Hajnoczi img_size = (uint64_t)sval;
5433fd03c2b8SStefan Hajnoczi }
5434fd03c2b8SStefan Hajnoczi break;
5435fd03c2b8SStefan Hajnoczi }
5436fd03c2b8SStefan Hajnoczi }
5437fd03c2b8SStefan Hajnoczi
5438fd03c2b8SStefan Hajnoczi if (argc - optind > 1) {
5439fd03c2b8SStefan Hajnoczi error_report("At most one filename argument is allowed.");
5440fd03c2b8SStefan Hajnoczi goto out;
5441fd03c2b8SStefan Hajnoczi } else if (argc - optind == 1) {
5442fd03c2b8SStefan Hajnoczi filename = argv[optind];
5443fd03c2b8SStefan Hajnoczi }
5444fd03c2b8SStefan Hajnoczi
5445c3673dcfSStefan Hajnoczi if (!filename && (image_opts || fmt || snapshot_name || sn_opts)) {
5446c3673dcfSStefan Hajnoczi error_report("--image-opts, -f, and -l require a filename argument.");
5447fd03c2b8SStefan Hajnoczi goto out;
5448fd03c2b8SStefan Hajnoczi }
5449fd03c2b8SStefan Hajnoczi if (filename && img_size != UINT64_MAX) {
5450fd03c2b8SStefan Hajnoczi error_report("--size N cannot be used together with a filename.");
5451fd03c2b8SStefan Hajnoczi goto out;
5452fd03c2b8SStefan Hajnoczi }
5453fd03c2b8SStefan Hajnoczi if (!filename && img_size == UINT64_MAX) {
5454fd03c2b8SStefan Hajnoczi error_report("Either --size N or one filename must be specified.");
5455fd03c2b8SStefan Hajnoczi goto out;
5456fd03c2b8SStefan Hajnoczi }
5457fd03c2b8SStefan Hajnoczi
5458fd03c2b8SStefan Hajnoczi if (filename) {
5459fd03c2b8SStefan Hajnoczi in_blk = img_open(image_opts, filename, fmt, 0,
5460fd03c2b8SStefan Hajnoczi false, false, force_share);
5461fd03c2b8SStefan Hajnoczi if (!in_blk) {
5462fd03c2b8SStefan Hajnoczi goto out;
5463fd03c2b8SStefan Hajnoczi }
5464fd03c2b8SStefan Hajnoczi
5465fd03c2b8SStefan Hajnoczi if (sn_opts) {
5466fd03c2b8SStefan Hajnoczi bdrv_snapshot_load_tmp(blk_bs(in_blk),
5467fd03c2b8SStefan Hajnoczi qemu_opt_get(sn_opts, SNAPSHOT_OPT_ID),
5468fd03c2b8SStefan Hajnoczi qemu_opt_get(sn_opts, SNAPSHOT_OPT_NAME),
5469fd03c2b8SStefan Hajnoczi &local_err);
5470fd03c2b8SStefan Hajnoczi } else if (snapshot_name != NULL) {
5471fd03c2b8SStefan Hajnoczi bdrv_snapshot_load_tmp_by_id_or_name(blk_bs(in_blk),
5472fd03c2b8SStefan Hajnoczi snapshot_name, &local_err);
5473fd03c2b8SStefan Hajnoczi }
5474fd03c2b8SStefan Hajnoczi if (local_err) {
5475fd03c2b8SStefan Hajnoczi error_reportf_err(local_err, "Failed to load snapshot: ");
5476fd03c2b8SStefan Hajnoczi goto out;
5477fd03c2b8SStefan Hajnoczi }
5478fd03c2b8SStefan Hajnoczi }
5479fd03c2b8SStefan Hajnoczi
5480fd03c2b8SStefan Hajnoczi drv = bdrv_find_format(out_fmt);
5481fd03c2b8SStefan Hajnoczi if (!drv) {
5482fd03c2b8SStefan Hajnoczi error_report("Unknown file format '%s'", out_fmt);
5483fd03c2b8SStefan Hajnoczi goto out;
5484fd03c2b8SStefan Hajnoczi }
5485fd03c2b8SStefan Hajnoczi if (!drv->create_opts) {
5486fd03c2b8SStefan Hajnoczi error_report("Format driver '%s' does not support image creation",
5487fd03c2b8SStefan Hajnoczi drv->format_name);
5488fd03c2b8SStefan Hajnoczi goto out;
5489fd03c2b8SStefan Hajnoczi }
5490fd03c2b8SStefan Hajnoczi
5491fd03c2b8SStefan Hajnoczi create_opts = qemu_opts_append(create_opts, drv->create_opts);
5492fd03c2b8SStefan Hajnoczi create_opts = qemu_opts_append(create_opts, bdrv_file.create_opts);
5493fd03c2b8SStefan Hajnoczi opts = qemu_opts_create(create_opts, NULL, 0, &error_abort);
5494fd03c2b8SStefan Hajnoczi if (options) {
5495235e59cfSMarkus Armbruster if (!qemu_opts_do_parse(opts, options, NULL, &local_err)) {
5496fd03c2b8SStefan Hajnoczi error_report_err(local_err);
5497fd03c2b8SStefan Hajnoczi error_report("Invalid options for file format '%s'", out_fmt);
5498fd03c2b8SStefan Hajnoczi goto out;
5499fd03c2b8SStefan Hajnoczi }
5500fd03c2b8SStefan Hajnoczi }
5501fd03c2b8SStefan Hajnoczi if (img_size != UINT64_MAX) {
5502fd03c2b8SStefan Hajnoczi qemu_opt_set_number(opts, BLOCK_OPT_SIZE, img_size, &error_abort);
5503fd03c2b8SStefan Hajnoczi }
5504fd03c2b8SStefan Hajnoczi
5505fd03c2b8SStefan Hajnoczi info = bdrv_measure(drv, opts, in_blk ? blk_bs(in_blk) : NULL, &local_err);
5506fd03c2b8SStefan Hajnoczi if (local_err) {
5507fd03c2b8SStefan Hajnoczi error_report_err(local_err);
5508fd03c2b8SStefan Hajnoczi goto out;
5509fd03c2b8SStefan Hajnoczi }
5510fd03c2b8SStefan Hajnoczi
5511fd03c2b8SStefan Hajnoczi if (output_format == OFORMAT_HUMAN) {
5512fd03c2b8SStefan Hajnoczi printf("required size: %" PRIu64 "\n", info->required);
5513fd03c2b8SStefan Hajnoczi printf("fully allocated size: %" PRIu64 "\n", info->fully_allocated);
55145d72c68bSEric Blake if (info->has_bitmaps) {
55155d72c68bSEric Blake printf("bitmaps size: %" PRIu64 "\n", info->bitmaps);
55165d72c68bSEric Blake }
5517fd03c2b8SStefan Hajnoczi } else {
5518fd03c2b8SStefan Hajnoczi dump_json_block_measure_info(info);
5519fd03c2b8SStefan Hajnoczi }
5520fd03c2b8SStefan Hajnoczi
5521fd03c2b8SStefan Hajnoczi ret = 0;
5522fd03c2b8SStefan Hajnoczi
5523fd03c2b8SStefan Hajnoczi out:
5524fd03c2b8SStefan Hajnoczi qapi_free_BlockMeasureInfo(info);
5525fd03c2b8SStefan Hajnoczi qemu_opts_del(object_opts);
5526fd03c2b8SStefan Hajnoczi qemu_opts_del(opts);
5527fd03c2b8SStefan Hajnoczi qemu_opts_del(sn_opts);
5528fd03c2b8SStefan Hajnoczi qemu_opts_free(create_opts);
5529fd03c2b8SStefan Hajnoczi g_free(options);
5530fd03c2b8SStefan Hajnoczi blk_unref(in_blk);
5531fd03c2b8SStefan Hajnoczi return ret;
5532fd03c2b8SStefan Hajnoczi }
5533b6133b8cSKevin Wolf
5534c227f099SAnthony Liguori static const img_cmd_t img_cmds[] = {
5535153859beSStuart Brady #define DEF(option, callback, arg_string) \
5536153859beSStuart Brady { option, callback },
5537153859beSStuart Brady #include "qemu-img-cmds.h"
5538153859beSStuart Brady #undef DEF
5539153859beSStuart Brady { NULL, NULL, },
5540153859beSStuart Brady };
5541153859beSStuart Brady
main(int argc,char ** argv)5542ea2384d3Sbellard int main(int argc, char **argv)
5543ea2384d3Sbellard {
5544c227f099SAnthony Liguori const img_cmd_t *cmd;
5545153859beSStuart Brady const char *cmdname;
55467db1689cSJeff Cody int c;
55477db1689cSJeff Cody static const struct option long_options[] = {
55487db1689cSJeff Cody {"help", no_argument, 0, 'h'},
554910985131SDenis V. Lunev {"version", no_argument, 0, 'V'},
555006a1e0c1SDenis V. Lunev {"trace", required_argument, NULL, 'T'},
55517db1689cSJeff Cody {0, 0, 0, 0}
55527db1689cSJeff Cody };
5553ea2384d3Sbellard
5554526eda14SMORITA Kazutaka #ifdef CONFIG_POSIX
5555526eda14SMORITA Kazutaka signal(SIGPIPE, SIG_IGN);
5556526eda14SMORITA Kazutaka #endif
5557526eda14SMORITA Kazutaka
555898c5d2e7SDaniel P. Berrangé socket_init();
5559f5852efaSChristophe Fergeau error_init(argv[0]);
5560fe4db84dSDaniel P. Berrange module_call_init(MODULE_INIT_TRACE);
556110f5bff6SFam Zheng qemu_init_exec_dir(argv[0]);
556253f76e58SKevin Wolf
5563f9734d5dSMarkus Armbruster qemu_init_main_loop(&error_fatal);
55642f78e491SChrysostomos Nanakos
5565e8f2d272SEduardo Habkost qcrypto_init(&error_fatal);
5566c2297088SDaniel P. Berrange
5567064097d9SDaniel P. Berrange module_call_init(MODULE_INIT_QOM);
5568ea2384d3Sbellard bdrv_init();
5569ac1307abSFam Zheng if (argc < 2) {
5570ac1307abSFam Zheng error_exit("Not enough arguments");
5571ac1307abSFam Zheng }
5572153859beSStuart Brady
5573eb769f74SDaniel P. Berrange qemu_add_opts(&qemu_source_opts);
557406a1e0c1SDenis V. Lunev qemu_add_opts(&qemu_trace_opts);
55753babeb15SDaniel P. Berrange
5576c9192973SStefan Hajnoczi while ((c = getopt_long(argc, argv, "+:hVT:", long_options, NULL)) != -1) {
557710985131SDenis V. Lunev switch (c) {
5578c9192973SStefan Hajnoczi case ':':
5579c9192973SStefan Hajnoczi missing_argument(argv[optind - 1]);
5580c9192973SStefan Hajnoczi return 0;
55814581c16fSStefan Hajnoczi case '?':
5582c9192973SStefan Hajnoczi unrecognized_option(argv[optind - 1]);
5583c9192973SStefan Hajnoczi return 0;
5584c9192973SStefan Hajnoczi case 'h':
558510985131SDenis V. Lunev help();
558610985131SDenis V. Lunev return 0;
558710985131SDenis V. Lunev case 'V':
558810985131SDenis V. Lunev printf(QEMU_IMG_VERSION);
558910985131SDenis V. Lunev return 0;
559006a1e0c1SDenis V. Lunev case 'T':
559192eecfffSPaolo Bonzini trace_opt_parse(optarg);
559206a1e0c1SDenis V. Lunev break;
559310985131SDenis V. Lunev }
559410985131SDenis V. Lunev }
559510985131SDenis V. Lunev
559610985131SDenis V. Lunev cmdname = argv[optind];
559710985131SDenis V. Lunev
559810985131SDenis V. Lunev /* reset getopt_long scanning */
559910985131SDenis V. Lunev argc -= optind;
560010985131SDenis V. Lunev if (argc < 1) {
560110985131SDenis V. Lunev return 0;
560210985131SDenis V. Lunev }
560310985131SDenis V. Lunev argv += optind;
5604d339d766SRichard W.M. Jones qemu_reset_optind();
560510985131SDenis V. Lunev
560606a1e0c1SDenis V. Lunev if (!trace_init_backends()) {
560706a1e0c1SDenis V. Lunev exit(1);
560806a1e0c1SDenis V. Lunev }
560992eecfffSPaolo Bonzini trace_init_file();
5610c5955f4fSRichard Henderson qemu_set_log(LOG_TRACE, &error_fatal);
561106a1e0c1SDenis V. Lunev
5612153859beSStuart Brady /* find the command */
5613153859beSStuart Brady for (cmd = img_cmds; cmd->name != NULL; cmd++) {
5614153859beSStuart Brady if (!strcmp(cmdname, cmd->name)) {
561510985131SDenis V. Lunev return cmd->handler(argc, argv);
5616ea2384d3Sbellard }
5617153859beSStuart Brady }
5618153859beSStuart Brady
5619153859beSStuart Brady /* not found */
5620ac1307abSFam Zheng error_exit("Command not found: %s", cmdname);
5621ea2384d3Sbellard }
5622