@@ -219,11 +219,22 @@
# export before completion is signalled. (since: 5.2;
# default: false)
#
+# @iothread: The name of the iothread object where the export will run. The
+# default is to use the thread currently associated with the
+# block node. (since: 5.2)
+#
+# @fixed-iothread: True prevents the block node from being moved to another
+# thread while the export is active. If true and @iothread is
+# given, export creation fails if the block node cannot be
+# moved to the iothread. The default is false. (since: 5.2)
+#
# Since: 4.2
##
{ 'union': 'BlockExportOptions',
'base': { 'type': 'BlockExportType',
'id': 'str',
+ '*fixed-iothread': 'bool',
+ '*iothread': 'str',
'node-name': 'str',
'*writable': 'bool',
'*writethrough': 'bool' },
@@ -15,6 +15,7 @@
#include "block/block.h"
#include "sysemu/block-backend.h"
+#include "sysemu/iothread.h"
#include "block/export.h"
#include "block/nbd.h"
#include "qapi/error.h"
@@ -63,10 +64,11 @@ static const BlockExportDriver *blk_exp_find_driver(BlockExportType type)
BlockExport *blk_exp_add(BlockExportOptions *export, Error **errp)
{
+ bool fixed_iothread = export->has_fixed_iothread && export->fixed_iothread;
const BlockExportDriver *drv;
BlockExport *exp = NULL;
BlockDriverState *bs;
- BlockBackend *blk;
+ BlockBackend *blk = NULL;
AioContext *ctx;
uint64_t perm;
int ret;
@@ -102,6 +104,28 @@ BlockExport *blk_exp_add(BlockExportOptions *export, Error **errp)
ctx = bdrv_get_aio_context(bs);
aio_context_acquire(ctx);
+ if (export->has_iothread) {
+ IOThread *iothread;
+ AioContext *new_ctx;
+
+ iothread = iothread_by_id(export->iothread);
+ if (!iothread) {
+ error_setg(errp, "iothread \"%s\" not found", export->iothread);
+ goto fail;
+ }
+
+ new_ctx = iothread_get_aio_context(iothread);
+
+ ret = bdrv_try_set_aio_context(bs, new_ctx, errp);
+ if (ret == 0) {
+ aio_context_release(ctx);
+ aio_context_acquire(new_ctx);
+ ctx = new_ctx;
+ } else if (fixed_iothread) {
+ goto fail;
+ }
+ }
+
/*
* Block exports are used for non-shared storage migration. Make sure
* that BDRV_O_INACTIVE is cleared and the image is ready for write
@@ -116,6 +140,11 @@ BlockExport *blk_exp_add(BlockExportOptions *export, Error **errp)
}
blk = blk_new(ctx, perm, BLK_PERM_ALL);
+
+ if (!fixed_iothread) {
+ blk_set_allow_aio_context_change(blk, true);
+ }
+
ret = blk_insert_bs(blk, bs, errp);
if (ret < 0) {
goto fail;
@@ -323,13 +323,17 @@ static const VuDevIface vu_blk_iface = {
static void blk_aio_attached(AioContext *ctx, void *opaque)
{
VuBlkExport *vexp = opaque;
+
+ vexp->export.ctx = ctx;
vhost_user_server_attach_aio_context(&vexp->vu_server, ctx);
}
static void blk_aio_detach(void *opaque)
{
VuBlkExport *vexp = opaque;
+
vhost_user_server_detach_aio_context(&vexp->vu_server);
+ vexp->export.ctx = NULL;
}
static void
@@ -384,7 +388,6 @@ static int vu_blk_exp_create(BlockExport *exp, BlockExportOptions *opts,
vu_blk_initialize_config(blk_bs(exp->blk), &vexp->blkcfg,
logical_block_size);
- blk_set_allow_aio_context_change(exp->blk, true);
blk_add_aio_context_notifier(exp->blk, blk_aio_attached, blk_aio_detach,
vexp);
@@ -1517,8 +1517,6 @@ static int nbd_export_create(BlockExport *blk_exp, BlockExportOptions *exp_args,
return ret;
}
- blk_set_allow_aio_context_change(blk, true);
-
QTAILQ_INIT(&exp->clients);
exp->name = g_strdup(arg->name);
exp->description = g_strdup(arg->description);