[PATCH for-11.2 v3 00/15] qdev: Clarify and enforce the device realization lifecycle

Akihiko Odaki posted 15 patches 4 days, 1 hour ago
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/qemu tags/patchew/20260721-qdev-v3-0-d2e226fa002e@rsg.ci.i.u-tokyo.ac.jp
Maintainers: Paolo Bonzini <pbonzini@redhat.com>, "Daniel P. Berrangé" <berrange@redhat.com>, Luc Michel <luc@lmichel.fr>, "Maciej S. Szmigiero" <maciej.szmigiero@oracle.com>, "Michael S. Tsirkin" <mst@redhat.com>, David Hildenbrand <david@kernel.org>, Igor Mammedov <imammedo@redhat.com>, FangSheng Huang <FangSheng.Huang@amd.com>, Alistair Francis <alistair@alistair23.me>, "Edgar E. Iglesias" <edgar.iglesias@gmail.com>, Peter Maydell <peter.maydell@linaro.org>, Nicholas Piggin <npiggin@gmail.com>, Aditya Gupta <adityag@linux.ibm.com>, Glenn Miles <milesg@linux.ibm.com>, Harsh Prateek Bora <harshpb@linux.ibm.com>, Fam Zheng <fam@euphon.net>, Alex Williamson <alex@shazbot.org>, "Cédric Le Goater" <clg@redhat.com>, Eric Blake <eblake@redhat.com>, Markus Armbruster <armbru@redhat.com>, Zhao Liu <zhao1.liu@intel.com>, Hendrik Brueckner <brueckner@linux.ibm.com>, Cornelia Huck <cohuck@redhat.com>, Eric Farman <farman@linux.ibm.com>, Matthew Rosato <mjrosato@linux.ibm.com>, Richard Henderson <richard.henderson@linaro.org>, Ilya Leoshkevich <iii@linux.ibm.com>
qapi/common.json           |  19 ++++++
include/hw/core/qdev.h     |  62 ++++++++++---------
hw/core/qdev-clock.c       |   4 +-
hw/core/qdev-properties.c  |   4 +-
hw/core/qdev.c             | 147 ++++++++++++++++++++++++++++-----------------
hw/hyperv/hv-balloon.c     |   2 +-
hw/intc/apic_common.c      |   2 +-
hw/mem/memory-device.c     |   4 +-
hw/mem/pc-dimm.c           |   2 +-
hw/nvram/xlnx-bbram.c      |   2 +-
hw/nvram/xlnx-efuse.c      |   2 +-
hw/ppc/pnv_xscom.c         |   2 +-
hw/scsi/scsi-bus.c         |   4 +-
hw/vfio/container-legacy.c |   4 +-
hw/vfio/device.c           |   4 +-
hw/vfio/iommufd.c          |   2 +-
hw/virtio/virtio-mem.c     |   4 +-
hw/virtio/virtio-qmp.c     |   4 +-
qom/qom-qmp-cmds.c         |   2 +-
system/qdev-monitor.c      |   5 +-
target/i386/cpu.c          |   2 +-
target/s390x/cpu_models.c  |   4 +-
tests/unit/test-qdev.c     | 125 +++++++++++++++++++++++++++++++++++++-
23 files changed, 301 insertions(+), 111 deletions(-)
[PATCH for-11.2 v3 00/15] qdev: Clarify and enforce the device realization lifecycle
Posted by Akihiko Odaki 4 days, 1 hour ago
qdev currently represents a device's realization state with a single
boolean. This cannot distinguish a device that has never been realized
from one whose realization has failed or that has been unrealized, nor
can it represent realization in progress. Consequently, the same device
can enter DeviceClass::realize() reentrantly or more than once.
Supporting that complicates device implementations, and the behavior is
untested and likely broken.

This series first clarifies the division of work between
TypeInfo.instance_init, pre-realize property setting, and
DeviceClass::realize, including the implications of device introspection
and property-dependent child creation.

The remaining direct reads of DeviceState::realized are then converted
to qdev_is_realized(). Keeping users behind this accessor allows the
underlying lifecycle representation to change without exposing it; the
accessor is also made const so callers with a const DeviceState can use
it.

Before changing that representation, the series fixes an existing
qdev invariant. qdev_realize() can attach an unparented device to a
bus before giving it a QOM parent. A failure between those operations
leaves a bus child that object_unparent() cannot remove, causing
bus_unparent() to loop indefinitely. qdev_realize() now establishes
the QOM parent before attaching the device to its bus and rolls the
parent back on failure.

Finally, DeviceState::realized and the QOM realized property are
replaced with four explicit phases: initialized, realizing, realized,
and retired.
Entering the realizing phase before invoking callbacks prevents
reentrant realization. A failure after realization starts, or the start
of unrealization, moves the device to the terminal retired phase, so a
device's realize method is invoked at most once.

