aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2015-12-18 16:34:44 +0000
committerPeter Maydell <peter.maydell@linaro.org>2015-12-18 16:34:44 +0000
commitde532ff1df75cc80f0fb30885524e54b014d4983 (patch)
tree54c95dbb3a1da01df51886054694d5fec1f98f6b
parentb06f904f2e37eb2a9ab0a8344faec7e5d609508a (diff)
parent9d4a6cf0ea471fb5aeaba9360fec863ef8a0ab44 (diff)
downloadqemu-de532ff1df75cc80f0fb30885524e54b014d4983.zip
qemu-de532ff1df75cc80f0fb30885524e54b014d4983.tar.gz
qemu-de532ff1df75cc80f0fb30885524e54b014d4983.tar.bz2
Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging
Block layer patches # gpg: Signature made Fri 18 Dec 2015 13:41:03 GMT using RSA key ID C88F2FD6 # gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>" * remotes/kevin/tags/for-upstream: (48 commits) block/qapi: allow best-effort query qemu-img: abort when full_backing_filename not present block/qapi: explicitly warn if !has_full_backing_filename block/qapi: always report full_backing_filename block/qapi: do not redundantly print "actual path" qemu-iotests: s390x: fix test 068 qemu-iotests: s390x: fix test 051 qemu-iotests: refine common.config block: fix bdrv_ioctl called from coroutine block: use drained section around bdrv_snapshot_delete iotests: Update comments for bdrv_swap() in 094 block: Remove prototype of bdrv_swap from header raw-posix: Make aio=native option binding qcow2: insert assert into qcow2_get_specific_info() iotests: Extend test 112 for qemu-img amend qcow2: Point to amend function in check qcow2: Invoke refcount order amendment function qcow2: Add function for refcount order amendment qcow2: Use intermediate helper CB for amend qcow2: Split upgrade/downgrade paths for amend ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--block.c463
-rw-r--r--block/blkdebug.c24
-rw-r--r--block/blkverify.c2
-rw-r--r--block/io.c7
-rw-r--r--block/mirror.c30
-rw-r--r--block/nbd.c10
-rw-r--r--block/qapi.c19
-rw-r--r--block/qcow2-cluster.c14
-rw-r--r--block/qcow2-refcount.c450
-rw-r--r--block/qcow2.c229
-rw-r--r--block/qcow2.h7
-rw-r--r--block/quorum.c2
-rw-r--r--block/raw-posix.c20
-rw-r--r--block/snapshot.c23
-rw-r--r--blockdev.c57
-rw-r--r--include/block/block.h9
-rw-r--r--include/block/block_int.h11
-rw-r--r--qemu-img.c10
-rw-r--r--tests/hd-geo-test.c4
-rw-r--r--tests/qemu-iotests/043.out2
-rwxr-xr-xtests/qemu-iotests/05199
-rw-r--r--tests/qemu-iotests/051.out192
-rw-r--r--tests/qemu-iotests/051.pc.out482
-rw-r--r--tests/qemu-iotests/061.out14
-rwxr-xr-xtests/qemu-iotests/06814
-rwxr-xr-xtests/qemu-iotests/0948
-rw-r--r--tests/qemu-iotests/110.out5
-rwxr-xr-xtests/qemu-iotests/112109
-rw-r--r--tests/qemu-iotests/112.out71
-rw-r--r--tests/qemu-iotests/124148
-rwxr-xr-xtests/qemu-iotests/13390
-rw-r--r--tests/qemu-iotests/133.out22
-rwxr-xr-xtests/qemu-iotests/142354
-rw-r--r--tests/qemu-iotests/142.out773
-rw-r--r--tests/qemu-iotests/common.config9
-rw-r--r--tests/qemu-iotests/group2
-rw-r--r--tests/qemu-iotests/iotests.py4
-rw-r--r--util/qemu-progress.c3
38 files changed, 3326 insertions, 466 deletions
diff --git a/block.c b/block.c
index 9971976..411edbf 100644
--- a/block.c
+++ b/block.c
@@ -29,6 +29,7 @@
#include "qemu/error-report.h"
#include "qemu/module.h"
#include "qapi/qmp/qerror.h"
+#include "qapi/qmp/qbool.h"
#include "qapi/qmp/qjson.h"
#include "sysemu/block-backend.h"
#include "sysemu/sysemu.h"
@@ -624,6 +625,20 @@ static int refresh_total_sectors(BlockDriverState *bs, int64_t hint)
}
/**
+ * Combines a QDict of new block driver @options with any missing options taken
+ * from @old_options, so that leaving out an option defaults to its old value.
+ */
+static void bdrv_join_options(BlockDriverState *bs, QDict *options,
+ QDict *old_options)
+{
+ if (bs->drv && bs->drv->bdrv_join_options) {
+ bs->drv->bdrv_join_options(options, old_options);
+ } else {
+ qdict_join(options, old_options, false);
+ }
+}
+
+/**
* Set open flags for a given discard mode
*
* Return 0 on success, -1 if the discard mode was invalid.
@@ -681,60 +696,81 @@ static int bdrv_temp_snapshot_flags(int flags)
}
/*
- * Returns the flags that bs->file should get if a protocol driver is expected,
- * based on the given flags for the parent BDS
+ * Returns the options and flags that bs->file should get if a protocol driver
+ * is expected, based on the given options and flags for the parent BDS
*/
-static int bdrv_inherited_flags(int flags)
+static void bdrv_inherited_options(int *child_flags, QDict *child_options,
+ int parent_flags, QDict *parent_options)
{
+ int flags = parent_flags;
+
/* Enable protocol handling, disable format probing for bs->file */
flags |= BDRV_O_PROTOCOL;
+ /* If the cache mode isn't explicitly set, inherit direct and no-flush from
+ * the parent. */
+ qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_DIRECT);
+ qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_NO_FLUSH);
+
/* Our block drivers take care to send flushes and respect unmap policy,
- * so we can enable both unconditionally on lower layers. */
- flags |= BDRV_O_CACHE_WB | BDRV_O_UNMAP;
+ * so we can default to enable both on lower layers regardless of the
+ * corresponding parent options. */
+ qdict_set_default_str(child_options, BDRV_OPT_CACHE_WB, "on");
+ flags |= BDRV_O_UNMAP;
/* Clear flags that only apply to the top layer */
flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING | BDRV_O_COPY_ON_READ);
- return flags;
+ *child_flags = flags;
}
const BdrvChildRole child_file = {
- .inherit_flags = bdrv_inherited_flags,
+ .inherit_options = bdrv_inherited_options,
};
/*
- * Returns the flags that bs->file should get if the use of formats (and not
- * only protocols) is permitted for it, based on the given flags for the parent
- * BDS
+ * Returns the options and flags that bs->file should get if the use of formats
+ * (and not only protocols) is permitted for it, based on the given options and
+ * flags for the parent BDS
*/
-static int bdrv_inherited_fmt_flags(int parent_flags)
+static void bdrv_inherited_fmt_options(int *child_flags, QDict *child_options,
+ int parent_flags, QDict *parent_options)
{
- int flags = child_file.inherit_flags(parent_flags);
- return flags & ~BDRV_O_PROTOCOL;
+ child_file.inherit_options(child_flags, child_options,
+ parent_flags, parent_options);
+
+ *child_flags &= ~BDRV_O_PROTOCOL;
}
const BdrvChildRole child_format = {
- .inherit_flags = bdrv_inherited_fmt_flags,
+ .inherit_options = bdrv_inherited_fmt_options,
};
/*
- * Returns the flags that bs->backing should get, based on the given flags
- * for the parent BDS
+ * Returns the options and flags that bs->backing should get, based on the
+ * given options and flags for the parent BDS
*/
-static int bdrv_backing_flags(int flags)
+static void bdrv_backing_options(int *child_flags, QDict *child_options,
+ int parent_flags, QDict *parent_options)
{
+ int flags = parent_flags;
+
+ /* The cache mode is inherited unmodified for backing files */
+ qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_WB);
+ qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_DIRECT);
+ qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_NO_FLUSH);
+
/* backing files always opened read-only */
flags &= ~(BDRV_O_RDWR | BDRV_O_COPY_ON_READ);
/* snapshot=on is handled on the top layer */
flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_TEMPORARY);
- return flags;
+ *child_flags = flags;
}
static const BdrvChildRole child_backing = {
- .inherit_flags = bdrv_backing_flags,
+ .inherit_options = bdrv_backing_options,
};
static int bdrv_open_flags(BlockDriverState *bs, int flags)
@@ -757,6 +793,42 @@ static int bdrv_open_flags(BlockDriverState *bs, int flags)
return open_flags;
}
+static void update_flags_from_options(int *flags, QemuOpts *opts)
+{
+ *flags &= ~BDRV_O_CACHE_MASK;
+
+ assert(qemu_opt_find(opts, BDRV_OPT_CACHE_WB));
+ if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_WB, false)) {
+ *flags |= BDRV_O_CACHE_WB;
+ }
+
+ assert(qemu_opt_find(opts, BDRV_OPT_CACHE_NO_FLUSH));
+ if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_NO_FLUSH, false)) {
+ *flags |= BDRV_O_NO_FLUSH;
+ }
+
+ assert(qemu_opt_find(opts, BDRV_OPT_CACHE_DIRECT));
+ if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_DIRECT, false)) {
+ *flags |= BDRV_O_NOCACHE;
+ }
+}
+
+static void update_options_from_flags(QDict *options, int flags)
+{
+ if (!qdict_haskey(options, BDRV_OPT_CACHE_WB)) {
+ qdict_put(options, BDRV_OPT_CACHE_WB,
+ qbool_from_bool(flags & BDRV_O_CACHE_WB));
+ }
+ if (!qdict_haskey(options, BDRV_OPT_CACHE_DIRECT)) {
+ qdict_put(options, BDRV_OPT_CACHE_DIRECT,
+ qbool_from_bool(flags & BDRV_O_NOCACHE));
+ }
+ if (!qdict_haskey(options, BDRV_OPT_CACHE_NO_FLUSH)) {
+ qdict_put(options, BDRV_OPT_CACHE_NO_FLUSH,
+ qbool_from_bool(flags & BDRV_O_NO_FLUSH));
+ }
+}
+
static void bdrv_assign_node_name(BlockDriverState *bs,
const char *node_name,
Error **errp)
@@ -803,6 +875,26 @@ static QemuOptsList bdrv_runtime_opts = {
.type = QEMU_OPT_STRING,
.help = "Node name of the block device node",
},
+ {
+ .name = "driver",
+ .type = QEMU_OPT_STRING,
+ .help = "Block driver to use for the node",
+ },
+ {
+ .name = BDRV_OPT_CACHE_WB,
+ .type = QEMU_OPT_BOOL,
+ .help = "Enable writeback mode",
+ },
+ {
+ .name = BDRV_OPT_CACHE_DIRECT,
+ .type = QEMU_OPT_BOOL,
+ .help = "Bypass software writeback cache on the host",
+ },
+ {
+ .name = BDRV_OPT_CACHE_NO_FLUSH,
+ .type = QEMU_OPT_BOOL,
+ .help = "Ignore flush requests",
+ },
{ /* end of list */ }
},
};
@@ -813,18 +905,31 @@ static QemuOptsList bdrv_runtime_opts = {
* Removes all processed options from *options.
*/
static int bdrv_open_common(BlockDriverState *bs, BdrvChild *file,
- QDict *options, int flags, BlockDriver *drv, Error **errp)
+ QDict *options, int flags, Error **errp)
{
int ret, open_flags;
const char *filename;
+ const char *driver_name = NULL;
const char *node_name = NULL;
QemuOpts *opts;
+ BlockDriver *drv;
Error *local_err = NULL;
- assert(drv != NULL);
assert(bs->file == NULL);
assert(options != NULL && bs->options != options);
+ opts = qemu_opts_create(&bdrv_runtime_opts, NULL, 0, &error_abort);
+ qemu_opts_absorb_qdict(opts, options, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ ret = -EINVAL;
+ goto fail_opts;
+ }
+
+ driver_name = qemu_opt_get(opts, "driver");
+ drv = bdrv_find_format(driver_name);
+ assert(drv != NULL);
+
if (file != NULL) {
filename = file->bs->filename;
} else {
@@ -834,19 +939,12 @@ static int bdrv_open_common(BlockDriverState *bs, BdrvChild *file,
if (drv->bdrv_needs_filename && !filename) {
error_setg(errp, "The '%s' block driver requires a file name",
drv->format_name);
- return -EINVAL;
- }
-
- trace_bdrv_open_common(bs, filename ?: "", flags, drv->format_name);
-
- opts = qemu_opts_create(&bdrv_runtime_opts, NULL, 0, &error_abort);
- qemu_opts_absorb_qdict(opts, options, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
ret = -EINVAL;
goto fail_opts;
}
+ trace_bdrv_open_common(bs, filename ?: "", flags, drv->format_name);
+
node_name = qemu_opt_get(opts, "node-name");
bdrv_assign_node_name(bs, node_name, &local_err);
if (local_err) {
@@ -891,7 +989,9 @@ static int bdrv_open_common(BlockDriverState *bs, BdrvChild *file,
bs->drv = drv;
bs->opaque = g_malloc0(drv->instance_size);
- bs->enable_write_cache = !!(flags & BDRV_O_CACHE_WB);
+ /* Apply cache mode options */
+ update_flags_from_options(&bs->open_flags, opts);
+ bdrv_set_enable_write_cache(bs, bs->open_flags & BDRV_O_CACHE_WB);
/* Open the image, either directly or using a protocol */
if (drv->bdrv_file_open) {
@@ -984,37 +1084,45 @@ static QDict *parse_json_filename(const char *filename, Error **errp)
return options;
}
+static void parse_json_protocol(QDict *options, const char **pfilename,
+ Error **errp)
+{
+ QDict *json_options;
+ Error *local_err = NULL;
+
+ /* Parse json: pseudo-protocol */
+ if (!*pfilename || !g_str_has_prefix(*pfilename, "json:")) {
+ return;
+ }
+
+ json_options = parse_json_filename(*pfilename, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ /* Options given in the filename have lower priority than options
+ * specified directly */
+ qdict_join(options, json_options, false);
+ QDECREF(json_options);
+ *pfilename = NULL;
+}
+
/*
* Fills in default options for opening images and converts the legacy
* filename/flags pair to option QDict entries.
* The BDRV_O_PROTOCOL flag in *flags will be set or cleared accordingly if a
* block driver has been specified explicitly.
*/
-static int bdrv_fill_options(QDict **options, const char **pfilename,
+static int bdrv_fill_options(QDict **options, const char *filename,
int *flags, Error **errp)
{
- const char *filename = *pfilename;
const char *drvname;
bool protocol = *flags & BDRV_O_PROTOCOL;
bool parse_filename = false;
BlockDriver *drv = NULL;
Error *local_err = NULL;
- /* Parse json: pseudo-protocol */
- if (filename && g_str_has_prefix(filename, "json:")) {
- QDict *json_options = parse_json_filename(filename, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return -EINVAL;
- }
-
- /* Options given in the filename have lower priority than options
- * specified directly */
- qdict_join(*options, json_options, false);
- QDECREF(json_options);
- *pfilename = filename = NULL;
- }
-
drvname = qdict_get_try_str(*options, "driver");
if (drvname) {
drv = bdrv_find_format(drvname);
@@ -1033,6 +1141,9 @@ static int bdrv_fill_options(QDict **options, const char **pfilename,
*flags &= ~BDRV_O_PROTOCOL;
}
+ /* Translate cache options from flags into options */
+ update_options_from_flags(*options, *flags);
+
/* Fetch the file name from the options QDict if necessary */
if (protocol && filename) {
if (!qdict_haskey(*options, "filename")) {
@@ -1087,11 +1198,13 @@ static int bdrv_fill_options(QDict **options, const char **pfilename,
static BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs,
BlockDriverState *child_bs,
+ const char *child_name,
const BdrvChildRole *child_role)
{
BdrvChild *child = g_new(BdrvChild, 1);
*child = (BdrvChild) {
.bs = child_bs,
+ .name = g_strdup(child_name),
.role = child_role,
};
@@ -1105,6 +1218,7 @@ static void bdrv_detach_child(BdrvChild *child)
{
QLIST_REMOVE(child, next);
QLIST_REMOVE(child, next_parent);
+ g_free(child->name);
g_free(child);
}
@@ -1151,7 +1265,7 @@ void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd)
bs->backing = NULL;
goto out;
}
- bs->backing = bdrv_attach_child(bs, backing_hd, &child_backing);
+ bs->backing = bdrv_attach_child(bs, backing_hd, "backing", &child_backing);
bs->open_flags &= ~BDRV_O_NO_BACKING;
pstrcpy(bs->backing_file, sizeof(bs->backing_file), backing_hd->filename);
pstrcpy(bs->backing_format, sizeof(bs->backing_format),
@@ -1168,30 +1282,43 @@ out:
/*
* Opens the backing file for a BlockDriverState if not yet open
*
- * options is a QDict of options to pass to the block drivers, or NULL for an
- * empty set of options. The reference to the QDict is transferred to this
- * function (even on failure), so if the caller intends to reuse the dictionary,
- * it needs to use QINCREF() before calling bdrv_file_open.
+ * bdref_key specifies the key for the image's BlockdevRef in the options QDict.
+ * That QDict has to be flattened; therefore, if the BlockdevRef is a QDict
+ * itself, all options starting with "${bdref_key}." are considered part of the
+ * BlockdevRef.
+ *
+ * TODO Can this be unified with bdrv_open_image()?
*/
-int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
+int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
+ const char *bdref_key, Error **errp)
{
char *backing_filename = g_malloc0(PATH_MAX);
+ char *bdref_key_dot;
+ const char *reference = NULL;
int ret = 0;
BlockDriverState *backing_hd;
+ QDict *options;
+ QDict *tmp_parent_options = NULL;
Error *local_err = NULL;
if (bs->backing != NULL) {
- QDECREF(options);
goto free_exit;
}
/* NULL means an empty set of options */
- if (options == NULL) {
- options = qdict_new();
+ if (parent_options == NULL) {
+ tmp_parent_options = qdict_new();
+ parent_options = tmp_parent_options;
}
bs->open_flags &= ~BDRV_O_NO_BACKING;
- if (qdict_haskey(options, "file.filename")) {
+
+ bdref_key_dot = g_strdup_printf("%s.", bdref_key);
+ qdict_extract_subqdict(parent_options, &options, bdref_key_dot);
+ g_free(bdref_key_dot);
+
+ reference = qdict_get_try_str(parent_options, bdref_key);
+ if (reference || qdict_haskey(options, "file.filename")) {
backing_filename[0] = '\0';
} else if (bs->backing_file[0] == '\0' && qdict_size(options) == 0) {
QDECREF(options);
@@ -1214,19 +1341,16 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
goto free_exit;
}
- backing_hd = bdrv_new();
-
if (bs->backing_format[0] != '\0' && !qdict_haskey(options, "driver")) {
qdict_put(options, "driver", qstring_from_str(bs->backing_format));
}
- assert(bs->backing == NULL);
+ backing_hd = NULL;
ret = bdrv_open_inherit(&backing_hd,
*backing_filename ? backing_filename : NULL,
- NULL, options, 0, bs, &child_backing, &local_err);
+ reference, options, 0, bs, &child_backing,
+ &local_err);
if (ret < 0) {
- bdrv_unref(backing_hd);
- backing_hd = NULL;
bs->open_flags |= BDRV_O_NO_BACKING;
error_setg(errp, "Could not open backing file: %s",
error_get_pretty(local_err));
@@ -1239,8 +1363,11 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
bdrv_set_backing_hd(bs, backing_hd);
bdrv_unref(backing_hd);
+ qdict_del(parent_options, bdref_key);
+
free_exit:
g_free(backing_filename);
+ QDECREF(tmp_parent_options);
return ret;
}
@@ -1294,7 +1421,7 @@ BdrvChild *bdrv_open_child(const char *filename,
goto done;
}
- c = bdrv_attach_child(parent, bs, child_role);
+ c = bdrv_attach_child(parent, bs, bdref_key, child_role);
done:
qdict_del(options, bdref_key);
@@ -1437,21 +1564,34 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
options = qdict_new();
}
+ /* json: syntax counts as explicit options, as if in the QDict */
+ parse_json_protocol(options, &filename, &local_err);
+ if (local_err) {
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ bs->explicit_options = qdict_clone_shallow(options);
+
if (child_role) {
bs->inherits_from = parent;
- flags = child_role->inherit_flags(parent->open_flags);
+ child_role->inherit_options(&flags, options,
+ parent->open_flags, parent->options);
}
- ret = bdrv_fill_options(&options, &filename, &flags, &local_err);
+ ret = bdrv_fill_options(&options, filename, &flags, &local_err);
if (local_err) {
goto fail;
}
+ bs->open_flags = flags;
+ bs->options = options;
+ options = qdict_clone_shallow(options);
+
/* Find the right image format driver */
drvname = qdict_get_try_str(options, "driver");
if (drvname) {
drv = bdrv_find_format(drvname);
- qdict_del(options, "driver");
if (!drv) {
error_setg(errp, "Unknown driver: '%s'", drvname);
ret = -EINVAL;
@@ -1467,10 +1607,6 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
qdict_del(options, "backing");
}
- bs->open_flags = flags;
- bs->options = options;
- options = qdict_clone_shallow(options);
-
/* Open image file without format layer */
if ((flags & BDRV_O_PROTOCOL) == 0) {
if (flags & BDRV_O_RDWR) {
@@ -1478,7 +1614,7 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
}
if (flags & BDRV_O_SNAPSHOT) {
snapshot_flags = bdrv_temp_snapshot_flags(flags);
- flags = bdrv_backing_flags(flags);
+ bdrv_backing_options(&flags, options, flags, options);
}
bs->open_flags = flags;
@@ -1498,6 +1634,19 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
if (ret < 0) {
goto fail;
}
+ /*
+ * This option update would logically belong in bdrv_fill_options(),
+ * but we first need to open bs->file for the probing to work, while
+ * opening bs->file already requires the (mostly) final set of options
+ * so that cache mode etc. can be inherited.
+ *
+ * Adding the driver later is somewhat ugly, but it's not an option
+ * that would ever be inherited, so it's correct. We just need to make
+ * sure to update both bs->options (which has the full effective
+ * options for bs) and options (which has file.* already removed).
+ */
+ qdict_put(bs->options, "driver", qstring_from_str(drv->format_name));
+ qdict_put(options, "driver", qstring_from_str(drv->format_name));
} else if (!drv) {
error_setg(errp, "Must specify either driver or file");
ret = -EINVAL;
@@ -1511,7 +1660,7 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
assert(!(flags & BDRV_O_PROTOCOL) || !file);
/* Open the image */
- ret = bdrv_open_common(bs, file, options, flags, drv, &local_err);
+ ret = bdrv_open_common(bs, file, options, flags, &local_err);
if (ret < 0) {
goto fail;
}
@@ -1523,10 +1672,7 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
/* If there is a backing file, use it */
if ((flags & BDRV_O_NO_BACKING) == 0) {
- QDict *backing_options;
-
- qdict_extract_subqdict(options, &backing_options, "backing.");
- ret = bdrv_open_backing_file(bs, backing_options, &local_err);
+ ret = bdrv_open_backing_file(bs, options, "backing", &local_err);
if (ret < 0) {
goto close_and_fail;
}
@@ -1581,6 +1727,7 @@ fail:
if (file != NULL) {
bdrv_unref_child(bs, file);
}
+ QDECREF(bs->explicit_options);
QDECREF(bs->options);
QDECREF(options);
bs->options = NULL;
@@ -1643,15 +1790,19 @@ typedef struct BlockReopenQueueEntry {
* bs_queue, or the existing bs_queue being used.
*
*/
-BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
- BlockDriverState *bs,
- QDict *options, int flags)
+static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
+ BlockDriverState *bs,
+ QDict *options,
+ int flags,
+ const BdrvChildRole *role,
+ QDict *parent_options,
+ int parent_flags)
{
assert(bs != NULL);
BlockReopenQueueEntry *bs_entry;
BdrvChild *child;
- QDict *old_options;
+ QDict *old_options, *explicit_options;
if (bs_queue == NULL) {
bs_queue = g_new0(BlockReopenQueue, 1);
@@ -1662,23 +1813,63 @@ BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
options = qdict_new();
}
+ /*
+ * Precedence of options:
+ * 1. Explicitly passed in options (highest)
+ * 2. Set in flags (only for top level)
+ * 3. Retained from explicitly set options of bs
+ * 4. Inherited from parent node
+ * 5. Retained from effective options of bs
+ */
+
+ if (!parent_options) {
+ /*
+ * Any setting represented by flags is always updated. If the
+ * corresponding QDict option is set, it takes precedence. Otherwise
+ * the flag is translated into a QDict option. The old setting of bs is
+ * not considered.
+ */
+ update_options_from_flags(options, flags);
+ }
+
+ /* Old explicitly set values (don't overwrite by inherited value) */
+ old_options = qdict_clone_shallow(bs->explicit_options);
+ bdrv_join_options(bs, options, old_options);
+ QDECREF(old_options);
+
+ explicit_options = qdict_clone_shallow(options);
+
+ /* Inherit from parent node */
+ if (parent_options) {
+ assert(!flags);
+ role->inherit_options(&flags, options, parent_flags, parent_options);
+ }
+
+ /* Old values are used for options that aren't set yet */
old_options = qdict_clone_shallow(bs->options);
- qdict_join(options, old_options, false);
+ bdrv_join_options(bs, options, old_options);
QDECREF(old_options);
/* bdrv_open() masks this flag out */
flags &= ~BDRV_O_PROTOCOL;
QLIST_FOREACH(child, &bs->children, next) {
- int child_flags;
+ QDict *new_child_options;
+ char *child_key_dot;
+ /* reopen can only change the options of block devices that were
+ * implicitly created and inherited options. For other (referenced)
+ * block devices, a syntax like "backing.foo" results in an error. */
if (child->bs->inherits_from != bs) {
continue;
}
- child_flags = child->role->inherit_flags(flags);
- /* TODO Pass down child flags (backing.*, extents.*, ...) */
- bdrv_reopen_queue(bs_queue, child->bs, NULL, child_flags);
+ child_key_dot = g_strdup_printf("%s.", child->name);
+ qdict_extract_subqdict(options, &new_child_options, child_key_dot);
+ g_free(child_key_dot);
+
+ bdrv_reopen_queue_child(bs_queue, child->bs, new_child_options, 0,
+ child->role, options, flags);
}
bs_entry = g_new0(BlockReopenQueueEntry, 1);
@@ -1686,11 +1877,20 @@ BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
bs_entry->state.bs = bs;
bs_entry->state.options = options;
+ bs_entry->state.explicit_options = explicit_options;
bs_entry->state.flags = flags;
return bs_queue;
}
+BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
+ BlockDriverState *bs,
+ QDict *options, int flags)
+{
+ return bdrv_reopen_queue_child(bs_queue, bs, options, flags,
+ NULL, NULL, 0);
+}
+
/*
* Reopen multiple BlockDriverStates atomically & transactionally.
*
@@ -1737,6 +1937,8 @@ cleanup:
QSIMPLEQ_FOREACH_SAFE(bs_entry, bs_queue, entry, next) {
if (ret && bs_entry->prepared) {
bdrv_reopen_abort(&bs_entry->state);
+ } else if (ret) {
+ QDECREF(bs_entry->state.explicit_options);
}
QDECREF(bs_entry->state.options);
g_free(bs_entry);
@@ -1784,11 +1986,47 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
int ret = -1;
Error *local_err = NULL;
BlockDriver *drv;
+ QemuOpts *opts;
+ const char *value;
assert(reopen_state != NULL);
assert(reopen_state->bs->drv != NULL);
drv = reopen_state->bs->drv;
+ /* Process generic block layer options */
+ opts = qemu_opts_create(&bdrv_runtime_opts, NULL, 0, &error_abort);
+ qemu_opts_absorb_qdict(opts, reopen_state->options, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ update_flags_from_options(&reopen_state->flags, opts);
+
+ /* If a guest device is attached, it owns WCE */
+ if (reopen_state->bs->blk && blk_get_attached_dev(reopen_state->bs->blk)) {
+ bool old_wce = bdrv_enable_write_cache(reopen_state->bs);
+ bool new_wce = (reopen_state->flags & BDRV_O_CACHE_WB);
+ if (old_wce != new_wce) {
+ error_setg(errp, "Cannot change cache.writeback: Device attached");
+ ret = -EINVAL;
+ goto error;
+ }
+ }
+
+ /* node-name and driver must be unchanged. Put them back into the QDict, so
+ * that they are checked at the end of this function. */
+ value = qemu_opt_get(opts, "node-name");
+ if (value) {
+ qdict_put(reopen_state->options, "node-name", qstring_from_str(value));
+ }
+
+ value = qemu_opt_get(opts, "driver");
+ if (value) {
+ qdict_put(reopen_state->options, "driver", qstring_from_str(value));
+ }
+
/* if we are to stay read-only, do not allow permission change
* to r/w */
if (!(reopen_state->bs->open_flags & BDRV_O_ALLOW_RDWR) &&
@@ -1849,6 +2087,7 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
ret = 0;
error:
+ qemu_opts_del(opts);
return ret;
}
@@ -1871,6 +2110,9 @@ void bdrv_reopen_commit(BDRVReopenState *reopen_state)
}
/* set BDS specific flags now */
+ QDECREF(reopen_state->bs->explicit_options);
+
+ reopen_state->bs->explicit_options = reopen_state->explicit_options;
reopen_state->bs->open_flags = reopen_state->flags;
reopen_state->bs->enable_write_cache = !!(reopen_state->flags &
BDRV_O_CACHE_WB);
@@ -1894,6 +2136,8 @@ void bdrv_reopen_abort(BDRVReopenState *reopen_state)
if (drv->bdrv_reopen_abort) {
drv->bdrv_reopen_abort(reopen_state);
}
+
+ QDECREF(reopen_state->explicit_options);
}
@@ -1952,6 +2196,7 @@ void bdrv_close(BlockDriverState *bs)
bs->sg = 0;
bs->zero_beyond_eof = false;
QDECREF(bs->options);
+ QDECREF(bs->explicit_options);
bs->options = NULL;
QDECREF(bs->full_open_options);
bs->full_open_options = NULL;
@@ -3823,12 +4068,12 @@ void bdrv_remove_aio_context_notifier(BlockDriverState *bs,
}
int bdrv_amend_options(BlockDriverState *bs, QemuOpts *opts,
- BlockDriverAmendStatusCB *status_cb)
+ BlockDriverAmendStatusCB *status_cb, void *cb_opaque)
{
if (!bs->drv->bdrv_amend_options) {
return -ENOTSUP;
}
- return bs->drv->bdrv_amend_options(bs, opts, status_cb);
+ return bs->drv->bdrv_amend_options(bs, opts, status_cb, cb_opaque);
}
/* This function will be called by the bdrv_recurse_is_first_non_filter method
@@ -3926,20 +4171,39 @@ out:
static bool append_open_options(QDict *d, BlockDriverState *bs)
{
const QDictEntry *entry;
+ QemuOptDesc *desc;
+ BdrvChild *child;
bool found_any = false;
+ const char *p;
for (entry = qdict_first(bs->options); entry;
entry = qdict_next(bs->options, entry))
{
- /* Only take options for this level and exclude all non-driver-specific
- * options */
- if (!strchr(qdict_entry_key(entry), '.') &&
- strcmp(qdict_entry_key(entry), "node-name"))
- {
- qobject_incref(qdict_entry_value(entry));
- qdict_put_obj(d, qdict_entry_key(entry), qdict_entry_value(entry));
- found_any = true;
+ /* Exclude options for children */
+ QLIST_FOREACH(child, &bs->children, next) {
+ if (strstart(qdict_entry_key(entry), child->name, &p)
+ && (!*p || *p == '.'))
+ {
+ break;
+ }
}
+ if (child) {
+ continue;
+ }
+
+ /* And exclude all non-driver-specific options */
+ for (desc = bdrv_runtime_opts.desc; desc->name; desc++) {
+ if (!strcmp(qdict_entry_key(entry), desc->name)) {
+ break;
+ }
+ }
+ if (desc->name) {
+ continue;
+ }
+
+ qobject_incref(qdict_entry_value(entry));
+ qdict_put_obj(d, qdict_entry_key(entry), qdict_entry_value(entry));
+ found_any = true;
}
return found_any;
@@ -3981,7 +4245,10 @@ void bdrv_refresh_filename(BlockDriverState *bs)
bs->full_open_options = NULL;
}
- drv->bdrv_refresh_filename(bs);
+ opts = qdict_new();
+ append_open_options(opts, bs);
+ drv->bdrv_refresh_filename(bs, opts);
+ QDECREF(opts);
} else if (bs->file) {
/* Try to reconstruct valid information from the underlying file */
bool has_open_options;
diff --git a/block/blkdebug.c b/block/blkdebug.c
index 59c61eb..86b143d 100644
--- a/block/blkdebug.c
+++ b/block/blkdebug.c
@@ -674,17 +674,15 @@ static int blkdebug_truncate(BlockDriverState *bs, int64_t offset)
return bdrv_truncate(bs->file->bs, offset);
}
-static void blkdebug_refresh_filename(BlockDriverState *bs)
+static void blkdebug_refresh_filename(BlockDriverState *bs, QDict *options)
{
QDict *opts;
const QDictEntry *e;
bool force_json = false;
- for (e = qdict_first(bs->options); e; e = qdict_next(bs->options, e)) {
+ for (e = qdict_first(options); e; e = qdict_next(options, e)) {
if (strcmp(qdict_entry_key(e), "config") &&
- strcmp(qdict_entry_key(e), "x-image") &&
- strcmp(qdict_entry_key(e), "image") &&
- strncmp(qdict_entry_key(e), "image.", strlen("image.")))
+ strcmp(qdict_entry_key(e), "x-image"))
{
force_json = true;
break;
@@ -700,7 +698,7 @@ static void blkdebug_refresh_filename(BlockDriverState *bs)
if (!force_json && bs->file->bs->exact_filename[0]) {
snprintf(bs->exact_filename, sizeof(bs->exact_filename),
"blkdebug:%s:%s",
- qdict_get_try_str(bs->options, "config") ?: "",
+ qdict_get_try_str(options, "config") ?: "",
bs->file->bs->exact_filename);
}
@@ -710,11 +708,8 @@ static void blkdebug_refresh_filename(BlockDriverState *bs)
QINCREF(bs->file->bs->full_open_options);
qdict_put_obj(opts, "image", QOBJECT(bs->file->bs->full_open_options));
- for (e = qdict_first(bs->options); e; e = qdict_next(bs->options, e)) {
- if (strcmp(qdict_entry_key(e), "x-image") &&
- strcmp(qdict_entry_key(e), "image") &&
- strncmp(qdict_entry_key(e), "image.", strlen("image.")))
- {
+ for (e = qdict_first(options); e; e = qdict_next(options, e)) {
+ if (strcmp(qdict_entry_key(e), "x-image")) {
qobject_incref(qdict_entry_value(e));
qdict_put_obj(opts, qdict_entry_key(e), qdict_entry_value(e));
}
@@ -723,6 +718,12 @@ static void blkdebug_refresh_filename(BlockDriverState *bs)
bs->full_open_options = opts;
}
+static int blkdebug_reopen_prepare(BDRVReopenState *reopen_state,
+ BlockReopenQueue *queue, Error **errp)
+{
+ return 0;
+}
+
static BlockDriver bdrv_blkdebug = {
.format_name = "blkdebug",
.protocol_name = "blkdebug",
@@ -731,6 +732,7 @@ static BlockDriver bdrv_blkdebug = {
.bdrv_parse_filename = blkdebug_parse_filename,
.bdrv_file_open = blkdebug_open,
.bdrv_close = blkdebug_close,
+ .bdrv_reopen_prepare = blkdebug_reopen_prepare,
.bdrv_getlength = blkdebug_getlength,
.bdrv_truncate = blkdebug_truncate,
.bdrv_refresh_filename = blkdebug_refresh_filename,
diff --git a/block/blkverify.c b/block/blkverify.c
index c5f8e8d..1d75449 100644
--- a/block/blkverify.c
+++ b/block/blkverify.c
@@ -307,7 +307,7 @@ static void blkverify_attach_aio_context(BlockDriverState *bs,
bdrv_attach_aio_context(s->test_file->bs, new_context);
}
-static void blkverify_refresh_filename(BlockDriverState *bs)
+static void blkverify_refresh_filename(BlockDriverState *bs, QDict *options)
{
BDRVBlkverifyState *s = bs->opaque;
diff --git a/block/io.c b/block/io.c
index e00fb5d..841f5b5 100644
--- a/block/io.c
+++ b/block/io.c
@@ -2614,10 +2614,11 @@ int bdrv_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
bdrv_co_ioctl_entry(&data);
} else {
Coroutine *co = qemu_coroutine_create(bdrv_co_ioctl_entry);
+
qemu_coroutine_enter(co, &data);
- }
- while (data.ret == -EINPROGRESS) {
- aio_poll(bdrv_get_aio_context(bs), true);
+ while (data.ret == -EINPROGRESS) {
+ aio_poll(bdrv_get_aio_context(bs), true);
+ }
}
return data.ret;
}
diff --git a/block/mirror.c b/block/mirror.c
index 0e8f556..fc34a9c 100644
--- a/block/mirror.c
+++ b/block/mirror.c
@@ -18,6 +18,7 @@
#include "qapi/qmp/qerror.h"
#include "qemu/ratelimit.h"
#include "qemu/bitmap.h"
+#include "qemu/error-report.h"
#define SLICE_TIME 100000000ULL /* ns */
#define MAX_IN_FLIGHT 16
@@ -370,11 +371,22 @@ static void mirror_exit(BlockJob *job, void *opaque)
if (s->to_replace) {
to_replace = s->to_replace;
}
+
+ /* This was checked in mirror_start_job(), but meanwhile one of the
+ * nodes could have been newly attached to a BlockBackend. */
+ if (to_replace->blk && s->target->blk) {
+ error_report("block job: Can't create node with two BlockBackends");
+ data->ret = -EINVAL;
+ goto out;
+ }
+
if (bdrv_get_flags(s->target) != bdrv_get_flags(to_replace)) {
bdrv_reopen(s->target, bdrv_get_flags(to_replace), NULL);
}
bdrv_replace_in_backing_chain(to_replace, s->target);
}
+
+out:
if (s->to_replace) {
bdrv_op_unblock_all(s->to_replace, s->replace_blocker);
error_free(s->replace_blocker);
@@ -640,7 +652,7 @@ static void mirror_complete(BlockJob *job, Error **errp)
Error *local_err = NULL;
int ret;
- ret = bdrv_open_backing_file(s->target, NULL, &local_err);
+ ret = bdrv_open_backing_file(s->target, NULL, "backing", &local_err);
if (ret < 0) {
error_propagate(errp, local_err);
return;
@@ -705,6 +717,7 @@ static void mirror_start_job(BlockDriverState *bs, BlockDriverState *target,
bool is_none_mode, BlockDriverState *base)
{
MirrorBlockJob *s;
+ BlockDriverState *replaced_bs;
if (granularity == 0) {
granularity = bdrv_get_default_bitmap_granularity(target);
@@ -728,6 +741,21 @@ static void mirror_start_job(BlockDriverState *bs, BlockDriverState *target,
buf_size = DEFAULT_MIRROR_BUF_SIZE;
}
+ /* We can't support this case as long as the block layer can't handle
+ * multiple BlockBackends per BlockDriverState. */
+ if (replaces) {
+ replaced_bs = bdrv_lookup_bs(replaces, replaces, errp);
+ if (replaced_bs == NULL) {
+ return;
+ }
+ } else {
+ replaced_bs = bs;
+ }
+ if (replaced_bs->blk && target->blk) {
+ error_setg(errp, "Can't create node with two BlockBackends");
+ return;
+ }
+
s = block_job_create(driver, bs, speed, cb, opaque, errp);
if (!s) {
return;
diff --git a/block/nbd.c b/block/nbd.c
index cd6a587..416f42b 100644
--- a/block/nbd.c
+++ b/block/nbd.c
@@ -342,13 +342,13 @@ static void nbd_attach_aio_context(BlockDriverState *bs,
nbd_client_attach_aio_context(bs, new_context);
}
-static void nbd_refresh_filename(BlockDriverState *bs)
+static void nbd_refresh_filename(BlockDriverState *bs, QDict *options)
{
QDict *opts = qdict_new();
- const char *path = qdict_get_try_str(bs->options, "path");
- const char *host = qdict_get_try_str(bs->options, "host");
- const char *port = qdict_get_try_str(bs->options, "port");
- const char *export = qdict_get_try_str(bs->options, "export");
+ const char *path = qdict_get_try_str(options, "path");
+ const char *host = qdict_get_try_str(options, "host");
+ const char *port = qdict_get_try_str(options, "port");
+ const char *export = qdict_get_try_str(options, "export");
qdict_put_obj(opts, "driver", QOBJECT(qstring_from_str("nbd")));
diff --git a/block/qapi.c b/block/qapi.c
index c0e877e..fecac25 100644
--- a/block/qapi.c
+++ b/block/qapi.c
@@ -245,15 +245,17 @@ void bdrv_query_image_info(BlockDriverState *bs,
info->has_backing_filename = true;
bdrv_get_full_backing_filename(bs, backing_filename2, PATH_MAX, &err);
if (err) {
- error_propagate(errp, err);
- qapi_free_ImageInfo(info);
+ /* Can't reconstruct the full backing filename, so we must omit
+ * this field and apply a Best Effort to this query. */
g_free(backing_filename2);
- return;
+ backing_filename2 = NULL;
+ error_free(err);
}
- if (strcmp(backing_filename, backing_filename2) != 0) {
- info->full_backing_filename =
- g_strdup(backing_filename2);
+ /* Always report the full_backing_filename if present, even if it's the
+ * same as backing_filename. That they are same is useful info. */
+ if (backing_filename2) {
+ info->full_backing_filename = g_strdup(backing_filename2);
info->has_full_backing_filename = true;
}
@@ -676,7 +678,10 @@ void bdrv_image_info_dump(fprintf_function func_fprintf, void *f,
if (info->has_backing_filename) {
func_fprintf(f, "backing file: %s", info->backing_filename);
- if (info->has_full_backing_filename) {
+ if (!info->has_full_backing_filename) {
+ func_fprintf(f, " (cannot determine actual path)");
+ } else if (strcmp(info->backing_filename,
+ info->full_backing_filename) != 0) {
func_fprintf(f, " (actual path: %s)", info->full_backing_filename);
}
func_fprintf(f, "\n");
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index 24a60e2..34112c3 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -1641,7 +1641,8 @@ fail:
static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
int l1_size, int64_t *visited_l1_entries,
int64_t l1_entries,
- BlockDriverAmendStatusCB *status_cb)
+ BlockDriverAmendStatusCB *status_cb,
+ void *cb_opaque)
{
BDRVQcow2State *s = bs->opaque;
bool is_active_l1 = (l1_table == s->l1_table);
@@ -1667,7 +1668,7 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
/* unallocated */
(*visited_l1_entries)++;
if (status_cb) {
- status_cb(bs, *visited_l1_entries, l1_entries);
+ status_cb(bs, *visited_l1_entries, l1_entries, cb_opaque);
}
continue;
}
@@ -1804,7 +1805,7 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
(*visited_l1_entries)++;
if (status_cb) {
- status_cb(bs, *visited_l1_entries, l1_entries);
+ status_cb(bs, *visited_l1_entries, l1_entries, cb_opaque);
}
}
@@ -1828,7 +1829,8 @@ fail:
* qcow2 version which doesn't yet support metadata zero clusters.
*/
int qcow2_expand_zero_clusters(BlockDriverState *bs,
- BlockDriverAmendStatusCB *status_cb)
+ BlockDriverAmendStatusCB *status_cb,
+ void *cb_opaque)
{
BDRVQcow2State *s = bs->opaque;
uint64_t *l1_table = NULL;
@@ -1845,7 +1847,7 @@ int qcow2_expand_zero_clusters(BlockDriverState *bs,
ret = expand_zero_clusters_in_l1(bs, s->l1_table, s->l1_size,
&visited_l1_entries, l1_entries,
- status_cb);
+ status_cb, cb_opaque);
if (ret < 0) {
goto fail;
}
@@ -1881,7 +1883,7 @@ int qcow2_expand_zero_clusters(BlockDriverState *bs,
ret = expand_zero_clusters_in_l1(bs, l1_table, s->snapshots[i].l1_size,
&visited_l1_entries, l1_entries,
- status_cb);
+ status_cb, cb_opaque);
if (ret < 0) {
goto fail;
}
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index 820f412..af493f8 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -1345,6 +1345,9 @@ static int inc_refcounts(BlockDriverState *bs,
if (refcount == s->refcount_max) {
fprintf(stderr, "ERROR: overflow cluster offset=0x%" PRIx64
"\n", cluster_offset);
+ fprintf(stderr, "Use qemu-img amend to increase the refcount entry "
+ "width or qemu-img convert to create a clean copy if the "
+ "image cannot be opened for writing\n");
res->corruptions++;
continue;
}
@@ -2467,3 +2470,450 @@ int qcow2_pre_write_overlap_check(BlockDriverState *bs, int ign, int64_t offset,
return 0;
}
+
+/* A pointer to a function of this type is given to walk_over_reftable(). That
+ * function will create refblocks and pass them to a RefblockFinishOp once they
+ * are completed (@refblock). @refblock_empty is set if the refblock is
+ * completely empty.
+ *
+ * Along with the refblock, a corresponding reftable entry is passed, in the
+ * reftable @reftable (which may be reallocated) at @reftable_index.
+ *
+ * @allocated should be set to true if a new cluster has been allocated.
+ */
+typedef int (RefblockFinishOp)(BlockDriverState *bs, uint64_t **reftable,
+ uint64_t reftable_index, uint64_t *reftable_size,
+ void *refblock, bool refblock_empty,
+ bool *allocated, Error **errp);
+
+/**
+ * This "operation" for walk_over_reftable() allocates the refblock on disk (if
+ * it is not empty) and inserts its offset into the new reftable. The size of
+ * this new reftable is increased as required.
+ */
+static int alloc_refblock(BlockDriverState *bs, uint64_t **reftable,
+ uint64_t reftable_index, uint64_t *reftable_size,
+ void *refblock, bool refblock_empty, bool *allocated,
+ Error **errp)
+{
+ BDRVQcow2State *s = bs->opaque;
+ int64_t offset;
+
+ if (!refblock_empty && reftable_index >= *reftable_size) {
+ uint64_t *new_reftable;
+ uint64_t new_reftable_size;
+
+ new_reftable_size = ROUND_UP(reftable_index + 1,
+ s->cluster_size / sizeof(uint64_t));
+ if (new_reftable_size > QCOW_MAX_REFTABLE_SIZE / sizeof(uint64_t)) {
+ error_setg(errp,
+ "This operation would make the refcount table grow "
+ "beyond the maximum size supported by QEMU, aborting");
+ return -ENOTSUP;
+ }
+
+ new_reftable = g_try_realloc(*reftable, new_reftable_size *
+ sizeof(uint64_t));
+ if (!new_reftable) {
+ error_setg(errp, "Failed to increase reftable buffer size");
+ return -ENOMEM;
+ }
+
+ memset(new_reftable + *reftable_size, 0,
+ (new_reftable_size - *reftable_size) * sizeof(uint64_t));
+
+ *reftable = new_reftable;
+ *reftable_size = new_reftable_size;
+ }
+
+ if (!refblock_empty && !(*reftable)[reftable_index]) {
+ offset = qcow2_alloc_clusters(bs, s->cluster_size);
+ if (offset < 0) {
+ error_setg_errno(errp, -offset, "Failed to allocate refblock");
+ return offset;
+ }
+ (*reftable)[reftable_index] = offset;
+ *allocated = true;
+ }
+
+ return 0;
+}
+
+/**
+ * This "operation" for walk_over_reftable() writes the refblock to disk at the
+ * offset specified by the new reftable's entry. It does not modify the new
+ * reftable or change any refcounts.
+ */
+static int flush_refblock(BlockDriverState *bs, uint64_t **reftable,
+ uint64_t reftable_index, uint64_t *reftable_size,
+ void *refblock, bool refblock_empty, bool *allocated,
+ Error **errp)
+{
+ BDRVQcow2State *s = bs->opaque;
+ int64_t offset;
+ int ret;
+
+ if (reftable_index < *reftable_size && (*reftable)[reftable_index]) {
+ offset = (*reftable)[reftable_index];
+
+ ret = qcow2_pre_write_overlap_check(bs, 0, offset, s->cluster_size);
+ if (ret < 0) {
+ error_setg_errno(errp, -ret, "Overlap check failed");
+ return ret;
+ }
+
+ ret = bdrv_pwrite(bs->file->bs, offset, refblock, s->cluster_size);
+ if (ret < 0) {
+ error_setg_errno(errp, -ret, "Failed to write refblock");
+ return ret;
+ }
+ } else {
+ assert(refblock_empty);
+ }
+
+ return 0;
+}
+
+/**
+ * This function walks over the existing reftable and every referenced refblock;
+ * if @new_set_refcount is non-NULL, it is called for every refcount entry to
+ * create an equal new entry in the passed @new_refblock. Once that
+ * @new_refblock is completely filled, @operation will be called.
+ *
+ * @status_cb and @cb_opaque are used for the amend operation's status callback.
+ * @index is the index of the walk_over_reftable() calls and @total is the total
+ * number of walk_over_reftable() calls per amend operation. Both are used for
+ * calculating the parameters for the status callback.
+ *
+ * @allocated is set to true if a new cluster has been allocated.
+ */
+static int walk_over_reftable(BlockDriverState *bs, uint64_t **new_reftable,
+ uint64_t *new_reftable_index,
+ uint64_t *new_reftable_size,
+ void *new_refblock, int new_refblock_size,
+ int new_refcount_bits,
+ RefblockFinishOp *operation, bool *allocated,
+ Qcow2SetRefcountFunc *new_set_refcount,
+ BlockDriverAmendStatusCB *status_cb,
+ void *cb_opaque, int index, int total,
+ Error **errp)
+{
+ BDRVQcow2State *s = bs->opaque;
+ uint64_t reftable_index;
+ bool new_refblock_empty = true;
+ int refblock_index;
+ int new_refblock_index = 0;
+ int ret;
+
+ for (reftable_index = 0; reftable_index < s->refcount_table_size;
+ reftable_index++)
+ {
+ uint64_t refblock_offset = s->refcount_table[reftable_index]
+ & REFT_OFFSET_MASK;
+
+ status_cb(bs, (uint64_t)index * s->refcount_table_size + reftable_index,
+ (uint64_t)total * s->refcount_table_size, cb_opaque);
+
+ if (refblock_offset) {
+ void *refblock;
+
+ if (offset_into_cluster(s, refblock_offset)) {
+ qcow2_signal_corruption(bs, true, -1, -1, "Refblock offset %#"
+ PRIx64 " unaligned (reftable index: %#"
+ PRIx64 ")", refblock_offset,
+ reftable_index);
+ error_setg(errp,
+ "Image is corrupt (unaligned refblock offset)");
+ return -EIO;
+ }
+
+ ret = qcow2_cache_get(bs, s->refcount_block_cache, refblock_offset,
+ &refblock);
+ if (ret < 0) {
+ error_setg_errno(errp, -ret, "Failed to retrieve refblock");
+ return ret;
+ }
+
+ for (refblock_index = 0; refblock_index < s->refcount_block_size;
+ refblock_index++)
+ {
+ uint64_t refcount;
+
+ if (new_refblock_index >= new_refblock_size) {
+ /* new_refblock is now complete */
+ ret = operation(bs, new_reftable, *new_reftable_index,
+ new_reftable_size, new_refblock,
+ new_refblock_empty, allocated, errp);
+ if (ret < 0) {
+ qcow2_cache_put(bs, s->refcount_block_cache, &refblock);
+ return ret;
+ }
+
+ (*new_reftable_index)++;
+ new_refblock_index = 0;
+ new_refblock_empty = true;
+ }
+
+ refcount = s->get_refcount(refblock, refblock_index);
+ if (new_refcount_bits < 64 && refcount >> new_refcount_bits) {
+ uint64_t offset;
+
+ qcow2_cache_put(bs, s->refcount_block_cache, &refblock);
+
+ offset = ((reftable_index << s->refcount_block_bits)
+ + refblock_index) << s->cluster_bits;
+
+ error_setg(errp, "Cannot decrease refcount entry width to "
+ "%i bits: Cluster at offset %#" PRIx64 " has a "
+ "refcount of %" PRIu64, new_refcount_bits,
+ offset, refcount);
+ return -EINVAL;
+ }
+
+ if (new_set_refcount) {
+ new_set_refcount(new_refblock, new_refblock_index++,
+ refcount);
+ } else {
+ new_refblock_index++;
+ }
+ new_refblock_empty = new_refblock_empty && refcount == 0;
+ }
+
+ qcow2_cache_put(bs, s->refcount_block_cache, &refblock);
+ } else {
+ /* No refblock means every refcount is 0 */
+ for (refblock_index = 0; refblock_index < s->refcount_block_size;
+ refblock_index++)
+ {
+ if (new_refblock_index >= new_refblock_size) {
+ /* new_refblock is now complete */
+ ret = operation(bs, new_reftable, *new_reftable_index,
+ new_reftable_size, new_refblock,
+ new_refblock_empty, allocated, errp);
+ if (ret < 0) {
+ return ret;
+ }
+
+ (*new_reftable_index)++;
+ new_refblock_index = 0;
+ new_refblock_empty = true;
+ }
+
+ if (new_set_refcount) {
+ new_set_refcount(new_refblock, new_refblock_index++, 0);
+ } else {
+ new_refblock_index++;
+ }
+ }
+ }
+ }
+
+ if (new_refblock_index > 0) {
+ /* Complete the potentially existing partially filled final refblock */
+ if (new_set_refcount) {
+ for (; new_refblock_index < new_refblock_size;
+ new_refblock_index++)
+ {
+ new_set_refcount(new_refblock, new_refblock_index, 0);
+ }
+ }
+
+ ret = operation(bs, new_reftable, *new_reftable_index,
+ new_reftable_size, new_refblock, new_refblock_empty,
+ allocated, errp);
+ if (ret < 0) {
+ return ret;
+ }
+
+ (*new_reftable_index)++;
+ }
+
+ status_cb(bs, (uint64_t)(index + 1) * s->refcount_table_size,
+ (uint64_t)total * s->refcount_table_size, cb_opaque);
+
+ return 0;
+}
+
+int qcow2_change_refcount_order(BlockDriverState *bs, int refcount_order,
+ BlockDriverAmendStatusCB *status_cb,
+ void *cb_opaque, Error **errp)
+{
+ BDRVQcow2State *s = bs->opaque;
+ Qcow2GetRefcountFunc *new_get_refcount;
+ Qcow2SetRefcountFunc *new_set_refcount;
+ void *new_refblock = qemu_blockalign(bs->file->bs, s->cluster_size);
+ uint64_t *new_reftable = NULL, new_reftable_size = 0;
+ uint64_t *old_reftable, old_reftable_size, old_reftable_offset;
+ uint64_t new_reftable_index = 0;
+ uint64_t i;
+ int64_t new_reftable_offset = 0, allocated_reftable_size = 0;
+ int new_refblock_size, new_refcount_bits = 1 << refcount_order;
+ int old_refcount_order;
+ int walk_index = 0;
+ int ret;
+ bool new_allocation;
+
+ assert(s->qcow_version >= 3);
+ assert(refcount_order >= 0 && refcount_order <= 6);
+
+ /* see qcow2_open() */
+ new_refblock_size = 1 << (s->cluster_bits - (refcount_order - 3));
+
+ new_get_refcount = get_refcount_funcs[refcount_order];
+ new_set_refcount = set_refcount_funcs[refcount_order];
+
+
+ do {
+ int total_walks;
+
+ new_allocation = false;
+
+ /* At least we have to do this walk and the one which writes the
+ * refblocks; also, at least we have to do this loop here at least
+ * twice (normally), first to do the allocations, and second to
+ * determine that everything is correctly allocated, this then makes
+ * three walks in total */
+ total_walks = MAX(walk_index + 2, 3);
+
+ /* First, allocate the structures so they are present in the refcount
+ * structures */
+ ret = walk_over_reftable(bs, &new_reftable, &new_reftable_index,
+ &new_reftable_size, NULL, new_refblock_size,
+ new_refcount_bits, &alloc_refblock,
+ &new_allocation, NULL, status_cb, cb_opaque,
+ walk_index++, total_walks, errp);
+ if (ret < 0) {
+ goto done;
+ }
+
+ new_reftable_index = 0;
+
+ if (new_allocation) {
+ if (new_reftable_offset) {
+ qcow2_free_clusters(bs, new_reftable_offset,
+ allocated_reftable_size * sizeof(uint64_t),
+ QCOW2_DISCARD_NEVER);
+ }
+
+ new_reftable_offset = qcow2_alloc_clusters(bs, new_reftable_size *
+ sizeof(uint64_t));
+ if (new_reftable_offset < 0) {
+ error_setg_errno(errp, -new_reftable_offset,
+ "Failed to allocate the new reftable");
+ ret = new_reftable_offset;
+ goto done;
+ }
+ allocated_reftable_size = new_reftable_size;
+ }
+ } while (new_allocation);
+
+ /* Second, write the new refblocks */
+ ret = walk_over_reftable(bs, &new_reftable, &new_reftable_index,
+ &new_reftable_size, new_refblock,
+ new_refblock_size, new_refcount_bits,
+ &flush_refblock, &new_allocation, new_set_refcount,
+ status_cb, cb_opaque, walk_index, walk_index + 1,
+ errp);
+ if (ret < 0) {
+ goto done;
+ }
+ assert(!new_allocation);
+
+
+ /* Write the new reftable */
+ ret = qcow2_pre_write_overlap_check(bs, 0, new_reftable_offset,
+ new_reftable_size * sizeof(uint64_t));
+ if (ret < 0) {
+ error_setg_errno(errp, -ret, "Overlap check failed");
+ goto done;
+ }
+
+ for (i = 0; i < new_reftable_size; i++) {
+ cpu_to_be64s(&new_reftable[i]);
+ }
+
+ ret = bdrv_pwrite(bs->file->bs, new_reftable_offset, new_reftable,
+ new_reftable_size * sizeof(uint64_t));
+
+ for (i = 0; i < new_reftable_size; i++) {
+ be64_to_cpus(&new_reftable[i]);
+ }
+
+ if (ret < 0) {
+ error_setg_errno(errp, -ret, "Failed to write the new reftable");
+ goto done;
+ }
+
+
+ /* Empty the refcount cache */
+ ret = qcow2_cache_flush(bs, s->refcount_block_cache);
+ if (ret < 0) {
+ error_setg_errno(errp, -ret, "Failed to flush the refblock cache");
+ goto done;
+ }
+
+ /* Update the image header to point to the new reftable; this only updates
+ * the fields which are relevant to qcow2_update_header(); other fields
+ * such as s->refcount_table or s->refcount_bits stay stale for now
+ * (because we have to restore everything if qcow2_update_header() fails) */
+ old_refcount_order = s->refcount_order;
+ old_reftable_size = s->refcount_table_size;
+ old_reftable_offset = s->refcount_table_offset;
+
+ s->refcount_order = refcount_order;
+ s->refcount_table_size = new_reftable_size;
+ s->refcount_table_offset = new_reftable_offset;
+
+ ret = qcow2_update_header(bs);
+ if (ret < 0) {
+ s->refcount_order = old_refcount_order;
+ s->refcount_table_size = old_reftable_size;
+ s->refcount_table_offset = old_reftable_offset;
+ error_setg_errno(errp, -ret, "Failed to update the qcow2 header");
+ goto done;
+ }
+
+ /* Now update the rest of the in-memory information */
+ old_reftable = s->refcount_table;
+ s->refcount_table = new_reftable;
+
+ s->refcount_bits = 1 << refcount_order;
+ s->refcount_max = UINT64_C(1) << (s->refcount_bits - 1);
+ s->refcount_max += s->refcount_max - 1;
+
+ s->refcount_block_bits = s->cluster_bits - (refcount_order - 3);
+ s->refcount_block_size = 1 << s->refcount_block_bits;
+
+ s->get_refcount = new_get_refcount;
+ s->set_refcount = new_set_refcount;
+
+ /* For cleaning up all old refblocks and the old reftable below the "done"
+ * label */
+ new_reftable = old_reftable;
+ new_reftable_size = old_reftable_size;
+ new_reftable_offset = old_reftable_offset;
+
+done:
+ if (new_reftable) {
+ /* On success, new_reftable actually points to the old reftable (and
+ * new_reftable_size is the old reftable's size); but that is just
+ * fine */
+ for (i = 0; i < new_reftable_size; i++) {
+ uint64_t offset = new_reftable[i] & REFT_OFFSET_MASK;
+ if (offset) {
+ qcow2_free_clusters(bs, offset, s->cluster_size,
+ QCOW2_DISCARD_OTHER);
+ }
+ }
+ g_free(new_reftable);
+
+ if (new_reftable_offset > 0) {
+ qcow2_free_clusters(bs, new_reftable_offset,
+ new_reftable_size * sizeof(uint64_t),
+ QCOW2_DISCARD_OTHER);
+ }
+ }
+
+ qemu_vfree(new_refblock);
+ return ret;
+}
diff --git a/block/qcow2.c b/block/qcow2.c
index 5b59fa3..1789af4 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -1282,6 +1282,52 @@ static void qcow2_reopen_abort(BDRVReopenState *state)
g_free(state->opaque);
}
+static void qcow2_join_options(QDict *options, QDict *old_options)
+{
+ bool has_new_overlap_template =
+ qdict_haskey(options, QCOW2_OPT_OVERLAP) ||
+ qdict_haskey(options, QCOW2_OPT_OVERLAP_TEMPLATE);
+ bool has_new_total_cache_size =
+ qdict_haskey(options, QCOW2_OPT_CACHE_SIZE);
+ bool has_all_cache_options;
+
+ /* New overlap template overrides all old overlap options */
+ if (has_new_overlap_template) {
+ qdict_del(old_options, QCOW2_OPT_OVERLAP);
+ qdict_del(old_options, QCOW2_OPT_OVERLAP_TEMPLATE);
+ qdict_del(old_options, QCOW2_OPT_OVERLAP_MAIN_HEADER);
+ qdict_del(old_options, QCOW2_OPT_OVERLAP_ACTIVE_L1);
+ qdict_del(old_options, QCOW2_OPT_OVERLAP_ACTIVE_L2);
+ qdict_del(old_options, QCOW2_OPT_OVERLAP_REFCOUNT_TABLE);
+ qdict_del(old_options, QCOW2_OPT_OVERLAP_REFCOUNT_BLOCK);
+ qdict_del(old_options, QCOW2_OPT_OVERLAP_SNAPSHOT_TABLE);
+ qdict_del(old_options, QCOW2_OPT_OVERLAP_INACTIVE_L1);
+ qdict_del(old_options, QCOW2_OPT_OVERLAP_INACTIVE_L2);
+ }
+
+ /* New total cache size overrides all old options */
+ if (qdict_haskey(options, QCOW2_OPT_CACHE_SIZE)) {
+ qdict_del(old_options, QCOW2_OPT_L2_CACHE_SIZE);
+ qdict_del(old_options, QCOW2_OPT_REFCOUNT_CACHE_SIZE);
+ }
+
+ qdict_join(options, old_options, false);
+
+ /*
+ * If after merging all cache size options are set, an old total size is
+ * overwritten. Do keep all options, however, if all three are new. The
+ * resulting error message is what we want to happen.
+ */
+ has_all_cache_options =
+ qdict_haskey(options, QCOW2_OPT_CACHE_SIZE) ||
+ qdict_haskey(options, QCOW2_OPT_L2_CACHE_SIZE) ||
+ qdict_haskey(options, QCOW2_OPT_REFCOUNT_CACHE_SIZE);
+
+ if (has_all_cache_options && !has_new_total_cache_size) {
+ qdict_del(options, QCOW2_OPT_CACHE_SIZE);
+ }
+}
+
static int64_t coroutine_fn qcow2_co_get_block_status(BlockDriverState *bs,
int64_t sector_num, int nb_sectors, int *pnum)
{
@@ -2757,6 +2803,10 @@ static ImageInfoSpecific *qcow2_get_specific_info(BlockDriverState *bs)
.has_corrupt = true,
.refcount_bits = s->refcount_bits,
};
+ } else {
+ /* if this assertion fails, this probably means a new version was
+ * added without having it covered here */
+ assert(false);
}
return spec_info;
@@ -2824,7 +2874,7 @@ static int qcow2_load_vmstate(BlockDriverState *bs, uint8_t *buf,
* have to be removed.
*/
static int qcow2_downgrade(BlockDriverState *bs, int target_version,
- BlockDriverAmendStatusCB *status_cb)
+ BlockDriverAmendStatusCB *status_cb, void *cb_opaque)
{
BDRVQcow2State *s = bs->opaque;
int current_version = s->qcow_version;
@@ -2839,13 +2889,7 @@ static int qcow2_downgrade(BlockDriverState *bs, int target_version,
}
if (s->refcount_order != 4) {
- /* we would have to convert the image to a refcount_order == 4 image
- * here; however, since qemu (at the time of writing this) does not
- * support anything different than 4 anyway, there is no point in doing
- * so right now; however, we should error out (if qemu supports this in
- * the future and this code has not been adapted) */
- error_report("qcow2_downgrade: Image refcount orders other than 4 are "
- "currently not supported.");
+ error_report("compat=0.10 requires refcount_bits=16");
return -ENOTSUP;
}
@@ -2873,7 +2917,7 @@ static int qcow2_downgrade(BlockDriverState *bs, int target_version,
/* clearing autoclear features is trivial */
s->autoclear_features = 0;
- ret = qcow2_expand_zero_clusters(bs, status_cb);
+ ret = qcow2_expand_zero_clusters(bs, status_cb, cb_opaque);
if (ret < 0) {
return ret;
}
@@ -2887,8 +2931,79 @@ static int qcow2_downgrade(BlockDriverState *bs, int target_version,
return 0;
}
+typedef enum Qcow2AmendOperation {
+ /* This is the value Qcow2AmendHelperCBInfo::last_operation will be
+ * statically initialized to so that the helper CB can discern the first
+ * invocation from an operation change */
+ QCOW2_NO_OPERATION = 0,
+
+ QCOW2_CHANGING_REFCOUNT_ORDER,
+ QCOW2_DOWNGRADING,
+} Qcow2AmendOperation;
+
+typedef struct Qcow2AmendHelperCBInfo {
+ /* The code coordinating the amend operations should only modify
+ * these four fields; the rest will be managed by the CB */
+ BlockDriverAmendStatusCB *original_status_cb;
+ void *original_cb_opaque;
+
+ Qcow2AmendOperation current_operation;
+
+ /* Total number of operations to perform (only set once) */
+ int total_operations;
+
+ /* The following fields are managed by the CB */
+
+ /* Number of operations completed */
+ int operations_completed;
+
+ /* Cumulative offset of all completed operations */
+ int64_t offset_completed;
+
+ Qcow2AmendOperation last_operation;
+ int64_t last_work_size;
+} Qcow2AmendHelperCBInfo;
+
+static void qcow2_amend_helper_cb(BlockDriverState *bs,
+ int64_t operation_offset,
+ int64_t operation_work_size, void *opaque)
+{
+ Qcow2AmendHelperCBInfo *info = opaque;
+ int64_t current_work_size;
+ int64_t projected_work_size;
+
+ if (info->current_operation != info->last_operation) {
+ if (info->last_operation != QCOW2_NO_OPERATION) {
+ info->offset_completed += info->last_work_size;
+ info->operations_completed++;
+ }
+
+ info->last_operation = info->current_operation;
+ }
+
+ assert(info->total_operations > 0);
+ assert(info->operations_completed < info->total_operations);
+
+ info->last_work_size = operation_work_size;
+
+ current_work_size = info->offset_completed + operation_work_size;
+
+ /* current_work_size is the total work size for (operations_completed + 1)
+ * operations (which includes this one), so multiply it by the number of
+ * operations not covered and divide it by the number of operations
+ * covered to get a projection for the operations not covered */
+ projected_work_size = current_work_size * (info->total_operations -
+ info->operations_completed - 1)
+ / (info->operations_completed + 1);
+
+ info->original_status_cb(bs, info->offset_completed + operation_offset,
+ current_work_size + projected_work_size,
+ info->original_cb_opaque);
+}
+
static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
- BlockDriverAmendStatusCB *status_cb)
+ BlockDriverAmendStatusCB *status_cb,
+ void *cb_opaque)
{
BDRVQcow2State *s = bs->opaque;
int old_version = s->qcow_version, new_version = old_version;
@@ -2898,8 +3013,10 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
const char *compat = NULL;
uint64_t cluster_size = s->cluster_size;
bool encrypt;
+ int refcount_bits = s->refcount_bits;
int ret;
QemuOptDesc *desc = opts->list->desc;
+ Qcow2AmendHelperCBInfo helper_cb_info;
while (desc && desc->name) {
if (!qemu_opt_find(opts, desc->name)) {
@@ -2917,11 +3034,11 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
} else if (!strcmp(compat, "1.1")) {
new_version = 3;
} else {
- fprintf(stderr, "Unknown compatibility level %s.\n", compat);
+ error_report("Unknown compatibility level %s", compat);
return -EINVAL;
}
} else if (!strcmp(desc->name, BLOCK_OPT_PREALLOC)) {
- fprintf(stderr, "Cannot change preallocation mode.\n");
+ error_report("Cannot change preallocation mode");
return -ENOTSUP;
} else if (!strcmp(desc->name, BLOCK_OPT_SIZE)) {
new_size = qemu_opt_get_size(opts, BLOCK_OPT_SIZE, 0);
@@ -2934,47 +3051,74 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
!!s->cipher);
if (encrypt != !!s->cipher) {
- fprintf(stderr, "Changing the encryption flag is not "
- "supported.\n");
+ error_report("Changing the encryption flag is not supported");
return -ENOTSUP;
}
} else if (!strcmp(desc->name, BLOCK_OPT_CLUSTER_SIZE)) {
cluster_size = qemu_opt_get_size(opts, BLOCK_OPT_CLUSTER_SIZE,
cluster_size);
if (cluster_size != s->cluster_size) {
- fprintf(stderr, "Changing the cluster size is not "
- "supported.\n");
+ error_report("Changing the cluster size is not supported");
return -ENOTSUP;
}
} else if (!strcmp(desc->name, BLOCK_OPT_LAZY_REFCOUNTS)) {
lazy_refcounts = qemu_opt_get_bool(opts, BLOCK_OPT_LAZY_REFCOUNTS,
lazy_refcounts);
} else if (!strcmp(desc->name, BLOCK_OPT_REFCOUNT_BITS)) {
- error_report("Cannot change refcount entry width");
- return -ENOTSUP;
+ refcount_bits = qemu_opt_get_number(opts, BLOCK_OPT_REFCOUNT_BITS,
+ refcount_bits);
+
+ if (refcount_bits <= 0 || refcount_bits > 64 ||
+ !is_power_of_2(refcount_bits))
+ {
+ error_report("Refcount width must be a power of two and may "
+ "not exceed 64 bits");
+ return -EINVAL;
+ }
} else {
- /* if this assertion fails, this probably means a new option was
+ /* if this point is reached, this probably means a new option was
* added without having it covered here */
- assert(false);
+ abort();
}
desc++;
}
- if (new_version != old_version) {
- if (new_version > old_version) {
- /* Upgrade */
- s->qcow_version = new_version;
- ret = qcow2_update_header(bs);
- if (ret < 0) {
- s->qcow_version = old_version;
- return ret;
- }
- } else {
- ret = qcow2_downgrade(bs, new_version, status_cb);
- if (ret < 0) {
- return ret;
- }
+ helper_cb_info = (Qcow2AmendHelperCBInfo){
+ .original_status_cb = status_cb,
+ .original_cb_opaque = cb_opaque,
+ .total_operations = (new_version < old_version)
+ + (s->refcount_bits != refcount_bits)
+ };
+
+ /* Upgrade first (some features may require compat=1.1) */
+ if (new_version > old_version) {
+ s->qcow_version = new_version;
+ ret = qcow2_update_header(bs);
+ if (ret < 0) {
+ s->qcow_version = old_version;
+ return ret;
+ }
+ }
+
+ if (s->refcount_bits != refcount_bits) {
+ int refcount_order = ctz32(refcount_bits);
+ Error *local_error = NULL;
+
+ if (new_version < 3 && refcount_bits != 16) {
+ error_report("Different refcount widths than 16 bits require "
+ "compatibility level 1.1 or above (use compat=1.1 or "
+ "greater)");
+ return -EINVAL;
+ }
+
+ helper_cb_info.current_operation = QCOW2_CHANGING_REFCOUNT_ORDER;
+ ret = qcow2_change_refcount_order(bs, refcount_order,
+ &qcow2_amend_helper_cb,
+ &helper_cb_info, &local_error);
+ if (ret < 0) {
+ error_report_err(local_error);
+ return ret;
}
}
@@ -2989,9 +3133,9 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
if (s->use_lazy_refcounts != lazy_refcounts) {
if (lazy_refcounts) {
- if (s->qcow_version < 3) {
- fprintf(stderr, "Lazy refcounts only supported with compatibility "
- "level 1.1 and above (use compat=1.1 or greater)\n");
+ if (new_version < 3) {
+ error_report("Lazy refcounts only supported with compatibility "
+ "level 1.1 and above (use compat=1.1 or greater)");
return -EINVAL;
}
s->compatible_features |= QCOW2_COMPAT_LAZY_REFCOUNTS;
@@ -3025,6 +3169,16 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
}
}
+ /* Downgrade last (so unsupported features can be removed before) */
+ if (new_version < old_version) {
+ helper_cb_info.current_operation = QCOW2_DOWNGRADING;
+ ret = qcow2_downgrade(bs, new_version, &qcow2_amend_helper_cb,
+ &helper_cb_info);
+ if (ret < 0) {
+ return ret;
+ }
+ }
+
return 0;
}
@@ -3145,6 +3299,7 @@ BlockDriver bdrv_qcow2 = {
.bdrv_reopen_prepare = qcow2_reopen_prepare,
.bdrv_reopen_commit = qcow2_reopen_commit,
.bdrv_reopen_abort = qcow2_reopen_abort,
+ .bdrv_join_options = qcow2_join_options,
.bdrv_create = qcow2_create,
.bdrv_has_zero_init = bdrv_has_zero_init_1,
.bdrv_co_get_block_status = qcow2_co_get_block_status,
diff --git a/block/qcow2.h b/block/qcow2.h
index b8c500b..a063a3c 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -529,6 +529,10 @@ int qcow2_check_metadata_overlap(BlockDriverState *bs, int ign, int64_t offset,
int qcow2_pre_write_overlap_check(BlockDriverState *bs, int ign, int64_t offset,
int64_t size);
+int qcow2_change_refcount_order(BlockDriverState *bs, int refcount_order,
+ BlockDriverAmendStatusCB *status_cb,
+ void *cb_opaque, Error **errp);
+
/* qcow2-cluster.c functions */
int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
bool exact_size);
@@ -553,7 +557,8 @@ int qcow2_discard_clusters(BlockDriverState *bs, uint64_t offset,
int qcow2_zero_clusters(BlockDriverState *bs, uint64_t offset, int nb_sectors);
int qcow2_expand_zero_clusters(BlockDriverState *bs,
- BlockDriverAmendStatusCB *status_cb);
+ BlockDriverAmendStatusCB *status_cb,
+ void *cb_opaque);
/* qcow2-snapshot.c functions */
int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info);
diff --git a/block/quorum.c b/block/quorum.c
index d162459..6793f12 100644
--- a/block/quorum.c
+++ b/block/quorum.c
@@ -997,7 +997,7 @@ static void quorum_attach_aio_context(BlockDriverState *bs,
}
}
-static void quorum_refresh_filename(BlockDriverState *bs)
+static void quorum_refresh_filename(BlockDriverState *bs, QDict *options)
{
BDRVQuorumState *s = bs->opaque;
QDict *opts;
diff --git a/block/raw-posix.c b/block/raw-posix.c
index ffeebe1..076d070 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -500,21 +500,17 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
goto fail;
}
if (!s->use_aio && (bdrv_flags & BDRV_O_NATIVE_AIO)) {
- error_printf("WARNING: aio=native was specified for '%s', but "
- "it requires cache.direct=on, which was not "
- "specified. Falling back to aio=threads.\n"
- " This will become an error condition in "
- "future QEMU versions.\n",
- bs->filename);
+ error_setg(errp, "aio=native was specified, but it requires "
+ "cache.direct=on, which was not specified.");
+ ret = -EINVAL;
+ goto fail;
}
#else
if (bdrv_flags & BDRV_O_NATIVE_AIO) {
- error_printf("WARNING: aio=native was specified for '%s', but "
- "is not supported in this build. Falling back to "
- "aio=threads.\n"
- " This will become an error condition in "
- "future QEMU versions.\n",
- bs->filename);
+ error_setg(errp, "aio=native was specified, but is not supported "
+ "in this build.");
+ ret = -EINVAL;
+ goto fail;
}
#endif /* !defined(CONFIG_LINUX_AIO) */
diff --git a/block/snapshot.c b/block/snapshot.c
index 6e9fa8d..2d86b88 100644
--- a/block/snapshot.c
+++ b/block/snapshot.c
@@ -229,6 +229,8 @@ int bdrv_snapshot_delete(BlockDriverState *bs,
Error **errp)
{
BlockDriver *drv = bs->drv;
+ int ret;
+
if (!drv) {
error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, bdrv_get_device_name(bs));
return -ENOMEDIUM;
@@ -239,18 +241,21 @@ int bdrv_snapshot_delete(BlockDriverState *bs,
}
/* drain all pending i/o before deleting snapshot */
- bdrv_drain(bs);
+ bdrv_drained_begin(bs);
if (drv->bdrv_snapshot_delete) {
- return drv->bdrv_snapshot_delete(bs, snapshot_id, name, errp);
+ ret = drv->bdrv_snapshot_delete(bs, snapshot_id, name, errp);
+ } else if (bs->file) {
+ ret = bdrv_snapshot_delete(bs->file->bs, snapshot_id, name, errp);
+ } else {
+ error_setg(errp, "Block format '%s' used by device '%s' "
+ "does not support internal snapshot deletion",
+ drv->format_name, bdrv_get_device_name(bs));
+ ret = -ENOTSUP;
}
- if (bs->file) {
- return bdrv_snapshot_delete(bs->file->bs, snapshot_id, name, errp);
- }
- error_setg(errp, "Block format '%s' used by device '%s' "
- "does not support internal snapshot deletion",
- drv->format_name, bdrv_get_device_name(bs));
- return -ENOTSUP;
+
+ bdrv_drained_end(bs);
+ return ret;
}
int bdrv_snapshot_delete_by_id_or_name(BlockDriverState *bs,
diff --git a/blockdev.c b/blockdev.c
index 13eaa77..64dbfeb 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -387,16 +387,6 @@ static void extract_common_blockdev_options(QemuOpts *opts, int *bdrv_flags,
}
}
- if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_WB, true)) {
- *bdrv_flags |= BDRV_O_CACHE_WB;
- }
- if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_DIRECT, false)) {
- *bdrv_flags |= BDRV_O_NOCACHE;
- }
- if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_NO_FLUSH, false)) {
- *bdrv_flags |= BDRV_O_NO_FLUSH;
- }
-
if ((aio = qemu_opt_get(opts, "aio")) != NULL) {
if (!strcmp(aio, "native")) {
*bdrv_flags |= BDRV_O_NATIVE_AIO;
@@ -490,7 +480,6 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
QDict *interval_dict = NULL;
QList *interval_list = NULL;
const char *id;
- bool has_driver_specific_opts;
BlockdevDetectZeroesOptions detect_zeroes =
BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF;
const char *throttling_group = NULL;
@@ -514,8 +503,6 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
qdict_del(bs_opts, "id");
}
- has_driver_specific_opts = !!qdict_size(bs_opts);
-
/* extract parameters */
snapshot = qemu_opt_get_bool(opts, "snapshot", 0);
@@ -572,13 +559,11 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
}
if (snapshot) {
- /* always use cache=unsafe with snapshot */
- bdrv_flags &= ~BDRV_O_CACHE_MASK;
- bdrv_flags |= (BDRV_O_SNAPSHOT|BDRV_O_CACHE_WB|BDRV_O_NO_FLUSH);
+ bdrv_flags |= BDRV_O_SNAPSHOT;
}
/* init */
- if ((!file || !*file) && !has_driver_specific_opts) {
+ if ((!file || !*file) && !qdict_size(bs_opts)) {
BlockBackendRootState *blk_rs;
blk = blk_new(qemu_opts_id(opts), errp);
@@ -606,6 +591,20 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
file = NULL;
}
+ /* bdrv_open() defaults to the values in bdrv_flags (for compatibility
+ * with other callers) rather than what we want as the real defaults.
+ * Apply the defaults here instead. */
+ qdict_set_default_str(bs_opts, BDRV_OPT_CACHE_WB, "on");
+ qdict_set_default_str(bs_opts, BDRV_OPT_CACHE_DIRECT, "off");
+ qdict_set_default_str(bs_opts, BDRV_OPT_CACHE_NO_FLUSH, "off");
+
+ if (snapshot) {
+ /* always use cache=unsafe with snapshot */
+ qdict_put(bs_opts, BDRV_OPT_CACHE_WB, qstring_from_str("on"));
+ qdict_put(bs_opts, BDRV_OPT_CACHE_DIRECT, qstring_from_str("off"));
+ qdict_put(bs_opts, BDRV_OPT_CACHE_NO_FLUSH, qstring_from_str("on"));
+ }
+
blk = blk_new_open(qemu_opts_id(opts), file, NULL, bs_opts, bdrv_flags,
errp);
if (!blk) {
@@ -3873,18 +3872,6 @@ QemuOptsList qemu_common_drive_opts = {
.type = QEMU_OPT_STRING,
.help = "discard operation (ignore/off, unmap/on)",
},{
- .name = BDRV_OPT_CACHE_WB,
- .type = QEMU_OPT_BOOL,
- .help = "enables writeback mode for any caches",
- },{
- .name = BDRV_OPT_CACHE_DIRECT,
- .type = QEMU_OPT_BOOL,
- .help = "enables use of O_DIRECT (bypass the host page cache)",
- },{
- .name = BDRV_OPT_CACHE_NO_FLUSH,
- .type = QEMU_OPT_BOOL,
- .help = "ignore any flush requests for the device",
- },{
.name = "aio",
.type = QEMU_OPT_STRING,
.help = "host AIO implementation (threads, native)",
@@ -3992,18 +3979,6 @@ static QemuOptsList qemu_root_bds_opts = {
.type = QEMU_OPT_STRING,
.help = "discard operation (ignore/off, unmap/on)",
},{
- .name = "cache.writeback",
- .type = QEMU_OPT_BOOL,
- .help = "enables writeback mode for any caches",
- },{
- .name = "cache.direct",
- .type = QEMU_OPT_BOOL,
- .help = "enables use of O_DIRECT (bypass the host page cache)",
- },{
- .name = "cache.no-flush",
- .type = QEMU_OPT_BOOL,
- .help = "ignore any flush requests for the device",
- },{
.name = "aio",
.type = QEMU_OPT_STRING,
.help = "host AIO implementation (threads, native)",
diff --git a/include/block/block.h b/include/block/block.h
index d048bbf..db8e096 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -150,6 +150,7 @@ typedef struct BDRVReopenState {
BlockDriverState *bs;
int flags;
QDict *options;
+ QDict *explicit_options;
void *opaque;
} BDRVReopenState;
@@ -197,7 +198,6 @@ int bdrv_create_file(const char *filename, QemuOpts *opts, Error **errp);
BlockDriverState *bdrv_new_root(void);
BlockDriverState *bdrv_new(void);
void bdrv_make_anon(BlockDriverState *bs);
-void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old);
void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top);
void bdrv_replace_in_backing_chain(BlockDriverState *old,
BlockDriverState *new);
@@ -210,7 +210,8 @@ BdrvChild *bdrv_open_child(const char *filename,
const BdrvChildRole *child_role,
bool allow_none, Error **errp);
void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd);
-int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp);
+int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
+ const char *bdref_key, Error **errp);
int bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, Error **errp);
int bdrv_open(BlockDriverState **pbs, const char *filename,
const char *reference, QDict *options, int flags, Error **errp);
@@ -304,9 +305,9 @@ int bdrv_check(BlockDriverState *bs, BdrvCheckResult *res, BdrvCheckMode fix);
* block driver; total_work_size may change during the course of the amendment
* operation */
typedef void BlockDriverAmendStatusCB(BlockDriverState *bs, int64_t offset,
- int64_t total_work_size);
+ int64_t total_work_size, void *opaque);
int bdrv_amend_options(BlockDriverState *bs_new, QemuOpts *opts,
- BlockDriverAmendStatusCB *status_cb);
+ BlockDriverAmendStatusCB *status_cb, void *cb_opaque);
/* external snapshots */
bool bdrv_recurse_is_first_non_filter(BlockDriverState *bs,
diff --git a/include/block/block_int.h b/include/block/block_int.h
index 66e208d..9a1c466 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -121,6 +121,7 @@ struct BlockDriver {
BlockReopenQueue *queue, Error **errp);
void (*bdrv_reopen_commit)(BDRVReopenState *reopen_state);
void (*bdrv_reopen_abort)(BDRVReopenState *reopen_state);
+ void (*bdrv_join_options)(QDict *options, QDict *old_options);
int (*bdrv_open)(BlockDriverState *bs, QDict *options, int flags,
Error **errp);
@@ -135,7 +136,7 @@ struct BlockDriver {
int (*bdrv_set_key)(BlockDriverState *bs, const char *key);
int (*bdrv_make_empty)(BlockDriverState *bs);
- void (*bdrv_refresh_filename)(BlockDriverState *bs);
+ void (*bdrv_refresh_filename)(BlockDriverState *bs, QDict *options);
/* aio */
BlockAIOCB *(*bdrv_aio_readv)(BlockDriverState *bs,
@@ -242,7 +243,8 @@ struct BlockDriver {
BdrvCheckMode fix);
int (*bdrv_amend_options)(BlockDriverState *bs, QemuOpts *opts,
- BlockDriverAmendStatusCB *status_cb);
+ BlockDriverAmendStatusCB *status_cb,
+ void *cb_opaque);
void (*bdrv_debug_event)(BlockDriverState *bs, BlkdebugEvent event);
@@ -342,7 +344,8 @@ typedef struct BdrvAioNotifier {
} BdrvAioNotifier;
struct BdrvChildRole {
- int (*inherit_flags)(int parent_flags);
+ void (*inherit_options)(int *child_flags, QDict *child_options,
+ int parent_flags, QDict *parent_options);
};
extern const BdrvChildRole child_file;
@@ -350,6 +353,7 @@ extern const BdrvChildRole child_format;
struct BdrvChild {
BlockDriverState *bs;
+ char *name;
const BdrvChildRole *role;
QLIST_ENTRY(BdrvChild) next;
QLIST_ENTRY(BdrvChild) next_parent;
@@ -456,6 +460,7 @@ struct BlockDriverState {
QLIST_HEAD(, BdrvChild) parents;
QDict *options;
+ QDict *explicit_options;
BlockdevDetectZeroesOptions detect_zeroes;
/* The error object in use for blocking operations on backing_hd */
diff --git a/qemu-img.c b/qemu-img.c
index 033011c..3d48b4f 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -2040,7 +2040,10 @@ static ImageInfoList *collect_image_info_list(const char *filename,
if (info->has_full_backing_filename) {
filename = info->full_backing_filename;
} else if (info->has_backing_filename) {
- filename = 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) {
fmt = info->backing_filename_format;
@@ -2896,7 +2899,8 @@ out:
}
static void amend_status_cb(BlockDriverState *bs,
- int64_t offset, int64_t total_work_size)
+ int64_t offset, int64_t total_work_size,
+ void *opaque)
{
qemu_progress_print(100.f * offset / total_work_size, 0);
}
@@ -3020,7 +3024,7 @@ static int img_amend(int argc, char **argv)
/* In case the driver does not call amend_status_cb() */
qemu_progress_print(0.f, 0);
- ret = bdrv_amend_options(bs, opts, &amend_status_cb);
+ ret = bdrv_amend_options(bs, opts, &amend_status_cb, NULL);
qemu_progress_print(100.f, 0);
if (ret < 0) {
error_report("Error while amending options: %s", strerror(-ret));
diff --git a/tests/hd-geo-test.c b/tests/hd-geo-test.c
index 00afc20..13b763d 100644
--- a/tests/hd-geo-test.c
+++ b/tests/hd-geo-test.c
@@ -206,13 +206,13 @@ static int setup_ide(int argc, char *argv[], int argv_sz,
{
char *s1, *s2, *s3;
- s1 = g_strdup_printf("-drive id=drive%d,if=%s,format=raw",
+ s1 = g_strdup_printf("-drive id=drive%d,if=%s",
ide_idx, dev ? "none" : "ide");
s2 = dev ? g_strdup("") : g_strdup_printf(",index=%d", ide_idx);
if (img_secs[img_idx] >= 0) {
setup_mbr(img_idx, mbr);
- s3 = g_strdup_printf(",file=%s", img_file_name[img_idx]);
+ s3 = g_strdup_printf(",format=raw,file=%s", img_file_name[img_idx]);
} else {
s3 = g_strdup(",media=cdrom");
}
diff --git a/tests/qemu-iotests/043.out b/tests/qemu-iotests/043.out
index 33f8cc3..b37d2a3 100644
--- a/tests/qemu-iotests/043.out
+++ b/tests/qemu-iotests/043.out
@@ -44,6 +44,7 @@ cluster_size: 65536
"filename": "TEST_DIR/t.IMGFMT",
"cluster-size": 65536,
"format": "IMGFMT",
+ "full-backing-filename": "TEST_DIR/t.IMGFMT.2.base",
"backing-filename": "TEST_DIR/t.IMGFMT.2.base",
"dirty-flag": false
},
@@ -52,6 +53,7 @@ cluster_size: 65536
"filename": "TEST_DIR/t.IMGFMT.2.base",
"cluster-size": 65536,
"format": "IMGFMT",
+ "full-backing-filename": "TEST_DIR/t.IMGFMT.1.base",
"backing-filename": "TEST_DIR/t.IMGFMT.1.base",
"dirty-flag": false
},
diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051
index 17dbf04..75713c2 100755
--- a/tests/qemu-iotests/051
+++ b/tests/qemu-iotests/051
@@ -61,7 +61,7 @@ function do_run_qemu()
function run_qemu()
{
- do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu
+ do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu | _filter_generated_node_ids
}
size=128M
@@ -148,33 +148,49 @@ run_qemu -drive if=ide
run_qemu -drive if=virtio
run_qemu -drive if=scsi
-run_qemu -drive if=none,id=disk -device ide-cd,drive=disk
-run_qemu -drive if=none,id=disk -device lsi53c895a -device scsi-cd,drive=disk
-
-run_qemu -drive if=none,id=disk -device ide-drive,drive=disk
-run_qemu -drive if=none,id=disk -device ide-hd,drive=disk
-run_qemu -drive if=none,id=disk -device lsi53c895a -device scsi-disk,drive=disk
-run_qemu -drive if=none,id=disk -device lsi53c895a -device scsi-hd,drive=disk
+case "$QEMU_DEFAULT_MACHINE" in
+ pc)
+ run_qemu -drive if=none,id=disk -device ide-cd,drive=disk
+ run_qemu -drive if=none,id=disk -device lsi53c895a -device scsi-cd,drive=disk
+ run_qemu -drive if=none,id=disk -device ide-drive,drive=disk
+ run_qemu -drive if=none,id=disk -device ide-hd,drive=disk
+ run_qemu -drive if=none,id=disk -device lsi53c895a -device scsi-disk,drive=disk
+ run_qemu -drive if=none,id=disk -device lsi53c895a -device scsi-hd,drive=disk
+ ;;
+ *)
+ ;;
+esac
echo
echo === Read-only ===
echo
-run_qemu -drive file="$TEST_IMG",if=floppy,readonly=on
-run_qemu -drive file="$TEST_IMG",if=ide,media=cdrom,readonly=on
-run_qemu -drive file="$TEST_IMG",if=scsi,media=cdrom,readonly=on
+case "$QEMU_DEFAULT_MACHINE" in
+ pc)
+ run_qemu -drive file="$TEST_IMG",if=floppy,readonly=on
+ run_qemu -drive file="$TEST_IMG",if=ide,media=cdrom,readonly=on
+ run_qemu -drive file="$TEST_IMG",if=scsi,media=cdrom,readonly=on
+ run_qemu -drive file="$TEST_IMG",if=ide,readonly=on
+ ;;
+ *)
+ ;;
+esac
-run_qemu -drive file="$TEST_IMG",if=ide,readonly=on
run_qemu -drive file="$TEST_IMG",if=virtio,readonly=on
run_qemu -drive file="$TEST_IMG",if=scsi,readonly=on
-run_qemu -drive file="$TEST_IMG",if=none,id=disk,readonly=on -device ide-cd,drive=disk
-run_qemu -drive file="$TEST_IMG",if=none,id=disk,readonly=on -device lsi53c895a -device scsi-cd,drive=disk
-
-run_qemu -drive file="$TEST_IMG",if=none,id=disk,readonly=on -device ide-drive,drive=disk
-run_qemu -drive file="$TEST_IMG",if=none,id=disk,readonly=on -device ide-hd,drive=disk
-run_qemu -drive file="$TEST_IMG",if=none,id=disk,readonly=on -device lsi53c895a -device scsi-disk,drive=disk
-run_qemu -drive file="$TEST_IMG",if=none,id=disk,readonly=on -device lsi53c895a -device scsi-hd,drive=disk
+case "$QEMU_DEFAULT_MACHINE" in
+ pc)
+ run_qemu -drive file="$TEST_IMG",if=none,id=disk,readonly=on -device ide-cd,drive=disk
+ run_qemu -drive file="$TEST_IMG",if=none,id=disk,readonly=on -device lsi53c895a -device scsi-cd,drive=disk
+ run_qemu -drive file="$TEST_IMG",if=none,id=disk,readonly=on -device ide-drive,drive=disk
+ run_qemu -drive file="$TEST_IMG",if=none,id=disk,readonly=on -device ide-hd,drive=disk
+ run_qemu -drive file="$TEST_IMG",if=none,id=disk,readonly=on -device lsi53c895a -device scsi-disk,drive=disk
+ run_qemu -drive file="$TEST_IMG",if=none,id=disk,readonly=on -device lsi53c895a -device scsi-hd,drive=disk
+ ;;
+ *)
+ ;;
+esac
echo
echo === Cache modes ===
@@ -183,12 +199,20 @@ echo
# Cannot use the test image because cache=none might not work on the host FS
# Use cdrom so that we won't get errors about missing media
-run_qemu -drive media=cdrom,cache=none
-run_qemu -drive media=cdrom,cache=directsync
-run_qemu -drive media=cdrom,cache=writeback
-run_qemu -drive media=cdrom,cache=writethrough
-run_qemu -drive media=cdrom,cache=unsafe
-run_qemu -drive media=cdrom,cache=invalid_value
+run_qemu -drive driver=null-co,cache=none
+run_qemu -drive driver=null-co,cache=directsync
+run_qemu -drive driver=null-co,cache=writeback
+run_qemu -drive driver=null-co,cache=writethrough
+run_qemu -drive driver=null-co,cache=unsafe
+run_qemu -drive driver=null-co,cache=invalid_value
+
+# Can't test direct=on here because O_DIRECT might not be supported on this FS
+# Test 142 checks the direct=on cases
+
+for cache in writeback writethrough unsafe invalid_value; do
+ echo -e "info block\ninfo block file\ninfo block backing\ninfo block backing-file" | \
+ run_qemu -drive file="$TEST_IMG",cache=$cache,backing.file.filename="$TEST_IMG.base",backing.cache.no-flush=on,backing.cache.writeback=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file -nodefaults
+done
echo
echo === Specifying the protocol layer ===
@@ -253,26 +277,31 @@ echo
$QEMU_IO -c "write -P 0x11 0 4k" "$TEST_IMG" | _filter_qemu_io
-echo 'qemu-io ide0-hd0 "write -P 0x22 0 4k"' | run_qemu -drive file="$TEST_IMG" -snapshot | _filter_qemu_io
-echo 'qemu-io ide0-hd0 "write -P 0x22 0 4k"' | run_qemu -drive file="$TEST_IMG",snapshot=on | _filter_qemu_io
-echo 'qemu-io ide0-hd0 "write -P 0x22 0 4k"' | run_qemu -drive file.filename="$TEST_IMG",driver=qcow2,snapshot=on | _filter_qemu_io
-echo 'qemu-io ide0-hd0 "write -P 0x22 0 4k"' | run_qemu -drive file.filename="$TEST_IMG",driver=qcow2 -snapshot | _filter_qemu_io
-echo 'qemu-io ide0-hd0 "write -P 0x22 0 4k"' | run_qemu -drive file="file:$TEST_IMG" -snapshot | _filter_qemu_io
-echo 'qemu-io ide0-hd0 "write -P 0x22 0 4k"' | run_qemu -drive file="file:$TEST_IMG",snapshot=on | _filter_qemu_io
+device_id="drive0"
+
+echo "qemu-io $device_id \"write -P 0x22 0 4k\"" | run_qemu -drive file="$TEST_IMG",if=none,id=$device_id -snapshot | _filter_qemu_io
+echo "qemu-io $device_id \"write -P 0x22 0 4k\"" | run_qemu -drive file="$TEST_IMG",snapshot=on,if=none,id=$device_id | _filter_qemu_io
+echo "qemu-io $device_id \"write -P 0x22 0 4k\"" | run_qemu -drive file.filename="$TEST_IMG",driver=qcow2,snapshot=on,if=none,id=$device_id\
+ | _filter_qemu_io
+echo "qemu-io $device_id \"write -P 0x22 0 4k\"" | run_qemu -drive file.filename="$TEST_IMG",driver=qcow2,if=none,id=$device_id -snapshot\
+ | _filter_qemu_io
+echo "qemu-io $device_id \"write -P 0x22 0 4k\"" | run_qemu -drive file="file:$TEST_IMG",if=none,id=$device_id -snapshot | _filter_qemu_io
+echo "qemu-io $device_id \"write -P 0x22 0 4k\"" | run_qemu -drive file="file:$TEST_IMG",snapshot=on,if=none,id=$device_id | _filter_qemu_io
# Opening a read-only file r/w with snapshot=on
chmod u-w "$TEST_IMG"
-echo 'qemu-io ide0-hd0 "write -P 0x22 0 4k"' | run_qemu -drive file="$TEST_IMG" -snapshot | _filter_qemu_io
-echo 'qemu-io ide0-hd0 "write -P 0x22 0 4k"' | run_qemu -drive file="$TEST_IMG",snapshot=on | _filter_qemu_io
+echo "qemu-io $device_id \"write -P 0x22 0 4k\"" | run_qemu -drive file="$TEST_IMG",if=none,id=$device_id -snapshot | _filter_qemu_io
+echo "qemu-io $device_id \"write -P 0x22 0 4k\"" | run_qemu -drive file="$TEST_IMG",snapshot=on,if=none,id=$device_id | _filter_qemu_io
chmod u+w "$TEST_IMG"
$QEMU_IO -c "read -P 0x11 0 4k" "$TEST_IMG" | _filter_qemu_io
-echo 'qemu-io ide0-hd0 "write -P 0x22 0 4k"' | run_qemu -drive file="$TEST_IMG",snapshot=off | _filter_qemu_io
+echo "qemu-io $device_id \"write -P 0x22 0 4k\"" | run_qemu -drive file="$TEST_IMG",snapshot=off,if=none,id=$device_id | _filter_qemu_io
$QEMU_IO -c "read -P 0x22 0 4k" "$TEST_IMG" | _filter_qemu_io
-echo -e 'qemu-io ide0-hd0 "write -P 0x33 0 4k"\ncommit ide0-hd0' | run_qemu -drive file="$TEST_IMG",snapshot=on | _filter_qemu_io
+echo -e "qemu-io $device_id \"write -P 0x33 0 4k\"\ncommit $device_id" | run_qemu -drive file="$TEST_IMG",snapshot=on,if=none,id=$device_id\
+ | _filter_qemu_io
$QEMU_IO -c "read -P 0x33 0 4k" "$TEST_IMG" | _filter_qemu_io
diff --git a/tests/qemu-iotests/051.out b/tests/qemu-iotests/051.out
index 7765aa0..143e3ea 100644
--- a/tests/qemu-iotests/051.out
+++ b/tests/qemu-iotests/051.out
@@ -5,16 +5,16 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/
=== Unknown option ===
Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=
-QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=: Block format 'qcow2' used by device 'ide0-hd0' doesn't support the option 'unknown_opt'
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=: Block format 'qcow2' used by device 'virtio0' doesn't support the option 'unknown_opt'
Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=on
-QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=on: Block format 'qcow2' used by device 'ide0-hd0' doesn't support the option 'unknown_opt'
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=on: Block format 'qcow2' used by device 'virtio0' doesn't support the option 'unknown_opt'
Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=1234
-QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=1234: Block format 'qcow2' used by device 'ide0-hd0' doesn't support the option 'unknown_opt'
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=1234: Block format 'qcow2' used by device 'virtio0' doesn't support the option 'unknown_opt'
Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=foo
-QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=foo: Block format 'qcow2' used by device 'ide0-hd0' doesn't support the option 'unknown_opt'
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=foo: Block format 'qcow2' used by device 'virtio0' doesn't support the option 'unknown_opt'
=== Unknown protocol option ===
@@ -59,7 +59,7 @@ QEMU X.Y.Z monitor - type 'help' for more information
Testing: -drive file=TEST_DIR/t.qcow2,driver=qcow2,backing.file.filename=TEST_DIR/t.qcow2.orig -nodefaults
QEMU X.Y.Z monitor - type 'help' for more information
(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo block
-ide0-hd0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
+virtio0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
Cache mode: writeback
Backing file: TEST_DIR/t.qcow2.orig (chain depth: 1)
(qemu) qququiquit
@@ -109,20 +109,23 @@ QEMU X.Y.Z monitor - type 'help' for more information
Testing: -drive if=floppy
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
+(qemu) Warning: Orphaned drive without device: id=floppy0,file=,if=floppy,bus=0,unit=0
+qququiquit
Testing: -drive if=ide,media=cdrom
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
+(qemu) Warning: Orphaned drive without device: id=ide0-cd0,file=,if=ide,bus=0,unit=0
+qququiquit
Testing: -drive if=scsi,media=cdrom
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
+(qemu) Warning: Orphaned drive without device: id=scsi0-cd0,file=,if=scsi,bus=0,unit=0
+qququiquit
Testing: -drive if=ide
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) QEMU_PROG: Device needs media, but drive is empty
-QEMU_PROG: Initialization of device ide-hd failed: Device initialization failed.
+(qemu) Warning: Orphaned drive without device: id=ide0-hd0,file=,if=ide,bus=0,unit=0
+qququiquit
Testing: -drive if=virtio
QEMU X.Y.Z monitor - type 'help' for more information
@@ -130,113 +133,106 @@ QEMU X.Y.Z monitor - type 'help' for more information
Testing: -drive if=scsi
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) QEMU_PROG: Initialization of device lsi53c895a failed: Device needs media, but drive is empty
+(qemu) Warning: Orphaned drive without device: id=scsi0-hd0,file=,if=scsi,bus=0,unit=0
+qququiquit
-Testing: -drive if=none,id=disk -device ide-cd,drive=disk
-QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
-Testing: -drive if=none,id=disk -device lsi53c895a -device scsi-cd,drive=disk
-QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
-
-Testing: -drive if=none,id=disk -device ide-drive,drive=disk
-QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) QEMU_PROG: -device ide-drive,drive=disk: Device needs media, but drive is empty
-QEMU_PROG: -device ide-drive,drive=disk: Device initialization failed.
-
-Testing: -drive if=none,id=disk -device ide-hd,drive=disk
-QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) QEMU_PROG: -device ide-hd,drive=disk: Device needs media, but drive is empty
-QEMU_PROG: -device ide-hd,drive=disk: Device initialization failed.
+=== Read-only ===
-Testing: -drive if=none,id=disk -device lsi53c895a -device scsi-disk,drive=disk
+Testing: -drive file=TEST_DIR/t.qcow2,if=virtio,readonly=on
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) QEMU_PROG: -device scsi-disk,drive=disk: Device needs media, but drive is empty
+(qemu) qququiquit
-Testing: -drive if=none,id=disk -device lsi53c895a -device scsi-hd,drive=disk
+Testing: -drive file=TEST_DIR/t.qcow2,if=scsi,readonly=on
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) QEMU_PROG: -device scsi-hd,drive=disk: Device needs media, but drive is empty
+(qemu) Warning: Orphaned drive without device: id=scsi0-hd0,file=TEST_DIR/t.qcow2,if=scsi,bus=0,unit=0
+qququiquit
-=== Read-only ===
+=== Cache modes ===
-Testing: -drive file=TEST_DIR/t.qcow2,if=floppy,readonly=on
+Testing: -drive driver=null-co,cache=none
QEMU X.Y.Z monitor - type 'help' for more information
(qemu) qququiquit
-Testing: -drive file=TEST_DIR/t.qcow2,if=ide,media=cdrom,readonly=on
+Testing: -drive driver=null-co,cache=directsync
QEMU X.Y.Z monitor - type 'help' for more information
(qemu) qququiquit
-Testing: -drive file=TEST_DIR/t.qcow2,if=scsi,media=cdrom,readonly=on
+Testing: -drive driver=null-co,cache=writeback
QEMU X.Y.Z monitor - type 'help' for more information
(qemu) qququiquit
-Testing: -drive file=TEST_DIR/t.qcow2,if=ide,readonly=on
-QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) QEMU_PROG: Can't use a read-only drive
-QEMU_PROG: Initialization of device ide-hd failed: Device initialization failed.
-
-Testing: -drive file=TEST_DIR/t.qcow2,if=virtio,readonly=on
+Testing: -drive driver=null-co,cache=writethrough
QEMU X.Y.Z monitor - type 'help' for more information
(qemu) qququiquit
-Testing: -drive file=TEST_DIR/t.qcow2,if=scsi,readonly=on
+Testing: -drive driver=null-co,cache=unsafe
QEMU X.Y.Z monitor - type 'help' for more information
(qemu) qququiquit
-Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device ide-cd,drive=disk
-QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
+Testing: -drive driver=null-co,cache=invalid_value
+QEMU_PROG: -drive driver=null-co,cache=invalid_value: invalid cache option
-Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device lsi53c895a -device scsi-cd,drive=disk
+Testing: -drive file=TEST_DIR/t.qcow2,cache=writeback,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.cache.writeback=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file -nodefaults
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
-
-Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device ide-drive,drive=disk
-QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) QEMU_PROG: -device ide-drive,drive=disk: Can't use a read-only drive
-QEMU_PROG: -device ide-drive,drive=disk: Device initialization failed.
+(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo block
+ide0-hd0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
+ Cache mode: writeback
+ Backing file: TEST_DIR/t.qcow2.base (chain depth: 1)
+(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo blockinfo block info block finfo block fiinfo block filinfo block file
-Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device ide-hd,drive=disk
-QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) QEMU_PROG: -device ide-hd,drive=disk: Can't use a read-only drive
-QEMU_PROG: -device ide-hd,drive=disk: Device initialization failed.
+file: TEST_DIR/t.qcow2 (file)
+ Cache mode: writeback
+(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo blockinfo block info block binfo block bainfo block bacinfo block backinfo block backiinfo block backininfo block backing
+backing: TEST_DIR/t.qcow2.base (qcow2, read-only)
+ Cache mode: writeback, ignore flushes
+(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo blockinfo block info block binfo block bainfo block bacinfo block backinfo block backiinfo block backininfo block backinginfo block backing-info block backing-finfo block backing-fiinfo block backing-filinfo block backing-file
-Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device lsi53c895a -device scsi-disk,drive=disk
-QEMU X.Y.Z monitor - type 'help' for more information
+backing-file: TEST_DIR/t.qcow2.base (file, read-only)
+ Cache mode: writeback, ignore flushes
(qemu) qququiquit
-Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device lsi53c895a -device scsi-hd,drive=disk
+Testing: -drive file=TEST_DIR/t.qcow2,cache=writethrough,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.cache.writeback=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file -nodefaults
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
-
-
-=== Cache modes ===
+(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo block
+ide0-hd0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
+ Cache mode: writethrough
+ Backing file: TEST_DIR/t.qcow2.base (chain depth: 1)
+(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo blockinfo block info block finfo block fiinfo block filinfo block file
-Testing: -drive media=cdrom,cache=none
-QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
+file: TEST_DIR/t.qcow2 (file)
+ Cache mode: writeback
+(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo blockinfo block info block binfo block bainfo block bacinfo block backinfo block backiinfo block backininfo block backing
+backing: TEST_DIR/t.qcow2.base (qcow2, read-only)
+ Cache mode: writeback, ignore flushes
+(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo blockinfo block info block binfo block bainfo block bacinfo block backinfo block backiinfo block backininfo block backinginfo block backing-info block backing-finfo block backing-fiinfo block backing-filinfo block backing-file
-Testing: -drive media=cdrom,cache=directsync
-QEMU X.Y.Z monitor - type 'help' for more information
+backing-file: TEST_DIR/t.qcow2.base (file, read-only)
+ Cache mode: writeback, ignore flushes
(qemu) qququiquit
-Testing: -drive media=cdrom,cache=writeback
+Testing: -drive file=TEST_DIR/t.qcow2,cache=unsafe,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.cache.writeback=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file -nodefaults
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
+(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo block
+ide0-hd0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
+ Cache mode: writeback, ignore flushes
+ Backing file: TEST_DIR/t.qcow2.base (chain depth: 1)
+(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo blockinfo block info block finfo block fiinfo block filinfo block file
-Testing: -drive media=cdrom,cache=writethrough
-QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
+file: TEST_DIR/t.qcow2 (file)
+ Cache mode: writeback, ignore flushes
+(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo blockinfo block info block binfo block bainfo block bacinfo block backinfo block backiinfo block backininfo block backing
+backing: TEST_DIR/t.qcow2.base (qcow2, read-only)
+ Cache mode: writeback, ignore flushes
+(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo blockinfo block info block binfo block bainfo block bacinfo block backinfo block backiinfo block backininfo block backinginfo block backing-info block backing-finfo block backing-fiinfo block backing-filinfo block backing-file
-Testing: -drive media=cdrom,cache=unsafe
-QEMU X.Y.Z monitor - type 'help' for more information
+backing-file: TEST_DIR/t.qcow2.base (file, read-only)
+ Cache mode: writeback, ignore flushes
(qemu) qququiquit
-Testing: -drive media=cdrom,cache=invalid_value
-QEMU_PROG: -drive media=cdrom,cache=invalid_value: invalid cache option
+Testing: -drive file=TEST_DIR/t.qcow2,cache=invalid_value,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.cache.writeback=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file -nodefaults
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,cache=invalid_value,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.cache.writeback=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file: invalid cache option
=== Specifying the protocol layer ===
@@ -342,79 +338,79 @@ QEMU_PROG: -drive file.filename=file:TEST_DIR/t.qcow2: Could not open 'file:TEST
wrote 4096/4096 bytes at offset 0
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-Testing: -drive file=TEST_DIR/t.qcow2 -snapshot
+Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=drive0 -snapshot
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io iqemu-io idqemu-io ideqemu-io ide0qemu-io ide0-qemu-io ide0-hqemu-io ide0-hdqemu-io ide0-hd0qemu-io ide0-hd0 qemu-io ide0-hd0 "qemu-io ide0-hd0 "wqemu-io ide0-hd0 "wrqemu-io ide0-hd0 "wriqemu-io ide0-hd0 "writqemu-io ide0-hd0 "writeqemu-io ide0-hd0 "write qemu-io ide0-hd0 "write -qemu-io ide0-hd0 "write -Pqemu-io ide0-hd0 "write -P qemu-io ide0-hd0 "write -P 0qemu-io ide0-hd0 "write -P 0xqemu-io ide0-hd0 "write -P 0x2qemu-io ide0-hd0 "write -P 0x22qemu-io ide0-hd0 "write -P 0x22 qemu-io ide0-hd0 "write -P 0x22 0qemu-io ide0-hd0 "write -P 0x22 0 qemu-io ide0-hd0 "write -P 0x22 0 4qemu-io ide0-hd0 "write -P 0x22 0 4kqemu-io ide0-hd0 "write -P 0x22 0 4k"
+(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x2qemu-io drive0 "write -P 0x22qemu-io drive0 "write -P 0x22 qemu-io drive0 "write -P 0x22 0qemu-io drive0 "write -P 0x22 0 qemu-io drive0 "write -P 0x22 0 4qemu-io drive0 "write -P 0x22 0 4kqemu-io drive0 "write -P 0x22 0 4k"
wrote 4096/4096 bytes at offset 0
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
(qemu) qququiquit
-Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on
+Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on,if=none,id=drive0
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io iqemu-io idqemu-io ideqemu-io ide0qemu-io ide0-qemu-io ide0-hqemu-io ide0-hdqemu-io ide0-hd0qemu-io ide0-hd0 qemu-io ide0-hd0 "qemu-io ide0-hd0 "wqemu-io ide0-hd0 "wrqemu-io ide0-hd0 "wriqemu-io ide0-hd0 "writqemu-io ide0-hd0 "writeqemu-io ide0-hd0 "write qemu-io ide0-hd0 "write -qemu-io ide0-hd0 "write -Pqemu-io ide0-hd0 "write -P qemu-io ide0-hd0 "write -P 0qemu-io ide0-hd0 "write -P 0xqemu-io ide0-hd0 "write -P 0x2qemu-io ide0-hd0 "write -P 0x22qemu-io ide0-hd0 "write -P 0x22 qemu-io ide0-hd0 "write -P 0x22 0qemu-io ide0-hd0 "write -P 0x22 0 qemu-io ide0-hd0 "write -P 0x22 0 4qemu-io ide0-hd0 "write -P 0x22 0 4kqemu-io ide0-hd0 "write -P 0x22 0 4k"
+(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x2qemu-io drive0 "write -P 0x22qemu-io drive0 "write -P 0x22 qemu-io drive0 "write -P 0x22 0qemu-io drive0 "write -P 0x22 0 qemu-io drive0 "write -P 0x22 0 4qemu-io drive0 "write -P 0x22 0 4kqemu-io drive0 "write -P 0x22 0 4k"
wrote 4096/4096 bytes at offset 0
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
(qemu) qququiquit
-Testing: -drive file.filename=TEST_DIR/t.qcow2,driver=qcow2,snapshot=on
+Testing: -drive file.filename=TEST_DIR/t.qcow2,driver=qcow2,snapshot=on,if=none,id=drive0
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io iqemu-io idqemu-io ideqemu-io ide0qemu-io ide0-qemu-io ide0-hqemu-io ide0-hdqemu-io ide0-hd0qemu-io ide0-hd0 qemu-io ide0-hd0 "qemu-io ide0-hd0 "wqemu-io ide0-hd0 "wrqemu-io ide0-hd0 "wriqemu-io ide0-hd0 "writqemu-io ide0-hd0 "writeqemu-io ide0-hd0 "write qemu-io ide0-hd0 "write -qemu-io ide0-hd0 "write -Pqemu-io ide0-hd0 "write -P qemu-io ide0-hd0 "write -P 0qemu-io ide0-hd0 "write -P 0xqemu-io ide0-hd0 "write -P 0x2qemu-io ide0-hd0 "write -P 0x22qemu-io ide0-hd0 "write -P 0x22 qemu-io ide0-hd0 "write -P 0x22 0qemu-io ide0-hd0 "write -P 0x22 0 qemu-io ide0-hd0 "write -P 0x22 0 4qemu-io ide0-hd0 "write -P 0x22 0 4kqemu-io ide0-hd0 "write -P 0x22 0 4k"
+(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x2qemu-io drive0 "write -P 0x22qemu-io drive0 "write -P 0x22 qemu-io drive0 "write -P 0x22 0qemu-io drive0 "write -P 0x22 0 qemu-io drive0 "write -P 0x22 0 4qemu-io drive0 "write -P 0x22 0 4kqemu-io drive0 "write -P 0x22 0 4k"
wrote 4096/4096 bytes at offset 0
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
(qemu) qququiquit
-Testing: -drive file.filename=TEST_DIR/t.qcow2,driver=qcow2 -snapshot
+Testing: -drive file.filename=TEST_DIR/t.qcow2,driver=qcow2,if=none,id=drive0 -snapshot
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io iqemu-io idqemu-io ideqemu-io ide0qemu-io ide0-qemu-io ide0-hqemu-io ide0-hdqemu-io ide0-hd0qemu-io ide0-hd0 qemu-io ide0-hd0 "qemu-io ide0-hd0 "wqemu-io ide0-hd0 "wrqemu-io ide0-hd0 "wriqemu-io ide0-hd0 "writqemu-io ide0-hd0 "writeqemu-io ide0-hd0 "write qemu-io ide0-hd0 "write -qemu-io ide0-hd0 "write -Pqemu-io ide0-hd0 "write -P qemu-io ide0-hd0 "write -P 0qemu-io ide0-hd0 "write -P 0xqemu-io ide0-hd0 "write -P 0x2qemu-io ide0-hd0 "write -P 0x22qemu-io ide0-hd0 "write -P 0x22 qemu-io ide0-hd0 "write -P 0x22 0qemu-io ide0-hd0 "write -P 0x22 0 qemu-io ide0-hd0 "write -P 0x22 0 4qemu-io ide0-hd0 "write -P 0x22 0 4kqemu-io ide0-hd0 "write -P 0x22 0 4k"
+(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x2qemu-io drive0 "write -P 0x22qemu-io drive0 "write -P 0x22 qemu-io drive0 "write -P 0x22 0qemu-io drive0 "write -P 0x22 0 qemu-io drive0 "write -P 0x22 0 4qemu-io drive0 "write -P 0x22 0 4kqemu-io drive0 "write -P 0x22 0 4k"
wrote 4096/4096 bytes at offset 0
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
(qemu) qququiquit
-Testing: -drive file=file:TEST_DIR/t.qcow2 -snapshot
+Testing: -drive file=file:TEST_DIR/t.qcow2,if=none,id=drive0 -snapshot
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io iqemu-io idqemu-io ideqemu-io ide0qemu-io ide0-qemu-io ide0-hqemu-io ide0-hdqemu-io ide0-hd0qemu-io ide0-hd0 qemu-io ide0-hd0 "qemu-io ide0-hd0 "wqemu-io ide0-hd0 "wrqemu-io ide0-hd0 "wriqemu-io ide0-hd0 "writqemu-io ide0-hd0 "writeqemu-io ide0-hd0 "write qemu-io ide0-hd0 "write -qemu-io ide0-hd0 "write -Pqemu-io ide0-hd0 "write -P qemu-io ide0-hd0 "write -P 0qemu-io ide0-hd0 "write -P 0xqemu-io ide0-hd0 "write -P 0x2qemu-io ide0-hd0 "write -P 0x22qemu-io ide0-hd0 "write -P 0x22 qemu-io ide0-hd0 "write -P 0x22 0qemu-io ide0-hd0 "write -P 0x22 0 qemu-io ide0-hd0 "write -P 0x22 0 4qemu-io ide0-hd0 "write -P 0x22 0 4kqemu-io ide0-hd0 "write -P 0x22 0 4k"
+(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x2qemu-io drive0 "write -P 0x22qemu-io drive0 "write -P 0x22 qemu-io drive0 "write -P 0x22 0qemu-io drive0 "write -P 0x22 0 qemu-io drive0 "write -P 0x22 0 4qemu-io drive0 "write -P 0x22 0 4kqemu-io drive0 "write -P 0x22 0 4k"
wrote 4096/4096 bytes at offset 0
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
(qemu) qququiquit
-Testing: -drive file=file:TEST_DIR/t.qcow2,snapshot=on
+Testing: -drive file=file:TEST_DIR/t.qcow2,snapshot=on,if=none,id=drive0
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io iqemu-io idqemu-io ideqemu-io ide0qemu-io ide0-qemu-io ide0-hqemu-io ide0-hdqemu-io ide0-hd0qemu-io ide0-hd0 qemu-io ide0-hd0 "qemu-io ide0-hd0 "wqemu-io ide0-hd0 "wrqemu-io ide0-hd0 "wriqemu-io ide0-hd0 "writqemu-io ide0-hd0 "writeqemu-io ide0-hd0 "write qemu-io ide0-hd0 "write -qemu-io ide0-hd0 "write -Pqemu-io ide0-hd0 "write -P qemu-io ide0-hd0 "write -P 0qemu-io ide0-hd0 "write -P 0xqemu-io ide0-hd0 "write -P 0x2qemu-io ide0-hd0 "write -P 0x22qemu-io ide0-hd0 "write -P 0x22 qemu-io ide0-hd0 "write -P 0x22 0qemu-io ide0-hd0 "write -P 0x22 0 qemu-io ide0-hd0 "write -P 0x22 0 4qemu-io ide0-hd0 "write -P 0x22 0 4kqemu-io ide0-hd0 "write -P 0x22 0 4k"
+(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x2qemu-io drive0 "write -P 0x22qemu-io drive0 "write -P 0x22 qemu-io drive0 "write -P 0x22 0qemu-io drive0 "write -P 0x22 0 qemu-io drive0 "write -P 0x22 0 4qemu-io drive0 "write -P 0x22 0 4kqemu-io drive0 "write -P 0x22 0 4k"
wrote 4096/4096 bytes at offset 0
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
(qemu) qququiquit
-Testing: -drive file=TEST_DIR/t.qcow2 -snapshot
+Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=drive0 -snapshot
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io iqemu-io idqemu-io ideqemu-io ide0qemu-io ide0-qemu-io ide0-hqemu-io ide0-hdqemu-io ide0-hd0qemu-io ide0-hd0 qemu-io ide0-hd0 "qemu-io ide0-hd0 "wqemu-io ide0-hd0 "wrqemu-io ide0-hd0 "wriqemu-io ide0-hd0 "writqemu-io ide0-hd0 "writeqemu-io ide0-hd0 "write qemu-io ide0-hd0 "write -qemu-io ide0-hd0 "write -Pqemu-io ide0-hd0 "write -P qemu-io ide0-hd0 "write -P 0qemu-io ide0-hd0 "write -P 0xqemu-io ide0-hd0 "write -P 0x2qemu-io ide0-hd0 "write -P 0x22qemu-io ide0-hd0 "write -P 0x22 qemu-io ide0-hd0 "write -P 0x22 0qemu-io ide0-hd0 "write -P 0x22 0 qemu-io ide0-hd0 "write -P 0x22 0 4qemu-io ide0-hd0 "write -P 0x22 0 4kqemu-io ide0-hd0 "write -P 0x22 0 4k"
+(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x2qemu-io drive0 "write -P 0x22qemu-io drive0 "write -P 0x22 qemu-io drive0 "write -P 0x22 0qemu-io drive0 "write -P 0x22 0 qemu-io drive0 "write -P 0x22 0 4qemu-io drive0 "write -P 0x22 0 4kqemu-io drive0 "write -P 0x22 0 4k"
wrote 4096/4096 bytes at offset 0
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
(qemu) qququiquit
-Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on
+Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on,if=none,id=drive0
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io iqemu-io idqemu-io ideqemu-io ide0qemu-io ide0-qemu-io ide0-hqemu-io ide0-hdqemu-io ide0-hd0qemu-io ide0-hd0 qemu-io ide0-hd0 "qemu-io ide0-hd0 "wqemu-io ide0-hd0 "wrqemu-io ide0-hd0 "wriqemu-io ide0-hd0 "writqemu-io ide0-hd0 "writeqemu-io ide0-hd0 "write qemu-io ide0-hd0 "write -qemu-io ide0-hd0 "write -Pqemu-io ide0-hd0 "write -P qemu-io ide0-hd0 "write -P 0qemu-io ide0-hd0 "write -P 0xqemu-io ide0-hd0 "write -P 0x2qemu-io ide0-hd0 "write -P 0x22qemu-io ide0-hd0 "write -P 0x22 qemu-io ide0-hd0 "write -P 0x22 0qemu-io ide0-hd0 "write -P 0x22 0 qemu-io ide0-hd0 "write -P 0x22 0 4qemu-io ide0-hd0 "write -P 0x22 0 4kqemu-io ide0-hd0 "write -P 0x22 0 4k"
+(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x2qemu-io drive0 "write -P 0x22qemu-io drive0 "write -P 0x22 qemu-io drive0 "write -P 0x22 0qemu-io drive0 "write -P 0x22 0 qemu-io drive0 "write -P 0x22 0 4qemu-io drive0 "write -P 0x22 0 4kqemu-io drive0 "write -P 0x22 0 4k"
wrote 4096/4096 bytes at offset 0
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
(qemu) qququiquit
read 4096/4096 bytes at offset 0
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-Testing: -drive file=TEST_DIR/t.qcow2,snapshot=off
+Testing: -drive file=TEST_DIR/t.qcow2,snapshot=off,if=none,id=drive0
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io iqemu-io idqemu-io ideqemu-io ide0qemu-io ide0-qemu-io ide0-hqemu-io ide0-hdqemu-io ide0-hd0qemu-io ide0-hd0 qemu-io ide0-hd0 "qemu-io ide0-hd0 "wqemu-io ide0-hd0 "wrqemu-io ide0-hd0 "wriqemu-io ide0-hd0 "writqemu-io ide0-hd0 "writeqemu-io ide0-hd0 "write qemu-io ide0-hd0 "write -qemu-io ide0-hd0 "write -Pqemu-io ide0-hd0 "write -P qemu-io ide0-hd0 "write -P 0qemu-io ide0-hd0 "write -P 0xqemu-io ide0-hd0 "write -P 0x2qemu-io ide0-hd0 "write -P 0x22qemu-io ide0-hd0 "write -P 0x22 qemu-io ide0-hd0 "write -P 0x22 0qemu-io ide0-hd0 "write -P 0x22 0 qemu-io ide0-hd0 "write -P 0x22 0 4qemu-io ide0-hd0 "write -P 0x22 0 4kqemu-io ide0-hd0 "write -P 0x22 0 4k"
+(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x2qemu-io drive0 "write -P 0x22qemu-io drive0 "write -P 0x22 qemu-io drive0 "write -P 0x22 0qemu-io drive0 "write -P 0x22 0 qemu-io drive0 "write -P 0x22 0 4qemu-io drive0 "write -P 0x22 0 4kqemu-io drive0 "write -P 0x22 0 4k"
wrote 4096/4096 bytes at offset 0
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
(qemu) qququiquit
read 4096/4096 bytes at offset 0
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on
+Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on,if=none,id=drive0
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io iqemu-io idqemu-io ideqemu-io ide0qemu-io ide0-qemu-io ide0-hqemu-io ide0-hdqemu-io ide0-hd0qemu-io ide0-hd0 qemu-io ide0-hd0 "qemu-io ide0-hd0 "wqemu-io ide0-hd0 "wrqemu-io ide0-hd0 "wriqemu-io ide0-hd0 "writqemu-io ide0-hd0 "writeqemu-io ide0-hd0 "write qemu-io ide0-hd0 "write -qemu-io ide0-hd0 "write -Pqemu-io ide0-hd0 "write -P qemu-io ide0-hd0 "write -P 0qemu-io ide0-hd0 "write -P 0xqemu-io ide0-hd0 "write -P 0x3qemu-io ide0-hd0 "write -P 0x33qemu-io ide0-hd0 "write -P 0x33 qemu-io ide0-hd0 "write -P 0x33 0qemu-io ide0-hd0 "write -P 0x33 0 qemu-io ide0-hd0 "write -P 0x33 0 4qemu-io ide0-hd0 "write -P 0x33 0 4kqemu-io ide0-hd0 "write -P 0x33 0 4k"
+(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x3qemu-io drive0 "write -P 0x33qemu-io drive0 "write -P 0x33 qemu-io drive0 "write -P 0x33 0qemu-io drive0 "write -P 0x33 0 qemu-io drive0 "write -P 0x33 0 4qemu-io drive0 "write -P 0x33 0 4kqemu-io drive0 "write -P 0x33 0 4k"
wrote 4096/4096 bytes at offset 0
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-(qemu) ccocomcommcommicommitcommit commit icommit idcommit idecommit ide0commit ide0-commit ide0-hcommit ide0-hdcommit ide0-hd0
+(qemu) ccocomcommcommicommitcommit commit dcommit drcommit dricommit drivcommit drivecommit drive0
(qemu) qququiquit
read 4096/4096 bytes at offset 0
diff --git a/tests/qemu-iotests/051.pc.out b/tests/qemu-iotests/051.pc.out
new file mode 100644
index 0000000..05c925a
--- /dev/null
+++ b/tests/qemu-iotests/051.pc.out
@@ -0,0 +1,482 @@
+QA output created by 051
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base
+
+=== Unknown option ===
+
+Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=: Block format 'qcow2' used by device 'ide0-hd0' doesn't support the option 'unknown_opt'
+
+Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=on
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=on: Block format 'qcow2' used by device 'ide0-hd0' doesn't support the option 'unknown_opt'
+
+Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=1234
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=1234: Block format 'qcow2' used by device 'ide0-hd0' doesn't support the option 'unknown_opt'
+
+Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=foo
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=foo: Block format 'qcow2' used by device 'ide0-hd0' doesn't support the option 'unknown_opt'
+
+
+=== Unknown protocol option ===
+
+Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,file.unknown_opt=
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,file.unknown_opt=: Block protocol 'file' doesn't support the option 'unknown_opt'
+
+Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,file.unknown_opt=on
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,file.unknown_opt=on: Block protocol 'file' doesn't support the option 'unknown_opt'
+
+Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,file.unknown_opt=1234
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,file.unknown_opt=1234: Block protocol 'file' doesn't support the option 'unknown_opt'
+
+Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,file.unknown_opt=foo
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,file.unknown_opt=foo: Block protocol 'file' doesn't support the option 'unknown_opt'
+
+
+=== Invalid format ===
+
+Testing: -drive file=TEST_DIR/t.qcow2,format=foo
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=foo: Unknown driver 'foo'
+
+Testing: -drive file=TEST_DIR/t.qcow2,driver=foo
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,driver=foo: Unknown driver 'foo'
+
+Testing: -drive file=TEST_DIR/t.qcow2,driver=raw,format=qcow2
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,driver=raw,format=qcow2: Cannot specify both 'driver' and 'format'
+
+Testing: -drive file=TEST_DIR/t.qcow2,driver=qcow2,format=qcow2
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,driver=qcow2,format=qcow2: Cannot specify both 'driver' and 'format'
+
+
+=== Device without drive ===
+
+Testing: -device virtio-scsi-pci -device scsi-hd
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) QEMU_PROG: -device scsi-hd: drive property not set
+
+
+=== Overriding backing file ===
+
+Testing: -drive file=TEST_DIR/t.qcow2,driver=qcow2,backing.file.filename=TEST_DIR/t.qcow2.orig -nodefaults
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo block
+ide0-hd0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
+ Cache mode: writeback
+ Backing file: TEST_DIR/t.qcow2.orig (chain depth: 1)
+(qemu) qququiquit
+
+Testing: -drive file=TEST_DIR/t.qcow2,driver=raw,backing.file.filename=TEST_DIR/t.qcow2.orig
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,driver=raw,backing.file.filename=TEST_DIR/t.qcow2.orig: Driver doesn't support backing files
+
+Testing: -drive file=TEST_DIR/t.qcow2,file.backing.driver=file,file.backing.filename=TEST_DIR/t.qcow2.orig
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,file.backing.driver=file,file.backing.filename=TEST_DIR/t.qcow2.orig: Driver doesn't support backing files
+
+Testing: -drive file=TEST_DIR/t.qcow2,file.backing.driver=qcow2,file.backing.file.filename=TEST_DIR/t.qcow2.orig
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,file.backing.driver=qcow2,file.backing.file.filename=TEST_DIR/t.qcow2.orig: Driver doesn't support backing files
+
+
+=== Enable and disable lazy refcounting on the command line, plus some invalid values ===
+
+Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=on
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qququiquit
+
+Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=off
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qququiquit
+
+Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=: Parameter 'lazy-refcounts' expects 'on' or 'off'
+
+Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=42
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=42: Parameter 'lazy-refcounts' expects 'on' or 'off'
+
+Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=foo
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=foo: Parameter 'lazy-refcounts' expects 'on' or 'off'
+
+
+=== With version 2 images enabling lazy refcounts must fail ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
+Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=on
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=on: Lazy refcounts require a qcow2 image with at least qemu 1.1 compatibility level
+
+Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=off
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qququiquit
+
+
+=== No medium ===
+
+Testing: -drive if=floppy
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qququiquit
+
+Testing: -drive if=ide,media=cdrom
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qququiquit
+
+Testing: -drive if=scsi,media=cdrom
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qququiquit
+
+Testing: -drive if=ide
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) QEMU_PROG: Device needs media, but drive is empty
+QEMU_PROG: Initialization of device ide-hd failed: Device initialization failed.
+
+Testing: -drive if=virtio
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) QEMU_PROG: -drive if=virtio: Device needs media, but drive is empty
+
+Testing: -drive if=scsi
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) QEMU_PROG: Initialization of device lsi53c895a failed: Device needs media, but drive is empty
+
+Testing: -drive if=none,id=disk -device ide-cd,drive=disk
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qququiquit
+
+Testing: -drive if=none,id=disk -device lsi53c895a -device scsi-cd,drive=disk
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qququiquit
+
+Testing: -drive if=none,id=disk -device ide-drive,drive=disk
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) QEMU_PROG: -device ide-drive,drive=disk: Device needs media, but drive is empty
+QEMU_PROG: -device ide-drive,drive=disk: Device initialization failed.
+
+Testing: -drive if=none,id=disk -device ide-hd,drive=disk
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) QEMU_PROG: -device ide-hd,drive=disk: Device needs media, but drive is empty
+QEMU_PROG: -device ide-hd,drive=disk: Device initialization failed.
+
+Testing: -drive if=none,id=disk -device lsi53c895a -device scsi-disk,drive=disk
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) QEMU_PROG: -device scsi-disk,drive=disk: Device needs media, but drive is empty
+
+Testing: -drive if=none,id=disk -device lsi53c895a -device scsi-hd,drive=disk
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) QEMU_PROG: -device scsi-hd,drive=disk: Device needs media, but drive is empty
+
+
+=== Read-only ===
+
+Testing: -drive file=TEST_DIR/t.qcow2,if=floppy,readonly=on
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qququiquit
+
+Testing: -drive file=TEST_DIR/t.qcow2,if=ide,media=cdrom,readonly=on
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qququiquit
+
+Testing: -drive file=TEST_DIR/t.qcow2,if=scsi,media=cdrom,readonly=on
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qququiquit
+
+Testing: -drive file=TEST_DIR/t.qcow2,if=ide,readonly=on
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) QEMU_PROG: Can't use a read-only drive
+QEMU_PROG: Initialization of device ide-hd failed: Device initialization failed.
+
+Testing: -drive file=TEST_DIR/t.qcow2,if=virtio,readonly=on
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qququiquit
+
+Testing: -drive file=TEST_DIR/t.qcow2,if=scsi,readonly=on
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qququiquit
+
+Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device ide-cd,drive=disk
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qququiquit
+
+Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device lsi53c895a -device scsi-cd,drive=disk
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qququiquit
+
+Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device ide-drive,drive=disk
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) QEMU_PROG: -device ide-drive,drive=disk: Can't use a read-only drive
+QEMU_PROG: -device ide-drive,drive=disk: Device initialization failed.
+
+Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device ide-hd,drive=disk
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) QEMU_PROG: -device ide-hd,drive=disk: Can't use a read-only drive
+QEMU_PROG: -device ide-hd,drive=disk: Device initialization failed.
+
+Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device lsi53c895a -device scsi-disk,drive=disk
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qququiquit
+
+Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device lsi53c895a -device scsi-hd,drive=disk
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qququiquit
+
+
+=== Cache modes ===
+
+Testing: -drive driver=null-co,cache=none
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qququiquit
+
+Testing: -drive driver=null-co,cache=directsync
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qququiquit
+
+Testing: -drive driver=null-co,cache=writeback
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qququiquit
+
+Testing: -drive driver=null-co,cache=writethrough
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qququiquit
+
+Testing: -drive driver=null-co,cache=unsafe
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qququiquit
+
+Testing: -drive driver=null-co,cache=invalid_value
+QEMU_PROG: -drive driver=null-co,cache=invalid_value: invalid cache option
+
+Testing: -drive file=TEST_DIR/t.qcow2,cache=writeback,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.cache.writeback=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file -nodefaults
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo block
+ide0-hd0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
+ Cache mode: writeback
+ Backing file: TEST_DIR/t.qcow2.base (chain depth: 1)
+(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo blockinfo block info block finfo block fiinfo block filinfo block file
+
+file: TEST_DIR/t.qcow2 (file)
+ Cache mode: writeback
+(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo blockinfo block info block binfo block bainfo block bacinfo block backinfo block backiinfo block backininfo block backing
+backing: TEST_DIR/t.qcow2.base (qcow2, read-only)
+ Cache mode: writeback, ignore flushes
+(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo blockinfo block info block binfo block bainfo block bacinfo block backinfo block backiinfo block backininfo block backinginfo block backing-info block backing-finfo block backing-fiinfo block backing-filinfo block backing-file
+
+backing-file: TEST_DIR/t.qcow2.base (file, read-only)
+ Cache mode: writeback, ignore flushes
+(qemu) qququiquit
+
+Testing: -drive file=TEST_DIR/t.qcow2,cache=writethrough,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.cache.writeback=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file -nodefaults
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo block
+ide0-hd0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
+ Cache mode: writethrough
+ Backing file: TEST_DIR/t.qcow2.base (chain depth: 1)
+(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo blockinfo block info block finfo block fiinfo block filinfo block file
+
+file: TEST_DIR/t.qcow2 (file)
+ Cache mode: writeback
+(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo blockinfo block info block binfo block bainfo block bacinfo block backinfo block backiinfo block backininfo block backing
+backing: TEST_DIR/t.qcow2.base (qcow2, read-only)
+ Cache mode: writeback, ignore flushes
+(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo blockinfo block info block binfo block bainfo block bacinfo block backinfo block backiinfo block backininfo block backinginfo block backing-info block backing-finfo block backing-fiinfo block backing-filinfo block backing-file
+
+backing-file: TEST_DIR/t.qcow2.base (file, read-only)
+ Cache mode: writeback, ignore flushes
+(qemu) qququiquit
+
+Testing: -drive file=TEST_DIR/t.qcow2,cache=unsafe,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.cache.writeback=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file -nodefaults
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo block
+ide0-hd0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
+ Cache mode: writeback, ignore flushes
+ Backing file: TEST_DIR/t.qcow2.base (chain depth: 1)
+(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo blockinfo block info block finfo block fiinfo block filinfo block file
+
+file: TEST_DIR/t.qcow2 (file)
+ Cache mode: writeback, ignore flushes
+(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo blockinfo block info block binfo block bainfo block bacinfo block backinfo block backiinfo block backininfo block backing
+backing: TEST_DIR/t.qcow2.base (qcow2, read-only)
+ Cache mode: writeback, ignore flushes
+(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo blockinfo block info block binfo block bainfo block bacinfo block backinfo block backiinfo block backininfo block backinginfo block backing-info block backing-finfo block backing-fiinfo block backing-filinfo block backing-file
+
+backing-file: TEST_DIR/t.qcow2.base (file, read-only)
+ Cache mode: writeback, ignore flushes
+(qemu) qququiquit
+
+Testing: -drive file=TEST_DIR/t.qcow2,cache=invalid_value,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.cache.writeback=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file -nodefaults
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,cache=invalid_value,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.cache.writeback=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file: invalid cache option
+
+
+=== Specifying the protocol layer ===
+
+Testing: -drive file=TEST_DIR/t.qcow2,file.driver=file
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qququiquit
+
+
+=== Leaving out required options ===
+
+Testing: -drive driver=file
+QEMU_PROG: -drive driver=file: The 'file' block driver requires a file name
+
+Testing: -drive driver=nbd
+QEMU_PROG: -drive driver=nbd: one of path and host must be specified.
+
+Testing: -drive driver=raw
+QEMU_PROG: -drive driver=raw: Can't use 'raw' as a block driver for the protocol level
+
+Testing: -drive file.driver=file
+QEMU_PROG: -drive file.driver=file: The 'file' block driver requires a file name
+
+Testing: -drive file.driver=nbd
+QEMU_PROG: -drive file.driver=nbd: one of path and host must be specified.
+
+Testing: -drive file.driver=raw
+QEMU_PROG: -drive file.driver=raw: Can't use 'raw' as a block driver for the protocol level
+
+Testing: -drive foo=bar
+QEMU_PROG: -drive foo=bar: Must specify either driver or file
+
+
+=== Specifying both an option and its legacy alias ===
+
+Testing: -drive file=TEST_DIR/t.qcow2,iops=1234,throttling.iops-total=5678
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,iops=1234,throttling.iops-total=5678: 'throttling.iops-total' and its alias 'iops' can't be used at the same time
+
+Testing: -drive file=TEST_DIR/t.qcow2,iops_rd=1234,throttling.iops-read=5678
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,iops_rd=1234,throttling.iops-read=5678: 'throttling.iops-read' and its alias 'iops_rd' can't be used at the same time
+
+Testing: -drive file=TEST_DIR/t.qcow2,iops_wr=1234,throttling.iops-write=5678
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,iops_wr=1234,throttling.iops-write=5678: 'throttling.iops-write' and its alias 'iops_wr' can't be used at the same time
+
+Testing: -drive file=TEST_DIR/t.qcow2,bps=1234,throttling.bps-total=5678
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,bps=1234,throttling.bps-total=5678: 'throttling.bps-total' and its alias 'bps' can't be used at the same time
+
+Testing: -drive file=TEST_DIR/t.qcow2,bps_rd=1234,throttling.bps-read=5678
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,bps_rd=1234,throttling.bps-read=5678: 'throttling.bps-read' and its alias 'bps_rd' can't be used at the same time
+
+Testing: -drive file=TEST_DIR/t.qcow2,bps_wr=1234,throttling.bps-write=5678
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,bps_wr=1234,throttling.bps-write=5678: 'throttling.bps-write' and its alias 'bps_wr' can't be used at the same time
+
+Testing: -drive file=TEST_DIR/t.qcow2,iops_max=1234,throttling.iops-total-max=5678
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,iops_max=1234,throttling.iops-total-max=5678: 'throttling.iops-total-max' and its alias 'iops_max' can't be used at the same time
+
+Testing: -drive file=TEST_DIR/t.qcow2,iops_rd_max=1234,throttling.iops-read-max=5678
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,iops_rd_max=1234,throttling.iops-read-max=5678: 'throttling.iops-read-max' and its alias 'iops_rd_max' can't be used at the same time
+
+Testing: -drive file=TEST_DIR/t.qcow2,iops_wr_max=1234,throttling.iops-write-max=5678
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,iops_wr_max=1234,throttling.iops-write-max=5678: 'throttling.iops-write-max' and its alias 'iops_wr_max' can't be used at the same time
+
+Testing: -drive file=TEST_DIR/t.qcow2,bps_max=1234,throttling.bps-total-max=5678
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,bps_max=1234,throttling.bps-total-max=5678: 'throttling.bps-total-max' and its alias 'bps_max' can't be used at the same time
+
+Testing: -drive file=TEST_DIR/t.qcow2,bps_rd_max=1234,throttling.bps-read-max=5678
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,bps_rd_max=1234,throttling.bps-read-max=5678: 'throttling.bps-read-max' and its alias 'bps_rd_max' can't be used at the same time
+
+Testing: -drive file=TEST_DIR/t.qcow2,bps_wr_max=1234,throttling.bps-write-max=5678
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,bps_wr_max=1234,throttling.bps-write-max=5678: 'throttling.bps-write-max' and its alias 'bps_wr_max' can't be used at the same time
+
+Testing: -drive file=TEST_DIR/t.qcow2,iops_size=1234,throttling.iops-size=5678
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,iops_size=1234,throttling.iops-size=5678: 'throttling.iops-size' and its alias 'iops_size' can't be used at the same time
+
+Testing: -drive file=TEST_DIR/t.qcow2,readonly=on,read-only=off
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,readonly=on,read-only=off: 'read-only' and its alias 'readonly' can't be used at the same time
+
+
+=== Parsing protocol from file name ===
+
+Testing: -hda foo:bar
+QEMU_PROG: -hda foo:bar: Unknown protocol 'foo'
+
+Testing: -drive file=foo:bar
+QEMU_PROG: -drive file=foo:bar: Unknown protocol 'foo'
+
+Testing: -drive file.filename=foo:bar
+QEMU_PROG: -drive file.filename=foo:bar: Could not open 'foo:bar': No such file or directory
+
+Testing: -hda file:TEST_DIR/t.qcow2
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qququiquit
+
+Testing: -drive file=file:TEST_DIR/t.qcow2
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qququiquit
+
+Testing: -drive file.filename=file:TEST_DIR/t.qcow2
+QEMU_PROG: -drive file.filename=file:TEST_DIR/t.qcow2: Could not open 'file:TEST_DIR/t.qcow2': No such file or directory
+
+
+=== Snapshot mode ===
+
+wrote 4096/4096 bytes at offset 0
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=drive0 -snapshot
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x2qemu-io drive0 "write -P 0x22qemu-io drive0 "write -P 0x22 qemu-io drive0 "write -P 0x22 0qemu-io drive0 "write -P 0x22 0 qemu-io drive0 "write -P 0x22 0 4qemu-io drive0 "write -P 0x22 0 4kqemu-io drive0 "write -P 0x22 0 4k"
+wrote 4096/4096 bytes at offset 0
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+(qemu) qququiquit
+
+Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on,if=none,id=drive0
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x2qemu-io drive0 "write -P 0x22qemu-io drive0 "write -P 0x22 qemu-io drive0 "write -P 0x22 0qemu-io drive0 "write -P 0x22 0 qemu-io drive0 "write -P 0x22 0 4qemu-io drive0 "write -P 0x22 0 4kqemu-io drive0 "write -P 0x22 0 4k"
+wrote 4096/4096 bytes at offset 0
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+(qemu) qququiquit
+
+Testing: -drive file.filename=TEST_DIR/t.qcow2,driver=qcow2,snapshot=on,if=none,id=drive0
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x2qemu-io drive0 "write -P 0x22qemu-io drive0 "write -P 0x22 qemu-io drive0 "write -P 0x22 0qemu-io drive0 "write -P 0x22 0 qemu-io drive0 "write -P 0x22 0 4qemu-io drive0 "write -P 0x22 0 4kqemu-io drive0 "write -P 0x22 0 4k"
+wrote 4096/4096 bytes at offset 0
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+(qemu) qququiquit
+
+Testing: -drive file.filename=TEST_DIR/t.qcow2,driver=qcow2,if=none,id=drive0 -snapshot
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x2qemu-io drive0 "write -P 0x22qemu-io drive0 "write -P 0x22 qemu-io drive0 "write -P 0x22 0qemu-io drive0 "write -P 0x22 0 qemu-io drive0 "write -P 0x22 0 4qemu-io drive0 "write -P 0x22 0 4kqemu-io drive0 "write -P 0x22 0 4k"
+wrote 4096/4096 bytes at offset 0
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+(qemu) qququiquit
+
+Testing: -drive file=file:TEST_DIR/t.qcow2,if=none,id=drive0 -snapshot
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x2qemu-io drive0 "write -P 0x22qemu-io drive0 "write -P 0x22 qemu-io drive0 "write -P 0x22 0qemu-io drive0 "write -P 0x22 0 qemu-io drive0 "write -P 0x22 0 4qemu-io drive0 "write -P 0x22 0 4kqemu-io drive0 "write -P 0x22 0 4k"
+wrote 4096/4096 bytes at offset 0
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+(qemu) qququiquit
+
+Testing: -drive file=file:TEST_DIR/t.qcow2,snapshot=on,if=none,id=drive0
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x2qemu-io drive0 "write -P 0x22qemu-io drive0 "write -P 0x22 qemu-io drive0 "write -P 0x22 0qemu-io drive0 "write -P 0x22 0 qemu-io drive0 "write -P 0x22 0 4qemu-io drive0 "write -P 0x22 0 4kqemu-io drive0 "write -P 0x22 0 4k"
+wrote 4096/4096 bytes at offset 0
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+(qemu) qququiquit
+
+Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=drive0 -snapshot
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x2qemu-io drive0 "write -P 0x22qemu-io drive0 "write -P 0x22 qemu-io drive0 "write -P 0x22 0qemu-io drive0 "write -P 0x22 0 qemu-io drive0 "write -P 0x22 0 4qemu-io drive0 "write -P 0x22 0 4kqemu-io drive0 "write -P 0x22 0 4k"
+wrote 4096/4096 bytes at offset 0
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+(qemu) qququiquit
+
+Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on,if=none,id=drive0
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x2qemu-io drive0 "write -P 0x22qemu-io drive0 "write -P 0x22 qemu-io drive0 "write -P 0x22 0qemu-io drive0 "write -P 0x22 0 qemu-io drive0 "write -P 0x22 0 4qemu-io drive0 "write -P 0x22 0 4kqemu-io drive0 "write -P 0x22 0 4k"
+wrote 4096/4096 bytes at offset 0
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+(qemu) qququiquit
+
+read 4096/4096 bytes at offset 0
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+Testing: -drive file=TEST_DIR/t.qcow2,snapshot=off,if=none,id=drive0
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x2qemu-io drive0 "write -P 0x22qemu-io drive0 "write -P 0x22 qemu-io drive0 "write -P 0x22 0qemu-io drive0 "write -P 0x22 0 qemu-io drive0 "write -P 0x22 0 4qemu-io drive0 "write -P 0x22 0 4kqemu-io drive0 "write -P 0x22 0 4k"
+wrote 4096/4096 bytes at offset 0
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+(qemu) qququiquit
+
+read 4096/4096 bytes at offset 0
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on,if=none,id=drive0
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x3qemu-io drive0 "write -P 0x33qemu-io drive0 "write -P 0x33 qemu-io drive0 "write -P 0x33 0qemu-io drive0 "write -P 0x33 0 qemu-io drive0 "write -P 0x33 0 4qemu-io drive0 "write -P 0x33 0 4kqemu-io drive0 "write -P 0x33 0 4k"
+wrote 4096/4096 bytes at offset 0
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+(qemu) ccocomcommcommicommitcommit commit dcommit drcommit dricommit drivcommit drivecommit drive0
+(qemu) qququiquit
+
+read 4096/4096 bytes at offset 0
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+*** done
diff --git a/tests/qemu-iotests/061.out b/tests/qemu-iotests/061.out
index f2598a8..57aae28 100644
--- a/tests/qemu-iotests/061.out
+++ b/tests/qemu-iotests/061.out
@@ -291,18 +291,18 @@ No errors were found on the image.
=== Testing invalid configurations ===
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
-Lazy refcounts only supported with compatibility level 1.1 and above (use compat=1.1 or greater)
+qemu-img: Lazy refcounts only supported with compatibility level 1.1 and above (use compat=1.1 or greater)
qemu-img: Error while amending options: Invalid argument
-Lazy refcounts only supported with compatibility level 1.1 and above (use compat=1.1 or greater)
+qemu-img: Lazy refcounts only supported with compatibility level 1.1 and above (use compat=1.1 or greater)
qemu-img: Error while amending options: Invalid argument
-Unknown compatibility level 0.42.
+qemu-img: Unknown compatibility level 0.42
qemu-img: Error while amending options: Invalid argument
qemu-img: Invalid parameter 'foo'
-Changing the cluster size is not supported.
+qemu-img: Changing the cluster size is not supported
qemu-img: Error while amending options: Operation not supported
-Changing the encryption flag is not supported.
+qemu-img: Changing the encryption flag is not supported
qemu-img: Error while amending options: Operation not supported
-Cannot change preallocation mode.
+qemu-img: Cannot change preallocation mode
qemu-img: Error while amending options: Operation not supported
=== Testing correct handling of unset value ===
@@ -310,7 +310,7 @@ qemu-img: Error while amending options: Operation not supported
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
Should work:
Should not work:
-Changing the cluster size is not supported.
+qemu-img: Changing the cluster size is not supported
qemu-img: Error while amending options: Operation not supported
=== Testing zero expansion on inactive clusters ===
diff --git a/tests/qemu-iotests/068 b/tests/qemu-iotests/068
index b72e555..58d1d80 100755
--- a/tests/qemu-iotests/068
+++ b/tests/qemu-iotests/068
@@ -50,13 +50,23 @@ echo
echo "=== Saving and reloading a VM state to/from a qcow2 image ==="
echo
_make_test_img $IMG_SIZE
+
+case "$QEMU_DEFAULT_MACHINE" in
+ s390-ccw-virtio)
+ platform_parm="-no-shutdown -machine accel=kvm"
+ ;;
+ *)
+ platform_parm=""
+ ;;
+esac
+
# Give qemu some time to boot before saving the VM state
bash -c 'sleep 1; echo -e "savevm 0\nquit"' |\
- $QEMU -nographic -monitor stdio -serial none -hda "$TEST_IMG" |\
+ $QEMU $platform_parm -nographic -monitor stdio -serial none -hda "$TEST_IMG" |\
_filter_qemu
# Now try to continue from that VM state (this should just work)
echo quit |\
- $QEMU -nographic -monitor stdio -serial none -hda "$TEST_IMG" -loadvm 0 |\
+ $QEMU $platform_parm -nographic -monitor stdio -serial none -hda "$TEST_IMG" -loadvm 0 |\
_filter_qemu
# success, all done
diff --git a/tests/qemu-iotests/094 b/tests/qemu-iotests/094
index 27a2be2..57a68f8 100755
--- a/tests/qemu-iotests/094
+++ b/tests/qemu-iotests/094
@@ -1,6 +1,6 @@
#!/bin/bash
#
-# Test case for drive-mirror to NBD (especially bdrv_swap() on NBD BDS)
+# Test case for drive-mirror to NBD
#
# Copyright (C) 2015 Red Hat, Inc.
#
@@ -50,8 +50,10 @@ _send_qemu_cmd $QEMU_HANDLE \
"{'execute': 'qmp_capabilities'}" \
'return'
-# 'format': 'nbd' is not actually "correct", but this is probably the only way
-# to test bdrv_swap() on an NBD BDS
+# 'format': 'nbd' is not actually "correct", but this was the only way to
+# test the bug fixed in commit f53a829. Though the bug's related code
+# bdrv_swap() was replaced later, let's make sure we don't fall in the same
+# pit again.
_send_qemu_cmd $QEMU_HANDLE \
"{'execute': 'drive-mirror',
'arguments': {'device': 'src',
diff --git a/tests/qemu-iotests/110.out b/tests/qemu-iotests/110.out
index 0270980..b3584ff 100644
--- a/tests/qemu-iotests/110.out
+++ b/tests/qemu-iotests/110.out
@@ -11,7 +11,10 @@ backing file: t.IMGFMT.base (actual path: TEST_DIR/t.IMGFMT.base)
=== Non-reconstructable filename ===
-qemu-img: Cannot use relative backing file names for 'json:{"driver": "IMGFMT", "file": {"set-state.0.event": "read_aio", "image": {"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}, "driver": "blkdebug", "set-state.0.new_state": 42}}'
+image: json:{"driver": "IMGFMT", "file": {"set-state.0.event": "read_aio", "image": {"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}, "driver": "blkdebug", "set-state.0.new_state": 42}}
+file format: IMGFMT
+virtual size: 64M (67108864 bytes)
+backing file: t.IMGFMT.base (cannot determine actual path)
=== Backing name is always relative to the backed image ===
diff --git a/tests/qemu-iotests/112 b/tests/qemu-iotests/112
index 3f054a3..34ba06a 100755
--- a/tests/qemu-iotests/112
+++ b/tests/qemu-iotests/112
@@ -180,6 +180,115 @@ $QEMU_IMG snapshot -c foo "$TEST_IMG"
# leaked (refcount=UINT64_MAX reference=1)
_check_test_img
+echo
+echo '=== Amend from refcount_bits=16 to refcount_bits=1 ==='
+echo
+
+_make_test_img 64M
+print_refcount_bits
+
+$QEMU_IO -c 'write 16M 32M' "$TEST_IMG" | _filter_qemu_io
+$QEMU_IMG amend -o refcount_bits=1 "$TEST_IMG"
+_check_test_img
+print_refcount_bits
+
+echo
+echo '=== Amend from refcount_bits=1 to refcount_bits=64 ==='
+echo
+
+$QEMU_IMG amend -o refcount_bits=64 "$TEST_IMG"
+_check_test_img
+print_refcount_bits
+
+echo
+echo '=== Amend to compat=0.10 ==='
+echo
+
+# Should not work because refcount_bits needs to be 16 for compat=0.10
+$QEMU_IMG amend -o compat=0.10 "$TEST_IMG"
+print_refcount_bits
+# Should work
+$QEMU_IMG amend -o compat=0.10,refcount_bits=16 "$TEST_IMG"
+_check_test_img
+print_refcount_bits
+
+# Get back to compat=1.1 and refcount_bits=16
+$QEMU_IMG amend -o compat=1.1 "$TEST_IMG"
+print_refcount_bits
+# Should not work
+$QEMU_IMG amend -o refcount_bits=32,compat=0.10 "$TEST_IMG"
+print_refcount_bits
+
+echo
+echo '=== Amend with snapshot ==='
+echo
+
+$QEMU_IMG snapshot -c foo "$TEST_IMG"
+# Just to have different refcounts across the image
+$QEMU_IO -c 'write 0 16M' "$TEST_IMG" | _filter_qemu_io
+
+# Should not work (may work in the future by first decreasing all refcounts so
+# they fit into the target range by copying them)
+$QEMU_IMG amend -o refcount_bits=1 "$TEST_IMG"
+_check_test_img
+print_refcount_bits
+
+# Should work
+$QEMU_IMG amend -o refcount_bits=2 "$TEST_IMG"
+_check_test_img
+print_refcount_bits
+
+echo
+echo '=== Testing too many references for check ==='
+echo
+
+IMGOPTS="$IMGOPTS,refcount_bits=1" _make_test_img 64M
+print_refcount_bits
+
+# This cluster should be created at 0x50000
+$QEMU_IO -c 'write 0 64k' "$TEST_IMG" | _filter_qemu_io
+# Now make the second L2 entry (the L2 table should be at 0x40000) point to that
+# cluster, so we have two references
+poke_file "$TEST_IMG" $((0x40008)) "\x80\x00\x00\x00\x00\x05\x00\x00"
+
+# This should say "please use amend"
+_check_test_img -r all
+
+# So we do that
+$QEMU_IMG amend -o refcount_bits=2 "$TEST_IMG"
+print_refcount_bits
+
+# And try again
+_check_test_img -r all
+
+echo
+echo '=== Multiple walks necessary during amend ==='
+echo
+
+IMGOPTS="$IMGOPTS,refcount_bits=1,cluster_size=512" _make_test_img 64k
+
+# Cluster 0 is the image header, clusters 1 to 4 are used by the L1 table, a
+# single L2 table, the reftable and a single refblock. This creates 58 data
+# clusters (actually, the L2 table is created here, too), so in total there are
+# then 63 used clusters in the image. With a refcount width of 64, one refblock
+# describes 64 clusters (512 bytes / 64 bits/entry = 64 entries), so this will
+# make the first refblock in the amended image have exactly one free entry.
+$QEMU_IO -c "write 0 $((58 * 512))" "$TEST_IMG" | _filter_qemu_io
+
+# Now change the refcount width; since the first new refblock will have exactly
+# one free entry, that entry will be used to store its own reference. No other
+# refblocks are needed, so then the new reftable will be allocated; since the
+# first new refblock is completely filled up, this will require a new refblock
+# which is why the refcount width changing function will need to run through
+# everything one more time until the allocations are stable.
+# Having more walks than usual should be visible as regressing progress (from
+# 66.67 % (2/3 walks) to 50.00 % (2/4 walks)).
+$QEMU_IMG amend -o refcount_bits=64 -p "$TEST_IMG" | tr '\r' '\n' \
+ | grep -A 1 '66.67'
+print_refcount_bits
+
+_check_test_img
+
# success, all done
echo '*** done'
diff --git a/tests/qemu-iotests/112.out b/tests/qemu-iotests/112.out
index 8dd3df0..81b04d1 100644
--- a/tests/qemu-iotests/112.out
+++ b/tests/qemu-iotests/112.out
@@ -81,4 +81,75 @@ Leaked cluster 6 refcount=1 reference=0
2 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
+
+=== Amend from refcount_bits=16 to refcount_bits=1 ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+refcount bits: 16
+wrote 33554432/33554432 bytes at offset 16777216
+32 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+No errors were found on the image.
+refcount bits: 1
+
+=== Amend from refcount_bits=1 to refcount_bits=64 ===
+
+No errors were found on the image.
+refcount bits: 64
+
+=== Amend to compat=0.10 ===
+
+qemu-img: compat=0.10 requires refcount_bits=16
+qemu-img: Error while amending options: Operation not supported
+refcount bits: 64
+No errors were found on the image.
+refcount bits: 16
+refcount bits: 16
+qemu-img: Different refcount widths than 16 bits require compatibility level 1.1 or above (use compat=1.1 or greater)
+qemu-img: Error while amending options: Invalid argument
+refcount bits: 16
+
+=== Amend with snapshot ===
+
+wrote 16777216/16777216 bytes at offset 0
+16 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-img: Cannot decrease refcount entry width to 1 bits: Cluster at offset 0x50000 has a refcount of 2
+qemu-img: Error while amending options: Invalid argument
+No errors were found on the image.
+refcount bits: 16
+No errors were found on the image.
+refcount bits: 2
+
+=== Testing too many references for check ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+refcount bits: 1
+wrote 65536/65536 bytes at offset 0
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+ERROR: overflow cluster offset=0x50000
+Use qemu-img amend to increase the refcount entry width or qemu-img convert to create a clean copy if the image cannot be opened for writing
+
+1 errors were found on the image.
+Data may be corrupted, or further writes to the image may corrupt it.
+refcount bits: 2
+ERROR cluster 5 refcount=1 reference=2
+Repairing cluster 5 refcount=1 reference=2
+Repairing OFLAG_COPIED data cluster: l2_entry=8000000000050000 refcount=2
+Repairing OFLAG_COPIED data cluster: l2_entry=8000000000050000 refcount=2
+The following inconsistencies were found and repaired:
+
+ 0 leaked clusters
+ 3 corruptions
+
+Double checking the fixed image now...
+No errors were found on the image.
+
+=== Multiple walks necessary during amend ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=65536
+wrote 29696/29696 bytes at offset 0
+29 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+ (66.67/100%)
+ (50.00/100%)
+refcount bits: 64
+No errors were found on the image.
*** done
diff --git a/tests/qemu-iotests/124 b/tests/qemu-iotests/124
index c928f01..7d33422 100644
--- a/tests/qemu-iotests/124
+++ b/tests/qemu-iotests/124
@@ -91,24 +91,31 @@ class Bitmap:
try_remove(image)
-class TestIncrementalBackup(iotests.QMPTestCase):
- def setUp(self):
+class TestIncrementalBackupBase(iotests.QMPTestCase):
+ def __init__(self, *args):
+ super(TestIncrementalBackupBase, self).__init__(*args)
self.bitmaps = list()
self.files = list()
self.drives = list()
self.vm = iotests.VM()
self.err_img = os.path.join(iotests.test_dir, 'err.%s' % iotests.imgfmt)
+
+ def setUp(self):
# Create a base image with a distinctive patterning
drive0 = self.add_node('drive0')
self.img_create(drive0['file'], drive0['fmt'])
self.vm.add_drive(drive0['file'])
- io_write_patterns(drive0['file'], (('0x41', 0, 512),
- ('0xd5', '1M', '32k'),
- ('0xdc', '32M', '124k')))
+ self.write_default_pattern(drive0['file'])
self.vm.launch()
+ def write_default_pattern(self, target):
+ io_write_patterns(target, (('0x41', 0, 512),
+ ('0xd5', '1M', '32k'),
+ ('0xdc', '32M', '124k')))
+
+
def add_node(self, node_id, fmt=iotests.imgfmt, path=None, backup=None):
if path is None:
path = os.path.join(iotests.test_dir, '%s.%s' % (node_id, fmt))
@@ -259,6 +266,16 @@ class TestIncrementalBackup(iotests.QMPTestCase):
self.check_backups()
+ def tearDown(self):
+ self.vm.shutdown()
+ for bitmap in self.bitmaps:
+ bitmap.cleanup()
+ for filename in self.files:
+ try_remove(filename)
+
+
+
+class TestIncrementalBackup(TestIncrementalBackupBase):
def test_incremental_simple(self):
'''
Test: Create and verify three incremental backups.
@@ -327,63 +344,6 @@ class TestIncrementalBackup(iotests.QMPTestCase):
self.check_backups()
- def test_incremental_failure(self):
- '''Test: Verify backups made after a failure are correct.
-
- Simulate a failure during an incremental backup block job,
- emulate additional writes, then create another incremental backup
- afterwards and verify that the backup created is correct.
- '''
-
- # Create a blkdebug interface to this img as 'drive1',
- # but don't actually create a new image.
- drive1 = self.add_node('drive1', self.drives[0]['fmt'],
- path=self.drives[0]['file'],
- backup=self.drives[0]['backup'])
- result = self.vm.qmp('blockdev-add', options={
- 'id': drive1['id'],
- 'driver': drive1['fmt'],
- 'file': {
- 'driver': 'blkdebug',
- 'image': {
- 'driver': 'file',
- 'filename': drive1['file']
- },
- 'set-state': [{
- 'event': 'flush_to_disk',
- 'state': 1,
- 'new_state': 2
- }],
- 'inject-error': [{
- 'event': 'read_aio',
- 'errno': 5,
- 'state': 2,
- 'immediately': False,
- 'once': True
- }],
- }
- })
- self.assert_qmp(result, 'return', {})
-
- self.create_anchor_backup(self.drives[0])
- self.add_bitmap('bitmap0', drive1)
- # Note: at this point, during a normal execution,
- # Assume that the VM resumes and begins issuing IO requests here.
-
- self.hmp_io_writes(drive1['id'], (('0xab', 0, 512),
- ('0xfe', '16M', '256k'),
- ('0x64', '32736k', '64k')))
-
- result = self.create_incremental(validate=False)
- self.assertFalse(result)
- self.hmp_io_writes(drive1['id'], (('0x9a', 0, 512),
- ('0x55', '8M', '352k'),
- ('0x78', '15872k', '1M')))
- self.create_incremental()
- self.vm.shutdown()
- self.check_backups()
-
-
def test_transaction_failure(self):
'''Test: Verify backups made from a transaction that partially fails.
@@ -531,12 +491,66 @@ class TestIncrementalBackup(iotests.QMPTestCase):
granularity=64000)
- def tearDown(self):
+class TestIncrementalBackupBlkdebug(TestIncrementalBackupBase):
+ '''Incremental backup tests that utilize a BlkDebug filter on drive0.'''
+
+ def setUp(self):
+ drive0 = self.add_node('drive0')
+ self.img_create(drive0['file'], drive0['fmt'])
+ self.write_default_pattern(drive0['file'])
+ self.vm.launch()
+
+ def test_incremental_failure(self):
+ '''Test: Verify backups made after a failure are correct.
+
+ Simulate a failure during an incremental backup block job,
+ emulate additional writes, then create another incremental backup
+ afterwards and verify that the backup created is correct.
+ '''
+
+ drive0 = self.drives[0]
+ result = self.vm.qmp('blockdev-add', options={
+ 'id': drive0['id'],
+ 'driver': drive0['fmt'],
+ 'file': {
+ 'driver': 'blkdebug',
+ 'image': {
+ 'driver': 'file',
+ 'filename': drive0['file']
+ },
+ 'set-state': [{
+ 'event': 'flush_to_disk',
+ 'state': 1,
+ 'new_state': 2
+ }],
+ 'inject-error': [{
+ 'event': 'read_aio',
+ 'errno': 5,
+ 'state': 2,
+ 'immediately': False,
+ 'once': True
+ }],
+ }
+ })
+ self.assert_qmp(result, 'return', {})
+
+ self.create_anchor_backup(drive0)
+ self.add_bitmap('bitmap0', drive0)
+ # Note: at this point, during a normal execution,
+ # Assume that the VM resumes and begins issuing IO requests here.
+
+ self.hmp_io_writes(drive0['id'], (('0xab', 0, 512),
+ ('0xfe', '16M', '256k'),
+ ('0x64', '32736k', '64k')))
+
+ result = self.create_incremental(validate=False)
+ self.assertFalse(result)
+ self.hmp_io_writes(drive0['id'], (('0x9a', 0, 512),
+ ('0x55', '8M', '352k'),
+ ('0x78', '15872k', '1M')))
+ self.create_incremental()
self.vm.shutdown()
- for bitmap in self.bitmaps:
- bitmap.cleanup()
- for filename in self.files:
- try_remove(filename)
+ self.check_backups()
if __name__ == '__main__':
diff --git a/tests/qemu-iotests/133 b/tests/qemu-iotests/133
new file mode 100755
index 0000000..8587102
--- /dev/null
+++ b/tests/qemu-iotests/133
@@ -0,0 +1,90 @@
+#!/bin/bash
+#
+# Test for reopen
+#
+# Copyright (C) 2015 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+# creator
+owner=kwolf@redhat.com
+
+seq=`basename $0`
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1 # failure is the default!
+
+_cleanup()
+{
+ _cleanup_test_img
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+
+_supported_fmt qcow2
+_supported_proto file
+_supported_os Linux
+
+TEST_IMG="$TEST_IMG.base" _make_test_img 64M
+_make_test_img -b "$TEST_IMG.base"
+
+echo
+echo "=== Check that node-name can't be changed ==="
+echo
+
+$QEMU_IO -c 'reopen -o node-name=foo' $TEST_IMG
+$QEMU_IO -c 'reopen -o file.node-name=foo' $TEST_IMG
+$QEMU_IO -c 'reopen -o backing.node-name=foo' $TEST_IMG
+
+echo
+echo "=== Check that unchanged node-name is okay ==="
+echo
+
+# Explicitly repeated
+$QEMU_IO -c "open -o node-name=foo $TEST_IMG" -c 'reopen -o node-name=foo'
+$QEMU_IO -c "open -o file.node-name=foo $TEST_IMG" -c 'reopen -o file.node-name=foo'
+$QEMU_IO -c "open -o backing.node-name=foo $TEST_IMG" -c 'reopen -o backing.node-name=foo'
+
+# Implicitly retained
+$QEMU_IO -c "open -o node-name=foo $TEST_IMG" -c 'reopen'
+$QEMU_IO -c "open -o file.node-name=foo $TEST_IMG" -c 'reopen'
+$QEMU_IO -c "open -o backing.node-name=foo $TEST_IMG" -c 'reopen'
+
+echo
+echo "=== Check that driver can't be changed ==="
+echo
+
+$QEMU_IO -c 'reopen -o driver=raw' $TEST_IMG
+$QEMU_IO -c 'reopen -o file.driver=qcow2' $TEST_IMG
+$QEMU_IO -c 'reopen -o backing.driver=file' $TEST_IMG
+
+echo
+echo "=== Check that unchanged driver is okay ==="
+echo
+
+# Explicitly repeated (implicit case is covered in node-name test)
+$QEMU_IO -c 'reopen -o driver=qcow2' $TEST_IMG
+$QEMU_IO -c 'reopen -o file.driver=file' $TEST_IMG
+$QEMU_IO -c 'reopen -o backing.driver=qcow2' $TEST_IMG
+
+# success, all done
+echo "*** done"
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/133.out b/tests/qemu-iotests/133.out
new file mode 100644
index 0000000..cc86b94
--- /dev/null
+++ b/tests/qemu-iotests/133.out
@@ -0,0 +1,22 @@
+QA output created by 133
+Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base
+
+=== Check that node-name can't be changed ===
+
+Cannot change the option 'node-name'
+Cannot change the option 'node-name'
+Cannot change the option 'node-name'
+
+=== Check that unchanged node-name is okay ===
+
+
+=== Check that driver can't be changed ===
+
+Cannot change the option 'driver'
+Cannot change the option 'driver'
+Cannot change the option 'driver'
+
+=== Check that unchanged driver is okay ===
+
+*** done
diff --git a/tests/qemu-iotests/142 b/tests/qemu-iotests/142
new file mode 100755
index 0000000..8aa50f8
--- /dev/null
+++ b/tests/qemu-iotests/142
@@ -0,0 +1,354 @@
+#!/bin/bash
+#
+# Test for configuring cache modes of arbitrary nodes (requires O_DIRECT)
+#
+# Copyright (C) 2015 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+# creator
+owner=kwolf@redhat.com
+
+seq=`basename $0`
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1 # failure is the default!
+
+_cleanup()
+{
+ _cleanup_test_img
+ rm -f $TEST_IMG.snap
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+
+_supported_fmt qcow2
+_supported_proto file
+_supported_os Linux
+
+# We test all cache modes anyway, but O_DIRECT needs to be supported
+_default_cache_mode none
+_supported_cache_modes none directsync
+
+function do_run_qemu()
+{
+ echo Testing: "$@"
+ (
+ if ! test -t 0; then
+ while read cmd; do
+ echo $cmd
+ done
+ fi
+ echo quit
+ ) | $QEMU -nographic -monitor stdio -nodefaults "$@"
+ echo
+}
+
+function run_qemu()
+{
+ do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu
+}
+
+size=128M
+
+TEST_IMG="$TEST_IMG.base" _make_test_img $size
+TEST_IMG="$TEST_IMG.snap" _make_test_img $size
+_make_test_img -b "$TEST_IMG.base" $size
+
+echo
+echo === Simple test for all cache modes ===
+echo
+
+run_qemu -drive file="$TEST_IMG",cache=none
+run_qemu -drive file="$TEST_IMG",cache=directsync
+run_qemu -drive file="$TEST_IMG",cache=writeback
+run_qemu -drive file="$TEST_IMG",cache=writethrough
+run_qemu -drive file="$TEST_IMG",cache=unsafe
+run_qemu -drive file="$TEST_IMG",cache=invalid_value
+
+echo
+echo === Check inheritance of cache modes ===
+echo
+
+files="if=none,file=$TEST_IMG,backing.file.filename=$TEST_IMG.base"
+ids="node-name=image,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file"
+
+function check_cache_all()
+{
+ # cache.direct is supposed to be inherited by both bs->file and
+ # bs->backing
+
+ echo -e "cache.direct=on on none0"
+ echo "$hmp_cmds" | run_qemu -drive "$files","$ids",cache.direct=on | grep "Cache"
+ echo -e "\ncache.direct=on on file"
+ echo "$hmp_cmds" | run_qemu -drive "$files","$ids",file.cache.direct=on | grep "Cache"
+ echo -e "\ncache.direct=on on backing"
+ echo "$hmp_cmds" | run_qemu -drive "$files","$ids",backing.cache.direct=on | grep "Cache"
+ echo -e "\ncache.direct=on on backing-file"
+ echo "$hmp_cmds" | run_qemu -drive "$files","$ids",backing.file.cache.direct=on | grep "Cache"
+
+ # cache.writeback is supposed to be inherited by bs->backing; bs->file
+ # always gets cache.writeback=on
+
+ echo -e "\n\ncache.writeback=off on none0"
+ echo "$hmp_cmds" | run_qemu -drive "$files","$ids",cache.writeback=off | grep "Cache"
+ echo -e "\ncache.writeback=off on file"
+ echo "$hmp_cmds" | run_qemu -drive "$files","$ids",file.cache.writeback=off | grep "Cache"
+ echo -e "\ncache.writeback=off on backing"
+ echo "$hmp_cmds" | run_qemu -drive "$files","$ids",backing.cache.writeback=off | grep "Cache"
+ echo -e "\ncache.writeback=off on backing-file"
+ echo "$hmp_cmds" | run_qemu -drive "$files","$ids",backing.file.cache.writeback=off | grep "Cache"
+
+ # cache.no-flush is supposed to be inherited by both bs->file and bs->backing
+
+ echo -e "\n\ncache.no-flush=on on none0"
+ echo "$hmp_cmds" | run_qemu -drive "$files","$ids",cache.no-flush=on | grep "Cache"
+ echo -e "\ncache.no-flush=on on file"
+ echo "$hmp_cmds" | run_qemu -drive "$files","$ids",file.cache.no-flush=on | grep "Cache"
+ echo -e "\ncache.no-flush=on on backing"
+ echo "$hmp_cmds" | run_qemu -drive "$files","$ids",backing.cache.no-flush=on | grep "Cache"
+ echo -e "\ncache.no-flush=on on backing-file"
+ echo "$hmp_cmds" | run_qemu -drive "$files","$ids",backing.file.cache.no-flush=on | grep "Cache"
+}
+
+echo
+echo "--- Configure cache modes on the command line ---"
+echo
+
+# First check the inherited cache mode after opening the image.
+
+hmp_cmds="info block image
+info block file
+info block backing
+info block backing-file"
+
+check_cache_all
+
+echo
+echo "--- Cache modes after reopen (live snapshot) ---"
+echo
+
+# Then trigger a reopen and check that the cache modes are still the same.
+
+hmp_cmds="snapshot_blkdev -n none0 $TEST_IMG.snap $IMGFMT
+info block
+info block image
+info block file
+info block backing
+info block backing-file"
+
+check_cache_all
+
+echo
+echo "--- Change cache modes with reopen (qemu-io command, flags) ---"
+echo
+
+# This one actually changes the cache mode with the reopen. For this test, the
+# new cache mode is specified in the flags, not as an option.
+
+hmp_cmds='qemu-io none0 "reopen -c none"
+info block image
+info block file
+info block backing
+info block backing-file'
+
+check_cache_all
+
+echo
+echo "--- Change cache modes with reopen (qemu-io command, options) ---"
+echo
+
+# This one actually changes the cache mode with the reopen. For this test, the
+# new cache mode is specified as an option, not in the flags.
+
+hmp_cmds='qemu-io none0 "reopen -o cache.direct=on"
+info block image
+info block file
+info block backing
+info block backing-file'
+
+check_cache_all
+
+echo
+echo "--- Change cache modes after snapshot ---"
+echo
+
+# This checks that the original image doesn't inherit from the snapshot
+
+hmp_cmds="snapshot_blkdev -n none0 $TEST_IMG.snap $IMGFMT
+qemu-io none0 \"reopen -c none\"
+info block none0
+info block image
+info block file
+info block backing
+info block backing-file"
+
+check_cache_all
+
+echo
+echo "--- Change cache mode in parent, child has explicit option in JSON ---"
+echo
+
+# This checks that children with options explicitly set by the json:
+# pseudo-protocol don't inherit these options from their parents.
+#
+# Yes, blkdebug::json:... is criminal, but I can't see another way to have a
+# BDS initialised with the json: pseudo-protocol, but still have it inherit
+# options from its parent node.
+
+hmp_cmds="qemu-io none0 \"reopen -o cache.writeback=off,cache.direct=on,cache.no-flush=on\"
+info block image
+info block blkdebug
+info block file"
+
+echo "$hmp_cmds" | run_qemu -drive if=none,file="blkdebug::json:{\"filename\":\"$TEST_IMG\",,\"cache\":{\"writeback\":false,,\"direct\":false}}",node-name=image,file.node-name=blkdebug,file.image.node-name=file | grep "Cache"
+
+echo
+echo "=== Check that referenced BDSes don't inherit ==="
+echo
+
+drv_bkfile="if=none,driver=file,filename=$TEST_IMG.base,node-name=backing-file"
+drv_bk="if=none,file=json:{'driver':'$IMGFMT',,'file':'backing-file',,'node-name':'backing'}"
+drv_file="if=none,driver=file,filename=$TEST_IMG,node-name=file"
+drv_img="if=none,id=blk,file=json:{'driver':'$IMGFMT',,'file':'file',,'backing':'backing',,'node-name':'image'}"
+
+function check_cache_all_separate()
+{
+ # Check cache.direct
+
+ echo -e "cache.direct=on on blk"
+ echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk" -drive "$drv_file" -drive "$drv_img",cache.direct=on | grep "Cache"
+ echo -e "\ncache.direct=on on file"
+ echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk" -drive "$drv_file",cache.direct=on -drive "$drv_img" | grep "Cache"
+ echo -e "\ncache.direct=on on backing"
+ echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk",cache.direct=on -drive "$drv_file" -drive "$drv_img" | grep "Cache"
+ echo -e "\ncache.direct=on on backing-file"
+ echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile",cache.direct=on -drive "$drv_bk" -drive "$drv_file" -drive "$drv_img" | grep "Cache"
+
+ # Check cache.writeback
+
+ echo -e "\n\ncache.writeback=off on blk"
+ echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk" -drive "$drv_file" -drive "$drv_img",cache.writeback=off | grep "Cache"
+ echo -e "\ncache.writeback=off on file"
+ echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk" -drive "$drv_file",cache.writeback=off -drive "$drv_img" | grep "Cache"
+ echo -e "\ncache.writeback=off on backing"
+ echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk",cache.writeback=off -drive "$drv_file" -drive "$drv_img" | grep "Cache"
+ echo -e "\ncache.writeback=off on backing-file"
+ echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile",cache.writeback=off -drive "$drv_bk" -drive "$drv_file" -drive "$drv_img" | grep "Cache"
+
+ # Check cache.no-flush
+
+ echo -e "\n\ncache.no-flush=on on blk"
+ echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk" -drive "$drv_file" -drive "$drv_img",cache.no-flush=on | grep "Cache"
+ echo -e "\ncache.no-flush=on on file"
+ echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk" -drive "$drv_file",cache.no-flush=on -drive "$drv_img" | grep "Cache"
+ echo -e "\ncache.no-flush=on on backing"
+ echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk",cache.no-flush=on -drive "$drv_file" -drive "$drv_img" | grep "Cache"
+ echo -e "\ncache.no-flush=on on backing-file"
+ echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile",cache.no-flush=on -drive "$drv_bk" -drive "$drv_file" -drive "$drv_img" | grep "Cache"
+}
+
+echo
+echo "--- Configure cache modes on the command line ---"
+echo
+
+# First check the inherited cache mode after opening the image.
+
+hmp_cmds="info block image
+info block file
+info block backing
+info block backing-file"
+
+check_cache_all_separate
+
+echo
+echo "--- Cache modes after reopen (live snapshot) ---"
+echo
+
+# Then trigger a reopen and check that the cache modes are still the same.
+
+hmp_cmds="snapshot_blkdev -n blk $TEST_IMG.snap $IMGFMT
+info block blk
+info block image
+info block file
+info block backing
+info block backing-file"
+
+check_cache_all_separate
+
+echo
+echo "--- Change cache modes with reopen (qemu-io command, flags) ---"
+echo
+
+# This one actually changes the cache mode with the reopen. For this test, the
+# new cache mode is specified as flags, not as option.
+
+hmp_cmds='qemu-io blk "reopen -c none"
+info block image
+info block file
+info block backing
+info block backing-file'
+
+check_cache_all_separate
+
+
+echo
+echo "=== Reopening children instead of the root ==="
+echo
+
+files="if=none,file=$TEST_IMG,backing.file.filename=$TEST_IMG.base"
+ids="node-name=image,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file"
+
+echo
+echo "--- Basic reopen ---"
+echo
+
+hmp_cmds='qemu-io none0 "reopen -o backing.cache.direct=on"
+info block image
+info block file
+info block backing
+info block backing-file'
+
+check_cache_all
+
+echo
+echo "--- Change cache mode after reopening child ---"
+echo
+
+# This checks that children with options explicitly set with reopen don't
+# inherit these options from their parents any more
+
+# TODO Implement node-name support for 'qemu-io' HMP command for -c
+# Can use only -o to access child node options for now
+
+hmp_cmds="qemu-io none0 \"reopen -o file.cache.writeback=off,file.cache.direct=off,file.cache.no-flush=off\"
+qemu-io none0 \"reopen -o backing.file.cache.writeback=on,backing.file.cache.direct=off,backing.file.cache.no-flush=on\"
+qemu-io none0 \"reopen -c none\"
+info block image
+info block file
+info block backing
+info block backing-file"
+
+echo "$hmp_cmds" | run_qemu -drive "$files","$ids" | grep "Cache"
+
+# success, all done
+echo "*** done"
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/142.out b/tests/qemu-iotests/142.out
new file mode 100644
index 0000000..b555d5a
--- /dev/null
+++ b/tests/qemu-iotests/142.out
@@ -0,0 +1,773 @@
+QA output created by 142
+Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728
+Formatting 'TEST_DIR/t.IMGFMT.snap', fmt=IMGFMT size=134217728
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base
+
+=== Simple test for all cache modes ===
+
+Testing: -drive file=TEST_DIR/t.qcow2,cache=none
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qququiquit
+
+Testing: -drive file=TEST_DIR/t.qcow2,cache=directsync
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qququiquit
+
+Testing: -drive file=TEST_DIR/t.qcow2,cache=writeback
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qququiquit
+
+Testing: -drive file=TEST_DIR/t.qcow2,cache=writethrough
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qququiquit
+
+Testing: -drive file=TEST_DIR/t.qcow2,cache=unsafe
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qququiquit
+
+Testing: -drive file=TEST_DIR/t.qcow2,cache=invalid_value
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,cache=invalid_value: invalid cache option
+
+
+=== Check inheritance of cache modes ===
+
+
+--- Configure cache modes on the command line ---
+
+cache.direct=on on none0
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+
+cache.direct=on on file
+ Cache mode: writeback
+ Cache mode: writeback, direct
+ Cache mode: writeback
+ Cache mode: writeback
+
+cache.direct=on on backing
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+
+cache.direct=on on backing-file
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback, direct
+
+
+cache.writeback=off on none0
+ Cache mode: writethrough
+ Cache mode: writeback
+ Cache mode: writethrough
+ Cache mode: writeback
+
+cache.writeback=off on file
+ Cache mode: writeback
+ Cache mode: writethrough
+ Cache mode: writeback
+ Cache mode: writeback
+
+cache.writeback=off on backing
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writethrough
+ Cache mode: writeback
+
+cache.writeback=off on backing-file
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writethrough
+
+
+cache.no-flush=on on none0
+ Cache mode: writeback, ignore flushes
+ Cache mode: writeback, ignore flushes
+ Cache mode: writeback, ignore flushes
+ Cache mode: writeback, ignore flushes
+
+cache.no-flush=on on file
+ Cache mode: writeback
+ Cache mode: writeback, ignore flushes
+ Cache mode: writeback
+ Cache mode: writeback
+
+cache.no-flush=on on backing
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback, ignore flushes
+ Cache mode: writeback, ignore flushes
+
+cache.no-flush=on on backing-file
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback, ignore flushes
+
+--- Cache modes after reopen (live snapshot) ---
+
+cache.direct=on on none0
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+
+cache.direct=on on file
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback, direct
+ Cache mode: writeback
+ Cache mode: writeback
+
+cache.direct=on on backing
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+
+cache.direct=on on backing-file
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback, direct
+
+
+cache.writeback=off on none0
+ Cache mode: writethrough
+ Cache mode: writethrough
+ Cache mode: writeback
+ Cache mode: writethrough
+ Cache mode: writeback
+
+cache.writeback=off on file
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writethrough
+ Cache mode: writeback
+ Cache mode: writeback
+
+cache.writeback=off on backing
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writethrough
+ Cache mode: writeback
+
+cache.writeback=off on backing-file
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writethrough
+
+
+cache.no-flush=on on none0
+ Cache mode: writeback, ignore flushes
+ Cache mode: writeback, ignore flushes
+ Cache mode: writeback, ignore flushes
+ Cache mode: writeback, ignore flushes
+ Cache mode: writeback, ignore flushes
+
+cache.no-flush=on on file
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback, ignore flushes
+ Cache mode: writeback
+ Cache mode: writeback
+
+cache.no-flush=on on backing
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback, ignore flushes
+ Cache mode: writeback, ignore flushes
+
+cache.no-flush=on on backing-file
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback, ignore flushes
+
+--- Change cache modes with reopen (qemu-io command, flags) ---
+
+cache.direct=on on none0
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+
+cache.direct=on on file
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+
+cache.direct=on on backing
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+
+cache.direct=on on backing-file
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+
+
+cache.writeback=off on none0
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+
+cache.writeback=off on file
+ Cache mode: writeback, direct
+ Cache mode: writethrough, direct
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+
+cache.writeback=off on backing
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+ Cache mode: writethrough, direct
+ Cache mode: writeback, direct
+
+cache.writeback=off on backing-file
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+ Cache mode: writethrough, direct
+
+
+cache.no-flush=on on none0
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+
+cache.no-flush=on on file
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct, ignore flushes
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+
+cache.no-flush=on on backing
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct, ignore flushes
+ Cache mode: writeback, direct, ignore flushes
+
+cache.no-flush=on on backing-file
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct, ignore flushes
+
+--- Change cache modes with reopen (qemu-io command, options) ---
+
+cache.direct=on on none0
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+
+cache.direct=on on file
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+
+cache.direct=on on backing
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+
+cache.direct=on on backing-file
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+
+
+cache.writeback=off on none0
+ Cache mode: writethrough, direct
+ Cache mode: writeback, direct
+ Cache mode: writethrough, direct
+ Cache mode: writeback, direct
+
+cache.writeback=off on file
+ Cache mode: writeback, direct
+ Cache mode: writethrough, direct
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+
+cache.writeback=off on backing
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+ Cache mode: writethrough, direct
+ Cache mode: writeback, direct
+
+cache.writeback=off on backing-file
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+ Cache mode: writethrough, direct
+
+
+cache.no-flush=on on none0
+ Cache mode: writeback, direct, ignore flushes
+ Cache mode: writeback, direct, ignore flushes
+ Cache mode: writeback, direct, ignore flushes
+ Cache mode: writeback, direct, ignore flushes
+
+cache.no-flush=on on file
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct, ignore flushes
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+
+cache.no-flush=on on backing
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct, ignore flushes
+ Cache mode: writeback, direct, ignore flushes
+
+cache.no-flush=on on backing-file
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct, ignore flushes
+
+--- Change cache modes after snapshot ---
+
+cache.direct=on on none0
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+
+cache.direct=on on file
+ Cache mode: writeback, direct
+ Cache mode: writeback
+ Cache mode: writeback, direct
+ Cache mode: writeback
+ Cache mode: writeback
+
+cache.direct=on on backing
+ Cache mode: writeback, direct
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+
+cache.direct=on on backing-file
+ Cache mode: writeback, direct
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback, direct
+
+
+cache.writeback=off on none0
+ Cache mode: writeback, direct
+ Cache mode: writethrough
+ Cache mode: writeback
+ Cache mode: writethrough
+ Cache mode: writeback
+
+cache.writeback=off on file
+ Cache mode: writeback, direct
+ Cache mode: writeback
+ Cache mode: writethrough
+ Cache mode: writeback
+ Cache mode: writeback
+
+cache.writeback=off on backing
+ Cache mode: writeback, direct
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writethrough
+ Cache mode: writeback
+
+cache.writeback=off on backing-file
+ Cache mode: writeback, direct
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writethrough
+
+
+cache.no-flush=on on none0
+ Cache mode: writeback, direct
+ Cache mode: writeback, ignore flushes
+ Cache mode: writeback, ignore flushes
+ Cache mode: writeback, ignore flushes
+ Cache mode: writeback, ignore flushes
+
+cache.no-flush=on on file
+ Cache mode: writeback, direct
+ Cache mode: writeback
+ Cache mode: writeback, ignore flushes
+ Cache mode: writeback
+ Cache mode: writeback
+
+cache.no-flush=on on backing
+ Cache mode: writeback, direct
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback, ignore flushes
+ Cache mode: writeback, ignore flushes
+
+cache.no-flush=on on backing-file
+ Cache mode: writeback, direct
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback, ignore flushes
+
+--- Change cache mode in parent, child has explicit option in JSON ---
+
+ Cache mode: writethrough, direct, ignore flushes
+ Cache mode: writeback, direct, ignore flushes
+ Cache mode: writethrough, ignore flushes
+
+=== Check that referenced BDSes don't inherit ===
+
+
+--- Configure cache modes on the command line ---
+
+cache.direct=on on blk
+ Cache mode: writeback, direct
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback
+
+cache.direct=on on file
+ Cache mode: writeback
+ Cache mode: writeback, direct
+ Cache mode: writeback
+ Cache mode: writeback
+
+cache.direct=on on backing
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback, direct
+ Cache mode: writeback
+
+cache.direct=on on backing-file
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback, direct
+
+
+cache.writeback=off on blk
+ Cache mode: writethrough
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback
+
+cache.writeback=off on file
+ Cache mode: writeback
+ Cache mode: writethrough
+ Cache mode: writeback
+ Cache mode: writeback
+
+cache.writeback=off on backing
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writethrough
+ Cache mode: writeback
+
+cache.writeback=off on backing-file
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writethrough
+
+
+cache.no-flush=on on blk
+ Cache mode: writeback, ignore flushes
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback
+
+cache.no-flush=on on file
+ Cache mode: writeback
+ Cache mode: writeback, ignore flushes
+ Cache mode: writeback
+ Cache mode: writeback
+
+cache.no-flush=on on backing
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback, ignore flushes
+ Cache mode: writeback
+
+cache.no-flush=on on backing-file
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback, ignore flushes
+
+--- Cache modes after reopen (live snapshot) ---
+
+cache.direct=on on blk
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback
+
+cache.direct=on on file
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback, direct
+ Cache mode: writeback
+ Cache mode: writeback
+
+cache.direct=on on backing
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback, direct
+ Cache mode: writeback
+
+cache.direct=on on backing-file
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback, direct
+
+
+cache.writeback=off on blk
+ Cache mode: writethrough
+ Cache mode: writethrough
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback
+
+cache.writeback=off on file
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writethrough
+ Cache mode: writeback
+ Cache mode: writeback
+
+cache.writeback=off on backing
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writethrough
+ Cache mode: writeback
+
+cache.writeback=off on backing-file
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writethrough
+
+
+cache.no-flush=on on blk
+ Cache mode: writeback, ignore flushes
+ Cache mode: writeback, ignore flushes
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback
+
+cache.no-flush=on on file
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback, ignore flushes
+ Cache mode: writeback
+ Cache mode: writeback
+
+cache.no-flush=on on backing
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback, ignore flushes
+ Cache mode: writeback
+
+cache.no-flush=on on backing-file
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback, ignore flushes
+
+--- Change cache modes with reopen (qemu-io command, flags) ---
+
+cache.direct=on on blk
+ Cache mode: writeback, direct
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback
+
+cache.direct=on on file
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+ Cache mode: writeback
+ Cache mode: writeback
+
+cache.direct=on on backing
+ Cache mode: writeback, direct
+ Cache mode: writeback
+ Cache mode: writeback, direct
+ Cache mode: writeback
+
+cache.direct=on on backing-file
+ Cache mode: writeback, direct
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback, direct
+
+
+cache.writeback=off on blk
+ Cache mode: writeback, direct
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback
+
+cache.writeback=off on file
+ Cache mode: writeback, direct
+ Cache mode: writethrough
+ Cache mode: writeback
+ Cache mode: writeback
+
+cache.writeback=off on backing
+ Cache mode: writeback, direct
+ Cache mode: writeback
+ Cache mode: writethrough
+ Cache mode: writeback
+
+cache.writeback=off on backing-file
+ Cache mode: writeback, direct
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writethrough
+
+
+cache.no-flush=on on blk
+ Cache mode: writeback, direct
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback
+
+cache.no-flush=on on file
+ Cache mode: writeback, direct
+ Cache mode: writeback, ignore flushes
+ Cache mode: writeback
+ Cache mode: writeback
+
+cache.no-flush=on on backing
+ Cache mode: writeback, direct
+ Cache mode: writeback
+ Cache mode: writeback, ignore flushes
+ Cache mode: writeback
+
+cache.no-flush=on on backing-file
+ Cache mode: writeback, direct
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback, ignore flushes
+
+=== Reopening children instead of the root ===
+
+
+--- Basic reopen ---
+
+cache.direct=on on none0
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+
+cache.direct=on on file
+ Cache mode: writeback
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+
+cache.direct=on on backing
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+
+cache.direct=on on backing-file
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+
+
+cache.writeback=off on none0
+ Cache mode: writethrough
+ Cache mode: writeback
+ Cache mode: writethrough, direct
+ Cache mode: writeback, direct
+
+cache.writeback=off on file
+ Cache mode: writeback
+ Cache mode: writethrough
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+
+cache.writeback=off on backing
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writethrough, direct
+ Cache mode: writeback, direct
+
+cache.writeback=off on backing-file
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback, direct
+ Cache mode: writethrough, direct
+
+
+cache.no-flush=on on none0
+ Cache mode: writeback, ignore flushes
+ Cache mode: writeback, ignore flushes
+ Cache mode: writeback, direct, ignore flushes
+ Cache mode: writeback, direct, ignore flushes
+
+cache.no-flush=on on file
+ Cache mode: writeback
+ Cache mode: writeback, ignore flushes
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct
+
+cache.no-flush=on on backing
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback, direct, ignore flushes
+ Cache mode: writeback, direct, ignore flushes
+
+cache.no-flush=on on backing-file
+ Cache mode: writeback
+ Cache mode: writeback
+ Cache mode: writeback, direct
+ Cache mode: writeback, direct, ignore flushes
+
+--- Change cache mode after reopening child ---
+
+ Cache mode: writeback, direct
+ Cache mode: writethrough
+ Cache mode: writeback, direct
+ Cache mode: writeback, ignore flushes
+*** done
diff --git a/tests/qemu-iotests/common.config b/tests/qemu-iotests/common.config
index 3ed51b8..60bfabf 100644
--- a/tests/qemu-iotests/common.config
+++ b/tests/qemu-iotests/common.config
@@ -154,11 +154,10 @@ export QEMU_IMG=_qemu_img_wrapper
export QEMU_IO=_qemu_io_wrapper
export QEMU_NBD=_qemu_nbd_wrapper
-default_machine=$($QEMU -machine \? | awk '/(default)/{print $1}')
-default_alias_machine=$($QEMU -machine \? |\
- awk -v var_default_machine="$default_machine"\)\
- '{if ($(NF-2)=="(alias"&&$(NF-1)=="of"&&$(NF)==var_default_machine){print $1}}')
-if [ ! -z "$default_alias_machine" ]; then
+default_machine=$($QEMU -machine help | sed -n '/(default)/ s/ .*//p')
+default_alias_machine=$($QEMU -machine help | \
+ sed -n "/(alias of $default_machine)/ { s/ .*//p; q; }")
+if [[ "$default_alias_machine" ]]; then
default_machine="$default_alias_machine"
fi
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index 5a08808..d6e9219 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -134,9 +134,11 @@
130 rw auto quick
131 rw auto quick
132 rw auto quick
+133 auto quick
134 rw auto quick
135 rw auto
136 rw auto
137 rw auto
138 rw auto quick
139 rw auto quick
+142 auto
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
index e02245e..0a238ec 100644
--- a/tests/qemu-iotests/iotests.py
+++ b/tests/qemu-iotests/iotests.py
@@ -148,12 +148,12 @@ class VM(object):
def add_drive(self, path, opts='', interface='virtio'):
'''Add a virtio-blk drive to the VM'''
options = ['if=%s' % interface,
- 'format=%s' % imgfmt,
- 'cache=%s' % cachemode,
'id=drive%d' % self._num_drives]
if path is not None:
options.append('file=%s' % path)
+ options.append('format=%s' % imgfmt)
+ options.append('cache=%s' % cachemode)
if opts:
options.append(opts)
diff --git a/util/qemu-progress.c b/util/qemu-progress.c
index 4ee5cd0..532333e 100644
--- a/util/qemu-progress.c
+++ b/util/qemu-progress.c
@@ -152,7 +152,8 @@ void qemu_progress_print(float delta, int max)
state.current = current;
if (current > (state.last_print + state.min_skip) ||
- (current == 100) || (current == 0)) {
+ current < (state.last_print - state.min_skip) ||
+ current == 100 || current == 0) {
state.last_print = state.current;
state.print();
}