X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=qemu-img.c;h=9aeac69fa66e52b5e56340d726d6ffe55a58b8b3;hb=a937b6aa739f65f2cae2ad9a7eb65a309ad2a359;hp=ace3adf8aea49caef8af0f8527825004d4fdded6;hpb=6f592e5aca1a27fe1c1f661cfe68b35b90850acf;p=mirror_qemu.git diff --git a/qemu-img.c b/qemu-img.c index ace3adf8ae..9aeac69fa6 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -48,6 +48,7 @@ #include "sysemu/block-backend.h" #include "block/block_int.h" #include "block/blockjob.h" +#include "block/dirty-bitmap.h" #include "block/qapi.h" #include "crypto/init.h" #include "trace/control.h" @@ -449,6 +450,11 @@ static BlockBackend *img_open(bool image_opts, blk = img_open_file(filename, NULL, fmt, flags, writethrough, quiet, force_share); } + + if (blk) { + blk_set_force_allow_inactivate(blk); + } + return blk; } @@ -1119,6 +1125,14 @@ unref_backing: done: qemu_progress_end(); + /* + * Manually inactivate the image first because this way we can know whether + * an error occurred. blk_unref() doesn't tell us about failures. + */ + ret = bdrv_inactivate_all(); + if (ret < 0 && !local_err) { + error_setg_errno(&local_err, -ret, "Error while closing the image"); + } blk_unref(blk); if (local_err) { @@ -1977,7 +1991,9 @@ static void coroutine_fn convert_co_do_copy(void *opaque) qemu_co_mutex_unlock(&s->lock); break; } - n = convert_iteration_sectors(s, s->sector_num); + WITH_GRAPH_RDLOCK_GUARD() { + n = convert_iteration_sectors(s, s->sector_num); + } if (n < 0) { qemu_co_mutex_unlock(&s->lock); s->ret = n; @@ -2025,7 +2041,9 @@ retry: if (s->ret == -EINPROGRESS) { if (copy_range) { - ret = convert_co_copy_range(s, sector_num, n); + WITH_GRAPH_RDLOCK_GUARD() { + ret = convert_co_copy_range(s, sector_num, n); + } if (ret) { s->copy_range = false; goto retry; @@ -2803,13 +2821,13 @@ static void dump_snapshots(BlockDriverState *bs) g_free(sn_tab); } -static void dump_json_image_info_list(ImageInfoList *list) +static void dump_json_block_graph_info_list(BlockGraphInfoList *list) { GString *str; QObject *obj; Visitor *v = qobject_output_visitor_new(&obj); - visit_type_ImageInfoList(v, NULL, &list, &error_abort); + visit_type_BlockGraphInfoList(v, NULL, &list, &error_abort); visit_complete(v, &obj); str = qobject_to_json_pretty(obj, true); assert(str != NULL); @@ -2819,13 +2837,13 @@ static void dump_json_image_info_list(ImageInfoList *list) g_string_free(str, true); } -static void dump_json_image_info(ImageInfo *info) +static void dump_json_block_graph_info(BlockGraphInfo *info) { GString *str; QObject *obj; Visitor *v = qobject_output_visitor_new(&obj); - visit_type_ImageInfo(v, NULL, &info, &error_abort); + visit_type_BlockGraphInfo(v, NULL, &info, &error_abort); visit_complete(v, &obj); str = qobject_to_json_pretty(obj, true); assert(str != NULL); @@ -2835,9 +2853,30 @@ static void dump_json_image_info(ImageInfo *info) g_string_free(str, true); } -static void dump_human_image_info_list(ImageInfoList *list) +static void dump_human_image_info(BlockGraphInfo *info, int indentation, + const char *path) +{ + BlockChildInfoList *children_list; + + bdrv_node_info_dump(qapi_BlockGraphInfo_base(info), indentation, + info->children == NULL); + + for (children_list = info->children; children_list; + children_list = children_list->next) + { + BlockChildInfo *child = children_list->value; + g_autofree char *child_path = NULL; + + printf("%*sChild node '%s%s':\n", + indentation * 4, "", path, child->name); + child_path = g_strdup_printf("%s%s/", path, child->name); + dump_human_image_info(child->info, indentation + 1, child_path); + } +} + +static void dump_human_image_info_list(BlockGraphInfoList *list) { - ImageInfoList *elem; + BlockGraphInfoList *elem; bool delim = false; for (elem = list; elem; elem = elem->next) { @@ -2846,7 +2885,7 @@ static void dump_human_image_info_list(ImageInfoList *list) } delim = true; - bdrv_image_info_dump(elem->value); + dump_human_image_info(elem->value, 0, "/"); } } @@ -2856,24 +2895,24 @@ static gboolean str_equal_func(gconstpointer a, gconstpointer b) } /** - * Open an image file chain and return an ImageInfoList + * Open an image file chain and return an BlockGraphInfoList * * @filename: topmost image filename * @fmt: topmost image format (may be NULL to autodetect) * @chain: true - enumerate entire backing file chain * false - only topmost image file * - * Returns a list of ImageInfo objects or NULL if there was an error opening an - * image file. If there was an error a message will have been printed to - * stderr. + * Returns a list of BlockNodeInfo objects or NULL if there was an error + * opening an image file. If there was an error a message will have been + * printed to stderr. */ -static ImageInfoList *collect_image_info_list(bool image_opts, - const char *filename, - const char *fmt, - bool chain, bool force_share) +static BlockGraphInfoList *collect_image_info_list(bool image_opts, + const char *filename, + const char *fmt, + bool chain, bool force_share) { - ImageInfoList *head = NULL; - ImageInfoList **tail = &head; + BlockGraphInfoList *head = NULL; + BlockGraphInfoList **tail = &head; GHashTable *filenames; Error *err = NULL; @@ -2882,7 +2921,7 @@ static ImageInfoList *collect_image_info_list(bool image_opts, while (filename) { BlockBackend *blk; BlockDriverState *bs; - ImageInfo *info; + BlockGraphInfo *info; if (g_hash_table_lookup_extended(filenames, filename, NULL, NULL)) { error_report("Backing file '%s' creates an infinite loop.", @@ -2899,7 +2938,14 @@ static ImageInfoList *collect_image_info_list(bool image_opts, } bs = blk_bs(blk); - bdrv_query_image_info(bs, &info, &err); + /* + * Note that the returned BlockGraphInfo object will not have + * information about this image's backing node, because we have opened + * it with BDRV_O_NO_BACKING. Printing this object will therefore not + * duplicate the backing chain information that we obtain by walking + * the chain manually here. + */ + bdrv_query_block_graph_info(bs, &info, &err); if (err) { error_report_err(err); blk_unref(blk); @@ -2915,15 +2961,15 @@ static ImageInfoList *collect_image_info_list(bool image_opts, image_opts = false; if (chain) { - if (info->has_full_backing_filename) { + if (info->full_backing_filename) { filename = info->full_backing_filename; - } else if (info->has_backing_filename) { + } else if (info->backing_filename) { error_report("Could not determine absolute backing filename," " but backing filename '%s' present", info->backing_filename); goto err; } - if (info->has_backing_filename_format) { + if (info->backing_filename_format) { fmt = info->backing_filename_format; } } @@ -2932,7 +2978,7 @@ static ImageInfoList *collect_image_info_list(bool image_opts, return head; err: - qapi_free_ImageInfoList(head); + qapi_free_BlockGraphInfoList(head); g_hash_table_destroy(filenames); return NULL; } @@ -2943,7 +2989,7 @@ static int img_info(int argc, char **argv) OutputFormat output_format = OFORMAT_HUMAN; bool chain = false; const char *filename, *fmt, *output; - ImageInfoList *list; + BlockGraphInfoList *list; bool image_opts = false; bool force_share = false; @@ -3022,14 +3068,14 @@ static int img_info(int argc, char **argv) break; case OFORMAT_JSON: if (chain) { - dump_json_image_info_list(list); + dump_json_block_graph_info_list(list); } else { - dump_json_image_info(list->value); + dump_json_block_graph_info(list->value); } break; } - qapi_free_ImageInfoList(list); + qapi_free_BlockGraphInfoList(list); return 0; } @@ -3046,7 +3092,7 @@ static int dump_map_entry(OutputFormat output_format, MapEntry *e, printf("%#-16"PRIx64"%#-16"PRIx64"%#-16"PRIx64"%s\n", e->start, e->length, e->has_offset ? e->offset : 0, - e->has_filename ? e->filename : ""); + e->filename ?: ""); } /* This format ignores the distinction between 0, ZERO and ZERO|DATA. * Modify the flags here to allow more coalescing. @@ -3127,7 +3173,6 @@ static int get_block_status(BlockDriverState *bs, int64_t offset, .has_offset = has_offset, .depth = depth, .present = !!(ret & BDRV_BLOCK_ALLOCATED), - .has_filename = filename, .filename = filename, }; @@ -3143,11 +3188,11 @@ static inline bool entry_mergeable(const MapEntry *curr, const MapEntry *next) curr->data != next->data || curr->depth != next->depth || curr->present != next->present || - curr->has_filename != next->has_filename || + !curr->filename != !next->filename || curr->has_offset != next->has_offset) { return false; } - if (curr->has_filename && strcmp(curr->filename, next->filename)) { + if (curr->filename && strcmp(curr->filename, next->filename)) { return false; } if (curr->has_offset && curr->offset + curr->length != next->offset) { @@ -4371,7 +4416,7 @@ static int img_bench(int argc, char **argv) struct timeval t1, t2; int i; bool force_share = false; - size_t buf_size; + size_t buf_size = 0; for (;;) { static const struct option long_options[] = { @@ -4570,7 +4615,7 @@ static int img_bench(int argc, char **argv) data.buf = blk_blockalign(blk, buf_size); memset(data.buf, pattern, data.nrreq * data.bufsize); - blk_register_buf(blk, data.buf, buf_size); + blk_register_buf(blk, data.buf, buf_size, &error_fatal); data.qiov = g_new(QEMUIOVector, data.nrreq); for (i = 0; i < data.nrreq; i++) { @@ -4593,7 +4638,7 @@ static int img_bench(int argc, char **argv) out: if (data.buf) { - blk_unregister_buf(blk, data.buf); + blk_unregister_buf(blk, data.buf, buf_size); } qemu_vfree(data.buf); blk_unref(blk); @@ -4633,6 +4678,7 @@ static int img_bitmap(int argc, char **argv) QSIMPLEQ_HEAD(, ImgBitmapAction) actions; ImgBitmapAction *act, *act_next; const char *op; + int inactivate_ret; QSIMPLEQ_INIT(&actions); @@ -4817,6 +4863,16 @@ static int img_bitmap(int argc, char **argv) ret = 0; out: + /* + * Manually inactivate the images first because this way we can know whether + * an error occurred. blk_unref() doesn't tell us about failures. + */ + inactivate_ret = bdrv_inactivate_all(); + if (inactivate_ret < 0) { + error_report("Error while closing the image: %s", strerror(-inactivate_ret)); + ret = 1; + } + blk_unref(src); blk_unref(blk); qemu_opts_del(opts); @@ -4922,7 +4978,7 @@ static int img_dd(int argc, char **argv) const char *out_fmt = "raw"; const char *fmt = NULL; int64_t size = 0; - int64_t block_count = 0, out_pos, in_pos; + int64_t out_pos, in_pos; bool force_share = false; struct DdInfo dd = { .flags = 0, @@ -5122,7 +5178,7 @@ static int img_dd(int argc, char **argv) in.buf = g_new(uint8_t, in.bsz); - for (out_pos = 0; in_pos < size; block_count++) { + for (out_pos = 0; in_pos < size; ) { int bytes = (in_pos + in.bsz > size) ? size - in_pos : in.bsz; ret = blk_pread(blk1, in_pos, bytes, in.buf, 0);