Merge tag 'for-upstream' of https://gitlab.com/kmwolf/qemu into staging

Block layer patches

- Wire up 'flat' mode also for 'query-block'
- Never drop BLOCK_IO_ERROR with action=stop for rate limiting
- qcow2: Add keep_data_file command-line option
- vmdk: fix OOB read in vmdk_read_extent()
- curl: fix concurrent completion handling
- nfs: Fix deadlock
- mirror: Fix missed dirty bitmap writes during startup
- throttle-groups: fix deadlock with iolimits and muliple iothreads

# -----BEGIN PGP SIGNATURE-----
#
# iQJFBAABCgAvFiEE3D3rFZqa+V09dFb+fwmycsiPL9YFAmmrHbgRHGt3b2xmQHJl
# ZGhhdC5jb20ACgkQfwmycsiPL9b+ng/+P4B3q+Rrvb5WWrY8fro/3kzSqGAHjKeL
# QqEU8zywck5EorzK0H2f8BskxqXJ/LAe7ut4rFGqCA85l/eyWT7OhGm/DHnO/oI8
# /nU5r800/ZpvKn9HqK5+TSkswYQ6RmmMF9ZYIfYdB/JqPAmVmvbcjdqASVRT4PZ+
# v9QUKY309LDoaWm+vO/f0oPyxhog6yDHVh/rGhDkCOMyNExFyvfvAeLVuu+99Nzz
# GFxleM7JyHdVmIErbKRNp2Z/uVSQvlOg5uecI3IZnc2QUbACQWWc97PCP199JzZ+
# HaEq8tP+/TQZSsXEYKHmxYx4AyzCIu15qDmpnfhnoA9MC80P+eLrHJ5sXOsT6S32
# AyTLIE6KKLImtLyG6TZV05G127c7ekrMbY8OfY21ocACUstr4q6MY1J6ZCcLQRMZ
# E0BZR0CEOYtImrx0wr1XR0/q7SceiIaDcwFuPkHKz2akRS7bq9KH1RfxHYPpBJiX
# nkkLtilV4s/OlhrsoGJeq44C7jZA2MdrgouxNiPe+08CFeJra5wQybC7ZIYqknx6
# D/Eu4Y6KwMbyfnMd/4F0kbzHv9h8R+ri2hHUqfKEtl2pNTqe8JEpsPmn+yMpuRe4
# Cl66DFs0OzcONiUBNJVdGg0dm0jtIyCEo2am1MAJUgGkwYKxtgUQLsouSJS1d4EP
# iDe9pZmlytg=
# =kPKk
# -----END PGP SIGNATURE-----
# gpg: Signature made Fri Mar  6 18:32:24 2026 GMT
# gpg:                using RSA key DC3DEB159A9AF95D3D7456FE7F09B272C88F2FD6
# gpg:                issuer "kwolf@redhat.com"
# gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>" [full]
# Primary key fingerprint: DC3D EB15 9A9A F95D 3D74  56FE 7F09 B272 C88F 2FD6

* tag 'for-upstream' of https://gitlab.com/kmwolf/qemu:
  iotests/244: Add test cases for keep_data_file
  iotests/common.filter: Sort keep_data_file
  qcow2: Simplify size round-up in co_create_opts
  qcow2: Add keep_data_file command-line option
  block/nfs: Do not enter coroutine from CB
  block: Never drop BLOCK_IO_ERROR with action=stop for rate limiting
  block/throttle-groups: fix deadlock with iolimits and muliple iothreads
  mirror: Fix missed dirty bitmap writes during startup
  block/curl: fix concurrent completion handling
  hmp_nbd_server_start: Don't ask for backing image data
  block: Wire up 'flat' mode also for 'query-block'
  block/vmdk: fix OOB read in vmdk_read_extent()

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell
2026-03-06 18:57:12 +00:00
17 changed files with 309 additions and 75 deletions

View File

@@ -324,17 +324,11 @@ curl_find_buf(BDRVCURLState *s, uint64_t start, uint64_t len, CURLAIOCB *acb)
static void curl_multi_check_completion(BDRVCURLState *s)
{
int msgs_in_queue;
CURLMsg *msg;
/* Try to find done transfers, so we can free the easy
* handle again. */
for (;;) {
CURLMsg *msg;
msg = curl_multi_info_read(s->multi, &msgs_in_queue);
/* Quit when there are no more completions */
if (!msg)
break;
while ((msg = curl_multi_info_read(s->multi, &msgs_in_queue))) {
if (msg->msg == CURLMSG_DONE) {
int i;
CURLState *state = NULL;
@@ -397,7 +391,6 @@ static void curl_multi_check_completion(BDRVCURLState *s)
}
curl_clean_state(state);
break;
}
}
}

