X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=qemu-img.c;h=07b6e2a8088c1f6e15486884c9344d493c28bca8;hb=f38d7fbc015a3745ecdbf1e0158dbc1d1b061f9f;hp=1acddf693c649616e9bf4ff9b9ea2bd5e6e2bf44;hpb=fd76fef8e53e0f2876ef5f98e58b5c59fa1eb115;p=mirror_qemu.git diff --git a/qemu-img.c b/qemu-img.c index 1acddf693c..07b6e2a808 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -37,6 +37,7 @@ #include "qemu/option.h" #include "qemu/error-report.h" #include "qemu/log.h" +#include "qemu/units.h" #include "qom/object_interfaces.h" #include "sysemu/sysemu.h" #include "sysemu/block-backend.h" @@ -85,13 +86,11 @@ static void QEMU_NORETURN GCC_FMT_ATTR(1, 2) error_exit(const char *fmt, ...) { va_list ap; - error_printf("qemu-img: "); - va_start(ap, fmt); - error_vprintf(fmt, ap); + error_vreport(fmt, ap); va_end(ap); - error_printf("\nTry 'qemu-img --help' for more information\n"); + error_printf("Try 'qemu-img --help' for more information\n"); exit(EXIT_FAILURE); } @@ -198,7 +197,7 @@ static void QEMU_NORETURN help(void) " 'skip=N' skip N bs-sized blocks at the start of input\n"; printf("%s\nSupported formats:", help_msg); - bdrv_iterate_format(format_print, NULL); + bdrv_iterate_format(format_print, NULL, false); printf("\n\n" QEMU_HELP_BOTTOM "\n"); exit(EXIT_SUCCESS); } @@ -261,16 +260,28 @@ static int print_block_option_help(const char *filename, const char *fmt) return 1; } if (!proto_drv->create_opts) { - error_report("Protocal driver '%s' does not support image creation", + error_report("Protocol driver '%s' does not support image creation", proto_drv->format_name); + qemu_opts_free(create_opts); return 1; } create_opts = qemu_opts_append(create_opts, proto_drv->create_opts); } - printf("Supported options:\n"); - qemu_opts_print_help(create_opts); + if (filename) { + printf("Supported options:\n"); + } else { + printf("Supported %s options:\n", fmt); + } + qemu_opts_print_help(create_opts, false); qemu_opts_free(create_opts); + + if (!filename) { + printf("\n" + "The protocol level may support further options.\n" + "Specify the target filename to include those options.\n"); + } + return 0; } @@ -345,21 +356,6 @@ static int img_add_key_secrets(void *opaque, return 0; } -static BlockBackend *img_open_new_file(const char *filename, - QemuOpts *create_opts, - const char *fmt, int flags, - bool writethrough, bool quiet, - bool force_share) -{ - QDict *options = NULL; - - options = qdict_new(); - qemu_opt_foreach(create_opts, img_add_key_secrets, options, &error_abort); - - return img_open_file(filename, options, fmt, flags, writethrough, quiet, - force_share); -} - static BlockBackend *img_open(bool image_opts, const char *filename, @@ -517,7 +513,7 @@ static int img_create(int argc, char **argv) if (qemu_opts_foreach(&qemu_object_opts, user_creatable_add_opts_foreach, - NULL, NULL)) { + NULL, &error_fatal)) { goto fail; } @@ -767,7 +763,7 @@ static int img_check(int argc, char **argv) if (qemu_opts_foreach(&qemu_object_opts, user_creatable_add_opts_foreach, - NULL, NULL)) { + NULL, &error_fatal)) { return 1; } @@ -980,7 +976,7 @@ static int img_commit(int argc, char **argv) if (qemu_opts_foreach(&qemu_object_opts, user_creatable_add_opts_foreach, - NULL, NULL)) { + NULL, &error_fatal)) { return 1; } @@ -1044,6 +1040,7 @@ static int img_commit(int argc, char **argv) } job = block_job_get("commit"); + assert(job); run_block_job(job, &local_err); if (local_err) { goto unref_backing; @@ -1220,7 +1217,7 @@ static int compare_buffers(const uint8_t *buf1, const uint8_t *buf2, return res; } -#define IO_BUF_SIZE (2 * 1024 * 1024) +#define IO_BUF_SIZE (2 * MiB) /* * Check if passed sectors are empty (not allocated or contain only 0 bytes) @@ -1362,7 +1359,7 @@ static int img_compare(int argc, char **argv) if (qemu_opts_foreach(&qemu_object_opts, user_creatable_add_opts_foreach, - NULL, NULL)) { + NULL, &error_fatal)) { ret = 2; goto out4; } @@ -1643,6 +1640,8 @@ static int convert_iteration_sectors(ImgConvertState *s, int64_t sector_num) count, &count, NULL, NULL); } if (ret < 0) { + error_report("error while reading block status of sector %" PRId64 + ": %s", sector_num, strerror(-ret)); return ret; } n = DIV_ROUND_UP(count, BDRV_SECTOR_SIZE); @@ -1682,8 +1681,6 @@ static int coroutine_fn convert_co_read(ImgConvertState *s, int64_t sector_num, int nb_sectors, uint8_t *buf) { int n, ret; - QEMUIOVector qiov; - struct iovec iov; assert(nb_sectors <= s->buf_sectors); while (nb_sectors > 0) { @@ -1699,13 +1696,10 @@ static int coroutine_fn convert_co_read(ImgConvertState *s, int64_t sector_num, bs_sectors = s->src_sectors[src_cur]; n = MIN(nb_sectors, bs_sectors - (sector_num - src_cur_offset)); - iov.iov_base = buf; - iov.iov_len = n << BDRV_SECTOR_BITS; - qemu_iovec_init_external(&qiov, &iov, 1); - ret = blk_co_preadv( + ret = blk_co_pread( blk, (sector_num - src_cur_offset) << BDRV_SECTOR_BITS, - n << BDRV_SECTOR_BITS, &qiov, 0); + n << BDRV_SECTOR_BITS, buf, 0); if (ret < 0) { return ret; } @@ -1724,8 +1718,6 @@ static int coroutine_fn convert_co_write(ImgConvertState *s, int64_t sector_num, enum ImgConvertBlockStatus status) { int ret; - QEMUIOVector qiov; - struct iovec iov; while (nb_sectors > 0) { int n = nb_sectors; @@ -1753,12 +1745,8 @@ static int coroutine_fn convert_co_write(ImgConvertState *s, int64_t sector_num, (s->compressed && !buffer_is_zero(buf, n * BDRV_SECTOR_SIZE))) { - iov.iov_base = buf; - iov.iov_len = n << BDRV_SECTOR_BITS; - qemu_iovec_init_external(&qiov, &iov, 1); - - ret = blk_co_pwritev(s->target, sector_num << BDRV_SECTOR_BITS, - n << BDRV_SECTOR_BITS, &qiov, flags); + ret = blk_co_pwrite(s->target, sector_num << BDRV_SECTOR_BITS, + n << BDRV_SECTOR_BITS, buf, flags); if (ret < 0) { return ret; } @@ -1773,7 +1761,8 @@ static int coroutine_fn convert_co_write(ImgConvertState *s, int64_t sector_num, } ret = blk_co_pwrite_zeroes(s->target, sector_num << BDRV_SECTOR_BITS, - n << BDRV_SECTOR_BITS, 0); + n << BDRV_SECTOR_BITS, + BDRV_REQ_MAY_UNMAP); if (ret < 0) { return ret; } @@ -1951,7 +1940,7 @@ static int convert_do_copy(ImgConvertState *s) if (!s->has_zero_init && !s->target_has_backing && bdrv_can_write_zeroes_with_unmap(blk_bs(s->target))) { - ret = blk_make_zero(s->target, BDRV_REQ_MAY_UNMAP); + ret = blk_make_zero(s->target, BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK); if (ret == 0) { s->has_zero_init = true; } @@ -2018,6 +2007,7 @@ static int img_convert(int argc, char **argv) BlockDriverState *out_bs; QemuOpts *opts = NULL, *sn_opts = NULL; QemuOptsList *create_opts = NULL; + QDict *open_opts = NULL; char *options = NULL; Error *local_err = NULL; bool writethrough, src_writethrough, quiet = false, image_opts = false, @@ -2171,7 +2161,7 @@ static int img_convert(int argc, char **argv) if (qemu_opts_foreach(&qemu_object_opts, user_creatable_add_opts_foreach, - NULL, NULL)) { + NULL, &error_fatal)) { goto fail_getopt; } @@ -2362,6 +2352,16 @@ static int img_convert(int argc, char **argv) } } + /* + * The later open call will need any decryption secrets, and + * bdrv_create() will purge "opts", so extract them now before + * they are lost. + */ + if (!skip_create) { + open_opts = qdict_new(); + qemu_opt_foreach(opts, img_add_key_secrets, open_opts, &error_abort); + } + if (!skip_create) { /* Create the new image */ ret = bdrv_create(drv, out_filename, opts, &local_err); @@ -2388,8 +2388,9 @@ static int img_convert(int argc, char **argv) * That has to wait for bdrv_create to be improved * to allow filenames in option syntax */ - s.target = img_open_new_file(out_filename, opts, out_fmt, - flags, writethrough, quiet, false); + s.target = img_open_file(out_filename, open_opts, out_fmt, + flags, writethrough, quiet, false); + open_opts = NULL; /* blk_new_open will have freed it */ } if (!s.target) { ret = -1; @@ -2464,6 +2465,7 @@ out: qemu_opts_del(opts); qemu_opts_free(create_opts); qemu_opts_del(sn_opts); + qobject_unref(open_opts); blk_unref(s.target); if (s.src) { for (bs_i = 0; bs_i < s.src_num; bs_i++) { @@ -2488,11 +2490,11 @@ static void dump_snapshots(BlockDriverState *bs) if (nb_sns <= 0) return; printf("Snapshot list:\n"); - bdrv_snapshot_dump(fprintf, stdout, NULL); + bdrv_snapshot_dump(NULL); printf("\n"); for(i = 0; i < nb_sns; i++) { sn = &sn_tab[i]; - bdrv_snapshot_dump(fprintf, stdout, sn); + bdrv_snapshot_dump(sn); printf("\n"); } g_free(sn_tab); @@ -2541,7 +2543,7 @@ static void dump_human_image_info_list(ImageInfoList *list) } delim = true; - bdrv_image_info_dump(fprintf, stdout, elem->value); + bdrv_image_info_dump(elem->value); } } @@ -2713,7 +2715,7 @@ static int img_info(int argc, char **argv) if (qemu_opts_foreach(&qemu_object_opts, user_creatable_add_opts_foreach, - NULL, NULL)) { + NULL, &error_fatal)) { return 1; } @@ -2740,14 +2742,14 @@ static int img_info(int argc, char **argv) return 0; } -static void dump_map_entry(OutputFormat output_format, MapEntry *e, - MapEntry *next) +static int dump_map_entry(OutputFormat output_format, MapEntry *e, + MapEntry *next) { switch (output_format) { case OFORMAT_HUMAN: if (e->data && !e->has_offset) { error_report("File contains external, encrypted or compressed clusters."); - exit(1); + return -1; } if (e->data && !e->zero) { printf("%#-16"PRIx64"%#-16"PRIx64"%#-16"PRIx64"%s\n", @@ -2780,6 +2782,7 @@ static void dump_map_entry(OutputFormat output_format, MapEntry *e, } break; } + return 0; } static int get_block_status(BlockDriverState *bs, int64_t offset, @@ -2790,6 +2793,7 @@ static int get_block_status(BlockDriverState *bs, int64_t offset, BlockDriverState *file; bool has_offset; int64_t map; + char *filename = NULL; /* As an optimization, we could cache the current range of unallocated * clusters in each file of the chain, and avoid querying the same @@ -2817,6 +2821,11 @@ static int get_block_status(BlockDriverState *bs, int64_t offset, has_offset = !!(ret & BDRV_BLOCK_OFFSET_VALID); + if (file && has_offset) { + bdrv_refresh_filename(file); + filename = file->filename; + } + *e = (MapEntry) { .start = offset, .length = bytes, @@ -2825,8 +2834,8 @@ static int get_block_status(BlockDriverState *bs, int64_t offset, .offset = map, .has_offset = has_offset, .depth = depth, - .has_filename = file && has_offset, - .filename = file && has_offset ? file->filename : NULL, + .has_filename = filename, + .filename = filename, }; return 0; @@ -2932,7 +2941,7 @@ static int img_map(int argc, char **argv) if (qemu_opts_foreach(&qemu_object_opts, user_creatable_add_opts_foreach, - NULL, NULL)) { + NULL, &error_fatal)) { return 1; } @@ -2952,7 +2961,7 @@ static int img_map(int argc, char **argv) int64_t n; /* Probe up to 1 GiB at a time. */ - n = MIN(1 << 30, length - offset); + n = MIN(1 * GiB, length - offset); ret = get_block_status(bs, offset, n, &next); if (ret < 0) { @@ -2966,12 +2975,15 @@ static int img_map(int argc, char **argv) } if (curr.length > 0) { - dump_map_entry(output_format, &curr, &next); + ret = dump_map_entry(output_format, &curr, &next); + if (ret < 0) { + goto out; + } } curr = next; } - dump_map_entry(output_format, &curr, NULL); + ret = dump_map_entry(output_format, &curr, NULL); out: blk_unref(blk); @@ -3081,7 +3093,7 @@ static int img_snapshot(int argc, char **argv) if (qemu_opts_foreach(&qemu_object_opts, user_creatable_add_opts_foreach, - NULL, NULL)) { + NULL, &error_fatal)) { return 1; } @@ -3123,11 +3135,18 @@ static int img_snapshot(int argc, char **argv) break; case SNAPSHOT_DELETE: - bdrv_snapshot_delete_by_id_or_name(bs, snapshot_name, &err); - if (err) { - error_reportf_err(err, "Could not delete snapshot '%s': ", - snapshot_name); + ret = bdrv_snapshot_find(bs, &sn, snapshot_name); + if (ret < 0) { + error_report("Could not delete snapshot '%s': snapshot not " + "found", snapshot_name); ret = 1; + } else { + ret = bdrv_snapshot_delete(bs, sn.id_str, sn.name, &err); + if (ret < 0) { + error_reportf_err(err, "Could not delete snapshot '%s': ", + snapshot_name); + ret = 1; + } } break; } @@ -3145,7 +3164,7 @@ static int img_rebase(int argc, char **argv) BlockBackend *blk = NULL, *blk_old_backing = NULL, *blk_new_backing = NULL; uint8_t *buf_old = NULL; uint8_t *buf_new = NULL; - BlockDriverState *bs = NULL; + BlockDriverState *bs = NULL, *prefix_chain_bs = NULL; char *filename; const char *fmt, *cache, *src_cache, *out_basefmt, *out_baseimg; int c, flags, src_flags, ret; @@ -3241,7 +3260,7 @@ static int img_rebase(int argc, char **argv) if (qemu_opts_foreach(&qemu_object_opts, user_creatable_add_opts_foreach, - NULL, NULL)) { + NULL, &error_fatal)) { return 1; } @@ -3290,29 +3309,23 @@ static int img_rebase(int argc, char **argv) /* For safe rebasing we need to compare old and new backing file */ if (!unsafe) { - char backing_name[PATH_MAX]; QDict *options = NULL; - - if (bs->backing_format[0] != '\0') { - options = qdict_new(); - qdict_put_str(options, "driver", bs->backing_format); - } - - if (force_share) { - if (!options) { - options = qdict_new(); + BlockDriverState *base_bs = backing_bs(bs); + + if (base_bs) { + blk_old_backing = blk_new(qemu_get_aio_context(), + BLK_PERM_CONSISTENT_READ, + BLK_PERM_ALL); + ret = blk_insert_bs(blk_old_backing, base_bs, + &local_err); + if (ret < 0) { + error_reportf_err(local_err, + "Could not reuse old backing file '%s': ", + base_bs->filename); + goto out; } - qdict_put_bool(options, BDRV_OPT_FORCE_SHARE, true); - } - bdrv_get_backing_filename(bs, backing_name, sizeof(backing_name)); - blk_old_backing = blk_new_open(backing_name, NULL, - options, src_flags, &local_err); - if (!blk_old_backing) { - error_reportf_err(local_err, - "Could not open old backing file '%s': ", - backing_name); - ret = -1; - goto out; + } else { + blk_old_backing = NULL; } if (out_baseimg[0]) { @@ -3327,32 +3340,49 @@ static int img_rebase(int argc, char **argv) qdict_put_bool(options, BDRV_OPT_FORCE_SHARE, true); } + bdrv_refresh_filename(bs); overlay_filename = bs->exact_filename[0] ? bs->exact_filename : bs->filename; - out_real_path = g_malloc(PATH_MAX); - - bdrv_get_full_backing_filename_from_filename(overlay_filename, - out_baseimg, - out_real_path, - PATH_MAX, - &local_err); + out_real_path = + bdrv_get_full_backing_filename_from_filename(overlay_filename, + out_baseimg, + &local_err); if (local_err) { error_reportf_err(local_err, "Could not resolve backing filename: "); ret = -1; - g_free(out_real_path); goto out; } - blk_new_backing = blk_new_open(out_real_path, NULL, - options, src_flags, &local_err); - g_free(out_real_path); - if (!blk_new_backing) { - error_reportf_err(local_err, - "Could not open new backing file '%s': ", - out_baseimg); - ret = -1; - goto out; + /* + * Find out whether we rebase an image on top of a previous image + * in its chain. + */ + prefix_chain_bs = bdrv_find_backing_image(bs, out_real_path); + if (prefix_chain_bs) { + g_free(out_real_path); + blk_new_backing = blk_new(qemu_get_aio_context(), + BLK_PERM_CONSISTENT_READ, + BLK_PERM_ALL); + ret = blk_insert_bs(blk_new_backing, prefix_chain_bs, + &local_err); + if (ret < 0) { + error_reportf_err(local_err, + "Could not reuse backing file '%s': ", + out_baseimg); + goto out; + } + } else { + blk_new_backing = blk_new_open(out_real_path, NULL, + options, src_flags, &local_err); + g_free(out_real_path); + if (!blk_new_backing) { + error_reportf_err(local_err, + "Could not open new backing file '%s': ", + out_baseimg); + ret = -1; + goto out; + } } } } @@ -3368,7 +3398,7 @@ static int img_rebase(int argc, char **argv) */ if (!unsafe) { int64_t size; - int64_t old_backing_size; + int64_t old_backing_size = 0; int64_t new_backing_size = 0; uint64_t offset; int64_t n; @@ -3384,15 +3414,18 @@ static int img_rebase(int argc, char **argv) ret = -1; goto out; } - old_backing_size = blk_getlength(blk_old_backing); - if (old_backing_size < 0) { - char backing_name[PATH_MAX]; + if (blk_old_backing) { + old_backing_size = blk_getlength(blk_old_backing); + if (old_backing_size < 0) { + char backing_name[PATH_MAX]; - bdrv_get_backing_filename(bs, backing_name, sizeof(backing_name)); - error_report("Could not get size of '%s': %s", - backing_name, strerror(-old_backing_size)); - ret = -1; - goto out; + bdrv_get_backing_filename(bs, backing_name, + sizeof(backing_name)); + error_report("Could not get size of '%s': %s", + backing_name, strerror(-old_backing_size)); + ret = -1; + goto out; + } } if (blk_new_backing) { new_backing_size = blk_getlength(blk_new_backing); @@ -3409,6 +3442,8 @@ static int img_rebase(int argc, char **argv) } for (offset = 0; offset < size; offset += n) { + bool buf_old_is_zero = false; + /* How many bytes can we handle with the next read? */ n = MIN(IO_BUF_SIZE, size - offset); @@ -3423,12 +3458,30 @@ static int img_rebase(int argc, char **argv) continue; } + if (prefix_chain_bs) { + /* + * If cluster wasn't changed since prefix_chain, we don't need + * to take action + */ + ret = bdrv_is_allocated_above(backing_bs(bs), prefix_chain_bs, + offset, n, &n); + if (ret < 0) { + error_report("error while reading image metadata: %s", + strerror(-ret)); + goto out; + } + if (!ret) { + continue; + } + } + /* * Read old and new backing file and take into consideration that * backing files may be smaller than the COW image. */ if (offset >= old_backing_size) { memset(buf_old, 0, n); + buf_old_is_zero = true; } else { if (offset + n > old_backing_size) { n = old_backing_size - offset; @@ -3464,8 +3517,12 @@ static int img_rebase(int argc, char **argv) if (compare_buffers(buf_old + written, buf_new + written, n - written, &pnum)) { - ret = blk_pwrite(blk, offset + written, - buf_old + written, pnum, 0); + if (buf_old_is_zero) { + ret = blk_pwrite_zeroes(blk, offset + written, pnum, 0); + } else { + ret = blk_pwrite(blk, offset + written, + buf_old + written, pnum, 0); + } if (ret < 0) { error_report("Error while writing to COW image: %s", strerror(-ret)); @@ -3621,7 +3678,7 @@ static int img_resize(int argc, char **argv) if (qemu_opts_foreach(&qemu_object_opts, user_creatable_add_opts_foreach, - NULL, NULL)) { + NULL, &error_fatal)) { return 1; } @@ -3775,7 +3832,7 @@ static int print_amend_option_help(const char *format) assert(drv->create_opts); printf("Creation options for '%s':\n", format); - qemu_opts_print_help(drv->create_opts); + qemu_opts_print_help(drv->create_opts, false); printf("\nNote that not all of these options may be amendable.\n"); return 0; } @@ -3865,7 +3922,7 @@ static int img_amend(int argc, char **argv) if (qemu_opts_foreach(&qemu_object_opts, user_creatable_add_opts_foreach, - NULL, NULL)) { + NULL, &error_fatal)) { ret = -1; goto out_no_progress; } @@ -4509,7 +4566,7 @@ static int img_dd(int argc, char **argv) if (qemu_opts_foreach(&qemu_object_opts, user_creatable_add_opts_foreach, - NULL, NULL)) { + NULL, &error_fatal)) { ret = -1; goto out; } @@ -4786,7 +4843,7 @@ static int img_measure(int argc, char **argv) if (qemu_opts_foreach(&qemu_object_opts, user_creatable_add_opts_foreach, - NULL, NULL)) { + NULL, &error_fatal)) { goto out; } @@ -4912,8 +4969,8 @@ int main(int argc, char **argv) signal(SIGPIPE, SIG_IGN); #endif + error_init(argv[0]); module_call_init(MODULE_INIT_TRACE); - error_set_progname(argv[0]); qemu_init_exec_dir(argv[0]); if (qemu_init_main_loop(&local_error)) { @@ -4962,7 +5019,7 @@ int main(int argc, char **argv) return 0; } argv += optind; - optind = 0; + qemu_reset_optind(); if (!trace_init_backends()) { exit(1);