[RFC PATCH] hw/core: Avoid attaching qdevs to /machine/unattached if they have a bus

Thomas Huth posted 1 patch 1 month, 3 weeks ago
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/qemu tags/patchew/20260217164049.543975-1-thuth@redhat.com
Maintainers: Paolo Bonzini <pbonzini@redhat.com>, "Daniel P. Berrangé" <berrange@redhat.com>, Eduardo Habkost <eduardo@habkost.net>
hw/core/qdev.c | 10 ++++++++++
1 file changed, 10 insertions(+)
[RFC PATCH] hw/core: Avoid attaching qdevs to /machine/unattached if they have a bus
Posted by Thomas Huth 1 month, 3 weeks ago
From: Thomas Huth <thuth@redhat.com>

We still have a lot of devices that end up in /machine/unattached in
case the caller forgot to use object_property_add_child() to add it
to a proper location in the QOM tree. But at least for the devices
that get realized via qdev_realize() and that have a bus specified,
we can do better: Add the device automatically as a child to the bus
device instead! This way the QOM tree looks way more logical, with
way less devices hanging around in the /machine/unattached space.

While we're at it, use the type name as node name (instead of using
"device" like we did in the "unattached" space). But since these
entries might not be stable (they use a counting number in the square
brackets), the code also uses a "x-" prefix here to indicate that
this still might change in the course of time (once a board decides
to manually attach the device with a proper name instead).

Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 hw/core/qdev.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/hw/core/qdev.c b/hw/core/qdev.c
index 42641c5224e..5b773d0108a 100644
--- a/hw/core/qdev.c
+++ b/hw/core/qdev.c
@@ -266,9 +266,19 @@ bool qdev_realize(DeviceState *dev, BusState *bus, Error **errp)
     assert(!dev->realized && !dev->parent_bus);
 
     if (bus) {
+        Object *obj = OBJECT(dev);
+
         if (!qdev_set_parent_bus(dev, bus, errp)) {
             return false;
         }
+
+        if (!obj->parent) {
+            static int count;
+            g_autofree char *name = g_strdup_printf("x-%s[%d]",
+                                                    object_get_typename(obj),
+                                                    count++);
+            object_property_add_child(OBJECT(bus), name, obj);
+        }
     } else {
         assert(!DEVICE_GET_CLASS(dev)->bus_type);
     }
-- 
2.53.0
Re: [RFC PATCH] hw/core: Avoid attaching qdevs to /machine/unattached if they have a bus
Posted by Markus Armbruster 1 month, 3 weeks ago
Thomas Huth <thuth@redhat.com> writes:

> From: Thomas Huth <thuth@redhat.com>
>
> We still have a lot of devices that end up in /machine/unattached in
> case the caller forgot to use object_property_add_child() to add it
> to a proper location in the QOM tree.

This is QOM papering over sloppy modeling.  Predictably, it has enabled
us to remain sloppy slobs.

I think the decision to paper over sloppiness to get QOM off the ground
quickly was defensible back then.  It's a lot less defensible now that
QOM has been off the ground for more than a decade.

I believe people are by and large unaware of the need to add children.
This risks further accumulation of technical debt.

To really put a stop to it, we'd have to mark the existing misuses, then
warn or crash on umarked misuse.

None of the above is an objection to your patch.

>                                       But at least for the devices
> that get realized via qdev_realize() and that have a bus specified,
> we can do better: Add the device automatically as a child to the bus
> device instead! This way the QOM tree looks way more logical, with
> way less devices hanging around in the /machine/unattached space.
>
> While we're at it, use the type name as node name (instead of using
> "device" like we did in the "unattached" space). But since these
> entries might not be stable (they use a counting number in the square
> brackets), the code also uses a "x-" prefix here to indicate that
> this still might change in the course of time (once a board decides
> to manually attach the device with a proper name instead).
>
> Signed-off-by: Thomas Huth <thuth@redhat.com>
> ---
>  hw/core/qdev.c | 10 ++++++++++
>  1 file changed, 10 insertions(+)
>
> diff --git a/hw/core/qdev.c b/hw/core/qdev.c
> index 42641c5224e..5b773d0108a 100644
> --- a/hw/core/qdev.c
> +++ b/hw/core/qdev.c
> @@ -266,9 +266,19 @@ bool qdev_realize(DeviceState *dev, BusState *bus, Error **errp)
>      assert(!dev->realized && !dev->parent_bus);
>  
>      if (bus) {
> +        Object *obj = OBJECT(dev);
> +
>          if (!qdev_set_parent_bus(dev, bus, errp)) {
>              return false;
>          }
> +
> +        if (!obj->parent) {
> +            static int count;
> +            g_autofree char *name = g_strdup_printf("x-%s[%d]",
> +                                                    object_get_typename(obj),
> +                                                    count++);
> +            object_property_add_child(OBJECT(bus), name, obj);
> +        }
>      } else {
>          assert(!DEVICE_GET_CLASS(dev)->bus_type);
>      }

As a quick test, I ran

    $ qemu-system-x86_64 -S -display none -nodefaults -monitor stdio
    QEMU 10.2.50 monitor - type 'help' for more information
    (qemu) info qom-tree

before and after.  Diff of output appended.

Observations:

* 24 of 25 device[*] move out of /machine/unattached/.  Remaining:

  - /device[0] (qemu64-x86_64-cpu) because it doesn't plug into a bus.

  - /sysbus (System)

  - A bunch of memory regions and irqs.  Some of them smell like sloppy
    modeling: ide[*].

* The moved device[i] get renamed to x-type-name[j].  The number changes
  because the type-name[*] use their own global counter.  Changing the
  number is fine, but I wonder whether a counter local to the parent
  would be better.  BusClass does that for "automatically allocated bus
  ids".

--- info-qom-tree@master	2026-02-19 08:43:03.732267517 +0100
+++ -	2026-02-19 08:43:43.562332914 +0100
@@ -37,6 +37,156 @@
     /pci-conf-data[0] (memory-region)
     /pci-conf-idx[0] (memory-region)
     /pci.0 (PCI)
