From nobody Sat Sep 26 20:52:56 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=reject dis=none) header.from=rsg.ci.i.u-tokyo.ac.jp ARC-Seal: i=1; a=rsa-sha256; t=1789378501; cv=none; d=zohomail.com; s=zohoarc; b=IS4J/SwQh6bkc9X/yTgSViTj4e1VPOF8atn6LZsoU68D9bQoq5gZaraqglVW4pqLkx4AXae284ir4BPkBLOpuB7FS5qirr9qa9NMwSVgy6Y831dokpaH0dJo3wPToYdhOooInFO/h/V74lU+SG3v1etrHjgtGp3FCvLrEB7L2LU= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1789378501; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=/Bvxk6KnPo0hgWabVbGt/xH9R1ZKFET4Zr3/tO589OM=; b=Z54HvHoFV4r8GNbPbl+vVCukMPMTJd7ik/AWocJns7pblha0fP93JUMmGwveG8iWvA9aGau7Gw1cLN9JHvK9LW6B+pBB9qprziB+QOT/AAQKkquA4x9ZUCwktfQWInimF65Mqg97pUDbEyAxsGLPFiOhrFSHunqBozZuIXptQy4= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=reject dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1789378501055799.7036683809123; Mon, 14 Sep 2026 02:35:01 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1x634q-0000oX-1M; Mon, 14 Sep 2026 05:34:16 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1x634R-0000hd-MU; Mon, 14 Sep 2026 05:33:53 -0400 Received: from www3579.sakura.ne.jp ([49.212.243.89]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1x634M-0000S1-SX; Mon, 14 Sep 2026 05:33:50 -0400 Received: from h183.csg.ci.i.u-tokyo.ac.jp (h183.csg.ci.i.u-tokyo.ac.jp [133.11.54.183]) (authenticated bits=0) by www3579.sakura.ne.jp (8.16.1/8.16.1) with ESMTPSA id 68E9WXEW020350 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO); Mon, 14 Sep 2026 18:32:38 +0900 (JST) (envelope-from odaki@rsg.ci.i.u-tokyo.ac.jp) DKIM-Signature: a=rsa-sha256; bh=/Bvxk6KnPo0hgWabVbGt/xH9R1ZKFET4Zr3/tO589OM=; c=relaxed/relaxed; d=rsg.ci.i.u-tokyo.ac.jp; h=From:Message-Id:To:Subject:Date; s=rs20250326; t=1789378358; v=1; b=ClVR0MZMbJCOXXzXdwjsc+A5CXKty+BnArkLQzVeJiBl/u6RUfjMNicLUV8QM0wz UfAR+7GYG780CyJrKHyK50AbHh25aBXvo7jjxnQPPjEMfUI0G6C6LyCqx4q/C72K 17jMDZH/7/kxWmQSe5d87aYoVcJW3/UFgF28m9EsdbjEP7xvYo4ocTbnObWgJGx8 5GMhMIrWKfqBh5JV04PKwQq/Qk05gWNbVUHRuE/umB8/rqPsHnESUoEeb69tHyP+ XHM7R/OGXMduIpDscl63tOpPNGIbs6e9yaA/VIN8HY0I6WirG7TN15Yj61UABXNj UEEJdT/upDWYAJHn05kGNw== From: Akihiko Odaki Date: Mon, 14 Sep 2026 18:31:49 +0900 Subject: [PATCH v4 1/4] qdev: Clarify instantiation and realization MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260914-qdev-v4-1-93f849b4865c@rsg.ci.i.u-tokyo.ac.jp> References: <20260914-qdev-v4-0-93f849b4865c@rsg.ci.i.u-tokyo.ac.jp> In-Reply-To: <20260914-qdev-v4-0-93f849b4865c@rsg.ci.i.u-tokyo.ac.jp> To: qemu-devel@nongnu.org Cc: BALATON Zoltan , Paolo Bonzini , =?utf-8?q?Daniel_P=2E_Berrang=C3=A9?= , Eduardo Habkost , "Maciej S. Szmigiero" , "Michael S. Tsirkin" , David Hildenbrand , Igor Mammedov , FangSheng Huang , Alistair Francis , "Edgar E. Iglesias" , Peter Maydell , qemu-arm@nongnu.org, Nicholas Piggin , Aditya Gupta , Glenn Miles , Harsh Prateek Bora , qemu-ppc@nongnu.org, Alex Williamson , =?utf-8?q?C=C3=A9dric_Le_Goater?= , Zhao Liu , Hendrik Brueckner , Richard Henderson , Ilya Leoshkevich , Cornelia Huck , Eric Farman , Matthew Rosato , qemu-s390x@nongnu.org, Luc Michel , Fam Zheng , Eric Blake , Markus Armbruster , Akihiko Odaki X-Mailer: b4 0.17-dev X-Developer-Signature: v=1; a=openpgp-sha256; l=5771; i=odaki@rsg.ci.i.u-tokyo.ac.jp; h=from:subject:message-id; bh=b0gqtLvYz6FByvP/TSQ7Ojke53C6GB4YJE92Ws3z45A=; b=owGbwMvMwCWmMbc20y1CyJDxtFoSQ9by/XriIUsz/xyrYilSODyluFB8guGUz/9W7wnbw3Hrk tOukCPiHaUsDGJcDLJiiiwpRbu5NaJrPxUmxLfAzGFlAhnCwMUpABOR6Gb4nxt8/U4V76Kqnfye j7l3Ojo8PjG7Ke1M+oWwurNBvskpjAz/lFezine2GTr932WiMrP2dPd8zk61b5zbb0yI+XfD7KI 1LwA= X-Developer-Key: i=odaki@rsg.ci.i.u-tokyo.ac.jp; a=openpgp; fpr=AEDC03C9AF734F2EC26A7BFFA4BAEAA73536753C Received-SPF: pass (zohomail.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=lists1p.gnu.org; Received-SPF: pass client-ip=49.212.243.89; envelope-from=odaki@rsg.ci.i.u-tokyo.ac.jp; helo=www3579.sakura.ne.jp X-Spam_score_int: -19 X-Spam_score: -2.0 X-Spam_bar: -- X-Spam_report: (-2.0 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @rsg.ci.i.u-tokyo.ac.jp) X-ZM-MESSAGEID: 1789378502882158500 The distinction of instantiation and realization was vague in the old documentation so this change clarifies it. The old documentation said: > The former may not fail (and must not abort or exit, since it is > called during device introspection already), and the latter may return > error information to the caller and must be re-entrant. > Trivial field initializations should go into #TypeInfo.instance_init. > Operations depending on @props static properties should go into > @realize. The first problem with the old documentation is that it is unclear what "trivial field initializations" means and why triviality makes initialization appropriate for #TypeInfo.instance_init. Another problem is that the documentation is not comprehensive enough; for example, it mentions @props static properties, but it does not say anything about the other properties. The keys to distinguish instantiation and realization are instance property setting and device introspection. The fact that initial instance property setting happens after #TypeInfo.instance_init and before realization implies that operations depending on properties should go into @realize. The fact that instantiation happens during device introspection but realization does not implies: - Instance properties may be added in #TypeInfo.instance_init. - Instantiation must not have any side effect not contained in the instance. - Any operations without special requirements should go into @realize so that they can be skipped during device introspection. - Instance properties added during realization will not be configurable or introspectable before realization. Note these two facts to guide appropriate instantiation and realization. We also omit mention of the realized property because it is a QOM interface detail, not part of the device API. The statements regarding a future prospect to propagate the realization state change are removed. Device realization is propagated to child buses, but not to the devices on those buses. The proposed recursive propagation to child devices has not been achieved after 13 years, has been questioned [1], and is not relevant with the current API usage. [1] https://lore.kernel.org/qemu-devel/878syd84s3.fsf@dusky.pond.sub.org/ Signed-off-by: Akihiko Odaki Reviewed-by: Peter Maydell --- include/hw/core/qdev.h | 42 ++++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/include/hw/core/qdev.h b/include/hw/core/qdev.h index f054a214fc6a..b1c5f4780a90 100644 --- a/include/hw/core/qdev.h +++ b/include/hw/core/qdev.h @@ -23,27 +23,27 @@ * Realization * ----------- * - * Devices are constructed in two stages: + * Devices are constructed in the following order: * - * 1) object instantiation via object_initialize() and - * 2) device realization via the #DeviceState.realized property + * 1) #TypeInfo.instance_init + * 2) pre-realize property value setting + * 3) device realization * - * The former may not fail (and must not abort or exit, since it is called - * during device introspection already), and the latter may return error - * information to the caller and must be re-entrant. - * Trivial field initializations should go into #TypeInfo.instance_init. - * Operations depending on @props static properties should go into @realiz= e. - * After successful realization, setting static properties will fail. + * #TypeInfo.instance_init may not fail. #DeviceClass.realize can + * fail, returning error information to the caller, and must be re-entrant. + * + * #TypeInfo.instance_init should add instance properties but must not + * have any side effect not contained in the instance, since it happens + * during device introspection already. Any operations without special + * requirements should go into @realize so that they can be skipped + * during device introspection. It is possible to add properties + * during realization, but they will not be introspectable or + * configurable before realization. * - * As an interim step, the #DeviceState.realized property can also be - * set with qdev_realize(). In the future, devices will propagate this - * state change to their children and along busses they expose. The - * point in time will be deferred to machine creation, so that values - * set in @realize will not be introspectable beforehand. Therefore - * devices must not create children during @realize; they should - * initialize them via object_initialize() in their own - * #TypeInfo.instance_init and forward the realization events - * appropriately. + * Child buses are automatically realized. Child devices must be manually + * realized (e.g. by calling qdev_realize()). + * + * After successful realization, setting static properties will fail. * * Any type may override the @realize and/or @unrealize callbacks but needs * to call the parent type's implementation if keeping their functionality @@ -102,10 +102,8 @@ typedef int (*DeviceSyncConfig)(DeviceState *dev, Erro= r **errp); /** * struct DeviceClass - The base class for all devices. * @props: Properties accessing state fields. - * @realize: Callback function invoked when the #DeviceState:realized - * property is changed to %true. - * @unrealize: Callback function invoked when the #DeviceState:realized - * property is changed to %false. + * @realize: Callback function to realize the device. + * @unrealize: Callback function to unrealize the device. * @sync_config: Callback function invoked when QMP command device-sync-co= nfig * is called. Should synchronize device configuration from host to guest p= art * and notify the guest about the change. --=20 2.55.0 From nobody Sat Sep 26 20:52:56 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=reject dis=none) header.from=rsg.ci.i.u-tokyo.ac.jp ARC-Seal: i=1; a=rsa-sha256; t=1789378501; cv=none; d=zohomail.com; s=zohoarc; b=i7xOTUGki36TlWriIOLFF0Nc0g588O8Cemf4ARmw/xc+rFBv+mzjTB7i8iINcSJ6uiZ6IqHr3yPEtkM5nkTBgL5l4zzQaqi5/66PO0Z+GQcr9xIbNXvJ/Yfg1GrMy6KpAq5y2WnnmnOWloikG4gyGk6GhB5awMak1ZKhLw2rOO4= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1789378501; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=pNDWp1wjDVxMJm/uJywo6dRmA13XDrmoXUjAwLN19uU=; b=WC10dbxAqTSLcfq4LpMaPAeGPItHrkMTVJHVDPoYhn98BogP9wlB86elspiISQ9z0VwSt0Zy8MgbvBtwmfoSOAdV7F4SzfooWeeRwY1VdgtxtxF6n57C2D2p51FnRMwPZyRgdG1bkqx8J6jAkSfPZJR0ifHXrPPiyf5SEzK+QvQ= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=reject dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1789378500619310.0294691741707; Mon, 14 Sep 2026 02:35:00 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1x634q-0000pW-KL; Mon, 14 Sep 2026 05:34:16 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1x634T-0000hz-MH; Mon, 14 Sep 2026 05:33:55 -0400 Received: from www3579.sakura.ne.jp ([49.212.243.89]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1x634M-0000S3-U7; Mon, 14 Sep 2026 05:33:51 -0400 Received: from h183.csg.ci.i.u-tokyo.ac.jp (h183.csg.ci.i.u-tokyo.ac.jp [133.11.54.183]) (authenticated bits=0) by www3579.sakura.ne.jp (8.16.1/8.16.1) with ESMTPSA id 68E9WXEX020350 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO); Mon, 14 Sep 2026 18:32:38 +0900 (JST) (envelope-from odaki@rsg.ci.i.u-tokyo.ac.jp) DKIM-Signature: a=rsa-sha256; bh=pNDWp1wjDVxMJm/uJywo6dRmA13XDrmoXUjAwLN19uU=; c=relaxed/relaxed; d=rsg.ci.i.u-tokyo.ac.jp; h=From:Message-Id:To:Subject:Date; s=rs20250326; t=1789378359; v=1; b=KS/3EtfE9+kWhN+Ty6lLnn3hJdJa5pDtFe4S9ONW797jTVED2UnkHtnmm97rgC6m L7ko4Fi9gphWLUbkeDeTwyXSYDrpHiHckNq7ALvA/GwYRYR5wK/uMtW+aHxdBedo FdpV5tc8yvClYN3Gi226/sOLqUkwbZsEAR3qLDxqo467NKt2AJMfA0SVa826oFkw cp8HSy+GInbNonZurw2VVKhnJY2xFfU2/plZqTIwkvYvyhHU+M3YsPf1JsV+DnsM 5zFrhZFsbsnt3RZPDc3X2AdAj2BAT7JU7mP/Y42/+gqKAbkmSOjWRU0T1mpaA2Cq bWaPSksrEQSs8URC3vFnXg== From: Akihiko Odaki Date: Mon, 14 Sep 2026 18:31:50 +0900 Subject: [PATCH v4 2/4] hw/qdev: Introduce DevicePhase MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260914-qdev-v4-2-93f849b4865c@rsg.ci.i.u-tokyo.ac.jp> References: <20260914-qdev-v4-0-93f849b4865c@rsg.ci.i.u-tokyo.ac.jp> In-Reply-To: <20260914-qdev-v4-0-93f849b4865c@rsg.ci.i.u-tokyo.ac.jp> To: qemu-devel@nongnu.org Cc: BALATON Zoltan , Paolo Bonzini , =?utf-8?q?Daniel_P=2E_Berrang=C3=A9?= , Eduardo Habkost , "Maciej S. Szmigiero" , "Michael S. Tsirkin" , David Hildenbrand , Igor Mammedov , FangSheng Huang , Alistair Francis , "Edgar E. Iglesias" , Peter Maydell , qemu-arm@nongnu.org, Nicholas Piggin , Aditya Gupta , Glenn Miles , Harsh Prateek Bora , qemu-ppc@nongnu.org, Alex Williamson , =?utf-8?q?C=C3=A9dric_Le_Goater?= , Zhao Liu , Hendrik Brueckner , Richard Henderson , Ilya Leoshkevich , Cornelia Huck , Eric Farman , Matthew Rosato , qemu-s390x@nongnu.org, Luc Michel , Fam Zheng , Eric Blake , Markus Armbruster , Akihiko Odaki X-Mailer: b4 0.17-dev X-Developer-Signature: v=1; a=openpgp-sha256; l=12149; i=odaki@rsg.ci.i.u-tokyo.ac.jp; h=from:subject:message-id; bh=sovqxL/01FU2H2HTkQTqy4GMeDyj8MX23w6O2PdfADA=; b=owGbwMvMwCWmMbc20y1CyJDxtFoSQ9by/XpGq95pChkvzj3I3W0WtDXiv8mmzH1cO/kTu1tZp vPmuG7uKGVhEONikBVTZEkp2s2tEV37qTAhvgVmDisTyBAGLk4BmMgBe4Z/+idr30ywanRRrLQW X3Pwt8/1VPcVrncrVKt9mT8nTjx0gOF/Uo3DwfoOvUV7zyzb/SyyhWnf8zvPMg2mLVaqmeCU42X DDgA= X-Developer-Key: i=odaki@rsg.ci.i.u-tokyo.ac.jp; a=openpgp; fpr=AEDC03C9AF734F2EC26A7BFFA4BAEAA73536753C Received-SPF: pass (zohomail.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=lists1p.gnu.org; Received-SPF: pass client-ip=49.212.243.89; envelope-from=odaki@rsg.ci.i.u-tokyo.ac.jp; helo=www3579.sakura.ne.jp X-Spam_score_int: -19 X-Spam_score: -2.0 X-Spam_bar: -- X-Spam_report: (-2.0 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @rsg.ci.i.u-tokyo.ac.jp) X-ZM-MESSAGEID: 1789378502912158500 Replace the bool DeviceState::realized field with the enum-valued DeviceState::phase field to express finer phases in following changes. The QOM realized property is an internal lifecycle property, not for end users. Replace it with the enum-valued phase property. Signed-off-by: Akihiko Odaki --- qapi/common.json | 14 ++++++++++++++ include/hw/core/qdev.h | 7 ++++--- hw/core/qdev-clock.c | 4 ++-- hw/core/qdev-properties.c | 4 ++-- hw/core/qdev.c | 45 +++++++++++++++++++++++--------------------= -- hw/scsi/scsi-bus.c | 4 ++-- qom/qom-qmp-cmds.c | 2 +- system/qdev-monitor.c | 5 +++-- 8 files changed, 51 insertions(+), 34 deletions(-) diff --git a/qapi/common.json b/qapi/common.json index af7e3d618a7c..415a2722fc1a 100644 --- a/qapi/common.json +++ b/qapi/common.json @@ -7,6 +7,20 @@ # ***************** ## =20 +## +# @DevicePhase: +# +# An enumeration of the device phases +# +# @unrealized: the initial phase +# +# @realized: the phase after realization +# +# Since: 11.2 +## +{ 'enum': 'DevicePhase', + 'data': [ 'unrealized', 'realized' ] } + ## # @IoOperationType: # diff --git a/include/hw/core/qdev.h b/include/hw/core/qdev.h index b1c5f4780a90..ff367b2a5f98 100644 --- a/include/hw/core/qdev.h +++ b/include/hw/core/qdev.h @@ -1,6 +1,7 @@ #ifndef QDEV_CORE_H #define QDEV_CORE_H =20 +#include "qapi/qapi-types-common.h" #include "qemu/atomic.h" #include "qemu/queue.h" #include "qemu/bitmap.h" @@ -232,9 +233,9 @@ struct DeviceState { */ char *canonical_path; /** - * @realized: has device been realized? + * @phase: the current phase */ - bool realized; + DevicePhase phase; /** * @pending_deleted_event: track pending deletion events during unplug */ @@ -440,7 +441,7 @@ DeviceState *qdev_try_new(const char *name); */ static inline bool qdev_is_realized(const DeviceState *dev) { - return qatomic_load_acquire(&dev->realized); + return qatomic_load_acquire(&dev->phase) =3D=3D DEVICE_PHASE_REALIZED; } =20 /** diff --git a/hw/core/qdev-clock.c b/hw/core/qdev-clock.c index 861f78f94c64..efb33a3a27e7 100644 --- a/hw/core/qdev-clock.c +++ b/hw/core/qdev-clock.c @@ -30,7 +30,7 @@ static NamedClockList *qdev_init_clocklist(DeviceState *d= ev, const char *name, * Clock must be added before realize() so that we can compute the * clock's canonical path during device_realize(). */ - assert(!dev->realized); + assert(dev->phase !=3D DEVICE_PHASE_REALIZED); =20 /* * The ncl structure is freed by qdev_finalize_clocklist() which will @@ -186,6 +186,6 @@ Clock *qdev_alias_clock(DeviceState *dev, const char *n= ame, =20 void qdev_connect_clock_in(DeviceState *dev, const char *name, Clock *sour= ce) { - assert(!dev->realized); + assert(dev->phase !=3D DEVICE_PHASE_REALIZED); clock_set_source(qdev_get_clock_in(dev, name), source); } diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c index 34d7b26a7303..66cff4b9338c 100644 --- a/hw/core/qdev-properties.c +++ b/hw/core/qdev-properties.c @@ -33,7 +33,7 @@ static bool qdev_prop_allow_set(Object *obj, const char *= name, { DeviceState *dev =3D DEVICE(obj); =20 - if (dev->realized && !info->realized_set_allowed) { + if (dev->phase =3D=3D DEVICE_PHASE_REALIZED && !info->realized_set_all= owed) { qdev_prop_set_after_realize(dev, name, errp); return false; } @@ -46,7 +46,7 @@ void qdev_prop_allow_set_link_before_realize(const Object= *obj, { DeviceState *dev =3D DEVICE(obj); =20 - if (dev->realized) { + if (dev->phase =3D=3D DEVICE_PHASE_REALIZED) { error_setg(errp, "Attempt to set link property '%s' on device '%s'= " "(type '%s') after it was realized", name, dev->id, object_get_typename(obj)); diff --git a/hw/core/qdev.c b/hw/core/qdev.c index 0b0f2f47fa78..3623fbf69e78 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -134,7 +134,7 @@ bool qdev_set_parent_bus(DeviceState *dev, BusState *bu= s, Error **errp) dev->parent_bus =3D bus; object_ref(OBJECT(bus)); bus_add_child(bus, dev); - if (dev->realized) { + if (dev->phase =3D=3D DEVICE_PHASE_REALIZED) { resettable_change_parent(OBJECT(dev), OBJECT(bus), OBJECT(old_parent_bus)); } @@ -230,7 +230,7 @@ bool qdev_should_hide_device(const QDict *opts, bool fr= om_json, Error **errp) void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id, int required_for_version) { - assert(!dev->realized); + assert(dev->phase !=3D DEVICE_PHASE_REALIZED); dev->instance_id_alias =3D alias_id; dev->alias_required_for_version =3D required_for_version; } @@ -286,7 +286,7 @@ bool qdev_realize(DeviceState *dev, BusState *bus, Erro= r **errp) assert(!DEVICE_GET_CLASS(dev)->bus_type); } =20 - if (object_property_set_bool(OBJECT(dev), "realized", true, errp)) { + if (object_property_set_str(OBJECT(dev), "phase", "realized", errp)) { return true; } =20 @@ -314,7 +314,7 @@ bool qdev_realize_and_unref(DeviceState *dev, BusState = *bus, Error **errp) =20 void qdev_unrealize(DeviceState *dev) { - object_property_set_bool(OBJECT(dev), "realized", false, &error_abort); + object_property_set_str(OBJECT(dev), "phase", "unrealized", &error_abo= rt); } =20 static int qdev_assert_realized_properly_cb(Object *obj, void *opaque) @@ -324,7 +324,7 @@ static int qdev_assert_realized_properly_cb(Object *obj= , void *opaque) =20 if (dev) { dc =3D DEVICE_GET_CLASS(dev); - assert(dev->realized); + assert(dev->phase =3D=3D DEVICE_PHASE_REALIZED); assert(dev->parent_bus || !dc->bus_type); } return 0; @@ -477,10 +477,10 @@ bool qdev_unplug_blocked(DeviceState *dev, Error **er= rp) return false; } =20 -static bool device_get_realized(Object *obj, Error **errp) +static int device_get_phase(Object *obj, Error **errp) { DeviceState *dev =3D DEVICE(obj); - return dev->realized; + return dev->phase; } =20 static bool check_only_migratable(Object *obj, Error **errp) @@ -497,7 +497,7 @@ static bool check_only_migratable(Object *obj, Error **= errp) return true; } =20 -static void device_set_realized(Object *obj, bool value, Error **errp) +static void device_set_phase(Object *obj, int value, Error **errp) { DeviceState *dev =3D DEVICE(obj); DeviceClass *dc =3D DEVICE_GET_CLASS(dev); @@ -512,15 +512,15 @@ static void device_set_realized(Object *obj, bool val= ue, Error **errp) return; } =20 - if (value && !dev->realized) { + if (value =3D=3D DEVICE_PHASE_REALIZED && dev->phase !=3D DEVICE_PHASE= _REALIZED) { if (!check_only_migratable(obj, errp)) { goto fail; } =20 hotplug_ctrl =3D qdev_get_hotplug_handler(dev); if (hotplug_ctrl) { - hotplug_handler_pre_plug(hotplug_ctrl, dev, &local_err); - if (local_err !=3D NULL) { + hotplug_handler_pre_plug(hotplug_ctrl, dev, errp); + if (*errp) { goto fail; } } @@ -589,19 +589,19 @@ static void device_set_realized(Object *obj, bool val= ue, Error **errp) } } =20 - qatomic_store_release(&dev->realized, value); - - } else if (!value && dev->realized) { + qatomic_store_release(&dev->phase, value); =20 + } else if (value !=3D DEVICE_PHASE_REALIZED && + dev->phase =3D=3D DEVICE_PHASE_REALIZED) { /* * Change the value so that any concurrent users are aware * that the device is going to be unrealized * - * TODO: change .realized property to enum that states - * each phase of the device realization/unrealization + * TODO: change .phase property to state + * each sub-phase of the device realization/unrealization */ =20 - qatomic_set(&dev->realized, value); + qatomic_set(&dev->phase, value); /* * Ensure that concurrent users see this update prior to * any other changes done by unrealize. @@ -670,7 +670,7 @@ static void device_initfn(Object *obj) } =20 dev->instance_id_alias =3D -1; - dev->realized =3D false; + dev->phase =3D DEVICE_PHASE_UNREALIZED; dev->allow_unplug_during_migration =3D false; =20 QLIST_INIT(&dev->gpios); @@ -736,7 +736,7 @@ static void device_unparent(Object *obj) DeviceState *dev =3D DEVICE(obj); BusState *bus; =20 - if (dev->realized) { + if (dev->phase =3D=3D DEVICE_PHASE_REALIZED) { qdev_unrealize(dev); } while (dev->num_child_bus) { @@ -768,7 +768,7 @@ static void device_class_init(ObjectClass *class, const= void *data) =20 /* by default all devices were considered as hotpluggable, * so with intent to check it in generic qdev_unplug() / - * device_set_realized() functions make every device + * device_set_phase() functions make every device * hotpluggable. Devices that shouldn't be hotpluggable, * should override it in their class_init() */ @@ -786,8 +786,9 @@ static void device_class_init(ObjectClass *class, const= void *data) */ dc->legacy_reset =3D NULL; =20 - object_class_property_add_bool(class, "realized", - device_get_realized, device_set_realize= d); + object_class_property_add_enum(class, "phase", "DevicePhase", + &DevicePhase_lookup, + device_get_phase, device_set_phase); object_class_property_add_bool(class, "hotpluggable", device_get_hotpluggable, NULL); object_class_property_add_bool(class, "hotplugged", diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index aa02ff631b71..612f272deb2a 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -57,8 +57,8 @@ static SCSIDevice *do_scsi_device_find(SCSIBus *bus, /* * This function might run on the IO thread and we might race against * main thread hot-plugging the device. - * We assume that as soon as .realized is set to true we can let - * the user access the device. + * We assume that as soon as the device is realized we can let + * the user access it. */ =20 if (retval && !include_unrealized && !qdev_is_realized(&retval->qdev))= { diff --git a/qom/qom-qmp-cmds.c b/qom/qom-qmp-cmds.c index 330895361d47..4d2db574144a 100644 --- a/qom/qom-qmp-cmds.c +++ b/qom/qom-qmp-cmds.c @@ -211,7 +211,7 @@ ObjectPropertyInfoList *qmp_device_list_properties(cons= t char *typename, =20 /* Skip Object and DeviceState properties */ if (strcmp(prop->name, "type") =3D=3D 0 || - strcmp(prop->name, "realized") =3D=3D 0 || + strcmp(prop->name, "phase") =3D=3D 0 || strcmp(prop->name, "hotpluggable") =3D=3D 0 || strcmp(prop->name, "hotplugged") =3D=3D 0 || strcmp(prop->name, "parent_bus") =3D=3D 0) { diff --git a/system/qdev-monitor.c b/system/qdev-monitor.c index 5c87fda50939..586c9aaac9c3 100644 --- a/system/qdev-monitor.c +++ b/system/qdev-monitor.c @@ -596,7 +596,7 @@ const char *qdev_set_id(DeviceState *dev, char *id, Err= or **errp) { ObjectProperty *prop; =20 - assert(!dev->id && !dev->realized); + assert(!dev->id && dev->phase !=3D DEVICE_PHASE_REALIZED); =20 /* * object_property_[try_]add_child() below will assert the device @@ -1083,7 +1083,8 @@ static int qdev_add_hotpluggable_device(Object *obj, = void *opaque) return 0; } =20 - if (dev->realized && object_property_get_bool(obj, "hotpluggable", NUL= L)) { + if (dev->phase =3D=3D DEVICE_PHASE_REALIZED && + object_property_get_bool(obj, "hotpluggable", NULL)) { *list =3D g_slist_append(*list, dev); } =20 --=20 2.55.0 From nobody Sat Sep 26 20:52:56 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=reject dis=none) header.from=rsg.ci.i.u-tokyo.ac.jp ARC-Seal: i=1; a=rsa-sha256; t=1789378524; cv=none; d=zohomail.com; s=zohoarc; b=hJlBRN5IM+Yn00BrnPM95GwrfmqmBj0+uNB+Hkjyq8DZ8OFH6K86zgikYFUpIWZCF22S9e2GQBV7kZbVJVxduySXVvCqHX/a3I2U0eofDdYlteDX8feB2ECwFcdfcRfu4/p755Ct1nt7OY05H8gldsbYP9X+NexewxNlgCQGUjQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1789378524; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=n9BWWfE0dQa97OtsMBDqaxa96143zTTodhNiQMz+voA=; b=YpZFYe1KYAXmjxN2byzYCJPkK5f0Gq4XFYJ+aDwoQyjQBIpVA9Qa59LK10GcPM1GULrpkcrS9KbLmBDKvzNHbskqgquZklarM6D+9Zy4ZrvjJFqfqd9SnOjij3i4lhctBC5JA9hWkzfwcvQEcKe4BUBZrecj/zplEpsDEZI2tOA= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=reject dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1789378524382361.6017294549699; Mon, 14 Sep 2026 02:35:24 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1x634r-0000s6-VI; Mon, 14 Sep 2026 05:34:18 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1x634T-0000i0-MM; Mon, 14 Sep 2026 05:33:55 -0400 Received: from www3579.sakura.ne.jp ([49.212.243.89]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1x634M-0000S0-TT; Mon, 14 Sep 2026 05:33:51 -0400 Received: from h183.csg.ci.i.u-tokyo.ac.jp (h183.csg.ci.i.u-tokyo.ac.jp [133.11.54.183]) (authenticated bits=0) by www3579.sakura.ne.jp (8.16.1/8.16.1) with ESMTPSA id 68E9WXEY020350 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO); Mon, 14 Sep 2026 18:32:39 +0900 (JST) (envelope-from odaki@rsg.ci.i.u-tokyo.ac.jp) DKIM-Signature: a=rsa-sha256; bh=n9BWWfE0dQa97OtsMBDqaxa96143zTTodhNiQMz+voA=; c=relaxed/relaxed; d=rsg.ci.i.u-tokyo.ac.jp; h=From:Message-Id:To:Subject:Date; s=rs20250326; t=1789378359; v=1; b=NhKF2pog4wmir/D/gQysVSaZxemR8yaKACfGtJ7fO2Wv/AZxj6fCNpEUZHZtqRyC /uLBH69H9NBhrLCeLd7N4Uv1A0utWAaw/QNF2+RxaSNJfy6rfbdIDKxS0JwxmaTz 3SSJx1xD72xeARN9aF4lgc2LGzAjXn6yozvc5O+t8u9jU1jp9KQRhBjJKR+D8JxW LDcAqw2w8rVXLQ9R+ilacwi/RKd85nHGuEJMUmAMZge8aESlW9qWwiv2U+3Cys8J M9RJqeYNM5v2ddkV5W7AQHshsDMtRoOLoLHCeM4DAc+IIQ64Rl3UUGWG7wdSh77e PhlP9kxR8wk65v18pv0MBQ== From: Akihiko Odaki Date: Mon, 14 Sep 2026 18:31:51 +0900 Subject: [PATCH v4 3/4] hw/qdev: Introduce the initialized and retired phases MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260914-qdev-v4-3-93f849b4865c@rsg.ci.i.u-tokyo.ac.jp> References: <20260914-qdev-v4-0-93f849b4865c@rsg.ci.i.u-tokyo.ac.jp> In-Reply-To: <20260914-qdev-v4-0-93f849b4865c@rsg.ci.i.u-tokyo.ac.jp> To: qemu-devel@nongnu.org Cc: BALATON Zoltan , Paolo Bonzini , =?utf-8?q?Daniel_P=2E_Berrang=C3=A9?= , Eduardo Habkost , "Maciej S. Szmigiero" , "Michael S. Tsirkin" , David Hildenbrand , Igor Mammedov , FangSheng Huang , Alistair Francis , "Edgar E. Iglesias" , Peter Maydell , qemu-arm@nongnu.org, Nicholas Piggin , Aditya Gupta , Glenn Miles , Harsh Prateek Bora , qemu-ppc@nongnu.org, Alex Williamson , =?utf-8?q?C=C3=A9dric_Le_Goater?= , Zhao Liu , Hendrik Brueckner , Richard Henderson , Ilya Leoshkevich , Cornelia Huck , Eric Farman , Matthew Rosato , qemu-s390x@nongnu.org, Luc Michel , Fam Zheng , Eric Blake , Markus Armbruster , Akihiko Odaki X-Mailer: b4 0.17-dev X-Developer-Signature: v=1; a=openpgp-sha256; l=10749; i=odaki@rsg.ci.i.u-tokyo.ac.jp; h=from:subject:message-id; bh=3i74lwjzvE2YCcOnqcK5z/mmWwz3jiRm5sw61tECvh8=; b=kA0DAAoWKJ19aUZYEjEByyZiAGqnvy/IM/hlLzcBPLvpdcE40rJRvEPAg0fJeWvYB3e3nd1wG Yh1BAAWCgAdFiEEZHK7CyhbffJxYF+EKJ19aUZYEjEFAmqnvy8ACgkQKJ19aUZYEjH6twD/cBtZ ur5RTBjtgp7tXqW8YmsnS21ltwcIm04yhOK5P8UBAIFano5DiEhqg57wwV3u0MJmB6lnD1uRuCV Mv4HgZPgL X-Developer-Key: i=odaki@rsg.ci.i.u-tokyo.ac.jp; a=openpgp; fpr=AEDC03C9AF734F2EC26A7BFFA4BAEAA73536753C Received-SPF: pass (zohomail.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=lists1p.gnu.org; Received-SPF: pass client-ip=49.212.243.89; envelope-from=odaki@rsg.ci.i.u-tokyo.ac.jp; helo=www3579.sakura.ne.jp X-Spam_score_int: -19 X-Spam_score: -2.0 X-Spam_bar: -- X-Spam_report: (-2.0 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @rsg.ci.i.u-tokyo.ac.jp) X-ZM-MESSAGEID: 1789378524873158500 qdev currently permits another realization attempt after a device has been unrealized or a previous attempt has failed, which can invoke DeviceClass::realize() more than once. Supporting repeated realization adds complexity to device implementations. It is untested and likely broken. Replace the unrealized phase with two finer phases: initialized and retired. Realization can start only in the initialized phase. Successful realization moves it to the realized phase; failure after realization has started moves it to the retired phase. Unrealization also moves a device to the retired phase. Signed-off-by: Akihiko Odaki --- qapi/common.json | 7 +++-- include/hw/core/qdev.h | 3 +- hw/core/qdev.c | 53 +++++++++++++++++++++++----------- tests/unit/test-qdev.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++= +++- 4 files changed, 121 insertions(+), 20 deletions(-) diff --git a/qapi/common.json b/qapi/common.json index 415a2722fc1a..f3218b846ce8 100644 --- a/qapi/common.json +++ b/qapi/common.json @@ -12,14 +12,17 @@ # # An enumeration of the device phases # -# @unrealized: the initial phase +# @initialized: the initial phase # # @realized: the phase after realization # +# @retired: the phase entered when unrealization begins or +# realization fails after starting +# # Since: 11.2 ## { 'enum': 'DevicePhase', - 'data': [ 'unrealized', 'realized' ] } + 'data': [ 'initialized', 'realized', 'retired' ] } =20 ## # @IoOperationType: diff --git a/include/hw/core/qdev.h b/include/hw/core/qdev.h index ff367b2a5f98..a0aa7e3f6e35 100644 --- a/include/hw/core/qdev.h +++ b/include/hw/core/qdev.h @@ -32,7 +32,8 @@ * * #TypeInfo.instance_init may not fail. #DeviceClass.realize can * fail, returning error information to the caller, and must be re-entrant. - * + * A device's realize method will not be called after realization, even + * if realization fails or the device is later unrealized. * #TypeInfo.instance_init should add instance properties but must not * have any side effect not contained in the instance, since it happens * during device introspection already. Any operations without special diff --git a/hw/core/qdev.c b/hw/core/qdev.c index 3623fbf69e78..ca150ecad023 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -314,7 +314,7 @@ bool qdev_realize_and_unref(DeviceState *dev, BusState = *bus, Error **errp) =20 void qdev_unrealize(DeviceState *dev) { - object_property_set_str(OBJECT(dev), "phase", "unrealized", &error_abo= rt); + object_property_set_str(OBJECT(dev), "phase", "retired", &error_abort); } =20 static int qdev_assert_realized_properly_cb(Object *obj, void *opaque) @@ -499,12 +499,22 @@ static bool check_only_migratable(Object *obj, Error = **errp) =20 static void device_set_phase(Object *obj, int value, Error **errp) { + ERRP_GUARD(); DeviceState *dev =3D DEVICE(obj); DeviceClass *dc =3D DEVICE_GET_CLASS(dev); + DevicePhase old_value =3D dev->phase; HotplugHandler *hotplug_ctrl; BusState *bus; NamedClockList *ncl; - Error *local_err =3D NULL; + + if (value =3D=3D old_value) { + return; + } + + if (old_value =3D=3D DEVICE_PHASE_RETIRED) { + error_setg(errp, "A device cannot transition from retired to anoth= er phase"); + return; + } =20 if (dev->hotplugged && !dc->hotpluggable) { error_setg(errp, "Device '%s' does not support hotplugging", @@ -512,7 +522,12 @@ static void device_set_phase(Object *obj, int value, E= rror **errp) return; } =20 - if (value =3D=3D DEVICE_PHASE_REALIZED && dev->phase !=3D DEVICE_PHASE= _REALIZED) { + switch (value) { + case DEVICE_PHASE_INITIALIZED: + error_setg(errp, "A device cannot transition from another phase to= initialized"); + return; + + case DEVICE_PHASE_REALIZED: if (!check_only_migratable(obj, errp)) { goto fail; } @@ -526,8 +541,8 @@ static void device_set_phase(Object *obj, int value, Er= ror **errp) } =20 if (dc->realize) { - dc->realize(dev, &local_err); - if (local_err !=3D NULL) { + dc->realize(dev, errp); + if (*errp) { goto fail; } } @@ -554,7 +569,7 @@ static void device_set_phase(Object *obj, int value, Er= ror **errp) qdev_get_vmsd(dev), dev, dev->instance_id_alias, dev->alias_required_for_ver= sion, - &local_err) < 0) { + errp) < 0) { goto post_realize_fail; } } @@ -583,25 +598,30 @@ static void device_set_phase(Object *obj, int value, = Error **errp) dev->pending_deleted_event =3D false; =20 if (hotplug_ctrl) { - hotplug_handler_plug(hotplug_ctrl, dev, &local_err); - if (local_err !=3D NULL) { + hotplug_handler_plug(hotplug_ctrl, dev, errp); + if (*errp) { goto child_realize_fail; } } =20 qatomic_store_release(&dev->phase, value); + return; =20 - } else if (value !=3D DEVICE_PHASE_REALIZED && - dev->phase =3D=3D DEVICE_PHASE_REALIZED) { + case DEVICE_PHASE_RETIRED: /* * Change the value so that any concurrent users are aware - * that the device is going to be unrealized + * that the device is going to be retired * * TODO: change .phase property to state * each sub-phase of the device realization/unrealization */ =20 qatomic_set(&dev->phase, value); + + if (old_value =3D=3D DEVICE_PHASE_INITIALIZED) { + return; + } + /* * Ensure that concurrent users see this update prior to * any other changes done by unrealize. @@ -619,10 +639,11 @@ static void device_set_phase(Object *obj, int value, = Error **errp) } dev->pending_deleted_event =3D true; DEVICE_LISTENER_CALL(unrealize, Reverse, dev); - } + return; =20 - assert(local_err =3D=3D NULL); - return; + default: + g_assert_not_reached(); + } =20 child_realize_fail: QLIST_FOREACH(bus, &dev->child_bus, sibling) { @@ -641,7 +662,7 @@ post_realize_fail: } =20 fail: - error_propagate(errp, local_err); + qatomic_store_release(&dev->phase, DEVICE_PHASE_RETIRED); } =20 static bool device_get_hotpluggable(Object *obj, Error **errp) @@ -670,7 +691,7 @@ static void device_initfn(Object *obj) } =20 dev->instance_id_alias =3D -1; - dev->phase =3D DEVICE_PHASE_UNREALIZED; + dev->phase =3D DEVICE_PHASE_INITIALIZED; dev->allow_unplug_during_migration =3D false; =20 QLIST_INIT(&dev->gpios); diff --git a/tests/unit/test-qdev.c b/tests/unit/test-qdev.c index 77c3eee71713..bb1049fa9919 100644 --- a/tests/unit/test-qdev.c +++ b/tests/unit/test-qdev.c @@ -17,6 +17,9 @@ struct MyDev { char *prop_string; uint32_t *prop_array_u32; uint32_t prop_array_u32_nb; + uint16_t realization_count; + uint16_t unrealization_count; + Error *realization_err; }; =20 static const Property my_dev_props[] =3D { @@ -26,11 +29,25 @@ static const Property my_dev_props[] =3D { qdev_prop_uint32, uint32_t), }; =20 +static void my_dev_realize(DeviceState *dev, Error **errp) +{ + MyDev *mt =3D STATIC_TYPE(dev); + mt->realization_count++; + error_propagate(errp, g_steal_pointer(&mt->realization_err)); +} + +static void my_dev_unrealize(DeviceState *dev) +{ + MyDev *mt =3D STATIC_TYPE(dev); + mt->unrealization_count++; +} + static void my_dev_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc =3D DEVICE_CLASS(oc); =20 - dc->realize =3D NULL; + dc->realize =3D my_dev_realize; + dc->unrealize =3D my_dev_unrealize; device_class_set_props(dc, my_dev_props); } =20 @@ -82,8 +99,55 @@ static void test_qdev_double_realization(void) { MyDev *mt =3D STATIC_TYPE(object_new(TYPE_MY_DEV)); =20 + g_assert_cmpint(mt->realization_count, =3D=3D, 0); qdev_realize(DEVICE(mt), NULL, &error_fatal); + g_assert_cmpint(mt->realization_count, =3D=3D, 1); qdev_realize(DEVICE(mt), NULL, &error_fatal); + g_assert_cmpint(mt->realization_count, =3D=3D, 1); + object_unparent(OBJECT(mt)); + object_unref(OBJECT(mt)); +} + +static void test_qdev_realize_after_unrealization(void) +{ + Object *mt =3D object_new(TYPE_MY_DEV); + + qdev_unrealize(DEVICE(mt)); + g_assert_false(qdev_realize(DEVICE(mt), NULL, NULL)); + object_unparent(mt); + object_unref(mt); +} + +static void test_qdev_retry_realization(void) +{ + MyDev *mt =3D STATIC_TYPE(object_new(TYPE_MY_DEV)); + + error_setg(&mt->realization_err, "error"); + g_assert_false(qdev_realize(DEVICE(mt), NULL, NULL)); + g_assert_false(qdev_realize(DEVICE(mt), NULL, NULL)); + object_unparent(OBJECT(mt)); + object_unref(OBJECT(mt)); +} + +static void test_qdev_unrealize_after_realization(void) +{ + MyDev *mt =3D STATIC_TYPE(object_new(TYPE_MY_DEV)); + + qdev_realize(DEVICE(mt), NULL, &error_fatal); + g_assert_cmpint(mt->unrealization_count, =3D=3D, 0); + qdev_unrealize(DEVICE(mt)); + g_assert_cmpint(mt->unrealization_count, =3D=3D, 1); + object_unparent(OBJECT(mt)); + object_unref(OBJECT(mt)); +} + +static void test_qdev_unrealize_without_realization(void) +{ + MyDev *mt =3D STATIC_TYPE(object_new(TYPE_MY_DEV)); + + g_assert_cmpint(mt->unrealization_count, =3D=3D, 0); + qdev_unrealize(DEVICE(mt)); + g_assert_cmpint(mt->unrealization_count, =3D=3D, 0); object_unparent(OBJECT(mt)); object_unref(OBJECT(mt)); } @@ -103,6 +167,18 @@ int main(int argc, char **argv) g_test_add_func("/qdev/double-realization", test_qdev_double_realization); =20 + g_test_add_func("/qdev/realize-after-unrealization", + test_qdev_realize_after_unrealization); + + g_test_add_func("/qdev/retry-realization", + test_qdev_retry_realization); + + g_test_add_func("/qdev/unrealize-after-realization", + test_qdev_unrealize_after_realization); + + g_test_add_func("/qdev/unrealize-without-realization", + test_qdev_unrealize_without_realization); + g_test_run(); =20 return 0; --=20 2.55.0 From nobody Sat Sep 26 20:52:56 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=reject dis=none) header.from=rsg.ci.i.u-tokyo.ac.jp ARC-Seal: i=1; a=rsa-sha256; t=1789378495; cv=none; d=zohomail.com; s=zohoarc; b=M994QY1OBJcuG13l9Y0F7x5jX/SDgJT58BhPeppqmbGbqGbzh2zusXKh+LMl1cFkesHG5mVNCb/v46/HaOHCwq4FYQvWmf6kSHIAsvix0JUtufEqzQ62XFlDvA81G68Yh8Ny7zVPu1M1rAercyd4ZhuLI4IxU3DdQlNuVEYbseo= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1789378495; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=O5wDgXC/TuaFHn1dcGoYTVezrrNNB83UDSJG4TY3Oyo=; b=eiXgnTsBI0DN/siArWMXrQ834wP790bmkqYErQ8SQMT3loFbnSnDXiHE1zMHDXKMyY3bvuLWoN8xlAvm7W+ickCmZD55WEAEWykr5jxh0FdZUgTonIUVq99OWeM5oFZf126QZfQrW3dlLhJVkLD3GN0junumd090HoPdAfnQTos= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=reject dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1789378495249750.4790137107237; Mon, 14 Sep 2026 02:34:55 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1x634r-0000qd-K5; Mon, 14 Sep 2026 05:34:17 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1x634R-0000he-NA; Mon, 14 Sep 2026 05:33:53 -0400 Received: from www3579.sakura.ne.jp ([49.212.243.89]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1x634M-0000S6-Sx; Mon, 14 Sep 2026 05:33:49 -0400 Received: from h183.csg.ci.i.u-tokyo.ac.jp (h183.csg.ci.i.u-tokyo.ac.jp [133.11.54.183]) (authenticated bits=0) by www3579.sakura.ne.jp (8.16.1/8.16.1) with ESMTPSA id 68E9WXEZ020350 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO); Mon, 14 Sep 2026 18:32:39 +0900 (JST) (envelope-from odaki@rsg.ci.i.u-tokyo.ac.jp) DKIM-Signature: a=rsa-sha256; bh=O5wDgXC/TuaFHn1dcGoYTVezrrNNB83UDSJG4TY3Oyo=; c=relaxed/relaxed; d=rsg.ci.i.u-tokyo.ac.jp; h=From:Message-Id:To:Subject:Date; s=rs20250326; t=1789378360; v=1; b=rtoouPYCadezWfB6yc131UGlYHIuD1NFayTaA8z2OphmB4LUUn5JMs7kmhJtE5El XgLyccwX3Ox2T+HZuorZ/RCbMRc2TJ5zgpzqwgJV2V3sSf739fFX3zEWXDegEb0n HjqjVhns5XATbUEXvQpEUWrOuL8HbIB1d+jeLM8zwl55e92fkV1wxEQvgEhfebNf IXs1mMiDM9QPVIc6eabwc2itrKOORm1z2WbxfuhAnRUBGvodh2FQfj1beeciGGCI 0719JJ1Tzr4H1S3bA0Tk1EAzXYykF/WjUFpoaXrxqHPQ8wAfUieA7H6NLk8vmhDC 23euKPbwQJscgvRbQjQ5uQ== From: Akihiko Odaki Date: Mon, 14 Sep 2026 18:31:52 +0900 Subject: [PATCH v4 4/4] hw/qdev: Introduce the realizing phase MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260914-qdev-v4-4-93f849b4865c@rsg.ci.i.u-tokyo.ac.jp> References: <20260914-qdev-v4-0-93f849b4865c@rsg.ci.i.u-tokyo.ac.jp> In-Reply-To: <20260914-qdev-v4-0-93f849b4865c@rsg.ci.i.u-tokyo.ac.jp> To: qemu-devel@nongnu.org Cc: BALATON Zoltan , Paolo Bonzini , =?utf-8?q?Daniel_P=2E_Berrang=C3=A9?= , Eduardo Habkost , "Maciej S. Szmigiero" , "Michael S. Tsirkin" , David Hildenbrand , Igor Mammedov , FangSheng Huang , Alistair Francis , "Edgar E. Iglesias" , Peter Maydell , qemu-arm@nongnu.org, Nicholas Piggin , Aditya Gupta , Glenn Miles , Harsh Prateek Bora , qemu-ppc@nongnu.org, Alex Williamson , =?utf-8?q?C=C3=A9dric_Le_Goater?= , Zhao Liu , Hendrik Brueckner , Richard Henderson , Ilya Leoshkevich , Cornelia Huck , Eric Farman , Matthew Rosato , qemu-s390x@nongnu.org, Luc Michel , Fam Zheng , Eric Blake , Markus Armbruster , Akihiko Odaki X-Mailer: b4 0.17-dev X-Developer-Signature: v=1; a=openpgp-sha256; l=5563; i=odaki@rsg.ci.i.u-tokyo.ac.jp; h=from:subject:message-id; bh=M+YVSnl+FD4HvWRd/TW0KV+djv8mwPLa3roXX6sR2bk=; b=owGbwMvMwCWmMbc20y1CyJDxtFoSQ9by/QYrdQsXXv550ldCdpc6e67E8nuenGpRLt98lsVFM raZs6l2lLIwiHExyIopsqQU7ebWiK79VJgQ3wIzh5UJZAgDF6cATGR3LsP/sj8BTwMyJh4omX9H sPV52MRVb9T7uIsU7q6SPGLRIG2xmJFhmj9zm0n6ktWXdpsnqBRqhM5sc9N7skPixu4wvk3xcSv YAQ== X-Developer-Key: i=odaki@rsg.ci.i.u-tokyo.ac.jp; a=openpgp; fpr=AEDC03C9AF734F2EC26A7BFFA4BAEAA73536753C Received-SPF: pass (zohomail.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=lists1p.gnu.org; Received-SPF: pass client-ip=49.212.243.89; envelope-from=odaki@rsg.ci.i.u-tokyo.ac.jp; helo=www3579.sakura.ne.jp X-Spam_score_int: -19 X-Spam_score: -2.0 X-Spam_bar: -- X-Spam_report: (-2.0 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @rsg.ci.i.u-tokyo.ac.jp) X-ZM-MESSAGEID: 1789378496908158500 qdev currently permits reentrant realization of the same device, but supporting it adds complexity to device implementations. It is untested and likely broken. Add the realizing phase, and move the device to the new phase before invoking realization callbacks, preventing another realization attempt. Signed-off-by: Akihiko Odaki --- qapi/common.json | 6 ++++-- include/hw/core/qdev.h | 6 +++--- hw/core/qdev.c | 11 +++++++++++ tests/unit/test-qdev.c | 34 ++++++++++++++++++++++++++++++++++ 4 files changed, 52 insertions(+), 5 deletions(-) diff --git a/qapi/common.json b/qapi/common.json index f3218b846ce8..c77fc6b01a2a 100644 --- a/qapi/common.json +++ b/qapi/common.json @@ -14,15 +14,17 @@ # # @initialized: the initial phase # +# @realizing: the phase during realization +# # @realized: the phase after realization # -# @retired: the phase entered when unrealization begins or +# @retired: the terminal phase entered when unrealization begins or # realization fails after starting # # Since: 11.2 ## { 'enum': 'DevicePhase', - 'data': [ 'initialized', 'realized', 'retired' ] } + 'data': [ 'initialized', 'realizing', 'realized', 'retired' ] } =20 ## # @IoOperationType: diff --git a/include/hw/core/qdev.h b/include/hw/core/qdev.h index a0aa7e3f6e35..0d10410f6f06 100644 --- a/include/hw/core/qdev.h +++ b/include/hw/core/qdev.h @@ -31,9 +31,9 @@ * 3) device realization * * #TypeInfo.instance_init may not fail. #DeviceClass.realize can - * fail, returning error information to the caller, and must be re-entrant. - * A device's realize method will not be called after realization, even - * if realization fails or the device is later unrealized. + * fail, returning error information to the caller. + * A device's realize method is called at most once, even if realization + * fails or the device is later unrealized. * #TypeInfo.instance_init should add instance properties but must not * have any side effect not contained in the instance, since it happens * during device introspection already. Any operations without special diff --git a/hw/core/qdev.c b/hw/core/qdev.c index ca150ecad023..63b87f20d645 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -511,6 +511,11 @@ static void device_set_phase(Object *obj, int value, E= rror **errp) return; } =20 + if (old_value =3D=3D DEVICE_PHASE_REALIZING) { + error_setg(errp, "The device is currently realizing"); + return; + } + if (old_value =3D=3D DEVICE_PHASE_RETIRED) { error_setg(errp, "A device cannot transition from retired to anoth= er phase"); return; @@ -527,7 +532,13 @@ static void device_set_phase(Object *obj, int value, E= rror **errp) error_setg(errp, "A device cannot transition from another phase to= initialized"); return; =20 + case DEVICE_PHASE_REALIZING: + error_setg(errp, "The realizing phase cannot be set via property"); + return; + case DEVICE_PHASE_REALIZED: + qatomic_set(&dev->phase, DEVICE_PHASE_REALIZING); + if (!check_only_migratable(obj, errp)) { goto fail; } diff --git a/tests/unit/test-qdev.c b/tests/unit/test-qdev.c index bb1049fa9919..14935f4d3d9e 100644 --- a/tests/unit/test-qdev.c +++ b/tests/unit/test-qdev.c @@ -10,6 +10,8 @@ typedef struct MyDev MyDev; DECLARE_INSTANCE_CHECKER(MyDev, STATIC_TYPE, TYPE_MY_DEV) =20 +#define TYPE_REENTRANT_REALIZATION "reentrant-realization" + struct MyDev { DeviceState parent_obj; =20 @@ -58,6 +60,25 @@ static const TypeInfo my_dev_type_info =3D { .class_init =3D my_dev_class_init, }; =20 +static void reentrant_realization_realize(DeviceState *dev, Error **errp) +{ + g_assert_false(qdev_realize(dev, NULL, NULL)); +} + +static void reentrant_realization_class_init(ObjectClass *oc, const void *= data) +{ + DeviceClass *dc =3D DEVICE_CLASS(oc); + + dc->realize =3D reentrant_realization_realize; +} + +static const TypeInfo reentrant_realization_type_info =3D { + .name =3D TYPE_REENTRANT_REALIZATION, + .parent =3D TYPE_DEVICE, + .instance_size =3D sizeof(DeviceState), + .class_init =3D reentrant_realization_class_init, +}; + /* * Initialize a fake machine, being prepared for future tests. * @@ -118,6 +139,15 @@ static void test_qdev_realize_after_unrealization(void) object_unref(mt); } =20 +static void test_qdev_reentrant_realization(void) +{ + Object *obj =3D object_new(TYPE_REENTRANT_REALIZATION); + + qdev_realize(DEVICE(obj), NULL, &error_fatal); + object_unparent(OBJECT(obj)); + object_unref(obj); +} + static void test_qdev_retry_realization(void) { MyDev *mt =3D STATIC_TYPE(object_new(TYPE_MY_DEV)); @@ -159,6 +189,7 @@ int main(int argc, char **argv) =20 module_call_init(MODULE_INIT_QOM); type_register_static(&my_dev_type_info); + type_register_static(&reentrant_realization_type_info); test_init_machine(); =20 g_test_add_func("/qdev/free-properties", @@ -170,6 +201,9 @@ int main(int argc, char **argv) g_test_add_func("/qdev/realize-after-unrealization", test_qdev_realize_after_unrealization); =20 + g_test_add_func("/qdev/reentrant-realization", + test_qdev_reentrant_realization); + g_test_add_func("/qdev/retry-realization", test_qdev_retry_realization); =20 --=20 2.55.0