View File

@@ -99,6 +99,7 @@ typedef struct MirrorBlockJob {
typedef struct MirrorBDSOpaque {
MirrorBlockJob *job;
BdrvDirtyBitmap *dirty_bitmap;
bool stop;
bool is_commit;
} MirrorBDSOpaque;
@@ -1675,9 +1676,11 @@ bdrv_mirror_top_do_write(BlockDriverState *bs, MirrorMethod method,
abort();
}
if (!copy_to_target && s->job && s->job->dirty_bitmap) {
qatomic_set(&s->job->actively_synced, false);
bdrv_set_dirty_bitmap(s->job->dirty_bitmap, offset, bytes);
if (!copy_to_target) {
if (s->job) {
qatomic_set(&s->job->actively_synced, false);
}
bdrv_set_dirty_bitmap(s->dirty_bitmap, offset, bytes);
}
if (ret < 0) {
@@ -1904,13 +1907,35 @@ static BlockJob *mirror_start_job(
bdrv_drained_begin(bs);
ret = bdrv_append(mirror_top_bs, bs, errp);
bdrv_drained_end(bs);
if (ret < 0) {
bdrv_drained_end(bs);
bdrv_unref(mirror_top_bs);
return NULL;
}
bs_opaque->dirty_bitmap = bdrv_create_dirty_bitmap(mirror_top_bs,
granularity,
NULL, errp);
if (!bs_opaque->dirty_bitmap) {
bdrv_drained_end(bs);
bdrv_unref(mirror_top_bs);
return NULL;
}
/*
* The mirror job doesn't use the block layer's dirty tracking because it
* needs to be able to switch seemlessly between background copy mode (which
* does need dirty tracking) and write blocking mode (which doesn't) and
* doing that would require draining the node. Instead, mirror_top_bs takes
* care of updating the dirty bitmap as appropriate.
*
* Note that write blocking mode only becomes effective after mirror_run()
* sets mirror_top_opaque->job (see should_copy_to_target()). Until then,
* we're still in background copy mode irrespective of @copy_mode.
*/
bdrv_disable_dirty_bitmap(bs_opaque->dirty_bitmap);
bdrv_drained_end(bs);
/* Make sure that the source is not resized while the job is running */
s = block_job_create(job_id, driver, NULL, mirror_top_bs,
BLK_PERM_CONSISTENT_READ,
@@ -2005,24 +2030,13 @@ static BlockJob *mirror_start_job(
s->base_overlay = bdrv_find_overlay(bs, base);
s->granularity = granularity;
s->buf_size = ROUND_UP(buf_size, granularity);
s->dirty_bitmap = bs_opaque->dirty_bitmap;
s->unmap = unmap;
if (auto_complete) {
s->should_complete = true;
}
bdrv_graph_rdunlock_main_loop();
s->dirty_bitmap = bdrv_create_dirty_bitmap(s->mirror_top_bs, granularity,
NULL, errp);
if (!s->dirty_bitmap) {
goto fail;
}
/*
* The dirty bitmap is set by bdrv_mirror_top_do_write() when not in active
* mode.
*/
bdrv_disable_dirty_bitmap(s->dirty_bitmap);
bdrv_graph_wrlock_drained();
ret = block_job_add_bdrv(&s->common, "source", bs, 0,
BLK_PERM_WRITE_UNCHANGED | BLK_PERM_WRITE |
@@ -2102,9 +2116,6 @@ fail:
g_free(s->replaces);
blk_unref(s->target);
bs_opaque->job = NULL;
if (s->dirty_bitmap) {
bdrv_release_dirty_bitmap(s->dirty_bitmap);
}
job_early_fail(&s->common.job);
}
@@ -2118,6 +2129,7 @@ fail:
bdrv_graph_wrunlock();
bdrv_drained_end(bs);
bdrv_release_dirty_bitmap(bs_opaque->dirty_bitmap);
bdrv_unref(mirror_top_bs);
return NULL;

View File

@@ -422,7 +422,7 @@ void hmp_nbd_server_start(Monitor *mon, const QDict *qdict)
/* Then try adding all block devices. If one fails, close all and
* exit.
*/
block_list = qmp_query_block(NULL);
block_list = qmp_query_block(true, true, NULL);
for (info = block_list; info; info = info->next) {
if (!info->value->inserted) {
@@ -741,7 +741,7 @@ void hmp_info_block(Monitor *mon, const QDict *qdict)
/* Print BlockBackend information */
if (!nodes) {
block_list = qmp_query_block(NULL);
block_list = qmp_query_block(false, false, NULL);
} else {
block_list = NULL;
}

View File

@@ -249,14 +249,15 @@ nfs_co_generic_cb(int ret, struct nfs_context *nfs, void *data,
}
/*
* Safe to call: nfs_service(), which called us, is only run from the FD
* handlers, never from the request coroutine. The request coroutine in
* turn will yield unconditionally.
* No need to release the lock, even if we directly enter the coroutine, as
* the lock is never re-taken after yielding. (Note: If we do enter the
* coroutine, @task will probably be dangling once aio_co_wake() returns.)
* Using aio_co_wake() here could re-enter the coroutine directly, while we
* still hold the mutex. The current request will not attempt to re-take
* the mutex, so that is fine; but if the same coroutine then goes on to
* submit another request, that new request will try to re-take the mutex,
* resulting in a deadlock.
* To prevent that, only schedule the coroutine so it will be entered later,
* with the mutex released.
*/
aio_co_wake(task->co);
aio_co_schedule(qemu_coroutine_get_aio_context(task->co), task->co);
}
static int coroutine_fn nfs_co_preadv(BlockDriverState *bs, int64_t offset,
@@ -716,8 +717,8 @@ nfs_get_allocated_file_size_cb(int ret, struct nfs_context *nfs, void *data,
if (task->ret < 0) {
error_report("NFS Error: %s", nfs_get_error(nfs));
}
/* Safe to call, see nfs_co_generic_cb() */
aio_co_wake(task->co);
/* Must not use aio_co_wake(), see nfs_co_generic_cb() */
aio_co_schedule(qemu_coroutine_get_aio_context(task->co), task->co);
}
static int64_t coroutine_fn nfs_co_get_allocated_file_size(BlockDriverState *bs)

View File

@@ -456,7 +456,7 @@ fail:
/* @p_info will be set only on success. */
static void GRAPH_RDLOCK
bdrv_query_info(BlockBackend *blk, BlockInfo **p_info, Error **errp)
bdrv_query_info(BlockBackend *blk, bool flat, BlockInfo **p_info, Error **errp)
{
BlockInfo *info = g_malloc0(sizeof(*info));
BlockDriverState *bs = blk_bs(blk);
@@ -488,7 +488,7 @@ bdrv_query_info(BlockBackend *blk, BlockInfo **p_info, Error **errp)
}
if (bs && bs->drv) {
info->inserted = bdrv_block_device_info(blk, bs, false, errp);
info->inserted = bdrv_block_device_info(blk, bs, flat, errp);
if (info->inserted == NULL) {
goto err;
}
@@ -698,7 +698,7 @@ bdrv_query_bds_stats(BlockDriverState *bs, bool blk_level)
return s;
}
BlockInfoList *qmp_query_block(Error **errp)
BlockInfoList *qmp_query_block(bool has_flat, bool flat, Error **errp)
{
BlockInfoList *head = NULL, **p_next = &head;
BlockBackend *blk;
@@ -714,7 +714,7 @@ BlockInfoList *qmp_query_block(Error **errp)
}
info = g_malloc0(sizeof(*info));
bdrv_query_info(blk, &info->value, &local_err);
bdrv_query_info(blk, flat, &info->value, &local_err);
if (local_err) {
error_propagate(errp, local_err);
g_free(info);

View File

@@ -3991,6 +3991,8 @@ qcow2_co_create_opts(BlockDriver *drv, const char *filename, QemuOpts *opts,
BlockDriverState *bs = NULL;
BlockDriverState *data_bs = NULL;
const char *val;
bool keep_data_file = false;
BlockdevCreateOptionsQcow2 *qcow2_opts;
int ret;
/* 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,
qdict_put_str(qdict, BLOCK_OPT_COMPAT_LEVEL, "v3");
}
val = qdict_get_try_str(qdict, BLOCK_OPT_KEEP_DATA_FILE);
if (val) {
if (!strcmp(val, "on")) {
keep_data_file = true;
} else if (!strcmp(val, "off")) {
keep_data_file = false;
} else {
error_setg(errp,
"Invalid value '%s' for '%s': Must be 'on' or 'off'",
val, BLOCK_OPT_KEEP_DATA_FILE);
ret = -EINVAL;
goto finish;
}
qdict_del(qdict, BLOCK_OPT_KEEP_DATA_FILE);
}
/* Change legacy command line options into QMP ones */
static const QDictRenames opt_renames[] = {
{ BLOCK_OPT_BACKING_FILE, "backing-file" },
@@ -4058,9 +4076,11 @@ qcow2_co_create_opts(BlockDriver *drv, const char *filename, QemuOpts *opts,
/* Create and open an external data file (protocol layer) */
val = qdict_get_try_str(qdict, BLOCK_OPT_DATA_FILE);
if (val) {
ret = bdrv_co_create_file(val, opts, false, errp);
if (ret < 0) {
goto finish;
if (!keep_data_file) {
ret = bdrv_co_create_file(val, opts, false, errp);
if (ret < 0) {
goto finish;
}
}
data_bs = bdrv_co_open(val, NULL, NULL,
@@ -4073,6 +4093,11 @@ qcow2_co_create_opts(BlockDriver *drv, const char *filename, QemuOpts *opts,
qdict_del(qdict, BLOCK_OPT_DATA_FILE);
qdict_put_str(qdict, "data-file", data_bs->node_name);
} else if (keep_data_file) {
error_setg(errp, "Must not use '%s=on' without '%s'",
BLOCK_OPT_KEEP_DATA_FILE, BLOCK_OPT_DATA_FILE);
ret = -EINVAL;
goto finish;
}
/* Set 'driver' and 'node' options */
@@ -4093,9 +4118,39 @@ qcow2_co_create_opts(BlockDriver *drv, const char *filename, QemuOpts *opts,
goto finish;
}
qcow2_opts = &create_options->u.qcow2;
if (!qcow2_opts->has_preallocation) {
qcow2_opts->preallocation = PREALLOC_MODE_OFF;
}
if (keep_data_file &&
qcow2_opts->preallocation != PREALLOC_MODE_OFF &&
qcow2_opts->preallocation != PREALLOC_MODE_METADATA)
{
error_setg(errp, "Preallocating more than only metadata would "
"overwrite the external data file's content and is "
"therefore incompatible with '%s=on'",
BLOCK_OPT_KEEP_DATA_FILE);
ret = -EINVAL;
goto finish;
}
if (keep_data_file &&
qcow2_opts->preallocation == PREALLOC_MODE_OFF &&
!qcow2_opts->data_file_raw)
{
error_setg(errp, "'%s=on' requires '%s=metadata' or '%s=on', or the "
"file contents will not be visible",
BLOCK_OPT_KEEP_DATA_FILE,
BLOCK_OPT_PREALLOC,
BLOCK_OPT_DATA_FILE_RAW);
ret = -EINVAL;
goto finish;
}
/* Silently round up size */
create_options->u.qcow2.size = ROUND_UP(create_options->u.qcow2.size,
BDRV_SECTOR_SIZE);
qcow2_opts->size = ROUND_UP(qcow2_opts->size, BDRV_SECTOR_SIZE);
/* Create the qcow2 image (format layer) */
ret = qcow2_co_create(create_options, errp);
@@ -4103,7 +4158,9 @@ finish:
if (ret < 0) {
bdrv_graph_co_rdlock();
bdrv_co_delete_file_noerr(bs);
bdrv_co_delete_file_noerr(data_bs);
if (!keep_data_file) {
bdrv_co_delete_file_noerr(data_bs);
}
bdrv_graph_co_rdunlock();
} else {
ret = 0;
@@ -6202,6 +6259,12 @@ static QemuOptsList qcow2_create_opts = {
.help = "Compression method used for image cluster " \
"compression", \
.def_value_str = "zlib" \
}, \
{ \
.name = BLOCK_OPT_KEEP_DATA_FILE, \
.type = QEMU_OPT_BOOL, \
.help = "Assume the external data file already exists and " \
"do not overwrite it" \
},
QCOW_COMMON_OPTIONS,
{ /* end of list */ }

View File

@@ -295,19 +295,15 @@ static bool throttle_group_schedule_timer(ThrottleGroupMember *tgm,
/* Start the next pending I/O request for a ThrottleGroupMember. Return whether
* any request was actually pending.
*
* This assumes that tg->lock is held.
*
* @tgm: the current ThrottleGroupMember
* @direction: the ThrottleDirection
*/
static bool coroutine_fn throttle_group_co_restart_queue(ThrottleGroupMember *tgm,
ThrottleDirection direction)
{
bool ret;
qemu_co_mutex_lock(&tgm->throttled_reqs_lock);
ret = qemu_co_queue_next(&tgm->throttled_reqs[direction]);
qemu_co_mutex_unlock(&tgm->throttled_reqs_lock);
return ret;
return qemu_co_queue_next(&tgm->throttled_reqs[direction]);
}
/* Look for the next pending I/O request and schedule it.
@@ -378,12 +374,8 @@ void coroutine_fn throttle_group_co_io_limits_intercept(ThrottleGroupMember *tgm
/* Wait if there's a timer set or queued requests of this type */
if (must_wait || tgm->pending_reqs[direction]) {
tgm->pending_reqs[direction]++;
qemu_mutex_unlock(&tg->lock);
qemu_co_mutex_lock(&tgm->throttled_reqs_lock);
qemu_co_queue_wait(&tgm->throttled_reqs[direction],
&tgm->throttled_reqs_lock);
qemu_co_mutex_unlock(&tgm->throttled_reqs_lock);
qemu_mutex_lock(&tg->lock);
&tg->lock);
tgm->pending_reqs[direction]--;
}
@@ -410,15 +402,15 @@ static void coroutine_fn throttle_group_restart_queue_entry(void *opaque)
ThrottleDirection direction = data->direction;
bool empty_queue;
qemu_mutex_lock(&tg->lock);
empty_queue = !throttle_group_co_restart_queue(tgm, direction);
/* If the request queue was empty then we have to take care of
* scheduling the next one */
if (empty_queue) {
qemu_mutex_lock(&tg->lock);
schedule_next_request(tgm, direction);
qemu_mutex_unlock(&tg->lock);
}
qemu_mutex_unlock(&tg->lock);
g_free(data);
@@ -569,7 +561,6 @@ void throttle_group_register_tgm(ThrottleGroupMember *tgm,
read_timer_cb,
write_timer_cb,
tgm);
qemu_co_mutex_init(&tgm->throttled_reqs_lock);
}
/* Unregister a ThrottleGroupMember from its group, removing it from the list,

View File

@@ -1951,10 +1951,10 @@ vmdk_read_extent(VmdkExtent *extent, int64_t cluster_offset,
marker = (VmdkGrainMarker *)cluster_buf;
compressed_data = marker->data;
data_len = le32_to_cpu(marker->size);
}
if (!data_len || data_len > buf_bytes) {
ret = -EINVAL;
goto out;
if (!data_len || data_len > buf_bytes - sizeof(VmdkGrainMarker)) {
ret = -EINVAL;
goto out;
}
}
ret = uncompress(uncomp_buf, &buf_len, compressed_data, data_len);
if (ret != Z_OK) {

View File

@@ -56,6 +56,7 @@
#define BLOCK_OPT_DATA_FILE_RAW "data_file_raw"
#define BLOCK_OPT_COMPRESSION_TYPE "compression_type"
#define BLOCK_OPT_EXTL2 "extended_l2"
#define BLOCK_OPT_KEEP_DATA_FILE "keep_data_file"
#define BLOCK_PROBE_BUF_SIZE 512

View File

@@ -35,8 +35,7 @@
typedef struct ThrottleGroupMember {
AioContext *aio_context;
/* throttled_reqs_lock protects the CoQueues for throttled requests. */
CoMutex throttled_reqs_lock;
/* Protected by ThrottleGroup.lock */
CoQueue throttled_reqs[THROTTLE_MAX];
/* Nonzero if the I/O limits are currently being ignored; generally

View File

@@ -330,14 +330,33 @@ monitor_qapi_event_queue_no_reenter(QAPIEvent event, QDict *qdict)
{
MonitorQAPIEventConf *evconf;
MonitorQAPIEventState *evstate;
bool throttled;
assert(event < QAPI_EVENT__MAX);
evconf = &monitor_qapi_event_conf[event];
trace_monitor_protocol_event_queue(event, qdict, evconf->rate);
throttled = evconf->rate;
/*
* Rate limit BLOCK_IO_ERROR only for action != "stop".
*
* If the VM is stopped after an I/O error, this is important information
* for the management tool to keep track of the state of QEMU and we can't
* merge any events. At the same time, stopping the VM means that the guest
* can't send additional requests and the number of events is already
* limited, so we can do without rate limiting.
*/
if (event == QAPI_EVENT_BLOCK_IO_ERROR) {
QDict *data = qobject_to(QDict, qdict_get(qdict, "data"));
const char *action = qdict_get_str(data, "action");
if (!strcmp(action, "stop")) {
throttled = false;
}
}
QEMU_LOCK_GUARD(&monitor_lock);
if (!evconf->rate) {
if (!throttled) {
/* Unthrottled event */
monitor_qapi_event_emit(event, qdict);
} else {

View File

@@ -855,6 +855,10 @@
#
# Get a list of `BlockInfo` for all virtual block devices.
#
# @flat: Omit nested data about the backing image, i.e. `BlockInfo`
# member 'inserted.image.backing-image' will be absent.
# Default is false. (Since 11.0)
#
# Returns: a list describing each virtual block device. Filter nodes
# that were created implicitly are skipped over.
#
@@ -945,6 +949,7 @@
# }
##
{ 'command': 'query-block', 'returns': ['BlockInfo'],
'data': { '*flat': 'bool' },
'allow-preconfig': true }
##
@@ -5789,7 +5794,7 @@
# .. note:: If action is "stop", a `STOP` event will eventually follow
# the `BLOCK_IO_ERROR` event.
#
# .. note:: This event is rate-limited.
# .. note:: This event is rate-limited, except if action is "stop".
#
# Since: 0.13
#

View File

@@ -66,6 +66,7 @@ Supported options:
encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
extended_l2=<bool (on/off)> - Extended L2 tables
extent_size_hint=<size> - Extent size hint for the image file, 0 to disable
keep_data_file=<bool (on/off)> - Assume the external data file already exists and do not overwrite it
lazy_refcounts=<bool (on/off)> - Postpone refcount updates
nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
@@ -92,6 +93,7 @@ Supported options:
encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
extended_l2=<bool (on/off)> - Extended L2 tables
extent_size_hint=<size> - Extent size hint for the image file, 0 to disable
keep_data_file=<bool (on/off)> - Assume the external data file already exists and do not overwrite it
lazy_refcounts=<bool (on/off)> - Postpone refcount updates
nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
@@ -118,6 +120,7 @@ Supported options:
encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
extended_l2=<bool (on/off)> - Extended L2 tables
extent_size_hint=<size> - Extent size hint for the image file, 0 to disable
keep_data_file=<bool (on/off)> - Assume the external data file already exists and do not overwrite it
lazy_refcounts=<bool (on/off)> - Postpone refcount updates
nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
@@ -144,6 +147,7 @@ Supported options:
encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
extended_l2=<bool (on/off)> - Extended L2 tables
extent_size_hint=<size> - Extent size hint for the image file, 0 to disable
keep_data_file=<bool (on/off)> - Assume the external data file already exists and do not overwrite it
lazy_refcounts=<bool (on/off)> - Postpone refcount updates
nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
@@ -170,6 +174,7 @@ Supported options:
encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
extended_l2=<bool (on/off)> - Extended L2 tables
extent_size_hint=<size> - Extent size hint for the image file, 0 to disable
keep_data_file=<bool (on/off)> - Assume the external data file already exists and do not overwrite it
lazy_refcounts=<bool (on/off)> - Postpone refcount updates
nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
@@ -196,6 +201,7 @@ Supported options:
encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
extended_l2=<bool (on/off)> - Extended L2 tables
extent_size_hint=<size> - Extent size hint for the image file, 0 to disable
keep_data_file=<bool (on/off)> - Assume the external data file already exists and do not overwrite it
lazy_refcounts=<bool (on/off)> - Postpone refcount updates
nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
@@ -222,6 +228,7 @@ Supported options:
encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
extended_l2=<bool (on/off)> - Extended L2 tables
extent_size_hint=<size> - Extent size hint for the image file, 0 to disable
keep_data_file=<bool (on/off)> - Assume the external data file already exists and do not overwrite it
lazy_refcounts=<bool (on/off)> - Postpone refcount updates
nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
@@ -248,6 +255,7 @@ Supported options:
encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
extended_l2=<bool (on/off)> - Extended L2 tables
extent_size_hint=<size> - Extent size hint for the image file, 0 to disable
keep_data_file=<bool (on/off)> - Assume the external data file already exists and do not overwrite it
lazy_refcounts=<bool (on/off)> - Postpone refcount updates
nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
@@ -288,6 +296,7 @@ Supported qcow2 options:
encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
extended_l2=<bool (on/off)> - Extended L2 tables
keep_data_file=<bool (on/off)> - Assume the external data file already exists and do not overwrite it
lazy_refcounts=<bool (on/off)> - Postpone refcount updates
preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
refcount_bits=<num> - Width of a reference count entry in bits
@@ -376,6 +385,7 @@ Supported options:
encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
extended_l2=<bool (on/off)> - Extended L2 tables
extent_size_hint=<size> - Extent size hint for the image file, 0 to disable
keep_data_file=<bool (on/off)> - Assume the external data file already exists and do not overwrite it
lazy_refcounts=<bool (on/off)> - Postpone refcount updates
nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
@@ -402,6 +412,7 @@ Supported options:
encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
extended_l2=<bool (on/off)> - Extended L2 tables
extent_size_hint=<size> - Extent size hint for the image file, 0 to disable
keep_data_file=<bool (on/off)> - Assume the external data file already exists and do not overwrite it
lazy_refcounts=<bool (on/off)> - Postpone refcount updates
nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
@@ -428,6 +439,7 @@ Supported options:
encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
extended_l2=<bool (on/off)> - Extended L2 tables
extent_size_hint=<size> - Extent size hint for the image file, 0 to disable
keep_data_file=<bool (on/off)> - Assume the external data file already exists and do not overwrite it
lazy_refcounts=<bool (on/off)> - Postpone refcount updates
nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
@@ -454,6 +466,7 @@ Supported options:
encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
extended_l2=<bool (on/off)> - Extended L2 tables
extent_size_hint=<size> - Extent size hint for the image file, 0 to disable
keep_data_file=<bool (on/off)> - Assume the external data file already exists and do not overwrite it
lazy_refcounts=<bool (on/off)> - Postpone refcount updates
nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
@@ -480,6 +493,7 @@ Supported options:
encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
extended_l2=<bool (on/off)> - Extended L2 tables
extent_size_hint=<size> - Extent size hint for the image file, 0 to disable
keep_data_file=<bool (on/off)> - Assume the external data file already exists and do not overwrite it
lazy_refcounts=<bool (on/off)> - Postpone refcount updates
nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
@@ -506,6 +520,7 @@ Supported options:
encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
extended_l2=<bool (on/off)> - Extended L2 tables
extent_size_hint=<size> - Extent size hint for the image file, 0 to disable
keep_data_file=<bool (on/off)> - Assume the external data file already exists and do not overwrite it
lazy_refcounts=<bool (on/off)> - Postpone refcount updates
nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
@@ -532,6 +547,7 @@ Supported options:
encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
extended_l2=<bool (on/off)> - Extended L2 tables
extent_size_hint=<size> - Extent size hint for the image file, 0 to disable
keep_data_file=<bool (on/off)> - Assume the external data file already exists and do not overwrite it
lazy_refcounts=<bool (on/off)> - Postpone refcount updates
nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
@@ -558,6 +574,7 @@ Supported options:
encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
extended_l2=<bool (on/off)> - Extended L2 tables
extent_size_hint=<size> - Extent size hint for the image file, 0 to disable
keep_data_file=<bool (on/off)> - Assume the external data file already exists and do not overwrite it
lazy_refcounts=<bool (on/off)> - Postpone refcount updates
nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
@@ -598,6 +615,7 @@ Supported qcow2 options:
encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
extended_l2=<bool (on/off)> - Extended L2 tables
keep_data_file=<bool (on/off)> - Assume the external data file already exists and do not overwrite it
lazy_refcounts=<bool (on/off)> - Postpone refcount updates
preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
refcount_bits=<num> - Width of a reference count entry in bits

View File

@@ -384,6 +384,77 @@ $QEMU_IMG compare --image-opts \
"driver=raw,file.filename=$TEST_IMG.data" \
"file.filename=$TEST_IMG,backing.file.filename=$TEST_IMG.base"
echo
echo '=== keep_data_file tests ==='
echo
echo '--- Creating test data file ---'
# Easiest way to create the raw data file without having to create and
# access it manually
_make_test_img -o "data_file=$TEST_IMG.data,data_file_raw=on" 1M
# Values chosen by a fair random.org evaluation
$QEMU_IO -c 'write -P 3 0 512k' -c 'write -P 96 512k 512k' "$TEST_IMG" |
_filter_qemu_io
echo
echo '--- Testing stand-alone option ---'
# Cannot work, needs data file
_make_test_img -o "keep_data_file=on" 1M
# Invalid option value
_make_test_img -o "keep_data_file=true" 1M
# Should be the same as omitting
_make_test_img -o "keep_data_file=off" 1M
# No preallocation is OK when also specifying data_file_raw; otherwise, none of
# the data file will be mapped, i.e. its contents will stay hidden, so
# requesting its contents to be kept (but hidden) doesn't make much sense.
#
# Metadata preallocation is OK: It will not overwrite the data file's contents,
# but ensure the contents are mapped and visible.
#
# Any data preallocation (like falloc) is not OK, as this would overwrite the
# data file's contents despite keep_data_file requesting they should not be
# overwritten.
#
# Note that all of these cases use the data file created above: This verifies
# that when passing keep_data_file=on, the data file is always kept as-is (and
# e.g. not deleted on error).
for prealloc in off metadata falloc full; do
# Without metadata preallocation, the data_file_raw flag is required so that
# the data file's contents are visible.
for data_file_raw in off on; do
echo
echo "--- Testing prealloc=$prealloc data_file_raw=$data_file_raw ---"
# Remove previously existing qcow2 (metadata) file
_cleanup_test_img
opts="data_file=$TEST_IMG.data,keep_data_file=on"
opts+=",preallocation=$prealloc"
opts+=",data_file_raw=$data_file_raw"
_make_test_img -o "$opts" 1M
if [ -f "$TEST_IMG" ]; then
$QEMU_IO -c 'read -P 3 0 512k' -c 'read -P 96 512k 512k' "$TEST_IMG" |
_filter_qemu_io
fi
done
done
echo
echo '--- Testing non-existent data file ---'
# Maybe a matter of taste whether this should fail or create the file, but
# failing is simpler (= will always skip create) and seems safer (users may
# expect the file to exist, and the error will warn them when it does not).
_make_test_img \
-o "data_file=$TEST_IMG.doesnotexist,keep_data_file=on,data_file_raw=on" \
1M
# success, all done
echo "*** done"
rm -f $seq.full

View File

@@ -197,4 +197,65 @@ wrote 1048576/1048576 bytes at offset 0
Comparing qcow2 image and raw data file:
Images are identical.
=== keep_data_file tests ===
--- Creating test data file ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 data_file=TEST_DIR/t.IMGFMT.data data_file_raw=on
wrote 524288/524288 bytes at offset 0
512 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 524288/524288 bytes at offset 524288
512 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
--- Testing stand-alone option ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 keep_data_file=on
qemu-img: TEST_DIR/t.IMGFMT: Must not use 'keep_data_file=on' without 'data_file'
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 keep_data_file=true
qemu-img: TEST_DIR/t.IMGFMT: Invalid value 'true' for 'keep_data_file': Must be 'on' or 'off'
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 keep_data_file=off
--- Testing prealloc=off data_file_raw=off ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 data_file=TEST_DIR/t.IMGFMT.data data_file_raw=off keep_data_file=on preallocation=off
qemu-img: TEST_DIR/t.IMGFMT: 'keep_data_file=on' requires 'preallocation=metadata' or 'data_file_raw=on', or the file contents will not be visible
--- Testing prealloc=off data_file_raw=on ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 data_file=TEST_DIR/t.IMGFMT.data data_file_raw=on keep_data_file=on preallocation=off
read 524288/524288 bytes at offset 0
512 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
read 524288/524288 bytes at offset 524288
512 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
--- Testing prealloc=metadata data_file_raw=off ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 data_file=TEST_DIR/t.IMGFMT.data data_file_raw=off keep_data_file=on preallocation=metadata
read 524288/524288 bytes at offset 0
512 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
read 524288/524288 bytes at offset 524288
512 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
--- Testing prealloc=metadata data_file_raw=on ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 data_file=TEST_DIR/t.IMGFMT.data data_file_raw=on keep_data_file=on preallocation=metadata
read 524288/524288 bytes at offset 0
512 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
read 524288/524288 bytes at offset 524288
512 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
--- Testing prealloc=falloc data_file_raw=off ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 data_file=TEST_DIR/t.IMGFMT.data data_file_raw=off keep_data_file=on preallocation=falloc
qemu-img: TEST_DIR/t.IMGFMT: Preallocating more than only metadata would overwrite the external data file's content and is therefore incompatible with 'keep_data_file=on'
--- Testing prealloc=falloc data_file_raw=on ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 data_file=TEST_DIR/t.IMGFMT.data data_file_raw=on keep_data_file=on preallocation=falloc
qemu-img: TEST_DIR/t.IMGFMT: Preallocating more than only metadata would overwrite the external data file's content and is therefore incompatible with 'keep_data_file=on'
--- Testing prealloc=full data_file_raw=off ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 data_file=TEST_DIR/t.IMGFMT.data data_file_raw=off keep_data_file=on preallocation=full
qemu-img: TEST_DIR/t.IMGFMT: Preallocating more than only metadata would overwrite the external data file's content and is therefore incompatible with 'keep_data_file=on'
--- Testing prealloc=full data_file_raw=on ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 data_file=TEST_DIR/t.IMGFMT.data data_file_raw=on keep_data_file=on preallocation=full
qemu-img: TEST_DIR/t.IMGFMT: Preallocating more than only metadata would overwrite the external data file's content and is therefore incompatible with 'keep_data_file=on'
--- Testing non-existent data file ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 data_file=TEST_DIR/t.IMGFMT.doesnotexist data_file_raw=on keep_data_file=on
qemu-img: TEST_DIR/t.IMGFMT: Could not open 'TEST_DIR/t.IMGFMT.doesnotexist': No such file or directory
*** done

View File

@@ -182,7 +182,7 @@ _do_filter_img_create()
-e 's/^\(fmt\)/0-\1/' \
-e 's/^\(size\)/1-\1/' \
-e 's/^\(backing\)/2-\1/' \
-e 's/^\(data_file\)/3-\1/' \
-e 's/^\(\(keep_\)\?data_file\)/3-\1/' \
-e 's/^\(encryption\)/4-\1/' \
-e 's/^\(preallocation\)/8-\1/' \
| LC_ALL=C sort \

View File

@@ -1849,7 +1849,7 @@ static void addRemovableDevicesMenuItems(void)
BlockInfoList *currentDevice, *pointerToFree;
NSString *deviceName;
currentDevice = qmp_query_block(NULL);
currentDevice = qmp_query_block(false, false, NULL);
pointerToFree = currentDevice;
menu = [[[NSApp mainMenu] itemWithTitle:@"Machine"] submenu];