+      /x-PIIX3[2] (PIIX3)
+        /bus master container[0] (memory-region)
+        /bus master[0] (memory-region)
+        /dma[0] (i8257)
+          /dma-chan[0] (memory-region)
+          /dma-cont[0] (memory-region)
+          /dma-page[0] (memory-region)
+          /dma-page[1] (memory-region)
+        /dma[1] (i8257)
+          /dma-chan[0] (memory-region)
+          /dma-cont[0] (memory-region)
+          /dma-page[0] (memory-region)
+          /dma-page[1] (memory-region)
+        /ide (piix3-ide)
+          /bmdma[0] (memory-region)
+          /bmdma[1] (memory-region)
+          /bus master container[0] (memory-region)
+          /bus master[0] (memory-region)
+          /ide.0 (IDE)
+          /ide.1 (IDE)
+          /piix-bmdma-container[0] (memory-region)
+          /piix-bmdma[0] (memory-region)
+          /piix-bmdma[1] (memory-region)
+        /isa.0 (ISA)
+          /x-i8042[9] (i8042)
+            /i8042-cmd[0] (memory-region)
+            /i8042-data[0] (memory-region)
+            /ps2-kbd-input-irq[0] (irq)
+            /ps2-mouse-input-irq[0] (irq)
+            /ps2kbd (ps2-kbd)
+            /ps2mouse (ps2-mouse)
+          /x-isa-fdc[8] (isa-fdc)
+            /fdc[0] (memory-region)
+            /fdc[1] (memory-region)
+            /floppy-bus.0 (floppy-bus)
+          /x-isa-i8259[3] (isa-i8259)
+            /elcr[0] (memory-region)
+            /pic[0] (memory-region)
+            /unnamed-gpio-in[0] (irq)
+            /unnamed-gpio-in[1] (irq)
+            /unnamed-gpio-in[2] (irq)
+            /unnamed-gpio-in[3] (irq)
+            /unnamed-gpio-in[4] (irq)
+            /unnamed-gpio-in[5] (irq)
+            /unnamed-gpio-in[6] (irq)
+            /unnamed-gpio-in[7] (irq)
+          /x-isa-i8259[4] (isa-i8259)
+            /elcr[0] (memory-region)
+            /pic[0] (memory-region)
+            /unnamed-gpio-in[0] (irq)
+            /unnamed-gpio-in[1] (irq)
+            /unnamed-gpio-in[2] (irq)
+            /unnamed-gpio-in[3] (irq)
+            /unnamed-gpio-in[4] (irq)
+            /unnamed-gpio-in[5] (irq)
+            /unnamed-gpio-in[6] (irq)
+            /unnamed-gpio-in[7] (irq)
+          /x-isa-pcspk[7] (isa-pcspk)
+            /pcspk[0] (memory-region)
+          /x-isa-pit[6] (isa-pit)
+            /pit[0] (memory-region)
+            /unnamed-gpio-in[0] (irq)
+          /x-port92[12] (port92)
+            /port92[0] (memory-region)
+          /x-vmmouse[11] (vmmouse)
+          /x-vmport[10] (vmport)
+            /vmport[0] (memory-region)
+        /piix-reset-control[0] (memory-region)
+        /pm (PIIX4_PM)
+          /acpi-cnt[0] (memory-region)
+          /acpi-cpu-hotplug[0] (memory-region)
+          /acpi-evt[0] (memory-region)
+          /acpi-gpe0[0] (memory-region)
+          /acpi-pci-hotplug[0] (memory-region)
+          /acpi-tmr[0] (memory-region)
+          /apm-io[0] (memory-region)
+          /bus master container[0] (memory-region)
+          /bus master[0] (memory-region)
+          /i2c (i2c-bus)
+            /x-smbus-eeprom[13] (smbus-eeprom)
+            /x-smbus-eeprom[14] (smbus-eeprom)
+            /x-smbus-eeprom[15] (smbus-eeprom)
+            /x-smbus-eeprom[16] (smbus-eeprom)
+            /x-smbus-eeprom[17] (smbus-eeprom)
+            /x-smbus-eeprom[18] (smbus-eeprom)
+            /x-smbus-eeprom[19] (smbus-eeprom)
+            /x-smbus-eeprom[20] (smbus-eeprom)
+          /piix4-pm[0] (memory-region)
+          /pm-smbus[0] (memory-region)
+        /rtc (mc146818rtc)
+          /rtc-index[0] (memory-region)
+          /rtc[0] (memory-region)
+      /x-i440FX[1] (i440FX)
+        /bus master container[0] (memory-region)
+        /bus master[0] (memory-region)
+        /pam-pci[0] (memory-region)
+        /pam-pci[10] (memory-region)
+        /pam-pci[11] (memory-region)
+        /pam-pci[12] (memory-region)
+        /pam-pci[13] (memory-region)
+        /pam-pci[14] (memory-region)
+        /pam-pci[15] (memory-region)
+        /pam-pci[16] (memory-region)
+        /pam-pci[17] (memory-region)
+        /pam-pci[18] (memory-region)
+        /pam-pci[19] (memory-region)
+        /pam-pci[1] (memory-region)
+        /pam-pci[20] (memory-region)
+        /pam-pci[21] (memory-region)
+        /pam-pci[22] (memory-region)
+        /pam-pci[23] (memory-region)
+        /pam-pci[24] (memory-region)
+        /pam-pci[25] (memory-region)
+        /pam-pci[2] (memory-region)
+        /pam-pci[3] (memory-region)
+        /pam-pci[4] (memory-region)
+        /pam-pci[5] (memory-region)
+        /pam-pci[6] (memory-region)
+        /pam-pci[7] (memory-region)
+        /pam-pci[8] (memory-region)
+        /pam-pci[9] (memory-region)
+        /pam-ram[0] (memory-region)
+        /pam-ram[10] (memory-region)
+        /pam-ram[11] (memory-region)
+        /pam-ram[12] (memory-region)
+        /pam-ram[1] (memory-region)
+        /pam-ram[2] (memory-region)
+        /pam-ram[3] (memory-region)
+        /pam-ram[4] (memory-region)
+        /pam-ram[5] (memory-region)
+        /pam-ram[6] (memory-region)
+        /pam-ram[7] (memory-region)
+        /pam-ram[8] (memory-region)
+        /pam-ram[9] (memory-region)
+        /pam-rom[0] (memory-region)
+        /pam-rom[10] (memory-region)
+        /pam-rom[11] (memory-region)
+        /pam-rom[12] (memory-region)
+        /pam-rom[1] (memory-region)
+        /pam-rom[2] (memory-region)
+        /pam-rom[3] (memory-region)
+        /pam-rom[4] (memory-region)
+        /pam-rom[5] (memory-region)
+        /pam-rom[6] (memory-region)
+        /pam-rom[7] (memory-region)
+        /pam-rom[8] (memory-region)
+        /pam-rom[9] (memory-region)
+        /smram-low[0] (memory-region)
+        /smram-region[0] (memory-region)
+        /smram[0] (memory-region)
   /peripheral (container)
   /peripheral-anon (container)
   /unattached (container)
@@ -46,162 +196,6 @@
       /memory[0] (memory-region)
       /memory[1] (memory-region)
       /smram[0] (memory-region)
