summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2014-03-08 12:17:17 +0000
committerPeter Maydell <peter.maydell@linaro.org>2014-03-08 12:17:17 +0000
commitd7c698af8a5c7330a5ba70de0ff70904a661c20e (patch)
tree6020293bdb1385b8dcd5c04d250af2fec828b2f0
parent6570025e53df25c47486d79cc8d3aea725f1744e (diff)
parent4089f7c6a0d91020ca60ce8300784c93dd9ddcbe (diff)
downloadqemu-d7c698af8a5c7330a5ba70de0ff70904a661c20e.tar.gz
Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging
Block patches # gpg: Signature made Fri 07 Mar 2014 13:30:04 GMT using RSA key ID C88F2FD6 # gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>" * remotes/kevin/tags/for-upstream: block: qemu-iotests 085 - live snapshots tests hw/ide/ahci.h: Avoid shifting left into sign bit block: Fix error path segfault in bdrv_open() qemu-iotests: Test a few blockdev-add error cases blockdev: Fix NULL pointer dereference in blockdev-add blockdev: Fail blockdev-add with encrypted images block/raw-win32: Strip "file:" prefix on creation block/raw-win32: Implement bdrv_parse_filename() block/raw-posix: Strip "file:" prefix on creation block/raw-posix: Implement bdrv_parse_filename() block: Keep "filename" option after parsing block: mirror - remove code cruft that has no function block: make bdrv_swap rebuild the bs graph node list field. block: Fix bs->request_alignment assertion for bs->sg=1 iscsi: Use bs->sg for everything else than disks qemu-iotests: Test progress output for conversion qemu-img convert: Fix progress output gluster: Remove unused defines and header include gluster: Change licence to GPLv2+ Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--block.c34
-rw-r--r--block/gluster.c16
-rw-r--r--block/iscsi.c9
-rw-r--r--block/mirror.c3
-rw-r--r--block/raw-posix.c14
-rw-r--r--block/raw-win32.c14
-rw-r--r--blockdev.c15
-rw-r--r--hw/ide/ahci.h10
-rw-r--r--qemu-img.c20
-rwxr-xr-xtests/qemu-iotests/0519
-rw-r--r--tests/qemu-iotests/051.out15
-rwxr-xr-xtests/qemu-iotests/085192
-rw-r--r--tests/qemu-iotests/085.out55
-rwxr-xr-xtests/qemu-iotests/08665
-rw-r--r--tests/qemu-iotests/086.out18
-rwxr-xr-xtests/qemu-iotests/087122
-rw-r--r--tests/qemu-iotests/087.out40
-rw-r--r--tests/qemu-iotests/group3
18 files changed, 608 insertions, 46 deletions
diff --git a/block.c b/block.c
index 38bbdf3083..f1ef4b0109 100644
--- a/block.c
+++ b/block.c
@@ -935,7 +935,7 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
bdrv_refresh_limits(bs);
assert(bdrv_opt_mem_align(bs) != 0);
- assert(bs->request_alignment != 0);
+ assert((bs->request_alignment != 0) || bs->sg);
#ifndef _WIN32
if (bs->is_temporary) {
@@ -1017,7 +1017,12 @@ static int bdrv_file_open(BlockDriverState *bs, const char *filename,
ret = -EINVAL;
goto fail;
}
- qdict_del(*options, "filename");
+
+ if (!drv->bdrv_needs_filename) {
+ qdict_del(*options, "filename");
+ } else {
+ filename = qdict_get_str(*options, "filename");
+ }
}
if (!drv->bdrv_file_open) {
@@ -1229,6 +1234,7 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
ret = bdrv_file_open(bs, filename, &options, flags & ~BDRV_O_PROTOCOL,
&local_err);
if (!ret) {
+ drv = bs->drv;
goto done;
} else if (bs->drv) {
goto close_and_fail;
@@ -1847,11 +1853,6 @@ static void bdrv_move_feature_fields(BlockDriverState *bs_dest,
pstrcpy(bs_dest->device_name, sizeof(bs_dest->device_name),
bs_src->device_name);
bs_dest->device_list = bs_src->device_list;
-
- /* keep the same entry in graph_bdrv_states
- * We do want to swap name but don't want to swap linked list entries
- */
- bs_dest->node_list = bs_src->node_list;
}
/*
@@ -1870,6 +1871,17 @@ void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old)
{
BlockDriverState tmp;
+ /* The code needs to swap the node_name but simply swapping node_list won't
+ * work so first remove the nodes from the graph list, do the swap then
+ * insert them back if needed.
+ */
+ if (bs_new->node_name[0] != '\0') {
+ QTAILQ_REMOVE(&graph_bdrv_states, bs_new, node_list);
+ }
+ if (bs_old->node_name[0] != '\0') {
+ QTAILQ_REMOVE(&graph_bdrv_states, bs_old, node_list);
+ }
+
/* bs_new must be anonymous and shouldn't have anything fancy enabled */
assert(bs_new->device_name[0] == '\0');
assert(QLIST_EMPTY(&bs_new->dirty_bitmaps));
@@ -1898,6 +1910,14 @@ void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old)
assert(bs_new->io_limits_enabled == false);
assert(!throttle_have_timer(&bs_new->throttle_state));
+ /* insert the nodes back into the graph node list if needed */
+ if (bs_new->node_name[0] != '\0') {
+ QTAILQ_INSERT_TAIL(&graph_bdrv_states, bs_new, node_list);
+ }
+ if (bs_old->node_name[0] != '\0') {
+ QTAILQ_INSERT_TAIL(&graph_bdrv_states, bs_old, node_list);
+ }
+
bdrv_rebind(bs_new);
bdrv_rebind(bs_old);
}
diff --git a/block/gluster.c b/block/gluster.c
index fe7a10c30b..a44d612923 100644
--- a/block/gluster.c
+++ b/block/gluster.c
@@ -3,21 +3,12 @@
*
* Copyright (C) 2012 Bharata B Rao <bharata@linux.vnet.ibm.com>
*
- * Pipe handling mechanism in AIO implementation is derived from
- * block/rbd.c. Hence,
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
*
- * Copyright (C) 2010-2011 Christian Brunner <chb@muc.de>,
- * Josh Durgin <josh.durgin@dreamhost.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
*/
#include <glusterfs/api/glfs.h>
#include "block/block_int.h"
-#include "qemu/sockets.h"
#include "qemu/uri.h"
typedef struct GlusterAIOCB {
@@ -32,9 +23,6 @@ typedef struct BDRVGlusterState {
struct glfs_fd *fd;
} BDRVGlusterState;
-#define GLUSTER_FD_READ 0
-#define GLUSTER_FD_WRITE 1
-
typedef struct GlusterConf {
char *server;
int port;
diff --git a/block/iscsi.c b/block/iscsi.c
index 0a15f53f8c..b490e98c05 100644
--- a/block/iscsi.c
+++ b/block/iscsi.c
@@ -1231,12 +1231,11 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
bs->total_sectors = sector_lun2qemu(iscsilun->num_blocks, iscsilun);
bs->request_alignment = iscsilun->block_size;
- /* Medium changer or tape. We dont have any emulation for this so this must
- * be sg ioctl compatible. We force it to be sg, otherwise qemu will try
- * to read from the device to guess the image format.
+ /* We don't have any emulation for devices other than disks and CD-ROMs, so
+ * this must be sg ioctl compatible. We force it to be sg, otherwise qemu
+ * will try to read from the device to guess the image format.
*/
- if (iscsilun->type == TYPE_MEDIUM_CHANGER ||
- iscsilun->type == TYPE_TAPE) {
+ if (iscsilun->type != TYPE_DISK && iscsilun->type != TYPE_ROM) {
bs->sg = 1;
}
diff --git a/block/mirror.c b/block/mirror.c
index e683959570..dd5ee056b4 100644
--- a/block/mirror.c
+++ b/block/mirror.c
@@ -520,9 +520,6 @@ static void mirror_complete(BlockJob *job, Error **errp)
ret = bdrv_open_backing_file(s->target, NULL, &local_err);
if (ret < 0) {
- char backing_filename[PATH_MAX];
- bdrv_get_full_backing_filename(s->target, backing_filename,
- sizeof(backing_filename));
error_propagate(errp, local_err);
return;
}
diff --git a/block/raw-posix.c b/block/raw-posix.c
index 161ea14812..e6b4c1fe02 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -336,6 +336,17 @@ error:
}
#endif
+static void raw_parse_filename(const char *filename, QDict *options,
+ Error **errp)
+{
+ /* The filename does not have to be prefixed by the protocol name, since
+ * "file" is the default protocol; therefore, the return value of this
+ * function call can be ignored. */
+ strstart(filename, "file:", &filename);
+
+ qdict_put_obj(options, "filename", QOBJECT(qstring_from_str(filename)));
+}
+
static QemuOptsList raw_runtime_opts = {
.name = "raw",
.head = QTAILQ_HEAD_INITIALIZER(raw_runtime_opts.head),
@@ -1230,6 +1241,8 @@ static int raw_create(const char *filename, QEMUOptionParameter *options,
int result = 0;
int64_t total_size = 0;
+ strstart(filename, "file:", &filename);
+
/* Read out options */
while (options && options->name) {
if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
@@ -1412,6 +1425,7 @@ static BlockDriver bdrv_file = {
.instance_size = sizeof(BDRVRawState),
.bdrv_needs_filename = true,
.bdrv_probe = NULL, /* no probe for protocols */
+ .bdrv_parse_filename = raw_parse_filename,
.bdrv_file_open = raw_open,
.bdrv_reopen_prepare = raw_reopen_prepare,
.bdrv_reopen_commit = raw_reopen_commit,
diff --git a/block/raw-win32.c b/block/raw-win32.c
index ae1c8e6cca..99547488e4 100644
--- a/block/raw-win32.c
+++ b/block/raw-win32.c
@@ -251,6 +251,17 @@ static void raw_parse_flags(int flags, int *access_flags, DWORD *overlapped)
}
}
+static void raw_parse_filename(const char *filename, QDict *options,
+ Error **errp)
+{
+ /* The filename does not have to be prefixed by the protocol name, since
+ * "file" is the default protocol; therefore, the return value of this
+ * function call can be ignored. */
+ strstart(filename, "file:", &filename);
+
+ qdict_put_obj(options, "filename", QOBJECT(qstring_from_str(filename)));
+}
+
static QemuOptsList raw_runtime_opts = {
.name = "raw",
.head = QTAILQ_HEAD_INITIALIZER(raw_runtime_opts.head),
@@ -470,6 +481,8 @@ static int raw_create(const char *filename, QEMUOptionParameter *options,
int fd;
int64_t total_size = 0;
+ strstart(filename, "file:", &filename);
+
/* Read out options */
while (options && options->name) {
if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
@@ -504,6 +517,7 @@ static BlockDriver bdrv_file = {
.protocol_name = "file",
.instance_size = sizeof(BDRVRawState),
.bdrv_needs_filename = true,
+ .bdrv_parse_filename = raw_parse_filename,
.bdrv_file_open = raw_open,
.bdrv_close = raw_close,
.bdrv_create = raw_create,
diff --git a/blockdev.c b/blockdev.c
index 357f7607ff..c3422a1d41 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -2266,6 +2266,7 @@ void qmp_block_job_complete(const char *device, Error **errp)
void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
{
QmpOutputVisitor *ov = qmp_output_visitor_new();
+ DriveInfo *dinfo;
QObject *obj;
QDict *qdict;
Error *local_err = NULL;
@@ -2282,8 +2283,10 @@ void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
*
* For now, simply forbidding the combination for all drivers will do. */
if (options->has_aio && options->aio == BLOCKDEV_AIO_OPTIONS_NATIVE) {
- bool direct = options->cache->has_direct && options->cache->direct;
- if (!options->has_cache && !direct) {
+ bool direct = options->has_cache &&
+ options->cache->has_direct &&
+ options->cache->direct;
+ if (!direct) {
error_setg(errp, "aio=native requires cache.direct=true");
goto fail;
}
@@ -2301,12 +2304,18 @@ void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
qdict_flatten(qdict);
- blockdev_init(NULL, qdict, &local_err);
+ dinfo = blockdev_init(NULL, qdict, &local_err);
if (local_err) {
error_propagate(errp, local_err);
goto fail;
}
+ if (bdrv_key_required(dinfo->bdrv)) {
+ drive_uninit(dinfo);
+ error_setg(errp, "blockdev-add doesn't support encrypted devices");
+ goto fail;
+ }
+
fail:
qmp_output_visitor_cleanup(ov);
}
diff --git a/hw/ide/ahci.h b/hw/ide/ahci.h
index 20e412c240..9a4064f892 100644
--- a/hw/ide/ahci.h
+++ b/hw/ide/ahci.h
@@ -40,7 +40,7 @@
#define AHCI_PORT_PRIV_DMA_SZ (AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_AR_SZ + \
AHCI_RX_FIS_SZ)
-#define AHCI_IRQ_ON_SG (1 << 31)
+#define AHCI_IRQ_ON_SG (1U << 31)
#define AHCI_CMD_ATAPI (1 << 5)
#define AHCI_CMD_WRITE (1 << 6)
#define AHCI_CMD_PREFETCH (1 << 7)
@@ -61,7 +61,7 @@
/* HOST_CTL bits */
#define HOST_CTL_RESET (1 << 0) /* reset controller; self-clear */
#define HOST_CTL_IRQ_EN (1 << 1) /* global IRQ enable */
-#define HOST_CTL_AHCI_EN (1 << 31) /* AHCI enabled */
+#define HOST_CTL_AHCI_EN (1U << 31) /* AHCI enabled */
/* HOST_CAP bits */
#define HOST_CAP_SSC (1 << 14) /* Slumber capable */
@@ -69,7 +69,7 @@
#define HOST_CAP_CLO (1 << 24) /* Command List Override support */
#define HOST_CAP_SSS (1 << 27) /* Staggered Spin-up */
#define HOST_CAP_NCQ (1 << 30) /* Native Command Queueing */
-#define HOST_CAP_64 (1 << 31) /* PCI DAC (64-bit DMA) support */
+#define HOST_CAP_64 (1U << 31) /* PCI DAC (64-bit DMA) support */
/* registers for each SATA port */
#define PORT_LST_ADDR 0x00 /* command list DMA addr */
@@ -89,7 +89,7 @@
#define PORT_RESERVED 0x3c /* reserved */
/* PORT_IRQ_{STAT,MASK} bits */
-#define PORT_IRQ_COLD_PRES (1 << 31) /* cold presence detect */
+#define PORT_IRQ_COLD_PRES (1U << 31) /* cold presence detect */
#define PORT_IRQ_TF_ERR (1 << 30) /* task file error */
#define PORT_IRQ_HBUS_ERR (1 << 29) /* host bus fatal error */
#define PORT_IRQ_HBUS_DATA_ERR (1 << 28) /* host bus data error */
@@ -151,7 +151,7 @@
#define PORT_IRQ_STAT_HBDS (1 << 28) /* Host Bus Data Error Status */
#define PORT_IRQ_STAT_HBFS (1 << 29) /* Host Bus Fatal Error Status */
#define PORT_IRQ_STAT_TFES (1 << 30) /* Task File Error Status */
-#define PORT_IRQ_STAT_CPDS (1 << 31) /* Code Port Detect Status */
+#define PORT_IRQ_STAT_CPDS (1U << 31) /* Code Port Detect Status */
/* ap->flags bits */
#define AHCI_FLAG_NO_NCQ (1 << 24)
diff --git a/qemu-img.c b/qemu-img.c
index 886db881b3..2e40cc1e69 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -1162,9 +1162,6 @@ static int img_convert(int argc, char **argv)
Error *local_err = NULL;
QemuOpts *sn_opts = NULL;
- /* Initialize before goto out */
- qemu_progress_init(progress, 1.0);
-
fmt = NULL;
out_fmt = "raw";
cache = "unsafe";
@@ -1197,17 +1194,17 @@ static int img_convert(int argc, char **argv)
error_report("option -e is deprecated, please use \'-o "
"encryption\' instead!");
ret = -1;
- goto out;
+ goto fail_getopt;
case '6':
error_report("option -6 is deprecated, please use \'-o "
"compat6\' instead!");
ret = -1;
- goto out;
+ goto fail_getopt;
case 'o':
if (!is_valid_option_list(optarg)) {
error_report("Invalid option list: %s", optarg);
ret = -1;
- goto out;
+ goto fail_getopt;
}
if (!options) {
options = g_strdup(optarg);
@@ -1227,7 +1224,7 @@ static int img_convert(int argc, char **argv)
error_report("Failed in parsing snapshot param '%s'",
optarg);
ret = -1;
- goto out;
+ goto fail_getopt;
}
} else {
snapshot_name = optarg;
@@ -1241,7 +1238,7 @@ static int img_convert(int argc, char **argv)
if (sval < 0 || *end) {
error_report("Invalid minimum zero buffer size for sparse output specified");
ret = -1;
- goto out;
+ goto fail_getopt;
}
min_sparse = sval / BDRV_SECTOR_SIZE;
@@ -1262,9 +1259,12 @@ static int img_convert(int argc, char **argv)
}
}
+ /* Initialize before goto out */
if (quiet) {
progress = 0;
}
+ qemu_progress_init(progress, 1.0);
+
bs_n = argc - optind - 1;
out_filename = bs_n >= 1 ? argv[argc - 1] : NULL;
@@ -1667,7 +1667,6 @@ out:
free_option_parameters(create_options);
free_option_parameters(param);
qemu_vfree(buf);
- g_free(options);
if (sn_opts) {
qemu_opts_del(sn_opts);
}
@@ -1682,6 +1681,9 @@ out:
}
g_free(bs);
}
+fail_getopt:
+ g_free(options);
+
if (ret) {
return 1;
}
diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051
index 46345fb155..14694e176b 100755
--- a/tests/qemu-iotests/051
+++ b/tests/qemu-iotests/051
@@ -78,6 +78,15 @@ run_qemu -drive file="$TEST_IMG",format=qcow2,unknown_opt=1234
run_qemu -drive file="$TEST_IMG",format=qcow2,unknown_opt=foo
echo
+echo === Unknown protocol option ===
+echo
+
+run_qemu -drive file="$TEST_IMG",format=qcow2,file.unknown_opt=
+run_qemu -drive file="$TEST_IMG",format=qcow2,file.unknown_opt=on
+run_qemu -drive file="$TEST_IMG",format=qcow2,file.unknown_opt=1234
+run_qemu -drive file="$TEST_IMG",format=qcow2,file.unknown_opt=foo
+
+echo
echo === Invalid format ===
echo
diff --git a/tests/qemu-iotests/051.out b/tests/qemu-iotests/051.out
index 7de18704f8..f5e33ff395 100644
--- a/tests/qemu-iotests/051.out
+++ b/tests/qemu-iotests/051.out
@@ -17,6 +17,21 @@ 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: could not open disk image TEST_DIR/t.qcow2: 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=: could not open disk image TEST_DIR/t.qcow2: 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: could not open disk image TEST_DIR/t.qcow2: 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: could not open disk image TEST_DIR/t.qcow2: 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: could not open disk image TEST_DIR/t.qcow2: Block protocol 'file' doesn't support the option 'unknown_opt'
+
+
=== Invalid format ===
Testing: -drive file=TEST_DIR/t.qcow2,format=foo
diff --git a/tests/qemu-iotests/085 b/tests/qemu-iotests/085
new file mode 100755
index 0000000000..33c8dc410a
--- /dev/null
+++ b/tests/qemu-iotests/085
@@ -0,0 +1,192 @@
+#!/bin/bash
+#
+# Live snapshot tests
+#
+# This tests live snapshots of images on a running QEMU instance, using
+# QMP commands. Both single disk snapshots, and transactional group
+# snapshots are performed.
+#
+# Copyright (C) 2014 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=jcody@redhat.com
+
+seq=`basename $0`
+echo "QA output created by $seq"
+
+here=`pwd`
+status=1 # failure is the default!
+qemu_pid=
+
+QMP_IN="${TEST_DIR}/qmp-in-$$"
+QMP_OUT="${TEST_DIR}/qmp-out-$$"
+
+snapshot_virt0="snapshot-v0.qcow2"
+snapshot_virt1="snapshot-v1.qcow2"
+
+MAX_SNAPSHOTS=10
+
+_cleanup()
+{
+ kill -KILL ${qemu_pid}
+ wait ${qemu_pid} 2>/dev/null # silent kill
+
+ rm -f "${QMP_IN}" "${QMP_OUT}"
+ for i in $(seq 1 ${MAX_SNAPSHOTS})
+ do
+ rm -f "${TEST_DIR}/${i}-${snapshot_virt0}"
+ rm -f "${TEST_DIR}/${i}-${snapshot_virt1}"
+ done
+ _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
+
+# Wait for expected QMP response from QEMU. Will time out
+# after 10 seconds, which counts as failure.
+#
+# $1 is the string to expect
+#
+# If $silent is set to anything but an empty string, then
+# response is not echoed out.
+function timed_wait_for()
+{
+ while read -t 10 resp <&5
+ do
+ if [ "${silent}" == "" ]; then
+ echo "${resp}" | _filter_testdir | _filter_qemu
+ fi
+ grep -q "${1}" < <(echo ${resp})
+ if [ $? -eq 0 ]; then
+ return
+ fi
+ done
+ echo "Timeout waiting for ${1}"
+ exit 1 # Timeout means the test failed
+}
+
+# Sends QMP command to QEMU, and waits for the expected response
+#
+# ${1}: String of the QMP command to send
+# ${2}: String that the QEMU response should contain
+function send_qmp_cmd()
+{
+ echo "${1}" >&6
+ timed_wait_for "${2}"
+}
+
+# ${1}: unique identifier for the snapshot filename
+function create_single_snapshot()
+{
+ cmd="{ 'execute': 'blockdev-snapshot-sync',
+ 'arguments': { 'device': 'virtio0',
+ 'snapshot-file':'"${TEST_DIR}/${1}-${snapshot_virt0}"',
+ 'format': 'qcow2' } }"
+ send_qmp_cmd "${cmd}" "return"
+}
+
+# ${1}: unique identifier for the snapshot filename
+function create_group_snapshot()
+{
+ cmd="{ 'execute': 'transaction', 'arguments':
+ {'actions': [
+ { 'type': 'blockdev-snapshot-sync', 'data' :
+ { 'device': 'virtio0',
+ 'snapshot-file': '"${TEST_DIR}/${1}-${snapshot_virt0}"' } },
+ { 'type': 'blockdev-snapshot-sync', 'data' :
+ { 'device': 'virtio1',
+ 'snapshot-file': '"${TEST_DIR}/${1}-${snapshot_virt1}"' } } ]
+ } }"
+
+ send_qmp_cmd "${cmd}" "return"
+}
+
+size=128M
+
+mkfifo "${QMP_IN}"
+mkfifo "${QMP_OUT}"
+
+_make_test_img $size
+mv "${TEST_IMG}" "${TEST_IMG}.orig"
+_make_test_img $size
+
+echo
+echo === Running QEMU ===
+echo
+
+"${QEMU}" -nographic -monitor none -serial none -qmp stdio\
+ -drive file="${TEST_IMG}.orig",if=virtio\
+ -drive file="${TEST_IMG}",if=virtio 2>&1 >"${QMP_OUT}" <"${QMP_IN}"&
+qemu_pid=$!
+
+# redirect fifos to file descriptors, to keep from blocking
+exec 5<"${QMP_OUT}"
+exec 6>"${QMP_IN}"
+
+# Don't print response, since it has version information in it
+silent=yes timed_wait_for "capabilities"
+
+echo
+echo === Sending capabilities ===
+echo
+
+send_qmp_cmd "{ 'execute': 'qmp_capabilities' }" "return"
+
+echo
+echo === Create a single snapshot on virtio0 ===
+echo
+
+create_single_snapshot 1
+
+
+echo
+echo === Invalid command - missing device and nodename ===
+echo
+
+send_qmp_cmd "{ 'execute': 'blockdev-snapshot-sync',
+ 'arguments': { 'snapshot-file':'"${TEST_DIR}"/1-${snapshot_virt0}',
+ 'format': 'qcow2' } }" "error"
+
+echo
+echo === Invalid command - missing snapshot-file ===
+echo
+
+send_qmp_cmd "{ 'execute': 'blockdev-snapshot-sync',
+ 'arguments': { 'device': 'virtio0',
+ 'format': 'qcow2' } }" "error"
+echo
+echo
+echo === Create several transactional group snapshots ===
+echo
+
+for i in $(seq 2 ${MAX_SNAPSHOTS})
+do
+ create_group_snapshot ${i}
+done
+
+# success, all done
+echo "*** done"
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/085.out b/tests/qemu-iotests/085.out
new file mode 100644
index 0000000000..0f2b17f99e
--- /dev/null
+++ b/tests/qemu-iotests/085.out
@@ -0,0 +1,55 @@
+QA output created by 085
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
+
+=== Running QEMU ===
+
+
+=== Sending capabilities ===
+
+{"return": {}}
+
+=== Create a single snapshot on virtio0 ===
+
+Formatting 'TEST_DIR/1-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/t.qcow2.orig' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off
+{"return": {}}
+
+=== Invalid command - missing device and nodename ===
+
+{"error": {"class": "GenericError", "desc": "Cannot find device= nor node_name="}}
+
+=== Invalid command - missing snapshot-file ===
+
+{"error": {"class": "GenericError", "desc": "Parameter 'snapshot-file' is missing"}}
+
+
+=== Create several transactional group snapshots ===
+
+Formatting 'TEST_DIR/2-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/1-snapshot-v0.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/2-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/t.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off
+{"return": {}}
+Formatting 'TEST_DIR/3-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/2-snapshot-v0.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/3-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/2-snapshot-v1.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off
+{"return": {}}
+Formatting 'TEST_DIR/4-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/3-snapshot-v0.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/4-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/3-snapshot-v1.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off
+{"return": {}}
+Formatting 'TEST_DIR/5-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/4-snapshot-v0.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/5-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/4-snapshot-v1.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off
+{"return": {}}
+Formatting 'TEST_DIR/6-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/5-snapshot-v0.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/6-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/5-snapshot-v1.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off
+{"return": {}}
+Formatting 'TEST_DIR/7-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/6-snapshot-v0.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/7-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/6-snapshot-v1.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off
+{"return": {}}
+Formatting 'TEST_DIR/8-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/7-snapshot-v0.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/8-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/7-snapshot-v1.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off
+{"return": {}}
+Formatting 'TEST_DIR/9-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/8-snapshot-v0.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/9-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/8-snapshot-v1.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off
+{"return": {}}
+Formatting 'TEST_DIR/10-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/9-snapshot-v0.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/10-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/9-snapshot-v1.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off
+{"return": {}}
+*** done
diff --git a/tests/qemu-iotests/086 b/tests/qemu-iotests/086
new file mode 100755
index 0000000000..48fe85bc43
--- /dev/null
+++ b/tests/qemu-iotests/086
@@ -0,0 +1,65 @@
+#!/bin/bash
+#
+# Test qemu-img progress output
+#
+# Copyright (C) 2014 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
+
+function run_qemu_img()
+{
+ echo
+ echo Testing: "$@" | _filter_testdir
+}
+
+size=128M
+
+_make_test_img $size
+$QEMU_IO -c 'write 0 1M' $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c 'write 2M 1M' $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c 'write 4M 1M' $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c 'write 32M 1M' $TEST_IMG | _filter_qemu_io
+
+$QEMU_IMG convert -p -O $IMGFMT -f $IMGFMT "$TEST_IMG" "$TEST_IMG".base 2>&1 |\
+ _filter_testdir | sed -e 's/\r/\n/g'
+
+# success, all done
+echo "*** done"
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/086.out b/tests/qemu-iotests/086.out
new file mode 100644
index 0000000000..9c0bf23718
--- /dev/null
+++ b/tests/qemu-iotests/086.out
@@ -0,0 +1,18 @@
+QA output created by 086
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
+wrote 1048576/1048576 bytes at offset 0
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 1048576/1048576 bytes at offset 2097152
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 1048576/1048576 bytes at offset 4194304
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 1048576/1048576 bytes at offset 33554432
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+ (0.00/100%)
+ (25.00/100%)
+ (50.00/100%)
+ (75.00/100%)
+ (100.00/100%)
+ (100.00/100%)
+
+*** done
diff --git a/tests/qemu-iotests/087 b/tests/qemu-iotests/087
new file mode 100755
index 0000000000..53b6c43bff
--- /dev/null
+++ b/tests/qemu-iotests/087
@@ -0,0 +1,122 @@
+#!/bin/bash
+#
+# Test unsupported blockdev-add cases
+#
+# Copyright (C) 2014 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!
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+
+_supported_fmt qcow2
+_supported_proto file
+_supported_os Linux
+
+function do_run_qemu()
+{
+ echo Testing: "$@"
+ $QEMU -nographic -qmp stdio -serial none "$@"
+ echo
+}
+
+function run_qemu()
+{
+ do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp | sed -e 's/\("actual-size":\s*\)[0-9]\+/\1SIZE/g'
+}
+
+size=128M
+
+_make_test_img $size
+
+echo
+echo === Missing ID ===
+echo
+
+run_qemu <<EOF
+{ "execute": "qmp_capabilities" }
+{ "execute": "blockdev-add",
+ "arguments": {
+ "options": {
+ "driver": "$IMGFMT",
+ "file": {
+ "driver": "file",
+ "filename": "$TEST_IMG"
+ }
+ }
+ }
+ }
+{ "execute": "quit" }
+EOF
+
+echo
+echo === aio=native without O_DIRECT ===
+echo
+
+run_qemu <<EOF
+{ "execute": "qmp_capabilities" }
+{ "execute": "blockdev-add",
+ "arguments": {
+ "options": {
+ "driver": "$IMGFMT",
+ "id": "disk",
+ "aio": "native",
+ "file": {
+ "driver": "file",
+ "filename": "$TEST_IMG"
+ }
+ }
+ }
+ }
+{ "execute": "quit" }
+EOF
+
+echo
+echo === Encrypted image ===
+echo
+
+_make_test_img -o encryption=on $size
+run_qemu <<EOF
+{ "execute": "qmp_capabilities" }
+{ "execute": "blockdev-add",
+ "arguments": {
+ "options": {
+ "driver": "$IMGFMT",
+ "id": "disk",
+ "file": {
+ "driver": "file",
+ "filename": "$TEST_IMG"
+ }
+ }
+ }
+ }
+{ "execute": "quit" }
+EOF
+
+# success, all done
+echo "*** done"
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/087.out b/tests/qemu-iotests/087.out
new file mode 100644
index 0000000000..b87103252e
--- /dev/null
+++ b/tests/qemu-iotests/087.out
@@ -0,0 +1,40 @@
+QA output created by 087
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
+
+=== Missing ID ===
+
+Testing:
+QMP_VERSION
+{"return": {}}
+{"error": {"class": "GenericError", "desc": "Block device needs an ID"}}
+{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "floppy0", "tray-open": true}}
+
+
+=== aio=native without O_DIRECT ===
+
+Testing:
+QMP_VERSION
+{"return": {}}
+{"error": {"class": "GenericError", "desc": "aio=native requires cache.direct=true"}}
+{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "floppy0", "tray-open": true}}
+
+
+=== Encrypted image ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on
+Testing:
+QMP_VERSION
+{"return": {}}
+{"error": {"class": "GenericError", "desc": "blockdev-add doesn't support encrypted devices"}}
+{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "floppy0", "tray-open": true}}
+
+*** done
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index 8dd8553035..e96eafdf43 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -85,3 +85,6 @@
079 rw auto
081 rw auto
082 rw auto quick
+085 rw auto quick
+086 rw auto quick
+087 rw auto quick