@samitouri / QOSamiQemu / commits / 910451bc5b

qcow2: Add keep_data_file command-line option

Add a command-line-only option to prevent overwriting the file specified as external data file. This option is only available on the qemu-img create command line, not via blockdev-create, as it makes no sense there: That interface separates file creation and formatting, so where the external data file attached to a newly formatted qcow2 node comes from is completely up to the user. Implementation detail: Enabling this option will not only not overwrite the external data file, but also assume it already exists, for two reasons: - It is simpler than checking whether the file exists, and only skipping creating it when it does not. It is therefore also less error-prone, i.e. we can never accidentally overwrite an existing file because we made some mistake in checking whether it exists. - I think it makes sense from a user's perspective: You set this option when you want to use an existing data file, and you unset it when you want a new one. Getting an error when you expect to use an existing data file seems to me a nice warning that something is not right. Signed-off-by: Hanna Czenczek <hreitz@redhat.com> Message-ID: <20250530084448.192369-2-hreitz@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com> [kwolf: Removed redundant has_data_file_raw check] Reviewed-by: Kevin Wolf <kwolf@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>

Hanna Czenczek committed May 30, 2025 at 10:44 UTC 910451bc5b08b45863e173b58cbf2288b82d9fd2
3 files changed +87 -4
block/qcow2.c
+68 -4
@@ -3991,6 +3991,8 @@ qcow2_co_create_opts(BlockDriver *drv, const char *filename, QemuOpts *opts,
3991 BlockDriverState *bs = NULL;
3992 BlockDriverState *data_bs = NULL;
3993 const char *val;
3994 + bool keep_data_file = false;
3995 + BlockdevCreateOptionsQcow2 *qcow2_opts;
3996 int ret;
3997
3998 /* Only the keyval visitor supports the dotted syntax needed for
@@ -4022,6 +4024,22 @@ qcow2_co_create_opts(BlockDriver *drv, const char *filename, QemuOpts *opts,
4024 qdict_put_str(qdict, BLOCK_OPT_COMPAT_LEVEL, "v3");
4025 }
4026
4027 + val = qdict_get_try_str(qdict, BLOCK_OPT_KEEP_DATA_FILE);
4028 + if (val) {
4029 + if (!strcmp(val, "on")) {
4030 + keep_data_file = true;
4031 + } else if (!strcmp(val, "off")) {
4032 + keep_data_file = false;
4033 + } else {
4034 + error_setg(errp,
4035 + "Invalid value '%s' for '%s': Must be 'on' or 'off'",
4036 + val, BLOCK_OPT_KEEP_DATA_FILE);
4037 + ret = -EINVAL;
4038 + goto finish;
4039 + }
4040 + qdict_del(qdict, BLOCK_OPT_KEEP_DATA_FILE);
4041 + }
4042 +
4043 /* Change legacy command line options into QMP ones */
4044 static const QDictRenames opt_renames[] = {
4045 { BLOCK_OPT_BACKING_FILE, "backing-file" },
@@ -4058,9 +4076,11 @@ qcow2_co_create_opts(BlockDriver *drv, const char *filename, QemuOpts *opts,
4076 /* Create and open an external data file (protocol layer) */
4077 val = qdict_get_try_str(qdict, BLOCK_OPT_DATA_FILE);
4078 if (val) {
4061 - ret = bdrv_co_create_file(val, opts, false, errp);
4062 - if (ret < 0) {
4063 - goto finish;
4079 + if (!keep_data_file) {
4080 + ret = bdrv_co_create_file(val, opts, false, errp);
4081 + if (ret < 0) {
4082 + goto finish;
4083 + }
4084 }
4085
4086 data_bs = bdrv_co_open(val, NULL, NULL,
@@ -4073,6 +4093,11 @@ qcow2_co_create_opts(BlockDriver *drv, const char *filename, QemuOpts *opts,
4093
4094 qdict_del(qdict, BLOCK_OPT_DATA_FILE);
4095 qdict_put_str(qdict, "data-file", data_bs->node_name);
4096 + } else if (keep_data_file) {
4097 + error_setg(errp, "Must not use '%s=on' without '%s'",
4098 + BLOCK_OPT_KEEP_DATA_FILE, BLOCK_OPT_DATA_FILE);
4099 + ret = -EINVAL;
4100 + goto finish;
4101 }
4102
4103 /* Set 'driver' and 'node' options */
@@ -4093,6 +4118,37 @@ qcow2_co_create_opts(BlockDriver *drv, const char *filename, QemuOpts *opts,
4118 goto finish;
4119 }
4120
4121 + qcow2_opts = &create_options->u.qcow2;
4122 +
4123 + if (!qcow2_opts->has_preallocation) {
4124 + qcow2_opts->preallocation = PREALLOC_MODE_OFF;
4125 + }
4126 +
4127 + if (keep_data_file &&
4128 + qcow2_opts->preallocation != PREALLOC_MODE_OFF &&
4129 + qcow2_opts->preallocation != PREALLOC_MODE_METADATA)
4130 + {
4131 + error_setg(errp, "Preallocating more than only metadata would "
4132 + "overwrite the external data file's content and is "
4133 + "therefore incompatible with '%s=on'",
4134 + BLOCK_OPT_KEEP_DATA_FILE);
4135 + ret = -EINVAL;
4136 + goto finish;
4137 + }
4138 +
4139 + if (keep_data_file &&
4140 + qcow2_opts->preallocation == PREALLOC_MODE_OFF &&
4141 + !qcow2_opts->data_file_raw)
4142 + {
4143 + error_setg(errp, "'%s=on' requires '%s=metadata' or '%s=on', or the "
4144 + "file contents will not be visible",
4145 + BLOCK_OPT_KEEP_DATA_FILE,
4146 + BLOCK_OPT_PREALLOC,
4147 + BLOCK_OPT_DATA_FILE_RAW);
4148 + ret = -EINVAL;
4149 + goto finish;
4150 + }
4151 +
4152 /* Silently round up size */
4153 create_options->u.qcow2.size = ROUND_UP(create_options->u.qcow2.size,
4154 BDRV_SECTOR_SIZE);
@@ -4103,7 +4159,9 @@ finish:
4159 if (ret < 0) {
4160 bdrv_graph_co_rdlock();
4161 bdrv_co_delete_file_noerr(bs);
4106 - bdrv_co_delete_file_noerr(data_bs);
4162 + if (!keep_data_file) {
4163 + bdrv_co_delete_file_noerr(data_bs);
4164 + }
4165 bdrv_graph_co_rdunlock();
4166 } else {
4167 ret = 0;
@@ -6202,6 +6260,12 @@ static QemuOptsList qcow2_create_opts = {
6260 .help = "Compression method used for image cluster " \
6261 "compression", \
6262 .def_value_str = "zlib" \
6263 + }, \
6264 + { \
6265 + .name = BLOCK_OPT_KEEP_DATA_FILE, \
6266 + .type = QEMU_OPT_BOOL, \
6267 + .help = "Assume the external data file already exists and " \
6268 + "do not overwrite it" \
6269 },
6270 QCOW_COMMON_OPTIONS,
6271 { /* end of list */ }
include/block/block_int-common.h
+1
@@ -56,6 +56,7 @@
56 #define BLOCK_OPT_DATA_FILE_RAW "data_file_raw"
57 #define BLOCK_OPT_COMPRESSION_TYPE "compression_type"
58 #define BLOCK_OPT_EXTL2 "extended_l2"
59 +#define BLOCK_OPT_KEEP_DATA_FILE "keep_data_file"
60
61 #define BLOCK_PROBE_BUF_SIZE 512
62
tests/qemu-iotests/082.out
+18
@@ -66,6 +66,7 @@ Supported options:
66 encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
67 extended_l2=<bool (on/off)> - Extended L2 tables
68 extent_size_hint=<size> - Extent size hint for the image file, 0 to disable
69 + keep_data_file=<bool (on/off)> - Assume the external data file already exists and do not overwrite it
70 lazy_refcounts=<bool (on/off)> - Postpone refcount updates
71 nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
72 preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
@@ -92,6 +93,7 @@ Supported options:
93 encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
94 extended_l2=<bool (on/off)> - Extended L2 tables
95 extent_size_hint=<size> - Extent size hint for the image file, 0 to disable
96 + keep_data_file=<bool (on/off)> - Assume the external data file already exists and do not overwrite it
97 lazy_refcounts=<bool (on/off)> - Postpone refcount updates
98 nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
99 preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
@@ -118,6 +120,7 @@ Supported options:
120 encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
121 extended_l2=<bool (on/off)> - Extended L2 tables
122 extent_size_hint=<size> - Extent size hint for the image file, 0 to disable
123 + keep_data_file=<bool (on/off)> - Assume the external data file already exists and do not overwrite it
124 lazy_refcounts=<bool (on/off)> - Postpone refcount updates
125 nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
126 preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
@@ -144,6 +147,7 @@ Supported options:
147 encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
148 extended_l2=<bool (on/off)> - Extended L2 tables
149 extent_size_hint=<size> - Extent size hint for the image file, 0 to disable
150 + keep_data_file=<bool (on/off)> - Assume the external data file already exists and do not overwrite it
151 lazy_refcounts=<bool (on/off)> - Postpone refcount updates
152 nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
153 preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
@@ -170,6 +174,7 @@ Supported options:
174 encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
175 extended_l2=<bool (on/off)> - Extended L2 tables
176 extent_size_hint=<size> - Extent size hint for the image file, 0 to disable
177 + keep_data_file=<bool (on/off)> - Assume the external data file already exists and do not overwrite it
178 lazy_refcounts=<bool (on/off)> - Postpone refcount updates
179 nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
180 preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
@@ -196,6 +201,7 @@ Supported options:
201 encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
202 extended_l2=<bool (on/off)> - Extended L2 tables
203 extent_size_hint=<size> - Extent size hint for the image file, 0 to disable
204 + keep_data_file=<bool (on/off)> - Assume the external data file already exists and do not overwrite it
205 lazy_refcounts=<bool (on/off)> - Postpone refcount updates
206 nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
207 preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
@@ -222,6 +228,7 @@ Supported options:
228 encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
229 extended_l2=<bool (on/off)> - Extended L2 tables
230 extent_size_hint=<size> - Extent size hint for the image file, 0 to disable
231 + keep_data_file=<bool (on/off)> - Assume the external data file already exists and do not overwrite it
232 lazy_refcounts=<bool (on/off)> - Postpone refcount updates
233 nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
234 preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
@@ -248,6 +255,7 @@ Supported options:
255 encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
256 extended_l2=<bool (on/off)> - Extended L2 tables
257 extent_size_hint=<size> - Extent size hint for the image file, 0 to disable
258 + keep_data_file=<bool (on/off)> - Assume the external data file already exists and do not overwrite it
259 lazy_refcounts=<bool (on/off)> - Postpone refcount updates
260 nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
261 preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
@@ -288,6 +296,7 @@ Supported qcow2 options:
296 encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
297 encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
298 extended_l2=<bool (on/off)> - Extended L2 tables
299 + keep_data_file=<bool (on/off)> - Assume the external data file already exists and do not overwrite it
300 lazy_refcounts=<bool (on/off)> - Postpone refcount updates
301 preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
302 refcount_bits=<num> - Width of a reference count entry in bits
@@ -376,6 +385,7 @@ Supported options:
385 encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
386 extended_l2=<bool (on/off)> - Extended L2 tables
387 extent_size_hint=<size> - Extent size hint for the image file, 0 to disable
388 + keep_data_file=<bool (on/off)> - Assume the external data file already exists and do not overwrite it
389 lazy_refcounts=<bool (on/off)> - Postpone refcount updates
390 nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
391 preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
@@ -402,6 +412,7 @@ Supported options:
412 encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
413 extended_l2=<bool (on/off)> - Extended L2 tables
414 extent_size_hint=<size> - Extent size hint for the image file, 0 to disable
415 + keep_data_file=<bool (on/off)> - Assume the external data file already exists and do not overwrite it
416 lazy_refcounts=<bool (on/off)> - Postpone refcount updates
417 nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
418 preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
@@ -428,6 +439,7 @@ Supported options:
439 encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
440 extended_l2=<bool (on/off)> - Extended L2 tables
441 extent_size_hint=<size> - Extent size hint for the image file, 0 to disable
442 + keep_data_file=<bool (on/off)> - Assume the external data file already exists and do not overwrite it
443 lazy_refcounts=<bool (on/off)> - Postpone refcount updates
444 nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
445 preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
@@ -454,6 +466,7 @@ Supported options:
466 encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
467 extended_l2=<bool (on/off)> - Extended L2 tables
468 extent_size_hint=<size> - Extent size hint for the image file, 0 to disable
469 + keep_data_file=<bool (on/off)> - Assume the external data file already exists and do not overwrite it
470 lazy_refcounts=<bool (on/off)> - Postpone refcount updates
471 nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
472 preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
@@ -480,6 +493,7 @@ Supported options:
493 encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
494 extended_l2=<bool (on/off)> - Extended L2 tables
495 extent_size_hint=<size> - Extent size hint for the image file, 0 to disable
496 + keep_data_file=<bool (on/off)> - Assume the external data file already exists and do not overwrite it
497 lazy_refcounts=<bool (on/off)> - Postpone refcount updates
498 nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
499 preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
@@ -506,6 +520,7 @@ Supported options:
520 encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
521 extended_l2=<bool (on/off)> - Extended L2 tables
522 extent_size_hint=<size> - Extent size hint for the image file, 0 to disable
523 + keep_data_file=<bool (on/off)> - Assume the external data file already exists and do not overwrite it
524 lazy_refcounts=<bool (on/off)> - Postpone refcount updates
525 nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
526 preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
@@ -532,6 +547,7 @@ Supported options:
547 encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
548 extended_l2=<bool (on/off)> - Extended L2 tables
549 extent_size_hint=<size> - Extent size hint for the image file, 0 to disable
550 + keep_data_file=<bool (on/off)> - Assume the external data file already exists and do not overwrite it
551 lazy_refcounts=<bool (on/off)> - Postpone refcount updates
552 nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
553 preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
@@ -558,6 +574,7 @@ Supported options:
574 encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
575 extended_l2=<bool (on/off)> - Extended L2 tables
576 extent_size_hint=<size> - Extent size hint for the image file, 0 to disable
577 + keep_data_file=<bool (on/off)> - Assume the external data file already exists and do not overwrite it
578 lazy_refcounts=<bool (on/off)> - Postpone refcount updates
579 nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
580 preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
@@ -598,6 +615,7 @@ Supported qcow2 options:
615 encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
616 encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
617 extended_l2=<bool (on/off)> - Extended L2 tables
618 + keep_data_file=<bool (on/off)> - Assume the external data file already exists and do not overwrite it
619 lazy_refcounts=<bool (on/off)> - Postpone refcount updates
620 preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
621 refcount_bits=<num> - Width of a reference count entry in bits