-    /device[10] (i8042)
-      /i8042-cmd[0] (memory-region)
-      /i8042-data[0] (memory-region)
-      /ps2-kbd-input-irq[0] (irq)
-      /ps2-mouse-input-irq[0] (irq)
-      /ps2kbd (ps2-kbd)
-      /ps2mouse (ps2-mouse)
-    /device[11] (vmport)
-      /vmport[0] (memory-region)
-    /device[12] (vmmouse)
-    /device[13] (port92)
-      /port92[0] (memory-region)
-    /device[14] (smbus-eeprom)
-    /device[15] (smbus-eeprom)
-    /device[16] (smbus-eeprom)
-    /device[17] (smbus-eeprom)
-    /device[18] (smbus-eeprom)
-    /device[19] (smbus-eeprom)
-    /device[1] (kvmvapic)
-      /kvmvapic[0] (memory-region)
-    /device[20] (smbus-eeprom)
-    /device[21] (smbus-eeprom)
-    /device[2] (i440FX)
-      /bus master container[0] (memory-region)
-      /bus master[0] (memory-region)
-      /pam-pci[0] (memory-region)
-      /pam-pci[10] (memory-region)
-      /pam-pci[11] (memory-region)
-      /pam-pci[12] (memory-region)
-      /pam-pci[13] (memory-region)
-      /pam-pci[14] (memory-region)
-      /pam-pci[15] (memory-region)
-      /pam-pci[16] (memory-region)
-      /pam-pci[17] (memory-region)
-      /pam-pci[18] (memory-region)
-      /pam-pci[19] (memory-region)
-      /pam-pci[1] (memory-region)
-      /pam-pci[20] (memory-region)
-      /pam-pci[21] (memory-region)
-      /pam-pci[22] (memory-region)
-      /pam-pci[23] (memory-region)
-      /pam-pci[24] (memory-region)
-      /pam-pci[25] (memory-region)
-      /pam-pci[2] (memory-region)
-      /pam-pci[3] (memory-region)
-      /pam-pci[4] (memory-region)
-      /pam-pci[5] (memory-region)
-      /pam-pci[6] (memory-region)
-      /pam-pci[7] (memory-region)
-      /pam-pci[8] (memory-region)
-      /pam-pci[9] (memory-region)
-      /pam-ram[0] (memory-region)
-      /pam-ram[10] (memory-region)
-      /pam-ram[11] (memory-region)
-      /pam-ram[12] (memory-region)
-      /pam-ram[1] (memory-region)
-      /pam-ram[2] (memory-region)
-      /pam-ram[3] (memory-region)
-      /pam-ram[4] (memory-region)
-      /pam-ram[5] (memory-region)
-      /pam-ram[6] (memory-region)
-      /pam-ram[7] (memory-region)
-      /pam-ram[8] (memory-region)
-      /pam-ram[9] (memory-region)
-      /pam-rom[0] (memory-region)
-      /pam-rom[10] (memory-region)
-      /pam-rom[11] (memory-region)
-      /pam-rom[12] (memory-region)
-      /pam-rom[1] (memory-region)
-      /pam-rom[2] (memory-region)
-      /pam-rom[3] (memory-region)
-      /pam-rom[4] (memory-region)
-      /pam-rom[5] (memory-region)
-      /pam-rom[6] (memory-region)
-      /pam-rom[7] (memory-region)
-      /pam-rom[8] (memory-region)
-      /pam-rom[9] (memory-region)
-      /smram-low[0] (memory-region)
-      /smram-region[0] (memory-region)
-      /smram[0] (memory-region)
-    /device[3] (PIIX3)
-      /bus master container[0] (memory-region)
-      /bus master[0] (memory-region)
-      /dma[0] (i8257)
-        /dma-chan[0] (memory-region)
-        /dma-cont[0] (memory-region)
-        /dma-page[0] (memory-region)
-        /dma-page[1] (memory-region)
-      /dma[1] (i8257)
-        /dma-chan[0] (memory-region)
-        /dma-cont[0] (memory-region)
-        /dma-page[0] (memory-region)
-        /dma-page[1] (memory-region)
-      /ide (piix3-ide)
-        /bmdma[0] (memory-region)
-        /bmdma[1] (memory-region)
-        /bus master container[0] (memory-region)
-        /bus master[0] (memory-region)
-        /ide.0 (IDE)
-        /ide.1 (IDE)
-        /piix-bmdma-container[0] (memory-region)
-        /piix-bmdma[0] (memory-region)
-        /piix-bmdma[1] (memory-region)
-      /isa.0 (ISA)
-      /piix-reset-control[0] (memory-region)
-      /pm (PIIX4_PM)
-        /acpi-cnt[0] (memory-region)
-        /acpi-cpu-hotplug[0] (memory-region)
-        /acpi-evt[0] (memory-region)
-        /acpi-gpe0[0] (memory-region)
-        /acpi-pci-hotplug[0] (memory-region)
-        /acpi-tmr[0] (memory-region)
-        /apm-io[0] (memory-region)
-        /bus master container[0] (memory-region)
-        /bus master[0] (memory-region)
-        /i2c (i2c-bus)
-        /piix4-pm[0] (memory-region)
-        /pm-smbus[0] (memory-region)
-      /rtc (mc146818rtc)
-        /rtc-index[0] (memory-region)
-        /rtc[0] (memory-region)
-    /device[4] (isa-i8259)
-      /elcr[0] (memory-region)
-      /pic[0] (memory-region)
-      /unnamed-gpio-in[0] (irq)
-      /unnamed-gpio-in[1] (irq)
-      /unnamed-gpio-in[2] (irq)
-      /unnamed-gpio-in[3] (irq)
-      /unnamed-gpio-in[4] (irq)
-      /unnamed-gpio-in[5] (irq)
-      /unnamed-gpio-in[6] (irq)
-      /unnamed-gpio-in[7] (irq)
-    /device[5] (isa-i8259)
-      /elcr[0] (memory-region)
-      /pic[0] (memory-region)
-      /unnamed-gpio-in[0] (irq)
-      /unnamed-gpio-in[1] (irq)
-      /unnamed-gpio-in[2] (irq)
-      /unnamed-gpio-in[3] (irq)
-      /unnamed-gpio-in[4] (irq)
-      /unnamed-gpio-in[5] (irq)
-      /unnamed-gpio-in[6] (irq)
-      /unnamed-gpio-in[7] (irq)
-    /device[6] (hpet)
-      /hpet[0] (memory-region)
-      /unnamed-gpio-in[0] (irq)
-      /unnamed-gpio-in[1] (irq)
-    /device[7] (isa-pit)
-      /pit[0] (memory-region)
-      /unnamed-gpio-in[0] (irq)
-    /device[8] (isa-pcspk)
-      /pcspk[0] (memory-region)
-    /device[9] (isa-fdc)
-      /fdc[0] (memory-region)
-      /fdc[1] (memory-region)
-      /floppy-bus.0 (floppy-bus)
     /ide[0] (memory-region)
     /ide[1] (memory-region)
     /ide[2] (memory-region)
@@ -243,5 +237,11 @@
     /pci[0] (memory-region)
     /ram-below-4g[0] (memory-region)
     /sysbus (System)
+      /x-hpet[5] (hpet)
+        /hpet[0] (memory-region)
+        /unnamed-gpio-in[0] (irq)
+        /unnamed-gpio-in[1] (irq)
+      /x-kvmvapic[0] (kvmvapic)
+        /kvmvapic[0] (memory-region)
     /system[0] (memory-region)
Re: [RFC PATCH] hw/core: Avoid attaching qdevs to /machine/unattached if they have a bus
Posted by Daniel P. Berrangé 1 month, 2 weeks ago
On Thu, Feb 19, 2026 at 09:49:05AM +0100, Markus Armbruster wrote:
> Thomas Huth <thuth@redhat.com> writes:
> 
> > From: Thomas Huth <thuth@redhat.com>
> >
> > We still have a lot of devices that end up in /machine/unattached in
> > case the caller forgot to use object_property_add_child() to add it
> > to a proper location in the QOM tree.
> 
> This is QOM papering over sloppy modeling.  Predictably, it has enabled
> us to remain sloppy slobs.
> 
> I think the decision to paper over sloppiness to get QOM off the ground
> quickly was defensible back then.  It's a lot less defensible now that
> QOM has been off the ground for more than a decade.
> 
> I believe people are by and large unaware of the need to add children.
> This risks further accumulation of technical debt.

IMHO, it is slightly more subtle - people believe they are already
adding children.

Consider this code.

    port92 = isa_create_simple(isa_bus, TYPE_PORT92);

my reading of that is that I'm creating a "port92" device that is a
child of "isa_bus". Why would I need to tell QEMU that it is a child
for a second time ?

If I trace calls through isa_create_simple I get to a call to:

   qdev_realize_and_unref(dev, parent, errp);

and once I again I'm left wondering why I would need to tell
QEMU 'dev' is a child of 'parent' a second time.

Of course I know the answer. We need to give a name for the
child and it isn't trivial to "do the right thing" to invent
an automatic name.

Still, overall I'm inclined to largely blame our API designs for
not guiding people into doing the right thing.


Picking another random unattached set of objects "smbus-eeprom"
I again find they've being created with qdev_realize_and_unref.

Pick another unattached device 'i8259_init_chip', and again
we end up calling into qdev_realize_and_unref()


It feels like qdev_realize_and_unref() is a common point of
blame in unattached devices. IMHO it ought to be taking a
"const char *name" parameter.

There are 104 calls to qdev_realize_and_unref(), but it is in
the call path of many more wrapped calls.

A big-ish job to convert them all, so perhaps we need to add
a parallel

   qdev_realize_and_unref_child(...)

with the new 'name' parameter, and incrementally convert stuff,
though ideally a conversion that doesn't last "forever" like
so many of our conversion tasks.

> To really put a stop to it, we'd have to mark the existing misuses, then
> warn or crash on umarked misuse.

