mirror of https://github.com/xemu-project/xemu.git
Block patches from 2015-10-26 until 2015-11-11.
-----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQEcBAABCAAGBQJWQ2YyAAoJEDuxQgLoOKytN14IAKGIVOI1CfPNpWphrtc55Q0n NEHxu9AeectWxbxHrVbhHqB7wEfIoPdymuiIg8WO3GPrEII2EUHJntBy0LyIxJUC wj3waAsIs4bJPdkGBxFoqMkmXo+wKUFivh1aVx7pZwd0b3yjfgTZ117i3aHCBIEl hvAoLdTp/tqRQcBvPu+/jnl2mSquf6IJg8Yhg409HFUrNcQ4bg2+gOQgrSuAKle8 1Jp73umA2509/FOB3J1QT0GZnX9+rbjoWxXbGyPucb26x6ep3KDEbMy5lMAv0+W2 Zoi4YfjPiPFTswkuNvqu2zpzJz1q7WNCP3V5/Yn/2q9KXNicTfsWQWs+T/hoByw= =FKUB -----END PGP SIGNATURE----- Merge remote-tracking branch 'mreitz/tags/pull-block-for-kevin-2015-11-11' into queue-block Block patches from 2015-10-26 until 2015-11-11. # gpg: Signature made Wed Nov 11 17:00:50 2015 CET using RSA key ID E838ACAD # gpg: Good signature from "Max Reitz <mreitz@redhat.com>" * mreitz/tags/pull-block-for-kevin-2015-11-11: iotests: Check for quorum support in test 139 qcow2: Fix qcow2_get_cluster_offset() for zero clusters iotests: Add tests for the x-blockdev-del command block: Add 'x-blockdev-del' QMP command block: Add blk_get_refcnt() mirror: block all operations on the target image during the job qemu-iotests: fix -valgrind option for check qemu-iotests: fix cleanup of background processes Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
commit
4d07c720f4
|
@ -189,6 +189,11 @@ static void drive_info_del(DriveInfo *dinfo)
|
|||
g_free(dinfo);
|
||||
}
|
||||
|
||||
int blk_get_refcnt(BlockBackend *blk)
|
||||
{
|
||||
return blk ? blk->refcnt : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Increment @blk's reference count.
|
||||
* @blk must not be null.
|
||||
|
|
|
@ -384,6 +384,7 @@ static void mirror_exit(BlockJob *job, void *opaque)
|
|||
aio_context_release(replace_aio_context);
|
||||
}
|
||||
g_free(s->replaces);
|
||||
bdrv_op_unblock_all(s->target, s->common.blocker);
|
||||
bdrv_unref(s->target);
|
||||
block_job_completed(&s->common, data->ret);
|
||||
g_free(data);
|
||||
|
@ -744,6 +745,9 @@ static void mirror_start_job(BlockDriverState *bs, BlockDriverState *target,
|
|||
block_job_release(bs);
|
||||
return;
|
||||
}
|
||||
|
||||
bdrv_op_block_all(s->target, s->common.blocker);
|
||||
|
||||
bdrv_set_enable_write_cache(s->target, true);
|
||||
if (s->target->blk) {
|
||||
blk_set_on_error(s->target->blk, on_target_error, on_target_error);
|
||||
|
|
|
@ -312,7 +312,7 @@ static int count_contiguous_clusters(int nb_clusters, int cluster_size,
|
|||
if (!offset)
|
||||
return 0;
|
||||
|
||||
assert(qcow2_get_cluster_type(first_entry) != QCOW2_CLUSTER_COMPRESSED);
|
||||
assert(qcow2_get_cluster_type(first_entry) == QCOW2_CLUSTER_NORMAL);
|
||||
|
||||
for (i = 0; i < nb_clusters; i++) {
|
||||
uint64_t l2_entry = be64_to_cpu(l2_table[i]) & mask;
|
||||
|
@ -324,14 +324,16 @@ static int count_contiguous_clusters(int nb_clusters, int cluster_size,
|
|||
return i;
|
||||
}
|
||||
|
||||
static int count_contiguous_free_clusters(int nb_clusters, uint64_t *l2_table)
|
||||
static int count_contiguous_clusters_by_type(int nb_clusters,
|
||||
uint64_t *l2_table,
|
||||
int wanted_type)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < nb_clusters; i++) {
|
||||
int type = qcow2_get_cluster_type(be64_to_cpu(l2_table[i]));
|
||||
|
||||
if (type != QCOW2_CLUSTER_UNALLOCATED) {
|
||||
if (type != wanted_type) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -554,13 +556,14 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
|||
ret = -EIO;
|
||||
goto fail;
|
||||
}
|
||||
c = count_contiguous_clusters(nb_clusters, s->cluster_size,
|
||||
&l2_table[l2_index], QCOW_OFLAG_ZERO);
|
||||
c = count_contiguous_clusters_by_type(nb_clusters, &l2_table[l2_index],
|
||||
QCOW2_CLUSTER_ZERO);
|
||||
*cluster_offset = 0;
|
||||
break;
|
||||
case QCOW2_CLUSTER_UNALLOCATED:
|
||||
/* how many empty clusters ? */
|
||||
c = count_contiguous_free_clusters(nb_clusters, &l2_table[l2_index]);
|
||||
c = count_contiguous_clusters_by_type(nb_clusters, &l2_table[l2_index],
|
||||
QCOW2_CLUSTER_UNALLOCATED);
|
||||
*cluster_offset = 0;
|
||||
break;
|
||||
case QCOW2_CLUSTER_NORMAL:
|
||||
|
|
66
blockdev.c
66
blockdev.c
|
@ -3479,6 +3479,72 @@ fail:
|
|||
qmp_output_visitor_cleanup(ov);
|
||||
}
|
||||
|
||||
void qmp_x_blockdev_del(bool has_id, const char *id,
|
||||
bool has_node_name, const char *node_name, Error **errp)
|
||||
{
|
||||
AioContext *aio_context;
|
||||
BlockBackend *blk;
|
||||
BlockDriverState *bs;
|
||||
|
||||
if (has_id && has_node_name) {
|
||||
error_setg(errp, "Only one of id and node-name must be specified");
|
||||
return;
|
||||
} else if (!has_id && !has_node_name) {
|
||||
error_setg(errp, "No block device specified");
|
||||
return;
|
||||
}
|
||||
|
||||
if (has_id) {
|
||||
blk = blk_by_name(id);
|
||||
if (!blk) {
|
||||
error_setg(errp, "Cannot find block backend %s", id);
|
||||
return;
|
||||
}
|
||||
if (blk_get_refcnt(blk) > 1) {
|
||||
error_setg(errp, "Block backend %s is in use", id);
|
||||
return;
|
||||
}
|
||||
bs = blk_bs(blk);
|
||||
aio_context = blk_get_aio_context(blk);
|
||||
} else {
|
||||
bs = bdrv_find_node(node_name);
|
||||
if (!bs) {
|
||||
error_setg(errp, "Cannot find node %s", node_name);
|
||||
return;
|
||||
}
|
||||
blk = bs->blk;
|
||||
if (blk) {
|
||||
error_setg(errp, "Node %s is in use by %s",
|
||||
node_name, blk_name(blk));
|
||||
return;
|
||||
}
|
||||
aio_context = bdrv_get_aio_context(bs);
|
||||
}
|
||||
|
||||
aio_context_acquire(aio_context);
|
||||
|
||||
if (bs) {
|
||||
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_DRIVE_DEL, errp)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (bs->refcnt > 1 || !QLIST_EMPTY(&bs->parents)) {
|
||||
error_setg(errp, "Block device %s is in use",
|
||||
bdrv_get_device_or_node_name(bs));
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (blk) {
|
||||
blk_unref(blk);
|
||||
} else {
|
||||
bdrv_unref(bs);
|
||||
}
|
||||
|
||||
out:
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
|
||||
BlockJobInfoList *qmp_query_block_jobs(Error **errp)
|
||||
{
|
||||
BlockJobInfoList *head = NULL, **p_next = &head;
|
||||
|
|
|
@ -65,6 +65,7 @@ BlockBackend *blk_new_with_bs(const char *name, Error **errp);
|
|||
BlockBackend *blk_new_open(const char *name, const char *filename,
|
||||
const char *reference, QDict *options, int flags,
|
||||
Error **errp);
|
||||
int blk_get_refcnt(BlockBackend *blk);
|
||||
void blk_ref(BlockBackend *blk);
|
||||
void blk_unref(BlockBackend *blk);
|
||||
const char *blk_name(BlockBackend *blk);
|
||||
|
|
|
@ -1895,8 +1895,8 @@
|
|||
# level and no BlockBackend will be created.
|
||||
#
|
||||
# This command is still a work in progress. It doesn't support all
|
||||
# block drivers, it lacks a matching blockdev-del, and more. Stay
|
||||
# away from it unless you want to help with its development.
|
||||
# block drivers among other things. Stay away from it unless you want
|
||||
# to help with its development.
|
||||
#
|
||||
# @options: block device options for the new device
|
||||
#
|
||||
|
@ -1904,6 +1904,34 @@
|
|||
##
|
||||
{ 'command': 'blockdev-add', 'data': { 'options': 'BlockdevOptions' } }
|
||||
|
||||
##
|
||||
# @x-blockdev-del:
|
||||
#
|
||||
# Deletes a block device that has been added using blockdev-add.
|
||||
# The selected device can be either a block backend or a graph node.
|
||||
#
|
||||
# In the former case the backend will be destroyed, along with its
|
||||
# inserted medium if there's any. The command will fail if the backend
|
||||
# or its medium are in use.
|
||||
#
|
||||
# In the latter case the node will be destroyed. The command will fail
|
||||
# if the node is attached to a block backend or is otherwise being
|
||||
# used.
|
||||
#
|
||||
# One of @id or @node-name must be specified, but not both.
|
||||
#
|
||||
# This command is still a work in progress and is considered
|
||||
# experimental. Stay away from it unless you want to help with its
|
||||
# development.
|
||||
#
|
||||
# @id: #optional Name of the block backend device to delete.
|
||||
#
|
||||
# @node-name: #optional Name of the graph node to delete.
|
||||
#
|
||||
# Since: 2.5
|
||||
##
|
||||
{ 'command': 'x-blockdev-del', 'data': { '*id': 'str', '*node-name': 'str' } }
|
||||
|
||||
##
|
||||
# @blockdev-open-tray:
|
||||
#
|
||||
|
|
|
@ -3946,8 +3946,8 @@ blockdev-add
|
|||
Add a block device.
|
||||
|
||||
This command is still a work in progress. It doesn't support all
|
||||
block drivers, it lacks a matching blockdev-del, and more. Stay away
|
||||
from it unless you want to help with its development.
|
||||
block drivers among other things. Stay away from it unless you want
|
||||
to help with its development.
|
||||
|
||||
Arguments:
|
||||
|
||||
|
@ -3990,6 +3990,63 @@ Example (2):
|
|||
|
||||
<- { "return": {} }
|
||||
|
||||
EQMP
|
||||
|
||||
{
|
||||
.name = "x-blockdev-del",
|
||||
.args_type = "id:s?,node-name:s?",
|
||||
.mhandler.cmd_new = qmp_marshal_x_blockdev_del,
|
||||
},
|
||||
|
||||
SQMP
|
||||
x-blockdev-del
|
||||
------------
|
||||
Since 2.5
|
||||
|
||||
Deletes a block device thas has been added using blockdev-add.
|
||||
The selected device can be either a block backend or a graph node.
|
||||
|
||||
In the former case the backend will be destroyed, along with its
|
||||
inserted medium if there's any. The command will fail if the backend
|
||||
or its medium are in use.
|
||||
|
||||
In the latter case the node will be destroyed. The command will fail
|
||||
if the node is attached to a block backend or is otherwise being
|
||||
used.
|
||||
|
||||
One of "id" or "node-name" must be specified, but not both.
|
||||
|
||||
This command is still a work in progress and is considered
|
||||
experimental. Stay away from it unless you want to help with its
|
||||
development.
|
||||
|
||||
Arguments:
|
||||
|
||||
- "id": Name of the block backend device to delete (json-string, optional)
|
||||
- "node-name": Name of the graph node to delete (json-string, optional)
|
||||
|
||||
Example:
|
||||
|
||||
-> { "execute": "blockdev-add",
|
||||
"arguments": {
|
||||
"options": {
|
||||
"driver": "qcow2",
|
||||
"id": "drive0",
|
||||
"file": {
|
||||
"driver": "file",
|
||||
"filename": "test.qcow2"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
<- { "return": {} }
|
||||
|
||||
-> { "execute": "x-blockdev-del",
|
||||
"arguments": { "id": "drive0" }
|
||||
}
|
||||
<- { "return": {} }
|
||||
|
||||
EQMP
|
||||
|
||||
{
|
||||
|
|
|
@ -11,7 +11,11 @@ No errors were found on the image.
|
|||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
|
||||
wrote 512/512 bytes at offset 0
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
./common.config: Killed ( exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@" )
|
||||
./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
|
||||
exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@";
|
||||
else
|
||||
exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@";
|
||||
fi )
|
||||
incompatible_features 0x1
|
||||
ERROR cluster 5 refcount=0 reference=1
|
||||
ERROR OFLAG_COPIED data cluster: l2_entry=8000000000050000 refcount=0
|
||||
|
@ -46,7 +50,11 @@ read 512/512 bytes at offset 0
|
|||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
|
||||
wrote 512/512 bytes at offset 0
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
./common.config: Killed ( exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@" )
|
||||
./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
|
||||
exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@";
|
||||
else
|
||||
exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@";
|
||||
fi )
|
||||
incompatible_features 0x1
|
||||
ERROR cluster 5 refcount=0 reference=1
|
||||
Rebuilding refcount structure
|
||||
|
@ -60,7 +68,11 @@ incompatible_features 0x0
|
|||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
|
||||
wrote 512/512 bytes at offset 0
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
./common.config: Killed ( exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@" )
|
||||
./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
|
||||
exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@";
|
||||
else
|
||||
exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@";
|
||||
fi )
|
||||
incompatible_features 0x0
|
||||
No errors were found on the image.
|
||||
|
||||
|
@ -79,7 +91,11 @@ No errors were found on the image.
|
|||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
|
||||
wrote 512/512 bytes at offset 0
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
./common.config: Killed ( exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@" )
|
||||
./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
|
||||
exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@";
|
||||
else
|
||||
exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@";
|
||||
fi )
|
||||
incompatible_features 0x1
|
||||
ERROR cluster 5 refcount=0 reference=1
|
||||
ERROR OFLAG_COPIED data cluster: l2_entry=8000000000050000 refcount=0
|
||||
|
@ -89,7 +105,11 @@ Data may be corrupted, or further writes to the image may corrupt it.
|
|||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
|
||||
wrote 512/512 bytes at offset 0
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
./common.config: Killed ( exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@" )
|
||||
./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
|
||||
exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@";
|
||||
else
|
||||
exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@";
|
||||
fi )
|
||||
incompatible_features 0x0
|
||||
No errors were found on the image.
|
||||
*** done
|
||||
|
|
|
@ -32,11 +32,17 @@ status=1 # failure is the default!
|
|||
|
||||
nbd_unix_socket=$TEST_DIR/test_qemu_nbd_socket
|
||||
nbd_snapshot_img="nbd:unix:$nbd_unix_socket"
|
||||
rm -f "${TEST_DIR}/qemu-nbd.pid"
|
||||
|
||||
_cleanup_nbd()
|
||||
{
|
||||
if [ -n "$NBD_SNAPSHOT_PID" ]; then
|
||||
kill "$NBD_SNAPSHOT_PID"
|
||||
local NBD_SNAPSHOT_PID
|
||||
if [ -f "${TEST_DIR}/qemu-nbd.pid" ]; then
|
||||
read NBD_SNAPSHOT_PID < "${TEST_DIR}/qemu-nbd.pid"
|
||||
rm -f "${TEST_DIR}/qemu-nbd.pid"
|
||||
if [ -n "$NBD_SNAPSHOT_PID" ]; then
|
||||
kill "$NBD_SNAPSHOT_PID"
|
||||
fi
|
||||
fi
|
||||
rm -f "$nbd_unix_socket"
|
||||
}
|
||||
|
@ -60,7 +66,6 @@ _export_nbd_snapshot()
|
|||
{
|
||||
_cleanup_nbd
|
||||
$QEMU_NBD -v -t -k "$nbd_unix_socket" "$TEST_IMG" -l $1 &
|
||||
NBD_SNAPSHOT_PID=$!
|
||||
_wait_for_nbd
|
||||
}
|
||||
|
||||
|
@ -68,7 +73,6 @@ _export_nbd_snapshot1()
|
|||
{
|
||||
_cleanup_nbd
|
||||
$QEMU_NBD -v -t -k "$nbd_unix_socket" "$TEST_IMG" -l snapshot.name=$1 &
|
||||
NBD_SNAPSHOT_PID=$!
|
||||
_wait_for_nbd
|
||||
}
|
||||
|
||||
|
|
|
@ -57,7 +57,11 @@ No errors were found on the image.
|
|||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
|
||||
wrote 131072/131072 bytes at offset 0
|
||||
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
./common.config: Killed ( exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@" )
|
||||
./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
|
||||
exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@";
|
||||
else
|
||||
exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@";
|
||||
fi )
|
||||
magic 0x514649fb
|
||||
version 3
|
||||
backing_file_offset 0x0
|
||||
|
@ -215,7 +219,11 @@ No errors were found on the image.
|
|||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
|
||||
wrote 131072/131072 bytes at offset 0
|
||||
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
./common.config: Killed ( exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@" )
|
||||
./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
|
||||
exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@";
|
||||
else
|
||||
exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@";
|
||||
fi )
|
||||
magic 0x514649fb
|
||||
version 3
|
||||
backing_file_offset 0x0
|
||||
|
|
|
@ -31,7 +31,11 @@ Cache clean interval too big
|
|||
Unsupported value 'blubb' for qcow2 option 'overlap-check'. Allowed are any of the following: none, constant, cached, all
|
||||
wrote 512/512 bytes at offset 0
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
./common.config: Killed ( exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@" )
|
||||
./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
|
||||
exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@";
|
||||
else
|
||||
exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@";
|
||||
fi )
|
||||
incompatible_features 0x0
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
|
||||
wrote 65536/65536 bytes at offset 0
|
||||
|
|
|
@ -0,0 +1,416 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# Test cases for the QMP 'x-blockdev-del' command
|
||||
#
|
||||
# Copyright (C) 2015 Igalia, S.L.
|
||||
# Author: Alberto Garcia <berto@igalia.com>
|
||||
#
|
||||
# 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/>.
|
||||
#
|
||||
|
||||
import os
|
||||
import iotests
|
||||
import time
|
||||
|
||||
base_img = os.path.join(iotests.test_dir, 'base.img')
|
||||
new_img = os.path.join(iotests.test_dir, 'new.img')
|
||||
|
||||
class TestBlockdevDel(iotests.QMPTestCase):
|
||||
|
||||
def setUp(self):
|
||||
iotests.qemu_img('create', '-f', iotests.imgfmt, base_img, '1M')
|
||||
self.vm = iotests.VM()
|
||||
self.vm.launch()
|
||||
|
||||
def tearDown(self):
|
||||
self.vm.shutdown()
|
||||
os.remove(base_img)
|
||||
if os.path.isfile(new_img):
|
||||
os.remove(new_img)
|
||||
|
||||
# Check whether a BlockBackend exists
|
||||
def checkBlockBackend(self, backend, node, must_exist = True):
|
||||
result = self.vm.qmp('query-block')
|
||||
backends = filter(lambda x: x['device'] == backend, result['return'])
|
||||
self.assertLessEqual(len(backends), 1)
|
||||
self.assertEqual(must_exist, len(backends) == 1)
|
||||
if must_exist:
|
||||
if node:
|
||||
self.assertEqual(backends[0]['inserted']['node-name'], node)
|
||||
else:
|
||||
self.assertFalse(backends[0].has_key('inserted'))
|
||||
|
||||
# Check whether a BlockDriverState exists
|
||||
def checkBlockDriverState(self, node, must_exist = True):
|
||||
result = self.vm.qmp('query-named-block-nodes')
|
||||
nodes = filter(lambda x: x['node-name'] == node, result['return'])
|
||||
self.assertLessEqual(len(nodes), 1)
|
||||
self.assertEqual(must_exist, len(nodes) == 1)
|
||||
|
||||
# Add a new BlockBackend (with its attached BlockDriverState)
|
||||
def addBlockBackend(self, backend, node):
|
||||
file_node = '%s_file' % node
|
||||
self.checkBlockBackend(backend, node, False)
|
||||
self.checkBlockDriverState(node, False)
|
||||
self.checkBlockDriverState(file_node, False)
|
||||
opts = {'driver': iotests.imgfmt,
|
||||
'id': backend,
|
||||
'node-name': node,
|
||||
'file': {'driver': 'file',
|
||||
'node-name': file_node,
|
||||
'filename': base_img}}
|
||||
result = self.vm.qmp('blockdev-add', conv_keys = False, options = opts)
|
||||
self.assert_qmp(result, 'return', {})
|
||||
self.checkBlockBackend(backend, node)
|
||||
self.checkBlockDriverState(node)
|
||||
self.checkBlockDriverState(file_node)
|
||||
|
||||
# Add a BlockDriverState without a BlockBackend
|
||||
def addBlockDriverState(self, node):
|
||||
file_node = '%s_file' % node
|
||||
self.checkBlockDriverState(node, False)
|
||||
self.checkBlockDriverState(file_node, False)
|
||||
opts = {'driver': iotests.imgfmt,
|
||||
'node-name': node,
|
||||
'file': {'driver': 'file',
|
||||
'node-name': file_node,
|
||||
'filename': base_img}}
|
||||
result = self.vm.qmp('blockdev-add', conv_keys = False, options = opts)
|
||||
self.assert_qmp(result, 'return', {})
|
||||
self.checkBlockDriverState(node)
|
||||
self.checkBlockDriverState(file_node)
|
||||
|
||||
# Add a BlockDriverState that will be used as overlay for the base_img BDS
|
||||
def addBlockDriverStateOverlay(self, node):
|
||||
self.checkBlockDriverState(node, False)
|
||||
iotests.qemu_img('create', '-f', iotests.imgfmt,
|
||||
'-b', base_img, new_img, '1M')
|
||||
opts = {'driver': iotests.imgfmt,
|
||||
'node-name': node,
|
||||
'backing': '',
|
||||
'file': {'driver': 'file',
|
||||
'filename': new_img}}
|
||||
result = self.vm.qmp('blockdev-add', conv_keys = False, options = opts)
|
||||
self.assert_qmp(result, 'return', {})
|
||||
self.checkBlockDriverState(node)
|
||||
|
||||
# Delete a BlockBackend
|
||||
def delBlockBackend(self, backend, node, expect_error = False,
|
||||
destroys_media = True):
|
||||
self.checkBlockBackend(backend, node)
|
||||
if node:
|
||||
self.checkBlockDriverState(node)
|
||||
result = self.vm.qmp('x-blockdev-del', id = backend)
|
||||
if expect_error:
|
||||
self.assert_qmp(result, 'error/class', 'GenericError')
|
||||
if node:
|
||||
self.checkBlockDriverState(node)
|
||||
else:
|
||||
self.assert_qmp(result, 'return', {})
|
||||
if node:
|
||||
self.checkBlockDriverState(node, not destroys_media)
|
||||
self.checkBlockBackend(backend, node, must_exist = expect_error)
|
||||
|
||||
# Delete a BlockDriverState
|
||||
def delBlockDriverState(self, node, expect_error = False):
|
||||
self.checkBlockDriverState(node)
|
||||
result = self.vm.qmp('x-blockdev-del', node_name = node)
|
||||
if expect_error:
|
||||
self.assert_qmp(result, 'error/class', 'GenericError')
|
||||
else:
|
||||
self.assert_qmp(result, 'return', {})
|
||||
self.checkBlockDriverState(node, expect_error)
|
||||
|
||||
# Add a device model
|
||||
def addDeviceModel(self, device, backend):
|
||||
result = self.vm.qmp('device_add', id = device,
|
||||
driver = 'virtio-blk-pci', drive = backend)
|
||||
self.assert_qmp(result, 'return', {})
|
||||
|
||||
# Delete a device model
|
||||
def delDeviceModel(self, device):
|
||||
result = self.vm.qmp('device_del', id = device)
|
||||
self.assert_qmp(result, 'return', {})
|
||||
|
||||
result = self.vm.qmp('system_reset')
|
||||
self.assert_qmp(result, 'return', {})
|
||||
|
||||
device_path = '/machine/peripheral/%s/virtio-backend' % device
|
||||
event = self.vm.event_wait(name="DEVICE_DELETED",
|
||||
match={'data': {'path': device_path}})
|
||||
self.assertNotEqual(event, None)
|
||||
|
||||
event = self.vm.event_wait(name="DEVICE_DELETED",
|
||||
match={'data': {'device': device}})
|
||||
self.assertNotEqual(event, None)
|
||||
|
||||
# Remove a BlockDriverState
|
||||
def ejectDrive(self, backend, node, expect_error = False,
|
||||
destroys_media = True):
|
||||
self.checkBlockBackend(backend, node)
|
||||
self.checkBlockDriverState(node)
|
||||
result = self.vm.qmp('eject', device = backend)
|
||||
if expect_error:
|
||||
self.assert_qmp(result, 'error/class', 'GenericError')
|
||||
self.checkBlockDriverState(node)
|
||||
self.checkBlockBackend(backend, node)
|
||||
else:
|
||||
self.assert_qmp(result, 'return', {})
|
||||
self.checkBlockDriverState(node, not destroys_media)
|
||||
self.checkBlockBackend(backend, None)
|
||||
|
||||
# Insert a BlockDriverState
|
||||
def insertDrive(self, backend, node):
|
||||
self.checkBlockBackend(backend, None)
|
||||
self.checkBlockDriverState(node)
|
||||
result = self.vm.qmp('blockdev-insert-medium',
|
||||
device = backend, node_name = node)
|
||||
self.assert_qmp(result, 'return', {})
|
||||
self.checkBlockBackend(backend, node)
|
||||
self.checkBlockDriverState(node)
|
||||
|
||||
# Create a snapshot using 'blockdev-snapshot-sync'
|
||||
def createSnapshotSync(self, node, overlay):
|
||||
self.checkBlockDriverState(node)
|
||||
self.checkBlockDriverState(overlay, False)
|
||||
opts = {'node-name': node,
|
||||
'snapshot-file': new_img,
|
||||
'snapshot-node-name': overlay,
|
||||
'format': iotests.imgfmt}
|
||||
result = self.vm.qmp('blockdev-snapshot-sync', conv_keys=False, **opts)
|
||||
self.assert_qmp(result, 'return', {})
|
||||
self.checkBlockDriverState(node)
|
||||
self.checkBlockDriverState(overlay)
|
||||
|
||||
# Create a snapshot using 'blockdev-snapshot'
|
||||
def createSnapshot(self, node, overlay):
|
||||
self.checkBlockDriverState(node)
|
||||
self.checkBlockDriverState(overlay)
|
||||
result = self.vm.qmp('blockdev-snapshot',
|
||||
node = node, overlay = overlay)
|
||||
self.assert_qmp(result, 'return', {})
|
||||
self.checkBlockDriverState(node)
|
||||
self.checkBlockDriverState(overlay)
|
||||
|
||||
# Create a mirror
|
||||
def createMirror(self, backend, node, new_node):
|
||||
self.checkBlockBackend(backend, node)
|
||||
self.checkBlockDriverState(new_node, False)
|
||||
opts = {'device': backend,
|
||||
'target': new_img,
|
||||
'node-name': new_node,
|
||||
'sync': 'top',
|
||||
'format': iotests.imgfmt}
|
||||
result = self.vm.qmp('drive-mirror', conv_keys=False, **opts)
|
||||
self.assert_qmp(result, 'return', {})
|
||||
self.checkBlockBackend(backend, node)
|
||||
self.checkBlockDriverState(new_node)
|
||||
|
||||
# Complete an existing block job
|
||||
def completeBlockJob(self, backend, node_before, node_after):
|
||||
self.checkBlockBackend(backend, node_before)
|
||||
result = self.vm.qmp('block-job-complete', device=backend)
|
||||
self.assert_qmp(result, 'return', {})
|
||||
self.wait_until_completed(backend)
|
||||
self.checkBlockBackend(backend, node_after)
|
||||
|
||||
# Add a BlkDebug node
|
||||
# Note that the purpose of this is to test the x-blockdev-del
|
||||
# sanity checks, not to create a usable blkdebug drive
|
||||
def addBlkDebug(self, debug, node):
|
||||
self.checkBlockDriverState(node, False)
|
||||
self.checkBlockDriverState(debug, False)
|
||||
image = {'driver': iotests.imgfmt,
|
||||
'node-name': node,
|
||||
'file': {'driver': 'file',
|
||||
'filename': base_img}}
|
||||
opts = {'driver': 'blkdebug',
|
||||
'node-name': debug,
|
||||
'image': image}
|
||||
result = self.vm.qmp('blockdev-add', conv_keys = False, options = opts)
|
||||
self.assert_qmp(result, 'return', {})
|
||||
self.checkBlockDriverState(node)
|
||||
self.checkBlockDriverState(debug)
|
||||
|
||||
# Add a BlkVerify node
|
||||
# Note that the purpose of this is to test the x-blockdev-del
|
||||
# sanity checks, not to create a usable blkverify drive
|
||||
def addBlkVerify(self, blkverify, test, raw):
|
||||
self.checkBlockDriverState(test, False)
|
||||
self.checkBlockDriverState(raw, False)
|
||||
self.checkBlockDriverState(blkverify, False)
|
||||
iotests.qemu_img('create', '-f', iotests.imgfmt, new_img, '1M')
|
||||
node_0 = {'driver': iotests.imgfmt,
|
||||
'node-name': test,
|
||||
'file': {'driver': 'file',
|
||||
'filename': base_img}}
|
||||
node_1 = {'driver': iotests.imgfmt,
|
||||
'node-name': raw,
|
||||
'file': {'driver': 'file',
|
||||
'filename': new_img}}
|
||||
opts = {'driver': 'blkverify',
|
||||
'node-name': blkverify,
|
||||
'test': node_0,
|
||||
'raw': node_1}
|
||||
result = self.vm.qmp('blockdev-add', conv_keys = False, options = opts)
|
||||
self.assert_qmp(result, 'return', {})
|
||||
self.checkBlockDriverState(test)
|
||||
self.checkBlockDriverState(raw)
|
||||
self.checkBlockDriverState(blkverify)
|
||||
|
||||
# Add a Quorum node
|
||||
def addQuorum(self, quorum, child0, child1):
|
||||
self.checkBlockDriverState(child0, False)
|
||||
self.checkBlockDriverState(child1, False)
|
||||
self.checkBlockDriverState(quorum, False)
|
||||
iotests.qemu_img('create', '-f', iotests.imgfmt, new_img, '1M')
|
||||
child_0 = {'driver': iotests.imgfmt,
|
||||
'node-name': child0,
|
||||
'file': {'driver': 'file',
|
||||
'filename': base_img}}
|
||||
child_1 = {'driver': iotests.imgfmt,
|
||||
'node-name': child1,
|
||||
'file': {'driver': 'file',
|
||||
'filename': new_img}}
|
||||
opts = {'driver': 'quorum',
|
||||
'node-name': quorum,
|
||||
'vote-threshold': 1,
|
||||
'children': [ child_0, child_1 ]}
|
||||
result = self.vm.qmp('blockdev-add', conv_keys = False, options = opts)
|
||||
self.assert_qmp(result, 'return', {})
|
||||
self.checkBlockDriverState(child0)
|
||||
self.checkBlockDriverState(child1)
|
||||
self.checkBlockDriverState(quorum)
|
||||
|
||||
########################
|
||||
# The tests start here #
|
||||
########################
|
||||
|
||||
def testWrongParameters(self):
|
||||
self.addBlockBackend('drive0', 'node0')
|
||||
result = self.vm.qmp('x-blockdev-del')
|
||||
self.assert_qmp(result, 'error/class', 'GenericError')
|
||||
result = self.vm.qmp('x-blockdev-del', id='drive0', node_name='node0')
|
||||
self.assert_qmp(result, 'error/class', 'GenericError')
|
||||
self.delBlockBackend('drive0', 'node0')
|
||||
|
||||
def testBlockBackend(self):
|
||||
self.addBlockBackend('drive0', 'node0')
|
||||
# You cannot delete a BDS that is attached to a backend
|
||||
self.delBlockDriverState('node0', expect_error = True)
|
||||
self.delBlockBackend('drive0', 'node0')
|
||||
|
||||
def testBlockDriverState(self):
|
||||
self.addBlockDriverState('node0')
|
||||
# You cannot delete a file BDS directly
|
||||
self.delBlockDriverState('node0_file', expect_error = True)
|
||||
self.delBlockDriverState('node0')
|
||||
|
||||
def testEject(self):
|
||||
self.addBlockBackend('drive0', 'node0')
|
||||
self.ejectDrive('drive0', 'node0')
|
||||
self.delBlockBackend('drive0', None)
|
||||
|
||||
def testDeviceModel(self):
|
||||
self.addBlockBackend('drive0', 'node0')
|
||||
self.addDeviceModel('device0', 'drive0')
|
||||
self.ejectDrive('drive0', 'node0', expect_error = True)
|
||||
self.delBlockBackend('drive0', 'node0', expect_error = True)
|
||||
self.delDeviceModel('device0')
|
||||
self.delBlockBackend('drive0', 'node0')
|
||||
|
||||
def testAttachMedia(self):
|
||||
# This creates a BlockBackend and removes its media
|
||||
self.addBlockBackend('drive0', 'node0')
|
||||
self.ejectDrive('drive0', 'node0')
|
||||
# This creates a new BlockDriverState and inserts it into the backend
|
||||
self.addBlockDriverState('node1')
|
||||
self.insertDrive('drive0', 'node1')
|
||||
# The backend can't be removed: the new BDS has an extra reference
|
||||
self.delBlockBackend('drive0', 'node1', expect_error = True)
|
||||
self.delBlockDriverState('node1', expect_error = True)
|
||||
# The BDS still exists after being ejected, but now it can be removed
|
||||
self.ejectDrive('drive0', 'node1', destroys_media = False)
|
||||
self.delBlockDriverState('node1')
|
||||
self.delBlockBackend('drive0', None)
|
||||
|
||||
def testSnapshotSync(self):
|
||||
self.addBlockBackend('drive0', 'node0')
|
||||
self.createSnapshotSync('node0', 'overlay0')
|
||||
# This fails because node0 is now being used as a backing image
|
||||
self.delBlockDriverState('node0', expect_error = True)
|
||||
# This succeeds because overlay0 only has the backend reference
|
||||
self.delBlockBackend('drive0', 'overlay0')
|
||||
self.checkBlockDriverState('node0', False)
|
||||
|
||||
def testSnapshot(self):
|
||||
self.addBlockBackend('drive0', 'node0')
|
||||
self.addBlockDriverStateOverlay('overlay0')
|
||||
self.createSnapshot('node0', 'overlay0')
|
||||
self.delBlockBackend('drive0', 'overlay0', expect_error = True)
|
||||
self.delBlockDriverState('node0', expect_error = True)
|
||||
self.delBlockDriverState('overlay0', expect_error = True)
|
||||
self.ejectDrive('drive0', 'overlay0', destroys_media = False)
|
||||
self.delBlockBackend('drive0', None)
|
||||
self.delBlockDriverState('node0', expect_error = True)
|
||||
self.delBlockDriverState('overlay0')
|
||||
self.checkBlockDriverState('node0', False)
|
||||
|
||||
def testMirror(self):
|
||||
self.addBlockBackend('drive0', 'node0')
|
||||
self.createMirror('drive0', 'node0', 'mirror0')
|
||||
# The block job prevents removing the device
|
||||
self.delBlockBackend('drive0', 'node0', expect_error = True)
|
||||
self.delBlockDriverState('node0', expect_error = True)
|
||||
self.delBlockDriverState('mirror0', expect_error = True)
|
||||
self.wait_ready('drive0')
|
||||
self.completeBlockJob('drive0', 'node0', 'mirror0')
|
||||
self.assert_no_active_block_jobs()
|
||||
self.checkBlockDriverState('node0', False)
|
||||
# This succeeds because the backend now points to mirror0
|
||||
self.delBlockBackend('drive0', 'mirror0')
|
||||
|
||||
def testBlkDebug(self):
|
||||
self.addBlkDebug('debug0', 'node0')
|
||||
# 'node0' is used by the blkdebug node
|
||||
self.delBlockDriverState('node0', expect_error = True)
|
||||
# But we can remove the blkdebug node directly
|
||||
self.delBlockDriverState('debug0')
|
||||
self.checkBlockDriverState('node0', False)
|
||||
|
||||
def testBlkVerify(self):
|
||||
self.addBlkVerify('verify0', 'node0', 'node1')
|
||||
# We cannot remove the children of a blkverify device
|
||||
self.delBlockDriverState('node0', expect_error = True)
|
||||
self.delBlockDriverState('node1', expect_error = True)
|
||||
# But we can remove the blkverify node directly
|
||||
self.delBlockDriverState('verify0')
|
||||
self.checkBlockDriverState('node0', False)
|
||||
self.checkBlockDriverState('node1', False)
|
||||
|
||||
def testQuorum(self):
|
||||
if not 'quorum' in iotests.qemu_img_pipe('--help'):
|
||||
return
|
||||
self.addQuorum('quorum0', 'node0', 'node1')
|
||||
# We cannot remove the children of a Quorum device
|
||||
self.delBlockDriverState('node0', expect_error = True)
|
||||
self.delBlockDriverState('node1', expect_error = True)
|
||||
# But we can remove the Quorum node directly
|
||||
self.delBlockDriverState('quorum0')
|
||||
self.checkBlockDriverState('node0', False)
|
||||
self.checkBlockDriverState('node1', False)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
iotests.main(supported_fmts=["qcow2"])
|
|
@ -0,0 +1,5 @@
|
|||
............
|
||||
----------------------------------------------------------------------
|
||||
Ran 12 tests
|
||||
|
||||
OK
|
|
@ -41,7 +41,6 @@ sortme=false
|
|||
expunge=true
|
||||
have_test_arg=false
|
||||
randomize=false
|
||||
valgrind=false
|
||||
cachemode=false
|
||||
rm -f $tmp.list $tmp.tmp $tmp.sed
|
||||
|
||||
|
@ -53,6 +52,7 @@ export CACHEMODE="writeback"
|
|||
export QEMU_IO_OPTIONS=""
|
||||
export CACHEMODE_IS_DEFAULT=true
|
||||
export QEMU_OPTIONS="-nodefaults"
|
||||
export VALGRIND_QEMU=
|
||||
|
||||
for r
|
||||
do
|
||||
|
@ -278,7 +278,7 @@ testlist options
|
|||
;;
|
||||
|
||||
-valgrind)
|
||||
valgrind=true
|
||||
VALGRIND_QEMU='y'
|
||||
xpand=false
|
||||
;;
|
||||
|
||||
|
@ -436,8 +436,3 @@ fi
|
|||
if [ "$IMGPROTO" = "nbd" ] ; then
|
||||
[ "$QEMU_NBD" = "" ] && _fatal "qemu-nbd not found"
|
||||
fi
|
||||
|
||||
if $valgrind; then
|
||||
export REAL_QEMU_IO="$QEMU_IO_PROG"
|
||||
export QEMU_IO_PROG=valgrind_qemu_io
|
||||
fi
|
||||
|
|
|
@ -44,6 +44,8 @@ export HOST_OPTIONS=${HOST_OPTIONS:=local.config}
|
|||
export CHECK_OPTIONS=${CHECK_OPTIONS:="-g auto"}
|
||||
export PWD=`pwd`
|
||||
|
||||
export _QEMU_HANDLE=0
|
||||
|
||||
# $1 = prog to look for, $2* = default pathnames if not found in $PATH
|
||||
set_prog_path()
|
||||
{
|
||||
|
@ -105,7 +107,12 @@ fi
|
|||
|
||||
_qemu_wrapper()
|
||||
{
|
||||
(exec "$QEMU_PROG" $QEMU_OPTIONS "$@")
|
||||
(
|
||||
if [ -n "${QEMU_NEED_PID}" ]; then
|
||||
echo $BASHPID > "${TEST_DIR}/qemu-${_QEMU_HANDLE}.pid"
|
||||
fi
|
||||
exec "$QEMU_PROG" $QEMU_OPTIONS "$@"
|
||||
)
|
||||
}
|
||||
|
||||
_qemu_img_wrapper()
|
||||
|
@ -115,12 +122,31 @@ _qemu_img_wrapper()
|
|||
|
||||
_qemu_io_wrapper()
|
||||
{
|
||||
(exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@")
|
||||
local VALGRIND_LOGFILE=/tmp/$$.valgrind
|
||||
local RETVAL
|
||||
(
|
||||
if [ "${VALGRIND_QEMU}" == "y" ]; then
|
||||
exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@"
|
||||
else
|
||||
exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@"
|
||||
fi
|
||||
)
|
||||
RETVAL=$?
|
||||
if [ "${VALGRIND_QEMU}" == "y" ]; then
|
||||
if [ $RETVAL == 99 ]; then
|
||||
cat "${VALGRIND_LOGFILE}"
|
||||
fi
|
||||
rm -f "${VALGRIND_LOGFILE}"
|
||||
fi
|
||||
(exit $RETVAL)
|
||||
}
|
||||
|
||||
_qemu_nbd_wrapper()
|
||||
{
|
||||
(exec "$QEMU_NBD_PROG" $QEMU_NBD_OPTIONS "$@")
|
||||
(
|
||||
echo $BASHPID > "${TEST_DIR}/qemu-nbd.pid"
|
||||
exec "$QEMU_NBD_PROG" $QEMU_NBD_OPTIONS "$@"
|
||||
)
|
||||
}
|
||||
|
||||
export QEMU=_qemu_wrapper
|
||||
|
|
|
@ -30,8 +30,6 @@ QEMU_COMM_TIMEOUT=10
|
|||
QEMU_FIFO_IN="${TEST_DIR}/qmp-in-$$"
|
||||
QEMU_FIFO_OUT="${TEST_DIR}/qmp-out-$$"
|
||||
|
||||
QEMU_PID=
|
||||
_QEMU_HANDLE=0
|
||||
QEMU_HANDLE=0
|
||||
|
||||
# If bash version is >= 4.1, these will be overwritten and dynamic
|
||||
|
@ -153,11 +151,11 @@ function _launch_qemu()
|
|||
mkfifo "${fifo_out}"
|
||||
mkfifo "${fifo_in}"
|
||||
|
||||
QEMU_NEED_PID='y'\
|
||||
${QEMU} -nographic -serial none ${comm} -machine accel=qtest "${@}" \
|
||||
>"${fifo_out}" \
|
||||
2>&1 \
|
||||
<"${fifo_in}" &
|
||||
QEMU_PID[${_QEMU_HANDLE}]=$!
|
||||
|
||||
if [[ "${BASH_VERSINFO[0]}" -ge "5" ||
|
||||
("${BASH_VERSINFO[0]}" -ge "4" && "${BASH_VERSINFO[1]}" -ge "1") ]]
|
||||
|
@ -196,10 +194,18 @@ function _cleanup_qemu()
|
|||
# QEMU_PID[], QEMU_IN[], QEMU_OUT[] all use same indices
|
||||
for i in "${!QEMU_OUT[@]}"
|
||||
do
|
||||
if [ -z "${wait}" ]; then
|
||||
kill -KILL ${QEMU_PID[$i]} 2>/dev/null
|
||||
local QEMU_PID
|
||||
if [ -f "${TEST_DIR}/qemu-${i}.pid" ]; then
|
||||
read QEMU_PID < "${TEST_DIR}/qemu-${i}.pid"
|
||||
rm -f "${TEST_DIR}/qemu-${i}.pid"
|
||||
if [ -z "${wait}" ] && [ -n "${QEMU_PID}" ]; then
|
||||
kill -KILL ${QEMU_PID} 2>/dev/null
|
||||
fi
|
||||
if [ -n "${QEMU_PID}" ]; then
|
||||
wait ${QEMU_PID} 2>/dev/null # silent kill
|
||||
fi
|
||||
fi
|
||||
wait ${QEMU_PID[$i]} 2>/dev/null # silent kill
|
||||
|
||||
if [ -n "${wait}" ]; then
|
||||
cat <&${QEMU_OUT[$i]} | _filter_testdir | _filter_qemu \
|
||||
| _filter_qemu_io | _filter_qmp
|
||||
|
|
|
@ -70,16 +70,6 @@ else
|
|||
TEST_IMG=$IMGPROTO:$TEST_DIR/t.$IMGFMT
|
||||
fi
|
||||
|
||||
function valgrind_qemu_io()
|
||||
{
|
||||
valgrind --log-file=/tmp/$$.valgrind --error-exitcode=99 $REAL_QEMU_IO "$@"
|
||||
if [ $? != 0 ]; then
|
||||
cat /tmp/$$.valgrind
|
||||
fi
|
||||
rm -f /tmp/$$.valgrind
|
||||
}
|
||||
|
||||
|
||||
_optstr_add()
|
||||
{
|
||||
if [ -n "$1" ]; then
|
||||
|
@ -154,7 +144,6 @@ _make_test_img()
|
|||
# Start an NBD server on the image file, which is what we'll be talking to
|
||||
if [ $IMGPROTO = "nbd" ]; then
|
||||
eval "$QEMU_NBD -v -t -b 127.0.0.1 -p 10810 -f $IMGFMT $TEST_IMG_FILE &"
|
||||
QEMU_NBD_PID=$!
|
||||
sleep 1 # FIXME: qemu-nbd needs to be listening before we continue
|
||||
fi
|
||||
}
|
||||
|
@ -175,8 +164,11 @@ _cleanup_test_img()
|
|||
case "$IMGPROTO" in
|
||||
|
||||
nbd)
|
||||
if [ -n "$QEMU_NBD_PID" ]; then
|
||||
kill $QEMU_NBD_PID
|
||||
if [ -f "${TEST_DIR}/qemu-nbd.pid" ]; then
|
||||
local QEMU_NBD_PID
|
||||
read QEMU_NBD_PID < "${TEST_DIR}/qemu-nbd.pid"
|
||||
kill ${QEMU_NBD_PID}
|
||||
rm -f "${TEST_DIR}/qemu-nbd.pid"
|
||||
fi
|
||||
rm -f "$TEST_IMG_FILE"
|
||||
;;
|
||||
|
|
|
@ -138,3 +138,4 @@
|
|||
135 rw auto
|
||||
137 rw auto
|
||||
138 rw auto quick
|
||||
139 rw auto quick
|
||||
|
|
Loading…
Reference in New Issue