hw/core/qdev.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
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
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)
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 :|
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.
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
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.
+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. > >
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. >> >> >
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
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
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 >
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
© 2016 - 2026 Red Hat, Inc.