While marking / warning / crashing helps surface problems, I think
that fixing the API designs to guide developers at compile time is
more important.

> None of the above is an objection to your patch.

I guess even with the patch applied we can still identify broken
code by looking for any child with an "x-" property name.


With regards,
Daniel
-- 
|: https://berrange.com       ~~        https://hachyderm.io/@berrange :|
|: https://libvirt.org          ~~          https://entangle-photo.org :|
|: https://pixelfed.art/berrange   ~~    https://fstop138.berrange.com :|
Re: [RFC PATCH] hw/core: Avoid attaching qdevs to /machine/unattached if they have a bus
Posted by Markus Armbruster 1 month, 2 weeks ago
Daniel P. Berrangé <berrange@redhat.com> writes:

> On Thu, Feb 19, 2026 at 09:49:05AM +0100, Markus Armbruster wrote:
>> Thomas Huth <thuth@redhat.com> writes:
>> 
>> > From: Thomas Huth <thuth@redhat.com>
>> >
>> > We still have a lot of devices that end up in /machine/unattached in
>> > case the caller forgot to use object_property_add_child() to add it
>> > to a proper location in the QOM tree.
>> 
>> This is QOM papering over sloppy modeling.  Predictably, it has enabled
>> us to remain sloppy slobs.
>> 
>> I think the decision to paper over sloppiness to get QOM off the ground
>> quickly was defensible back then.  It's a lot less defensible now that
>> QOM has been off the ground for more than a decade.
>> 
>> I believe people are by and large unaware of the need to add children.
>> This risks further accumulation of technical debt.
>
> IMHO, it is slightly more subtle - people believe they are already
> adding children.
>
> Consider this code.
>
>     port92 = isa_create_simple(isa_bus, TYPE_PORT92);
>
> my reading of that is that I'm creating a "port92" device that is a
> child of "isa_bus". Why would I need to tell QEMU that it is a child
> for a second time ?
>
> If I trace calls through isa_create_simple I get to a call to:
>
>    qdev_realize_and_unref(dev, parent, errp);

Actually

    qdev_realize_and_unref(&dev->parent_obj, &bus->parent_obj, errp)

in isa_realize_and_unref().

> and once I again I'm left wondering why I would need to tell
> QEMU 'dev' is a child of 'parent' a second time.

Beware of confusion around "parent" here.

qdev_realize_and_unref() takes a qdev and optionally a qbus (a
DeviceState * and a BusState *).  qdev_realize() plugs the qdev into the
qbus with qdev_set_parent_bus() if the qbus is non-null.

The qdev concept "parent bus" is distinct from the QOM concept "parent
in the composition tree".  Evidence: the QOM parent of a qdev created
with -device is either "/machine/peripheral" or
"/machine/peripheral-anon".  Its parent qbus is something else.

"info qtree" shows the tree of qdevs and qbuses rooted at the main
system bus.

"info qom-tree <root>" shows the QOM composition tree rooted at <root>
(default "/machine").

> Of course I know the answer. We need to give a name for the
> child and it isn't trivial to "do the right thing" to invent
> an automatic name.

At least not in the general case.

> Still, overall I'm inclined to largely blame our API designs for
> not guiding people into doing the right thing.

Indeed!

> Picking another random unattached set of objects "smbus-eeprom"
> I again find they've being created with qdev_realize_and_unref.
>
> Pick another unattached device 'i8259_init_chip', and again
> we end up calling into qdev_realize_and_unref()
>
>
> It feels like qdev_realize_and_unref() is a common point of
> blame in unattached devices. IMHO it ought to be taking a
> "const char *name" parameter.

The problem are onboard devices without QOM composition tree parents.

Onboard devices need to be realized with qdev_realize().  Often called
via qdev_realize_and_unref().

Currently, we use that chokepoint to make devices without QOM parents
children of /machine/unattached.  That's bad.

Thomas's RFC PATCH changes this for devices that plug into a qbus: make
them children of the qbus (which is a QOM object) instead, with a
made-up name.  This may or may not be the parent we'd pick manually.

I'm curious: are there devices that plug into a qbus with a QOM parent
other than that qbus?

You propose to require callers to pass a name.

I think passing a name makes intent explicit: the qbus is the parent we
want.

> There are 104 calls to qdev_realize_and_unref(), but it is in
> the call path of many more wrapped calls.
>
> A big-ish job to convert them all, so perhaps we need to add
> a parallel
>
>    qdev_realize_and_unref_child(...)
>
> with the new 'name' parameter, and incrementally convert stuff,
> though ideally a conversion that doesn't last "forever" like
> so many of our conversion tasks.

There's just one way to get a feel for how big a job this is: try it.

>> To really put a stop to it, we'd have to mark the existing misuses, then
>> warn or crash on umarked misuse.
>
> While marking / warning / crashing helps surface problems, I think
> that fixing the API designs to guide developers at compile time is
> more important.

It's more helpful, so if we can pull it off...

>> None of the above is an objection to your patch.
>
> I guess even with the patch applied we can still identify broken
> code by looking for any child with an "x-" property name.

Yes.
Re: [RFC PATCH] hw/core: Avoid attaching qdevs to /machine/unattached if they have a bus
Posted by Peter Maydell 1 month, 2 weeks ago
On Tue, 24 Feb 2026 at 09:48, Daniel P. Berrangé <berrange@redhat.com> wrote:
> IMHO, it is slightly more subtle - people believe they are already
> adding children.
>
> Consider this code.
>
>     port92 = isa_create_simple(isa_bus, TYPE_PORT92);
>
> my reading of that is that I'm creating a "port92" device that is a
> child of "isa_bus". Why would I need to tell QEMU that it is a child
> for a second time ?
>
> If I trace calls through isa_create_simple I get to a call to:
>
>    qdev_realize_and_unref(dev, parent, errp);
>
> and once I again I'm left wondering why I would need to tell
> QEMU 'dev' is a child of 'parent' a second time.
>
> Of course I know the answer. We need to give a name for the
> child and it isn't trivial to "do the right thing" to invent
> an automatic name.
>
> Still, overall I'm inclined to largely blame our API designs for
> not guiding people into doing the right thing.
>
>
> Picking another random unattached set of objects "smbus-eeprom"
> I again find they've being created with qdev_realize_and_unref.
>
> Pick another unattached device 'i8259_init_chip', and again
> we end up calling into qdev_realize_and_unref()
>
>
> It feels like qdev_realize_and_unref() is a common point of
> blame in unattached devices. IMHO it ought to be taking a
> "const char *name" parameter.

I think that is because this is the function that is used
in older code that predates the "everything should be in
the QOM tree" model. Newer code doesn't use it, I think;
and it's not surprising that old pre-QOM code doesn't do
anything to put objects into the QOM tree.

The two patterns are:

 dev = qdev_new(...);
 ...
 qdev_realize_and_unref(dev, bus, errp);

and

 object_initialize_child(...);
 ...
 qdev_realize(dev, bus, errp);

This also is somewhat tangled up with the question of whether you want:

 * call a function which allocates memory and initializes it
   with an object of this type
 * I have the memory here, init the object in-place

If we could come to a definite conclusion on what we want then
we would probably be in a better position to try to enforce it.

thanks
-- PMM
Re: [RFC PATCH] hw/core: Avoid attaching qdevs to /machine/unattached if they have a bus
Posted by Mark Cave-Ayland 1 month, 2 weeks ago
On 24/02/2026 11:10, Peter Maydell wrote:

> On Tue, 24 Feb 2026 at 09:48, Daniel P. Berrangé <berrange@redhat.com> wrote:
>> IMHO, it is slightly more subtle - people believe they are already
>> adding children.
>>
>> Consider this code.
>>
>>      port92 = isa_create_simple(isa_bus, TYPE_PORT92);
>>
>> my reading of that is that I'm creating a "port92" device that is a
>> child of "isa_bus". Why would I need to tell QEMU that it is a child
>> for a second time ?
>>
>> If I trace calls through isa_create_simple I get to a call to:
>>
>>     qdev_realize_and_unref(dev, parent, errp);
>>
>> and once I again I'm left wondering why I would need to tell
>> QEMU 'dev' is a child of 'parent' a second time.
>>
>> Of course I know the answer. We need to give a name for the
>> child and it isn't trivial to "do the right thing" to invent
>> an automatic name.
>>
>> Still, overall I'm inclined to largely blame our API designs for
>> not guiding people into doing the right thing.
>>
>>
>> Picking another random unattached set of objects "smbus-eeprom"
>> I again find they've being created with qdev_realize_and_unref.
>>
>> Pick another unattached device 'i8259_init_chip', and again
>> we end up calling into qdev_realize_and_unref()
>>
>>
>> It feels like qdev_realize_and_unref() is a common point of
>> blame in unattached devices. IMHO it ought to be taking a
>> "const char *name" parameter.
> 
> I think that is because this is the function that is used
> in older code that predates the "everything should be in
> the QOM tree" model. Newer code doesn't use it, I think;
> and it's not surprising that old pre-QOM code doesn't do
> anything to put objects into the QOM tree.
> 
> The two patterns are:
> 
>   dev = qdev_new(...);
>   ...
>   qdev_realize_and_unref(dev, bus, errp);
> 
> and
> 
>   object_initialize_child(...);
>   ...
>   qdev_realize(dev, bus, errp);
> 
> This also is somewhat tangled up with the question of whether you want:
> 
>   * call a function which allocates memory and initializes it
>     with an object of this type
>   * I have the memory here, init the object in-place
> 
> If we could come to a definite conclusion on what we want then
> we would probably be in a better position to try to enforce it.

Exactly this! I think what tends to happen is that we get stuck in 
situations where someone suggests an improvement, but then we get hung 
up trying to work out the corner-cases where it doesn't work and then 
things don't progress.

The approach I believe we need to take is to work out what we want the 
API and QOM tree to look like first, and then work backwards from there.

I tend to be in agreement with Akihiko's argument that we want to 
deprecate in-place initialisation with object_initialize_child() and 
simply use refcounting everywhere because then we don't hit any lifcycle 
issues if something retains a reference to the internal object (memory 
regions!).

The questions I think we need to answer as a starting point:

   1. Which API shall we converge on: qdev or QOM? Can we come up with a
      code sample(s) showing what we want object/device initialisation to
      look lie? Longer term can we unify the QOM and qdev trees?

   2. Should we convert to use external object allocation with
      refcounting?

   3. How do we handle memory regions? With Akihiko's recent refcount
      fixes then Zoltan's memory region changes could work: I don't agree
      with the motivation of simplifying devices as I think it's i)
      subjective and ii) harder to debug if we lose the pointer to the
      memory region, but I can see how it fixes the RCU-thread doing an
      unref after the owner device has already been destroyed issue.

As several people have already pointed out in this thread, we do have a 
poor track record of API conversions but the introduction of memory 
regions shows how this can be done successfully.

Given that we already have multiple ways of doing the same thing, I tend 
to lean against not introducing yet-another-API unless we can come up 
with a long-term strategy for its use. In particular this causes 
problems in review where e.g. one reviewer may want to use QOM to setup 
a device whilst another may want to use qdev which is confusing for 
everyone, including the code submitter.

If we can at least get an answer to 1) then I'd be willing to have a go 
at writing some kind of specification document and put it out for 
feedback...


ATB,

Mark.


Re: [RFC PATCH] hw/core: Avoid attaching qdevs to /machine/unattached if they have a bus
Posted by Philippe Mathieu-Daudé 1 month, 2 weeks ago
+Bernhard

On 24/2/26 13:22, Mark Cave-Ayland wrote:
> On 24/02/2026 11:10, Peter Maydell wrote:
> 
>> On Tue, 24 Feb 2026 at 09:48, Daniel P. Berrangé <berrange@redhat.com> 
>> wrote:
>>> IMHO, it is slightly more subtle - people believe they are already
>>> adding children.
>>>
>>> Consider this code.
>>>
>>>      port92 = isa_create_simple(isa_bus, TYPE_PORT92);
>>>
>>> my reading of that is that I'm creating a "port92" device that is a
>>> child of "isa_bus". Why would I need to tell QEMU that it is a child
>>> for a second time ?
>>>
>>> If I trace calls through isa_create_simple I get to a call to:
>>>
>>>     qdev_realize_and_unref(dev, parent, errp);
>>>
>>> and once I again I'm left wondering why I would need to tell
>>> QEMU 'dev' is a child of 'parent' a second time.
>>>
>>> Of course I know the answer. We need to give a name for the
>>> child and it isn't trivial to "do the right thing" to invent
>>> an automatic name.
>>>
>>> Still, overall I'm inclined to largely blame our API designs for
>>> not guiding people into doing the right thing.
>>>
>>>
>>> Picking another random unattached set of objects "smbus-eeprom"
>>> I again find they've being created with qdev_realize_and_unref.
>>>
>>> Pick another unattached device 'i8259_init_chip', and again
>>> we end up calling into qdev_realize_and_unref()
>>>
>>>
>>> It feels like qdev_realize_and_unref() is a common point of
>>> blame in unattached devices. IMHO it ought to be taking a
>>> "const char *name" parameter.
>>
>> I think that is because this is the function that is used
>> in older code that predates the "everything should be in
>> the QOM tree" model. Newer code doesn't use it, I think;
>> and it's not surprising that old pre-QOM code doesn't do
>> anything to put objects into the QOM tree.
>>
>> The two patterns are:
>>
>>   dev = qdev_new(...);
>>   ...
>>   qdev_realize_and_unref(dev, bus, errp);
>>
>> and
>>
>>   object_initialize_child(...);
>>   ...
>>   qdev_realize(dev, bus, errp);
>>
>> This also is somewhat tangled up with the question of whether you want:
>>
>>   * call a function which allocates memory and initializes it
>>     with an object of this type
>>   * I have the memory here, init the object in-place
>>
>> If we could come to a definite conclusion on what we want then
>> we would probably be in a better position to try to enforce it.

I recall a previous discussion where we said in-place allocation
does not scale with dynamic machines (data driven config), and IIRC
Bernhard said by switching to dynamic heap allocation we'd use more
QOM cast macros and lose compiler safety type checks. Can't find it
now in the archives.

We have some model declension where we allocate in-place $MAX members
and expose a QOM property to initialize up to that number (or worst,
de-initialize and unparent what is left!) in the DeviceRealize handler.
Not "in-place" could simplify this.

