From nobody Wed Apr 16 03:53:25 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1558369281; cv=none; d=zoho.com; s=zohoarc; b=ZdLljebNk3NsZqBe662RLMzdrqvO2gboGFSZuOvCQc9mxTZQZJ2xh6cPX8m5uVhyFGGOjbzLWiAsRouZkfBzR3G+NWuOZVqir7wbaZ0KnFZt/Jsicfc1eZMz2TbuAnRvfRSfdhilXhVoiyZDgvLCIspCKqelvlPTYdxvd4ClUro= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1558369281; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To:ARC-Authentication-Results; bh=7oGZ2D6PPdfqz8dSmzGy8RA/muxgQ3MvEm2DzZkOXUc=; b=ANOfxBUJ1f2sT/LA8aFhrbRBxK58HcN94r6yDQcXY6B+BwsWHbIrqejPXYLU7GDDcaQ2/RiyOG0Hi5N1n5/vVRK2vUUtNLsau54V2Pi4MoyhktZd66qYdwRndpSGMshTkmdqKEe/sv6q/u4feACtXizY0H31xwy0KkUC1AGKCsw= ARC-Authentication-Results: i=1; mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1558369281076490.82214891568583; Mon, 20 May 2019 09:21:21 -0700 (PDT) Received: from localhost ([127.0.0.1]:38090 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1hSl2F-0004FY-2h for importer@patchew.org; Mon, 20 May 2019 12:21:11 -0400 Received: from eggs.gnu.org ([209.51.188.92]:38496) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1hSkws-0008Go-BH for qemu-devel@nongnu.org; Mon, 20 May 2019 12:15:39 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hSkwq-0003ZY-Vt for qemu-devel@nongnu.org; Mon, 20 May 2019 12:15:38 -0400 Received: from mx1.redhat.com ([209.132.183.28]:51642) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1hSkwm-0003Q3-LI; Mon, 20 May 2019 12:15:32 -0400 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 637798CB40; Mon, 20 May 2019 16:15:16 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-117-208.ams2.redhat.com [10.36.117.208]) by smtp.corp.redhat.com (Postfix) with ESMTP id 77C39189B6; Mon, 20 May 2019 16:15:14 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Date: Mon, 20 May 2019 18:14:36 +0200 Message-Id: <20190520161453.30723-8-kwolf@redhat.com> In-Reply-To: <20190520161453.30723-1-kwolf@redhat.com> References: <20190520161453.30723-1-kwolf@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.26]); Mon, 20 May 2019 16:15:19 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL 07/24] block: Add bdrv_try_set_aio_context() X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, qemu-devel@nongnu.org Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" Eventually, we want to make sure that all parents and all children of a node are in the same AioContext as the node itself. This means that changing the AioContext may fail because one of the other involved parties (e.g. a guest device that was configured with an iothread) cannot allow switching to a different AioContext. Introduce a set of functions that allow to first check whether all involved nodes can switch to a new context and only then do the actual switch. The check recursively covers children and parents. Signed-off-by: Kevin Wolf --- include/block/block.h | 8 ++++ include/block/block_int.h | 3 ++ block.c | 92 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 103 insertions(+) diff --git a/include/block/block.h b/include/block/block.h index 5e2b98b0ee..fc0239a887 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -586,6 +586,14 @@ void bdrv_coroutine_enter(BlockDriverState *bs, Corout= ine *co); * This function must be called with iothread lock held. */ void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context); +int bdrv_try_set_aio_context(BlockDriverState *bs, AioContext *ctx, + Error **errp); +int bdrv_child_try_set_aio_context(BlockDriverState *bs, AioContext *ctx, + BdrvChild *ignore_child, Error **errp); +bool bdrv_child_can_set_aio_context(BdrvChild *c, AioContext *ctx, + GSList **ignore, Error **errp); +bool bdrv_can_set_aio_context(BlockDriverState *bs, AioContext *ctx, + GSList **ignore, Error **errp); int bdrv_probe_blocksizes(BlockDriverState *bs, BlockSizes *bsz); int bdrv_probe_geometry(BlockDriverState *bs, HDGeometry *geo); =20 diff --git a/include/block/block_int.h b/include/block/block_int.h index 94d45c9708..b150c5f047 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -691,6 +691,9 @@ struct BdrvChildRole { * can update its reference. */ int (*update_filename)(BdrvChild *child, BlockDriverState *new_base, const char *filename, Error **errp); + + bool (*can_set_aio_ctx)(BdrvChild *child, AioContext *ctx, + GSList **ignore, Error **errp); }; =20 extern const BdrvChildRole child_file; diff --git a/block.c b/block.c index 6999aad446..8ff6ab1152 100644 --- a/block.c +++ b/block.c @@ -936,6 +936,13 @@ static int bdrv_child_cb_inactivate(BdrvChild *child) return 0; } =20 +static bool bdrv_child_cb_can_set_aio_ctx(BdrvChild *child, AioContext *ct= x, + GSList **ignore, Error **errp) +{ + BlockDriverState *bs =3D child->opaque; + return bdrv_can_set_aio_context(bs, ctx, ignore, errp); +} + /* * Returns the options and flags that a temporary snapshot should get, bas= ed on * the originally requested flags (the originally requested image will have @@ -1003,6 +1010,7 @@ const BdrvChildRole child_file =3D { .attach =3D bdrv_child_cb_attach, .detach =3D bdrv_child_cb_detach, .inactivate =3D bdrv_child_cb_inactivate, + .can_set_aio_ctx =3D bdrv_child_cb_can_set_aio_ctx, }; =20 /* @@ -1029,6 +1037,7 @@ const BdrvChildRole child_format =3D { .attach =3D bdrv_child_cb_attach, .detach =3D bdrv_child_cb_detach, .inactivate =3D bdrv_child_cb_inactivate, + .can_set_aio_ctx =3D bdrv_child_cb_can_set_aio_ctx, }; =20 static void bdrv_backing_attach(BdrvChild *c) @@ -1152,6 +1161,7 @@ const BdrvChildRole child_backing =3D { .drained_end =3D bdrv_child_cb_drained_end, .inactivate =3D bdrv_child_cb_inactivate, .update_filename =3D bdrv_backing_update_filename, + .can_set_aio_ctx =3D bdrv_child_cb_can_set_aio_ctx, }; =20 static int bdrv_open_flags(BlockDriverState *bs, int flags) @@ -5750,6 +5760,88 @@ void bdrv_set_aio_context(BlockDriverState *bs, AioC= ontext *new_context) aio_context_release(new_context); } =20 +static bool bdrv_parent_can_set_aio_context(BdrvChild *c, AioContext *ctx, + GSList **ignore, Error **errp) +{ + if (g_slist_find(*ignore, c)) { + return true; + } + *ignore =3D g_slist_prepend(*ignore, c); + + /* A BdrvChildRole that doesn't handle AioContext changes cannot + * tolerate any AioContext changes */ + if (!c->role->can_set_aio_ctx) { + char *user =3D bdrv_child_user_desc(c); + error_setg(errp, "Changing iothreads is not supported by %s", user= ); + g_free(user); + return false; + } + if (!c->role->can_set_aio_ctx(c, ctx, ignore, errp)) { + assert(!errp || *errp); + return false; + } + return true; +} + +bool bdrv_child_can_set_aio_context(BdrvChild *c, AioContext *ctx, + GSList **ignore, Error **errp) +{ + if (g_slist_find(*ignore, c)) { + return true; + } + *ignore =3D g_slist_prepend(*ignore, c); + return bdrv_can_set_aio_context(c->bs, ctx, ignore, errp); +} + +/* @ignore will accumulate all visited BdrvChild object. The caller is + * responsible for freeing the list afterwards. */ +bool bdrv_can_set_aio_context(BlockDriverState *bs, AioContext *ctx, + GSList **ignore, Error **errp) +{ + BdrvChild *c; + + if (bdrv_get_aio_context(bs) =3D=3D ctx) { + return true; + } + + QLIST_FOREACH(c, &bs->parents, next_parent) { + if (!bdrv_parent_can_set_aio_context(c, ctx, ignore, errp)) { + return false; + } + } + QLIST_FOREACH(c, &bs->children, next) { + if (!bdrv_child_can_set_aio_context(c, ctx, ignore, errp)) { + return false; + } + } + + return true; +} + +int bdrv_child_try_set_aio_context(BlockDriverState *bs, AioContext *ctx, + BdrvChild *ignore_child, Error **errp) +{ + GSList *ignore; + bool ret; + + ignore =3D ignore_child ? g_slist_prepend(NULL, ignore_child) : NULL; + ret =3D bdrv_can_set_aio_context(bs, ctx, &ignore, errp); + g_slist_free(ignore); + + if (!ret) { + return -EPERM; + } + + bdrv_set_aio_context(bs, ctx); + return 0; +} + +int bdrv_try_set_aio_context(BlockDriverState *bs, AioContext *ctx, + Error **errp) +{ + return bdrv_child_try_set_aio_context(bs, ctx, NULL, errp); +} + void bdrv_add_aio_context_notifier(BlockDriverState *bs, void (*attached_aio_context)(AioContext *new_context, void *opaque= ), void (*detach_aio_context)(void *opaque), void *opaque) --=20 2.20.1