[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH 1/2] qdev: Separate implementations of qdev_get_machine() for

From: Thomas Huth
Subject: Re: [PATCH 1/2] qdev: Separate implementations of qdev_get_machine() for user and system
Date: Sat, 10 Apr 2021 06:56:06 +0200
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Thunderbird/78.8.0

On 09/04/2021 18.03, Greg Kurz wrote:
Despite its simple name and common usage of "getting a pointer to
the machine" in system-mode emulation, qdev_get_machine() has some

First, it can be called when running user-mode emulation : this is
because user-mode partly relies on qdev to instantiate its CPU

Second, but not least, it has a side-effect : if it cannot find an
object at "/machine" in the QOM tree, it creates a dummy "container"
object and put it there. A simple check on the type returned by
qdev_get_machine() allows user-mode to run the common qdev code,
skipping the parts that only make sense for system-mode.

This side-effect turns out to complicate the use of qdev_get_machine()
for the system-mode case though. Most notably, qdev_get_machine() must
not be called before the machine object is added to the QOM tree by
qemu_create_machine(), otherwise the existing dummy "container" object
would cause qemu_create_machine() to fail with something like :

Unexpected error in object_property_try_add() at ../../qom/object.c:1223:
qemu-system-ppc64: attempt to add duplicate property 'machine' to
  object (type 'container')
Aborted (core dumped)

This situation doesn't exist in the current code base, mostly because
of preventive fixing of some "latent bugs" in QEMU 4.0 (see 1a3ec8c1564
and e2fb3fbbf9c for details).

A new kind of breakage was spotted very recently though :

$ ./qemu-system-ppc64 -device power8_v2.0-spapr-cpu-core,help
  MACHINE: Object 0x5635bd53af10 is not an instance of type machine
Aborted (core dumped)

This comes from the change 3df261b6676b in QEMU 5.0. It unwillingly
added a new condition for qdev_get_machine() to be called too early,
breaking MACHINE(qdev_get_machine()) in generic cpu-core code this

In order to avoid further subtle breakages like this, change the
implentation of qdev_get_machine() to:
- keep the existing behaviour of creating the dummy "container"
   object for the user-mode case only ;
- abort() if the machine doesn't exist yet in the QOM tree for
   the system-mode case. This gives a precise hint to developpers
   that calling qdev_get_machine() too early is a programming bug.

This is achieved with a new do_qdev_get_machine() function called
from qdev_get_machine(), with different implementations for system
and user mode.

$ ./qemu-system-ppc64 -device power8_v2.0-spapr-cpu-core,help
qemu-system-ppc64: ../../hw/core/machine.c:1290:
  qdev_get_machine: Assertion `machine != NULL' failed.
Aborted (core dumped)

Reported-by: Thomas Huth <thuth@redhat.com>
Signed-off-by: Greg Kurz <groug@kaod.org>
  hw/core/machine.c        | 14 ++++++++++++++
  hw/core/qdev.c           |  2 +-
  include/hw/qdev-core.h   |  1 +
  stubs/meson.build        |  1 +
  stubs/qdev-get-machine.c | 11 +++++++++++
  5 files changed, 28 insertions(+), 1 deletion(-)
  create mode 100644 stubs/qdev-get-machine.c

diff --git a/hw/core/machine.c b/hw/core/machine.c
index 40def78183a7..fecca4023105 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -1293,6 +1293,20 @@ void qdev_machine_creation_done(void)
+Object *do_qdev_get_machine(void)
+    Object *machine;
+    machine = object_resolve_path_component(object_get_root(), "machine");
+    /*
+     * qdev_get_machine() shouldn't be called before qemu_create_machine()
+     * has created the "/machine" path.
+     */
+    assert(machine != NULL);
+    return machine;
  static const TypeInfo machine_info = {
      .name = TYPE_MACHINE,
      .parent = TYPE_OBJECT,
diff --git a/hw/core/qdev.c b/hw/core/qdev.c
index cefc5eaa0a92..1122721b2bf0 100644
--- a/hw/core/qdev.c
+++ b/hw/core/qdev.c
@@ -1131,7 +1131,7 @@ Object *qdev_get_machine(void)
      static Object *dev;
if (dev == NULL) {
-        dev = container_get(object_get_root(), "/machine");
+        dev = do_qdev_get_machine();
return dev;
diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h
index bafc311bfa1b..90e295e0bc1a 100644
--- a/include/hw/qdev-core.h
+++ b/include/hw/qdev-core.h
@@ -782,6 +782,7 @@ const char *qdev_fw_name(DeviceState *dev);
void qdev_assert_realized_properly(void);
  Object *qdev_get_machine(void);
+Object *do_qdev_get_machine(void);
/* FIXME: make this a link<> */
  bool qdev_set_parent_bus(DeviceState *dev, BusState *bus, Error **errp);
diff --git a/stubs/meson.build b/stubs/meson.build
index be6f6d609e58..b99ee2b33e94 100644
--- a/stubs/meson.build
+++ b/stubs/meson.build
@@ -54,3 +54,4 @@ if have_system
diff --git a/stubs/qdev-get-machine.c b/stubs/qdev-get-machine.c
new file mode 100644
index 000000000000..ed4cdaa01900
--- /dev/null
+++ b/stubs/qdev-get-machine.c
@@ -0,0 +1,11 @@
+#include "qemu/osdep.h"
+#include "hw/qdev-core.h"
+Object *do_qdev_get_machine(void)
+    /*
+     * This will create a "container" and add it to the QOM tree, if there
+     * isn't one already.
+     */
+    return container_get(object_get_root(), "/machine");

Reviewed-by: Thomas Huth <thuth@redhat.com>

... but I think I agree with Eduardo, we should likely add this only after 6.0 has been released.

reply via email to

[Prev in Thread] Current Thread [Next in Thread]