> Exactly this! I think what tends to happen is that we get stuck in 
> situations where someone suggests an improvement, but then we get hung 
> up trying to work out the corner-cases where it doesn't work and then 
> things don't progress.
> 
> The approach I believe we need to take is to work out what we want the 
> API and QOM tree to look like first, and then work backwards from there.
> 
> I tend to be in agreement with Akihiko's argument that we want to 
> deprecate in-place initialisation with object_initialize_child() and 
> simply use refcounting everywhere because then we don't hit any lifcycle 
> issues if something retains a reference to the internal object (memory 
> regions!).
> 
> The questions I think we need to answer as a starting point:
> 
>    1. Which API shall we converge on: qdev or QOM? Can we come up with a
>       code sample(s) showing what we want object/device initialisation to
>       look lie? Longer term can we unify the QOM and qdev trees?
> 
>    2. Should we convert to use external object allocation with
>       refcounting?
> 
>    3. How do we handle memory regions? With Akihiko's recent refcount
>       fixes then Zoltan's memory region changes could work: I don't agree
>       with the motivation of simplifying devices as I think it's i)
>       subjective and ii) harder to debug if we lose the pointer to the
>       memory region, but I can see how it fixes the RCU-thread doing an
>       unref after the owner device has already been destroyed issue.
> 
> As several people have already pointed out in this thread, we do have a 
> poor track record of API conversions but the introduction of memory 
> regions shows how this can be done successfully.
> 
> Given that we already have multiple ways of doing the same thing, I tend 
> to lean against not introducing yet-another-API unless we can come up 
> with a long-term strategy for its use. In particular this causes 
> problems in review where e.g. one reviewer may want to use QOM to setup 
> a device whilst another may want to use qdev which is confusing for 
> everyone, including the code submitter.
> 
> If we can at least get an answer to 1) then I'd be willing to have a go 
> at writing some kind of specification document and put it out for 
> feedback...
> 
> 
> ATB,
> 
> Mark.
> 
> 


Re: [RFC PATCH] hw/core: Avoid attaching qdevs to /machine/unattached if they have a bus
Posted by Bernhard Beschow 1 month, 2 weeks ago

Am 25. Februar 2026 05:55:21 UTC schrieb "Philippe Mathieu-Daudé" <philmd@linaro.org>:
>+Bernhard
>
>On 24/2/26 13:22, Mark Cave-Ayland wrote:
>> On 24/02/2026 11:10, Peter Maydell wrote:
>> 
>>> On Tue, 24 Feb 2026 at 09:48, Daniel P. Berrangé <berrange@redhat.com> wrote:
>>>> IMHO, it is slightly more subtle - people believe they are already
>>>> adding children.
>>>> 
>>>> Consider this code.
>>>> 
>>>>      port92 = isa_create_simple(isa_bus, TYPE_PORT92);
>>>> 
>>>> my reading of that is that I'm creating a "port92" device that is a
>>>> child of "isa_bus". Why would I need to tell QEMU that it is a child
>>>> for a second time ?
>>>> 
>>>> If I trace calls through isa_create_simple I get to a call to:
>>>> 
>>>>     qdev_realize_and_unref(dev, parent, errp);
>>>> 
>>>> and once I again I'm left wondering why I would need to tell
>>>> QEMU 'dev' is a child of 'parent' a second time.
>>>> 
>>>> Of course I know the answer. We need to give a name for the
>>>> child and it isn't trivial to "do the right thing" to invent
>>>> an automatic name.
>>>> 
>>>> Still, overall I'm inclined to largely blame our API designs for
>>>> not guiding people into doing the right thing.
>>>> 
>>>> 
>>>> Picking another random unattached set of objects "smbus-eeprom"
>>>> I again find they've being created with qdev_realize_and_unref.
>>>> 
>>>> Pick another unattached device 'i8259_init_chip', and again
>>>> we end up calling into qdev_realize_and_unref()
>>>> 
>>>> 
>>>> It feels like qdev_realize_and_unref() is a common point of
>>>> blame in unattached devices. IMHO it ought to be taking a
>>>> "const char *name" parameter.
>>> 
>>> I think that is because this is the function that is used
>>> in older code that predates the "everything should be in
>>> the QOM tree" model. Newer code doesn't use it, I think;
>>> and it's not surprising that old pre-QOM code doesn't do
>>> anything to put objects into the QOM tree.
>>> 
>>> The two patterns are:
>>> 
>>>   dev = qdev_new(...);
>>>   ...
>>>   qdev_realize_and_unref(dev, bus, errp);
>>> 
>>> and
>>> 
>>>   object_initialize_child(...);
>>>   ...
>>>   qdev_realize(dev, bus, errp);
>>> 
>>> This also is somewhat tangled up with the question of whether you want:
>>> 
>>>   * call a function which allocates memory and initializes it
>>>     with an object of this type
>>>   * I have the memory here, init the object in-place
>>> 
>>> If we could come to a definite conclusion on what we want then
>>> we would probably be in a better position to try to enforce it.
>
>I recall a previous discussion where we said in-place allocation
>does not scale with dynamic machines (data driven config), and IIRC
>Bernhard said by switching to dynamic heap allocation we'd use more
>QOM cast macros and lose compiler safety type checks. Can't find it
>now in the archives.

It was probably this comment about type safety which was unrelated to heap allocations: https://lore.kernel.org/qemu-devel/49C85A05-2BE5-4D9B-A08A-B93039669BD8@gmail.com/

Best regards,
Bernhard

>
>We have some model declension where we allocate in-place $MAX members
>and expose a QOM property to initialize up to that number (or worst,
>de-initialize and unparent what is left!) in the DeviceRealize handler.
>Not "in-place" could simplify this.
>
>> Exactly this! I think what tends to happen is that we get stuck in situations where someone suggests an improvement, but then we get hung up trying to work out the corner-cases where it doesn't work and then things don't progress.
>> 
>> The approach I believe we need to take is to work out what we want the API and QOM tree to look like first, and then work backwards from there.
>> 
>> I tend to be in agreement with Akihiko's argument that we want to deprecate in-place initialisation with object_initialize_child() and simply use refcounting everywhere because then we don't hit any lifcycle issues if something retains a reference to the internal object (memory regions!).
>> 
>> The questions I think we need to answer as a starting point:
>> 
>>    1. Which API shall we converge on: qdev or QOM? Can we come up with a
>>       code sample(s) showing what we want object/device initialisation to
>>       look lie? Longer term can we unify the QOM and qdev trees?
>> 
>>    2. Should we convert to use external object allocation with
>>       refcounting?
>> 
>>    3. How do we handle memory regions? With Akihiko's recent refcount
>>       fixes then Zoltan's memory region changes could work: I don't agree
>>       with the motivation of simplifying devices as I think it's i)
>>       subjective and ii) harder to debug if we lose the pointer to the
>>       memory region, but I can see how it fixes the RCU-thread doing an
>>       unref after the owner device has already been destroyed issue.
>> 
>> As several people have already pointed out in this thread, we do have a poor track record of API conversions but the introduction of memory regions shows how this can be done successfully.
>> 
>> Given that we already have multiple ways of doing the same thing, I tend to lean against not introducing yet-another-API unless we can come up with a long-term strategy for its use. In particular this causes problems in review where e.g. one reviewer may want to use QOM to setup a device whilst another may want to use qdev which is confusing for everyone, including the code submitter.
>> 
>> If we can at least get an answer to 1) then I'd be willing to have a go at writing some kind of specification document and put it out for feedback...
>> 
>> 
>> ATB,
>> 
>> Mark.
>> 
>> 
>
Re: [RFC PATCH] hw/core: Avoid attaching qdevs to /machine/unattached if they have a bus
Posted by BALATON Zoltan 1 month, 2 weeks ago
On Tue, 24 Feb 2026, Mark Cave-Ayland wrote:
> On 24/02/2026 11:10, Peter Maydell wrote:
>> On Tue, 24 Feb 2026 at 09:48, Daniel P. Berrangé <berrange@redhat.com> 
>> wrote:
>>> IMHO, it is slightly more subtle - people believe they are already
>>> adding children.
>>> 
>>> Consider this code.
>>>
>>>      port92 = isa_create_simple(isa_bus, TYPE_PORT92);
>>> 
>>> my reading of that is that I'm creating a "port92" device that is a
>>> child of "isa_bus". Why would I need to tell QEMU that it is a child
>>> for a second time ?
>>> 
>>> If I trace calls through isa_create_simple I get to a call to:
>>>
>>>     qdev_realize_and_unref(dev, parent, errp);
>>> 
>>> and once I again I'm left wondering why I would need to tell
>>> QEMU 'dev' is a child of 'parent' a second time.
>>> 
>>> Of course I know the answer. We need to give a name for the
>>> child and it isn't trivial to "do the right thing" to invent
>>> an automatic name.
>>> 
>>> Still, overall I'm inclined to largely blame our API designs for
>>> not guiding people into doing the right thing.
>>> 
>>> 
>>> Picking another random unattached set of objects "smbus-eeprom"
>>> I again find they've being created with qdev_realize_and_unref.
>>> 
>>> Pick another unattached device 'i8259_init_chip', and again
>>> we end up calling into qdev_realize_and_unref()
>>> 
>>> 
>>> It feels like qdev_realize_and_unref() is a common point of
>>> blame in unattached devices. IMHO it ought to be taking a
>>> "const char *name" parameter.
>> 
>> I think that is because this is the function that is used
>> in older code that predates the "everything should be in
>> the QOM tree" model. Newer code doesn't use it, I think;
>> and it's not surprising that old pre-QOM code doesn't do
>> anything to put objects into the QOM tree.
>> 
>> The two patterns are:
>>
>>   dev = qdev_new(...);
>>   ...
>>   qdev_realize_and_unref(dev, bus, errp);
>> 
>> and
>>
>>   object_initialize_child(...);
>>   ...
>>   qdev_realize(dev, bus, errp);
>> 
>> This also is somewhat tangled up with the question of whether you want:
>>
>>   * call a function which allocates memory and initializes it
>>     with an object of this type
>>   * I have the memory here, init the object in-place

