#include "qemu/option.h"
#include "qemu/error-report.h"
#include "qemu/log.h"
+#include "qemu/main-loop.h"
#include "qemu/module.h"
#include "qemu/units.h"
#include "qom/object_interfaces.h"
-#include "sysemu/sysemu.h"
#include "sysemu/block-backend.h"
#include "block/block_int.h"
#include "block/blockjob.h"
OPTION_PREALLOCATION = 265,
OPTION_SHRINK = 266,
OPTION_SALVAGE = 267,
+ OPTION_TARGET_IS_ZERO = 268,
};
typedef enum OutputFormat {
},
};
+static bool qemu_img_object_print_help(const char *type, QemuOpts *opts)
+{
+ if (user_creatable_print_help(type, opts)) {
+ exit(0);
+ }
+ return true;
+}
+
static QemuOptsList qemu_source_opts = {
.name = "source",
.implied_opt_name = "file",
if (qemu_opts_foreach(&qemu_object_opts,
user_creatable_add_opts_foreach,
- NULL, &error_fatal)) {
+ qemu_img_object_print_help, &error_fatal)) {
goto fail;
}
if (qemu_opts_foreach(&qemu_object_opts,
user_creatable_add_opts_foreach,
- NULL, &error_fatal)) {
+ qemu_img_object_print_help, &error_fatal)) {
return 1;
}
check->corruptions_fixed);
}
+ qapi_free_ImageCheck(check);
+ check = g_new0(ImageCheck, 1);
ret = collect_image_check(bs, check, filename, fmt, 0);
check->leaks_fixed = leaks_fixed;
do {
float progress = 0.0f;
aio_poll(aio_context, true);
- if (job->job.progress_total) {
- progress = (float)job->job.progress_current /
- job->job.progress_total * 100.f;
+ if (job->job.progress.total) {
+ progress = (float)job->job.progress.current /
+ job->job.progress.total * 100.f;
}
qemu_progress_print(progress, 0);
} while (!job_is_ready(&job->job) && !job_is_completed(&job->job));
if (qemu_opts_foreach(&qemu_object_opts,
user_creatable_add_opts_foreach,
- NULL, &error_fatal)) {
+ qemu_img_object_print_help, &error_fatal)) {
return 1;
}
if (qemu_opts_foreach(&qemu_object_opts,
user_creatable_add_opts_foreach,
- NULL, &error_fatal)) {
+ qemu_img_object_print_help, &error_fatal)) {
ret = 2;
goto out4;
}
bool has_zero_init;
bool compressed;
bool unallocated_blocks_are_zero;
+ bool target_is_new;
bool target_has_backing;
int64_t target_backing_sectors; /* negative if unknown */
bool wr_in_order;
int64_t sector_num = 0;
/* Check whether we have zero initialisation or can get it efficiently */
- s->has_zero_init = s->min_sparse && !s->target_has_backing
- ? bdrv_has_zero_init(blk_bs(s->target))
- : false;
+ if (!s->has_zero_init && s->target_is_new && s->min_sparse &&
+ !s->target_has_backing) {
+ s->has_zero_init = bdrv_has_zero_init(blk_bs(s->target));
+ }
if (!s->has_zero_init && !s->target_has_backing &&
bdrv_can_write_zeroes_with_unmap(blk_bs(s->target)))
{"force-share", no_argument, 0, 'U'},
{"target-image-opts", no_argument, 0, OPTION_TARGET_IMAGE_OPTS},
{"salvage", no_argument, 0, OPTION_SALVAGE},
+ {"target-is-zero", no_argument, 0, OPTION_TARGET_IS_ZERO},
{0, 0, 0, 0}
};
c = getopt_long(argc, argv, ":hf:O:B:Cco:l:S:pt:T:qnm:WU",
int64_t sval;
sval = cvtnum(optarg);
- if (sval < 0 || sval & (BDRV_SECTOR_SIZE - 1) ||
+ if (sval < 0 || !QEMU_IS_ALIGNED(sval, BDRV_SECTOR_SIZE) ||
sval / BDRV_SECTOR_SIZE > MAX_BUF_SECTORS) {
error_report("Invalid buffer size for sparse output specified. "
"Valid sizes are multiples of %llu up to %llu. Select "
case OPTION_TARGET_IMAGE_OPTS:
tgt_image_opts = true;
break;
+ case OPTION_TARGET_IS_ZERO:
+ /*
+ * The user asserting that the target is blank has the
+ * same effect as the target driver supporting zero
+ * initialisation.
+ */
+ s.has_zero_init = true;
+ break;
}
}
if (qemu_opts_foreach(&qemu_object_opts,
user_creatable_add_opts_foreach,
- NULL, &error_fatal)) {
+ qemu_img_object_print_help, &error_fatal)) {
goto fail_getopt;
}
goto fail_getopt;
}
+ if (skip_create && options) {
+ warn_report("-o has no effect when skipping image creation");
+ warn_report("This will become an error in future QEMU versions.");
+ }
+
+ if (s.has_zero_init && !skip_create) {
+ error_report("--target-is-zero requires use of -n flag");
+ goto fail_getopt;
+ }
+
s.src_num = argc - optind - 1;
out_filename = s.src_num >= 1 ? argv[argc - 1] : NULL;
}
s.target_has_backing = (bool) out_baseimg;
+ if (s.has_zero_init && s.target_has_backing) {
+ error_report("Cannot use --target-is-zero when the destination "
+ "image has a backing file");
+ goto out;
+ }
+
if (s.src_num > 1 && out_baseimg) {
error_report("Having a backing file for the target makes no sense when "
"concatenating multiple input images");
const char *preallocation =
qemu_opt_get(opts, BLOCK_OPT_PREALLOC);
- if (drv && !drv->bdrv_co_pwritev_compressed) {
+ if (drv && !block_driver_can_compress(drv)) {
error_report("Compression not supported for this file format");
ret = -1;
goto out;
}
}
+ s.target_is_new = !skip_create;
+
flags = s.min_sparse ? (BDRV_O_RDWR | BDRV_O_UNMAP) : BDRV_O_RDWR;
ret = bdrv_parse_cache_mode(cache, &flags, &writethrough);
if (ret < 0) {
}
out_bs = blk_bs(s.target);
- if (s.compressed && !out_bs->drv->bdrv_co_pwritev_compressed) {
+ if (s.compressed && !block_driver_can_compress(out_bs->drv)) {
error_report("Compression not supported for this file format");
ret = -1;
goto out;
}
}
- if (s.target_has_backing) {
+ if (s.target_has_backing && s.target_is_new) {
/* Errors are treated as "backing length unknown" (which means
* s.target_backing_sectors has to be negative, which it will
* be automatically). The backing file length is used only
blk_unref(blk);
+ /* Clear parameters that only apply to the topmost image */
filename = fmt = NULL;
+ image_opts = false;
+
if (chain) {
if (info->has_full_backing_filename) {
filename = info->full_backing_filename;
if (qemu_opts_foreach(&qemu_object_opts,
user_creatable_add_opts_foreach,
- NULL, &error_fatal)) {
+ qemu_img_object_print_help, &error_fatal)) {
return 1;
}
if (qemu_opts_foreach(&qemu_object_opts,
user_creatable_add_opts_foreach,
- NULL, &error_fatal)) {
+ qemu_img_object_print_help, &error_fatal)) {
return 1;
}
if (qemu_opts_foreach(&qemu_object_opts,
user_creatable_add_opts_foreach,
- NULL, &error_fatal)) {
+ qemu_img_object_print_help, &error_fatal)) {
return 1;
}
if (qemu_opts_foreach(&qemu_object_opts,
user_creatable_add_opts_foreach,
- NULL, &error_fatal)) {
+ qemu_img_object_print_help, &error_fatal)) {
return 1;
}
Error *err = NULL;
int c, ret, relative;
const char *filename, *fmt, *size;
- int64_t n, total_size, current_size, new_size;
+ int64_t n, total_size, current_size;
bool quiet = false;
BlockBackend *blk = NULL;
PreallocMode prealloc = PREALLOC_MODE_OFF;
if (qemu_opts_foreach(&qemu_object_opts,
user_creatable_add_opts_foreach,
- NULL, &error_fatal)) {
+ qemu_img_object_print_help, &error_fatal)) {
return 1;
}
}
}
- ret = blk_truncate(blk, total_size, prealloc, &err);
- if (ret < 0) {
+ /*
+ * The user expects the image to have the desired size after
+ * resizing, so pass @exact=true. It is of no use to report
+ * success when the image has not actually been resized.
+ */
+ ret = blk_truncate(blk, total_size, true, prealloc, &err);
+ if (!ret) {
+ qprintf(quiet, "Image resized.\n");
+ } else {
error_report_err(err);
- goto out;
}
-
- new_size = blk_getlength(blk);
- if (new_size < 0) {
- error_report("Failed to verify truncated image length: %s",
- strerror(-new_size));
- ret = -1;
- goto out;
- }
-
- /* Some block drivers implement a truncation method, but only so
- * the user can cause qemu to refresh the image's size from disk.
- * The idea is that the user resizes the image outside of qemu and
- * then invokes block_resize to inform qemu about it.
- * (This includes iscsi and file-posix for device files.)
- * Of course, that is not the behavior someone invoking
- * qemu-img resize would find useful, so we catch that behavior
- * here and tell the user. */
- if (new_size != total_size && new_size == current_size) {
- error_report("Image was not resized; resizing may not be supported "
- "for this image");
- ret = -1;
- goto out;
- }
-
- if (new_size != total_size) {
- warn_report("Image should have been resized to %" PRIi64
- " bytes, but was resized to %" PRIi64 " bytes",
- total_size, new_size);
- }
-
- qprintf(quiet, "Image resized.\n");
-
out:
blk_unref(blk);
if (ret) {
if (qemu_opts_foreach(&qemu_object_opts,
user_creatable_add_opts_foreach,
- NULL, &error_fatal)) {
+ qemu_img_object_print_help, &error_fatal)) {
ret = -1;
goto out_no_progress;
}
{"force-share", no_argument, 0, 'U'},
{0, 0, 0, 0}
};
- c = getopt_long(argc, argv, ":hc:d:f:no:qs:S:t:wU", long_options, NULL);
+ c = getopt_long(argc, argv, ":hc:d:f:ni:o:qs:S:t:wU", long_options,
+ NULL);
if (c == -1) {
break;
}
case 'n':
flags |= BDRV_O_NATIVE_AIO;
break;
+ case 'i':
+ ret = bdrv_parse_aio(optarg, &flags);
+ if (ret < 0) {
+ error_report("Invalid aio option: %s", optarg);
+ ret = -1;
+ goto out;
+ }
+ break;
case 'o':
{
offset = cvtnum(optarg);
if (qemu_opts_foreach(&qemu_object_opts,
user_creatable_add_opts_foreach,
- NULL, &error_fatal)) {
+ qemu_img_object_print_help, &error_fatal)) {
ret = -1;
goto out;
}
if (qemu_opts_foreach(&qemu_object_opts,
user_creatable_add_opts_foreach,
- NULL, &error_fatal)) {
+ qemu_img_object_print_help, &error_fatal)) {
goto out;
}
filename = argv[optind];
}
- if (!filename &&
- (object_opts || image_opts || fmt || snapshot_name || sn_opts)) {
- error_report("--object, --image-opts, -f, and -l "
- "require a filename argument.");
+ if (!filename && (image_opts || fmt || snapshot_name || sn_opts)) {
+ error_report("--image-opts, -f, and -l require a filename argument.");
goto out;
}
if (filename && img_size != UINT64_MAX) {