blockdev: add x-blockdev-set-iothread testing command

Currently there is no easy way for iotests to ensure that a BDS is bound
to a particular IOThread.  Normally the virtio-blk device calls
blk_set_aio_context() when dataplane is enabled during guest driver
initialization.  This never happens in iotests since -machine
accel=qtest means there is no guest activity (including device driver
initialization).

This patch adds a QMP command to explicitly assign IOThreads in test
cases.  See qapi/block-core.json for a description of the command.

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-id: 20171206144550.22295-9-stefanha@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
Stefan Hajnoczi 2017-12-06 14:45:49 +00:00
parent fbcc6923b0
commit ca00bbb153
2 changed files with 77 additions and 0 deletions

View file

@ -45,6 +45,7 @@
#include "qapi/qmp/qerror.h"
#include "qapi/qobject-output-visitor.h"
#include "sysemu/sysemu.h"
#include "sysemu/iothread.h"
#include "block/block_int.h"
#include "qmp-commands.h"
#include "block/trace.h"
@ -4129,6 +4130,46 @@ BlockJobInfoList *qmp_query_block_jobs(Error **errp)
return head;
}
void qmp_x_blockdev_set_iothread(const char *node_name, StrOrNull *iothread,
Error **errp)
{
AioContext *old_context;
AioContext *new_context;
BlockDriverState *bs;
bs = bdrv_find_node(node_name);
if (!bs) {
error_setg(errp, "Cannot find node %s", node_name);
return;
}
/* If we want to allow more extreme test scenarios this guard could be
* removed. For now it protects against accidents. */
if (bdrv_has_blk(bs)) {
error_setg(errp, "Node %s is in use", node_name);
return;
}
if (iothread->type == QTYPE_QSTRING) {
IOThread *obj = iothread_by_id(iothread->u.s);
if (!obj) {
error_setg(errp, "Cannot find iothread %s", iothread->u.s);
return;
}
new_context = iothread_get_aio_context(obj);
} else {
new_context = qemu_get_aio_context();
}
old_context = bdrv_get_aio_context(bs);
aio_context_acquire(old_context);
bdrv_set_aio_context(bs, new_context);
aio_context_release(old_context);
}
QemuOptsList qemu_common_drive_opts = {
.name = "drive",
.head = QTAILQ_HEAD_INITIALIZER(qemu_common_drive_opts.head),

View file

@ -3949,3 +3949,39 @@
'data' : { 'parent': 'str',
'*child': 'str',
'*node': 'str' } }
##
# @x-blockdev-set-iothread:
#
# Move @node and its children into the @iothread. If @iothread is null then
# move @node and its children into the main loop.
#
# The node must not be attached to a BlockBackend.
#
# @node-name: the name of the block driver node
#
# @iothread: the name of the IOThread object or null for the main loop
#
# Note: this command is experimental and intended for test cases that need
# control over IOThreads only.
#
# Since: 2.12
#
# Example:
#
# 1. Move a node into an IOThread
# -> { "execute": "x-blockdev-set-iothread",
# "arguments": { "node-name": "disk1",
# "iothread": "iothread0" } }
# <- { "return": {} }
#
# 2. Move a node into the main loop
# -> { "execute": "x-blockdev-set-iothread",
# "arguments": { "node-name": "disk1",
# "iothread": null } }
# <- { "return": {} }
#
##
{ 'command': 'x-blockdev-set-iothread',
'data' : { 'node-name': 'str',
'iothread': 'StrOrNull' } }