Maybe it would not be tangled if there was a qdev_new_child or making the 
child relationship would not be done in object_initialize_child but with 
qdev_realize (but that may be too late). Or maybe we just need a set_child 
or add_child function that one should call after qdev_new or 
object_initialize and not entangle child init with object init as those 
are different operations. I think we don't have to decide if we want to 
allocate objects or init objects at preallocated memory as both could be 
useful in different cases but these should behave symmetrically so if 
there's something is only possible with object_initialize_child then it 
should be possible with allocated objects too.

>> If we could come to a definite conclusion on what we want then
>> we would probably be in a better position to try to enforce it.
>
> Exactly this! I think what tends to happen is that we get stuck in situations 
> where someone suggests an improvement, but then we get hung up trying to work 
> out the corner-cases where it doesn't work and then things don't progress.
>
> The approach I believe we need to take is to work out what we want the API 
> and QOM tree to look like first, and then work backwards from there.
>
> I tend to be in agreement with Akihiko's argument that we want to deprecate 
> in-place initialisation with object_initialize_child() and simply use 
> refcounting everywhere because then we don't hit any lifcycle issues if 
> something retains a reference to the internal object (memory regions!).
>
> The questions I think we need to answer as a starting point:
>
>  1. Which API shall we converge on: qdev or QOM? Can we come up with a
>     code sample(s) showing what we want object/device initialisation to
>     look lie? Longer term can we unify the QOM and qdev trees?

My first question is why do we have separate qom and qdev names and trees? 
The docs aren't very helpful. Qdev does not have a Glossary entry and only 
a brief summary at:
https://www.qemu.org/docs/master/devel/qdev-api.html
and some confusing info in an old doc here
https://habkost.net/posts/2016/11/incomplete-list-of-qemu-apis.html

For a long time I did not even know there was info qom-tree command in 
monitor but I was familiar with and used info qtree. I still don't know 
what the qom-tree is good for therefore I also don't care when creating 
machines or devices as I never use it and don't know why I would want to 
use it. To me it looks like some internal thing of QEMU that I don't have 
to be concerned with. All the useful info about devices are in info qtree.

>  2. Should we convert to use external object allocation with
>     refcounting?
>
>  3. How do we handle memory regions? With Akihiko's recent refcount
>     fixes then Zoltan's memory region changes could work: I don't agree
>     with the motivation of simplifying devices as I think it's i)
>     subjective and ii) harder to debug if we lose the pointer to the
>     memory region, but I can see how it fixes the RCU-thread doing an
>     unref after the owner device has already been destroyed issue.

These probably belong to the other thread and not directly related to 
naming and tree hierarchies but while debugging is also subjective (most 
of the time you can use traces or just add debug printfs) but you still 
have a pointer in the parent object or you may be able to get a pointer to 
the MemoryRegion from QEMU monitor so that's not a good reason to 
duplicate it in the device. The idea in object oriented design is to only 
put things in the subclass that it adds to the superclass and the 
superclass already handles memory regions for most common (PCI and sysbus) 
devices. And since memory regions are also added as children to their 
owner (or unattached) you should also be able to get a list of them from 
QOM.

> As several people have already pointed out in this thread, we do have a poor 
> track record of API conversions but the introduction of memory regions shows 
> how this can be done successfully.
>
> Given that we already have multiple ways of doing the same thing, I tend to 
> lean against not introducing yet-another-API unless we can come up with a 
> long-term strategy for its use. In particular this causes problems in review 
> where e.g. one reviewer may want to use QOM to setup a device whilst another 
> may want to use qdev which is confusing for everyone, including the code 
> submitter.
>
> If we can at least get an answer to 1) then I'd be willing to have a go at 
> writing some kind of specification document and put it out for feedback...

Clarifying the different naming and tree hierarchies would definitely 
help. So far I don't see what qom-tree is useful for and why it's not the 
same as qtree. I don't know if that's related but we also have type names 
and the fdt based machine creation may need to add aliases for those to 
match the names they are referenced in device trees (such as in 
"compatible" properties). Maybe finding a naming and hierarchy that's 
close to a dtb would make it less confusing.

Regards,
BALATON Zoltan
Re: [RFC PATCH] hw/core: Avoid attaching qdevs to /machine/unattached if they have a bus
Posted by Peter Maydell 1 month, 2 weeks ago
On Wed, 25 Feb 2026 at 01:05, BALATON Zoltan <balaton@eik.bme.hu> wrote:
>
> On Tue, 24 Feb 2026, Mark Cave-Ayland wrote:
> > The questions I think we need to answer as a starting point:
> >
> >  1. Which API shall we converge on: qdev or QOM? Can we come up with a
> >     code sample(s) showing what we want object/device initialisation to
> >     look lie? Longer term can we unify the QOM and qdev trees?
>
> My first question is why do we have separate qom and qdev names and trees?
> The docs aren't very helpful. Qdev does not have a Glossary entry and only
> a brief summary at:
> https://www.qemu.org/docs/master/devel/qdev-api.html
> and some confusing info in an old doc here
> https://habkost.net/posts/2016/11/incomplete-list-of-qemu-apis.html
>
> For a long time I did not even know there was info qom-tree command in
> monitor but I was familiar with and used info qtree. I still don't know
> what the qom-tree is good for therefore I also don't care when creating
> machines or devices as I never use it and don't know why I would want to
> use it. To me it looks like some internal thing of QEMU that I don't have
> to be concerned with. All the useful info about devices are in info qtree.

