From nobody Fri Nov 7 12:03:15 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; dkim=fail; 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 Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1547740292577431.70665426707194; Thu, 17 Jan 2019 07:51:32 -0800 (PST) Received: from localhost ([127.0.0.1]:46958 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gk9x5-0007Hq-HV for importer@patchew.org; Thu, 17 Jan 2019 10:51:31 -0500 Received: from eggs.gnu.org ([209.51.188.92]:39113) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gk9gp-0001uM-K5 for qemu-devel@nongnu.org; Thu, 17 Jan 2019 10:34:45 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gk9gn-0007pY-OA for qemu-devel@nongnu.org; Thu, 17 Jan 2019 10:34:43 -0500 Received: from fanzine.igalia.com ([91.117.99.155]:59840) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1gk9gn-0007O0-BY; Thu, 17 Jan 2019 10:34:41 -0500 Received: from [194.100.51.2] (helo=perseus.local) by fanzine.igalia.com with esmtpsa (Cipher TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim) id 1gk9gd-0003bn-01; Thu, 17 Jan 2019 16:34:31 +0100 Received: from berto by perseus.local with local (Exim 4.89) (envelope-from ) id 1gk9gI-0007R5-Pu; Thu, 17 Jan 2019 17:34:10 +0200 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=igalia.com; s=20170329; h=References:In-Reply-To:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From; bh=DnzH//xnpXhRQQd2SZ/z7vl3MuasoWtV2r0B3AcRJRU=; b=joT6GcpTC2/pbxDGtcCj1Nzyc0ZbNJ+SoTOHTn4zYGUvFFhw4y5hCI8BqxY5hfyYy6qSd0oFcr68yLTXdF9/LdsHKLlHfMm8a5iD/IIaH782YH5PX+Oubtquu3TTbFLHOaFEe0Temnv1XWD0EEnkxyBSif//Jmq27xMfojQsJYkT7V94I4PoVf2IlC2X0wm7Tj8KPwviK9zw93wKl2WiEg1KeHQxP+ZT3waRIRKib69teiIbVmoY9SB7KVYtdRETqXgTZgpEd2L31Px10E5jmDEBC4CDTYzTfoOaH7OrQnwpMACu4kGkQ8aQeZ14xauDChovmhHoRRlFRwf3z4xuQQ==; From: Alberto Garcia To: qemu-devel@nongnu.org Date: Thu, 17 Jan 2019 17:33:52 +0200 Message-Id: X-Mailer: git-send-email 2.11.0 In-Reply-To: References: In-Reply-To: References: X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x (no timestamps) [generic] [fuzzy] X-Received-From: 91.117.99.155 Subject: [Qemu-devel] [PATCH 01/13] block: Allow freezing BdrvChild links 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: Kevin Wolf , Alberto Garcia , qemu-block@nongnu.org, Max Reitz Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Our permission system is useful to define what operations are allowed on a certain block node and includes things like BLK_PERM_WRITE or BLK_PERM_RESIZE among others. One of the permissions is BLK_PERM_GRAPH_MOD which allows "changing the node that this BdrvChild points to". The exact meaning of this has never been very clear, but it can be understood as "change any of the links connected to the node". This can be used to prevent changing a backing link, but it's too coarse. This patch adds a new 'frozen' attribute to BdrvChild, which forbids detaching the link from the node it points to, and new API to freeze and unfreeze a backing chain. Signed-off-by: Alberto Garcia --- block.c | 66 +++++++++++++++++++++++++++++++++++++++++++= ++++ include/block/block.h | 5 ++++ include/block/block_int.h | 5 ++++ 3 files changed, 76 insertions(+) diff --git a/block.c b/block.c index 4f5ff2cc12..51fac086c7 100644 --- a/block.c +++ b/block.c @@ -2062,6 +2062,8 @@ static void bdrv_replace_child_noperm(BdrvChild *chil= d, BlockDriverState *old_bs =3D child->bs; int i; =20 + assert(!child->frozen); + if (old_bs && new_bs) { assert(bdrv_get_aio_context(old_bs) =3D=3D bdrv_get_aio_context(ne= w_bs)); } @@ -2278,6 +2280,10 @@ void bdrv_set_backing_hd(BlockDriverState *bs, Block= DriverState *backing_hd, bool update_inherits_from =3D bdrv_chain_contains(bs, backing_hd) && bdrv_inherits_from_recursive(backing_hd, bs); =20 + if (bdrv_is_backing_chain_frozen(bs, backing_bs(bs), errp)) { + return; + } + if (backing_hd) { bdrv_ref(backing_hd); } @@ -3813,6 +3819,62 @@ BlockDriverState *bdrv_find_base(BlockDriverState *b= s) } =20 /* + * Return true if at least one of the backing links between @bs and + * @base is frozen. @errp is set if that's the case. + */ +bool bdrv_is_backing_chain_frozen(BlockDriverState *bs, BlockDriverState *= base, + Error **errp) +{ + BlockDriverState *i; + + for (i =3D bs; i !=3D base && i->backing; i =3D backing_bs(i)) { + if (i->backing->frozen) { + error_setg(errp, "Cannot remove link from '%s' to '%s'", + i->node_name, backing_bs(i)->node_name); + return true; + } + } + + return false; +} + +/* + * Freeze all backing links between @bs and @base. + * If any of the links is already frozen the operation is aborted and + * none of the links are modified. + * Returns 0 on success. On failure returns < 0 and sets @errp. + */ +int bdrv_freeze_backing_chain(BlockDriverState *bs, BlockDriverState *base, + Error **errp) +{ + BlockDriverState *i; + + if (bdrv_is_backing_chain_frozen(bs, base, errp)) { + return -EPERM; + } + + for (i =3D bs; i !=3D base && i->backing; i =3D backing_bs(i)) { + i->backing->frozen =3D true; + } + + return 0; +} + +/* + * Unfreeze all backing links between @bs and @base. The caller must + * ensure that all links are frozen before using this function. + */ +void bdrv_unfreeze_backing_chain(BlockDriverState *bs, BlockDriverState *b= ase) +{ + BlockDriverState *i; + + for (i =3D bs; i !=3D base && i->backing; i =3D backing_bs(i)) { + assert(i->backing->frozen); + i->backing->frozen =3D false; + } +} + +/* * Drops images above 'base' up to and including 'top', and sets the image * above 'top' to have base as its backing file. * @@ -3861,6 +3923,10 @@ int bdrv_drop_intermediate(BlockDriverState *top, Bl= ockDriverState *base, goto exit; } =20 + if (bdrv_is_backing_chain_frozen(top, base, NULL)) { + goto exit; + } + /* If 'base' recursively inherits from 'top' then we should set * base->inherits_from to top->inherits_from after 'top' and all * other intermediate nodes have been dropped. diff --git a/include/block/block.h b/include/block/block.h index f70a843b72..6f10a8fcfc 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -353,6 +353,11 @@ int bdrv_drop_intermediate(BlockDriverState *top, Bloc= kDriverState *base, BlockDriverState *bdrv_find_overlay(BlockDriverState *active, BlockDriverState *bs); BlockDriverState *bdrv_find_base(BlockDriverState *bs); +bool bdrv_is_backing_chain_frozen(BlockDriverState *bs, BlockDriverState *= base, + Error **errp); +int bdrv_freeze_backing_chain(BlockDriverState *bs, BlockDriverState *base, + Error **errp); +void bdrv_unfreeze_backing_chain(BlockDriverState *bs, BlockDriverState *b= ase); =20 =20 typedef struct BdrvCheckResult { diff --git a/include/block/block_int.h b/include/block/block_int.h index f605622216..fd0e88d17a 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -661,6 +661,11 @@ struct BdrvChild { */ uint64_t shared_perm; =20 + /* + * This link is frozen: the child cannot be detached from the parent. + */ + bool frozen; + QLIST_ENTRY(BdrvChild) next; QLIST_ENTRY(BdrvChild) next_parent; }; --=20 2.11.0