Signed-off-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>
---
Changes in v3:
- Ensured devices are QOM-parented before attaching them to a bus,
  avoiding unparentable bus children when realization fails.
- Clarified property-dependent child creation.
- Removed documentation references to the QOM realized property.
- Replaced DeviceState::realized and the QOM realized property with
  device phases. The realizing phase prevents reentrant realization, and
  the terminal retired phase prevents another attempt after realization
  fails or unrealization begins.
- Link to v2: https://lore.kernel.org/qemu-devel/20260629-qdev-v2-1-8cd1d9be0d8d@rsg.ci.i.u-tokyo.ac.jp

Changes in v2:
- Clarified the ordering of #TypeInfo.instance_init, pre-realize
  property setting, and realization.
- Clarified that #TypeInfo.instance_init is for per-instance properties,
  not class properties.
- Link to v1: https://lore.kernel.org/qemu-devel/20250908-qdev-v1-1-df236f7ce5bd@rsg.ci.i.u-tokyo.ac.jp

---
Akihiko Odaki (15):
      qdev: Clarify instantiation and realization
      qdev: Make qdev_is_realized() take a const DeviceState *
      hw/hyperv/balloon: Use qdev_is_realized()
      hw/intc/apic: Use qdev_is_realized()
      hw/mem/memory-device: Use qdev_is_realized()
      hw/mem/pc-dimm: Use qdev_is_realized()
      hw/nvram: Use qdev_is_realized()
      hw/ppc/pnv_xscom: Use qdev_is_realized()
      hw/vfio: Use qdev_is_realized()
      hw/virtio/virtio-mem: Use qdev_is_realized()
      hw/virtio/virtio-qmp: Use qdev_is_realized()
      target/i386/cpu: Use qdev_is_realized()
      target/s390x: Use qdev_is_realized()
      hw/qdev: Parent device before setting parent bus
      hw/qdev: Prevent devices from being realized more than once

 qapi/common.json           |  19 ++++++
 include/hw/core/qdev.h     |  62 ++++++++++---------
 hw/core/qdev-clock.c       |   4 +-
 hw/core/qdev-properties.c  |   4 +-
 hw/core/qdev.c             | 147 ++++++++++++++++++++++++++++-----------------
 hw/hyperv/hv-balloon.c     |   2 +-
 hw/intc/apic_common.c      |   2 +-
 hw/mem/memory-device.c     |   4 +-
 hw/mem/pc-dimm.c           |   2 +-
 hw/nvram/xlnx-bbram.c      |   2 +-
 hw/nvram/xlnx-efuse.c      |   2 +-
 hw/ppc/pnv_xscom.c         |   2 +-
 hw/scsi/scsi-bus.c         |   4 +-
 hw/vfio/container-legacy.c |   4 +-
 hw/vfio/device.c           |   4 +-
 hw/vfio/iommufd.c          |   2 +-
 hw/virtio/virtio-mem.c     |   4 +-
 hw/virtio/virtio-qmp.c     |   4 +-
 qom/qom-qmp-cmds.c         |   2 +-
 system/qdev-monitor.c      |   5 +-
 target/i386/cpu.c          |   2 +-
 target/s390x/cpu_models.c  |   4 +-
 tests/unit/test-qdev.c     | 125 +++++++++++++++++++++++++++++++++++++-
 23 files changed, 301 insertions(+), 111 deletions(-)
---
base-commit: 499039798cdad7d86b787fec0eaf1da4151c0f05
change-id: 20250906-qdev-9e5cb7c06ffa

Best regards,
--  
Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>
Re: [PATCH for-11.2 v3 00/15] qdev: Clarify and enforce the device realization lifecycle
Posted by Markus Armbruster 21 hours ago
Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp> writes:

> qdev currently represents a device's realization state with a single
> boolean. This cannot distinguish a device that has never been realized
> from one whose realization has failed or that has been unrealized, nor
> can it represent realization in progress. Consequently, the same device
> can enter DeviceClass::realize() reentrantly or more than once.

.realized is initially false.  It is only ever modified in
device_set_realized(), which is the setter of QOM property "realized" of
"device" and its subtypes.  device_set_realized() is only called when
the property is set.  It does nothing when the new value is the same as
the old value.

Code changes property "realized" only in qdev_realize() and
qdev_unrealize().

Implementations of .realize may call qdev_realize() for their
components.  Having this loop back would be a bug.

If your claim "can enter reentrantly" is correct, we have bugs to fix.
I believe it is incorrect.

There are two kinds of devices, onboard and user-created.

User-created devices go through qdev_device_add_from_qdict().  If
qdev_realize() fails, the device is immediately destroyed.

Onboard devices get created and realized by board code.  It commonly
treats qdev_realize() failure as fatal error.  Trying again instead
would be a bug.