The qdev tree is the older of the two. It models the buses:
devices can own buses, and devices are (mostly) on buses. The classic
example is something like PCI: the PCI controller device owns a PCI
bus, and various PCI network devices etc are children of that bus.
Reset is (currently) done by traversing the this tree.
The qdev tree represents a real thing in the hardware we're modelling.
(The "sysbus" is an odd thing that has all the memory-mapped devices
on it, which is kind of broken in that a memory-mapped subcomponent
of a PCI device is still on the "sysbus". There are also problems
with devices that aren't on buses at all, notably the CPUs: they
don't get reset automatically, for instance.)

The QOM tree is newer, and was introduced when QOM was. It is a
tree of ownership of objects: the machine owns all the devices it
creates, including perhaps an SoC object; the SoC object owns all
the devices that are its subparts (the UART, the I2C controller, etc),
and so on. It provides a hierarchy that the qdev/qbus one cannot,
because not all "this object owns this other object" relations
are ones where the other object is on a bus owned by this one.
Conversely, not all "device A is on a bus owned by device B"
relations are "device B owns device A" ones -- consider an SoC
with a PCI controller and a PCI device that's created via the
command line: the PCI controller doesn't own that PCI device.
In that "PCI device with a memory mapped subcomponent" example above,
the memory-mapped subcomponent is a child of the PCI device in the
QOM tree, so here QOM gets something right that the qbus tree doesn't.

-- PMM
Re: [RFC PATCH] hw/core: Avoid attaching qdevs to /machine/unattached if they have a bus
Posted by Bernhard Beschow 1 month ago

Am 26. Februar 2026 11:58:34 UTC schrieb Peter Maydell <peter.maydell@linaro.org>:
>On Wed, 25 Feb 2026 at 01:05, BALATON Zoltan <balaton@eik.bme.hu> wrote:
>>
>> On Tue, 24 Feb 2026, Mark Cave-Ayland wrote:
>> > The questions I think we need to answer as a starting point:
>> >
>> >  1. Which API shall we converge on: qdev or QOM? Can we come up with a
>> >     code sample(s) showing what we want object/device initialisation to
>> >     look lie? Longer term can we unify the QOM and qdev trees?
>>
>> My first question is why do we have separate qom and qdev names and trees?
>> The docs aren't very helpful. Qdev does not have a Glossary entry and only
>> a brief summary at:
>> https://www.qemu.org/docs/master/devel/qdev-api.html
>> and some confusing info in an old doc here
>> https://habkost.net/posts/2016/11/incomplete-list-of-qemu-apis.html
>>
>> For a long time I did not even know there was info qom-tree command in
>> monitor but I was familiar with and used info qtree. I still don't know
>> what the qom-tree is good for therefore I also don't care when creating
>> machines or devices as I never use it and don't know why I would want to
>> use it. To me it looks like some internal thing of QEMU that I don't have
>> to be concerned with. All the useful info about devices are in info qtree.
>
>The qdev tree is the older of the two. It models the buses:
>devices can own buses, and devices are (mostly) on buses. The classic
>example is something like PCI: the PCI controller device owns a PCI
>bus, and various PCI network devices etc are children of that bus.
>Reset is (currently) done by traversing the this tree.
>The qdev tree represents a real thing in the hardware we're modelling.
>(The "sysbus" is an odd thing that has all the memory-mapped devices
>on it, which is kind of broken in that a memory-mapped subcomponent
>of a PCI device is still on the "sysbus". There are also problems
>with devices that aren't on buses at all, notably the CPUs: they
>don't get reset automatically, for instance.)
>
>The QOM tree is newer, and was introduced when QOM was. It is a
>tree of ownership of objects: the machine owns all the devices it
>creates, including perhaps an SoC object; the SoC object owns all
>the devices that are its subparts (the UART, the I2C controller, etc),
>and so on. It provides a hierarchy that the qdev/qbus one cannot,
>because not all "this object owns this other object" relations
>are ones where the other object is on a bus owned by this one.
>Conversely, not all "device A is on a bus owned by device B"
>relations are "device B owns device A" ones -- consider an SoC
>with a PCI controller and a PCI device that's created via the
>command line: the PCI controller doesn't own that PCI device.
>In that "PCI device with a memory mapped subcomponent" example above,
>the memory-mapped subcomponent is a child of the PCI device in the
>QOM tree, so here QOM gets something right that the qbus tree doesn't.

Yeah, QOM, among other things, seems to be the infrastructure for intrusive, ref-countes smart pointers. Unlike Rust or C++, C doesn't have a concept of destructors which are invoked implicitly and recursively when an object goes out of scope. So we need to maintain a tree that allows us to run destructors like that -- the QOM tree.

Ideally, we'd destruct the whole tree when the QEMU process finishes. However, this is marked as todo since years: <https://gitlab.com/qemu-project/qemu/-/blob/v10.2.1/system/runstate.c#L1002> . So it seems that we're basically leaking the whole machine and don't clean up properly.

Attempting to fix this first reveals that the machine object's refcount is 2, because apparently an object_unref() is required after setting its parent. After having fixed that as well, one can witness QEMU crashing in various interesting ways when quitting.

Fixing the unwinding of the QOM tree may perhaps shed some light on what we need and what we want... Clearly a rabbit hole.

Best regards,
Bernhard

>
>-- PMM
>
Re: [RFC PATCH] hw/core: Avoid attaching qdevs to /machine/unattached if they have a bus
Posted by BALATON Zoltan 1 month, 2 weeks ago
On Thu, 26 Feb 2026, Peter Maydell wrote:
> On Wed, 25 Feb 2026 at 01:05, BALATON Zoltan <balaton@eik.bme.hu> wrote:
>>
>> On Tue, 24 Feb 2026, Mark Cave-Ayland wrote:
>>> The questions I think we need to answer as a starting point:
>>>
>>>  1. Which API shall we converge on: qdev or QOM? Can we come up with a
>>>     code sample(s) showing what we want object/device initialisation to
>>>     look lie? Longer term can we unify the QOM and qdev trees?
>>
>> My first question is why do we have separate qom and qdev names and trees?
>> The docs aren't very helpful. Qdev does not have a Glossary entry and only
>> a brief summary at:
>> https://www.qemu.org/docs/master/devel/qdev-api.html
>> and some confusing info in an old doc here
>> https://habkost.net/posts/2016/11/incomplete-list-of-qemu-apis.html
>>
>> For a long time I did not even know there was info qom-tree command in
>> monitor but I was familiar with and used info qtree. I still don't know
>> what the qom-tree is good for therefore I also don't care when creating
>> machines or devices as I never use it and don't know why I would want to
>> use it. To me it looks like some internal thing of QEMU that I don't have
>> to be concerned with. All the useful info about devices are in info qtree.
>
> The qdev tree is the older of the two. It models the buses:
> devices can own buses, and devices are (mostly) on buses. The classic
> example is something like PCI: the PCI controller device owns a PCI
> bus, and various PCI network devices etc are children of that bus.
> Reset is (currently) done by traversing the this tree.
> The qdev tree represents a real thing in the hardware we're modelling.
> (The "sysbus" is an odd thing that has all the memory-mapped devices
> on it, which is kind of broken in that a memory-mapped subcomponent
> of a PCI device is still on the "sysbus". There are also problems
> with devices that aren't on buses at all, notably the CPUs: they
> don't get reset automatically, for instance.)
>
> The QOM tree is newer, and was introduced when QOM was. It is a
> tree of ownership of objects: the machine owns all the devices it
> creates, including perhaps an SoC object; the SoC object owns all
> the devices that are its subparts (the UART, the I2C controller, etc),
> and so on. It provides a hierarchy that the qdev/qbus one cannot,
> because not all "this object owns this other object" relations
> are ones where the other object is on a bus owned by this one.
> Conversely, not all "device A is on a bus owned by device B"
> relations are "device B owns device A" ones -- consider an SoC
> with a PCI controller and a PCI device that's created via the
> command line: the PCI controller doesn't own that PCI device.
> In that "PCI device with a memory mapped subcomponent" example above,
> the memory-mapped subcomponent is a child of the PCI device in the
> QOM tree, so here QOM gets something right that the qbus tree doesn't.

This probably answers the question of this patch if we should decide the 
qom-tree path based on bus and the answer seems to be no as these are 
different things. But then what is this ownership tree used for? Maybe it 
should be more clearly defined what this ownership relation means and why 
do we want to keep track of it. It looks like it works with most devices 
being unattached so this is just some info we don't really need. In that 
case why do we want to make effort setting it?

Regards,
BALATON Zoltan