If your claim "can enter more than once" is correct, we have bugs to
fix.  I believe it is incorrect.

Exception, sort of: users can manipulate properties with QMP command
qom-set.  This is generally unsupported and a Very Bad Idea[*].  There
might be supported exceptions (I don't know), but "realized" is
definitely not among them.  Unsurprisingly, it's a fast path to grief:

    $ qemu-system-x86_64 -S -display none -monitor stdio -nodefaults
    QEMU 11.0.90 monitor - type 'help' for more information
    (qemu) qom-set /machine/i440fx realized false
    (qemu) qom-set /machine/i440fx realized true
    qemu-system-x86_64: ../system/memory.c:2585: memory_region_add_subregion_common: Assertion `!subregion->container' failed.

I figure your series rejects the second qom-set.  I'm pretty sure the
first qom-set already wounds the VM fatally[**].  Same as for a
multitude of other properties that aren't prepared to be qom-set at
arbitrary times.

Mind, I'm not objecting to adding additional guards against .realize()
getting called more than exactly once.  I'm only challenging your cover
letter, and probably your commit messages (which I haven't read).

[...]


[*] One could argue that having command qom-set is a Very Bad Idea.

[**] It just doesn't crash a stopped VM right away for me.
Re: [PATCH for-11.2 v3 00/15] qdev: Clarify and enforce the device realization lifecycle
Posted by Akihiko Odaki an hour ago
On 2026/07/24 20:44, Markus Armbruster wrote:
> Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp> writes:
> 
>> qdev currently represents a device's realization state with a single
>> boolean. This cannot distinguish a device that has never been realized
>> from one whose realization has failed or that has been unrealized, nor
>> can it represent realization in progress. Consequently, the same device
>> can enter DeviceClass::realize() reentrantly or more than once.
> 
> .realized is initially false.  It is only ever modified in
> device_set_realized(), which is the setter of QOM property "realized" of
> "device" and its subtypes.  device_set_realized() is only called when
> the property is set.  It does nothing when the new value is the same as
> the old value.
> 
> Code changes property "realized" only in qdev_realize() and
> qdev_unrealize().
> 
> Implementations of .realize may call qdev_realize() for their
> components.  Having this loop back would be a bug.
> 
> If your claim "can enter reentrantly" is correct, we have bugs to fix.
> I believe it is incorrect.
> 
> There are two kinds of devices, onboard and user-created.
> 
> User-created devices go through qdev_device_add_from_qdict().  If
> qdev_realize() fails, the device is immediately destroyed.
> 
> Onboard devices get created and realized by board code.  It commonly
> treats qdev_realize() failure as fatal error.  Trying again instead
> would be a bug.
> 
> If your claim "can enter more than once" is correct, we have bugs to
> fix.  I believe it is incorrect.
> 
> Exception, sort of: users can manipulate properties with QMP command
> qom-set.  This is generally unsupported and a Very Bad Idea[*].  There
> might be supported exceptions (I don't know), but "realized" is
> definitely not among them.  Unsurprisingly, it's a fast path to grief:
> 
>      $ qemu-system-x86_64 -S -display none -monitor stdio -nodefaults
>      QEMU 11.0.90 monitor - type 'help' for more information
>      (qemu) qom-set /machine/i440fx realized false
>      (qemu) qom-set /machine/i440fx realized true
>      qemu-system-x86_64: ../system/memory.c:2585: memory_region_add_subregion_common: Assertion `!subregion->container' failed.
> 
> I figure your series rejects the second qom-set.  I'm pretty sure the
> first qom-set already wounds the VM fatally[**].  Same as for a
> multitude of other properties that aren't prepared to be qom-set at
> arbitrary times.
> 
> Mind, I'm not objecting to adding additional guards against .realize()
> getting called more than exactly once.  I'm only challenging your cover
> letter, and probably your commit messages (which I haven't read).
> 
> [...]
> 
> 
> [*] One could argue that having command qom-set is a Very Bad Idea.
> 
> [**] It just doesn't crash a stopped VM right away for me.
> 

You are right. The change assumes that the same device enters realize() 
twice in no supported scenario; otherwise it will break a real use case, 
so Philippe has requested confirmation from Igor [1].

The primary point the cover letter meant to convey is that the current 
QOM property itself does not actively prevent the "realized" state from 
being incorrectly toggled, as your qom-set example clearly demonstrates. 
This change is meant to align the setter's explicit checks with our 
actual assumption.

Since the cover letter omitted this explicit assumption, it 
inadvertently sounded like I was challenging it. Commit messages have 
the same issue. I will fix the wording in both the cover letter and the 
commit messages for the next version.

[1] 
https://lore.kernel.org/qemu-devel/a79f2ad8-d1ad-4536-85d1-0a01ad2f9513@oss.qualcomm.com/

Regards,
Akihiko Odaki