qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: "Philippe Mathieu-Daudé" <philmd@redhat.com>
To: Markus Armbruster <armbru@redhat.com>, qemu-devel@nongnu.org
Cc: Peter Maydell <peter.maydell@linaro.org>,
	"Michael S . Tsirkin" <mst@redhat.com>,
	Alistair Francis <alistair@alistair23.me>,
	Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>,
	Gerd Hoffmann <kraxel@redhat.com>, John Snow <jsnow@redhat.com>,
	David Gibson <david@gibson.dropbear.id.au>
Subject: Re: [PATCH v2 04/58] qdev: New qdev_new(), qdev_realize(), etc.
Date: Tue, 9 Jun 2020 09:59:35 +0200	[thread overview]
Message-ID: <a82f8ad1-0c53-b9e7-c837-3c05e8b96193@redhat.com> (raw)
In-Reply-To: <20200529134523.8477-5-armbru@redhat.com>

On 5/29/20 3:44 PM, Markus Armbruster wrote:
> We commonly plug devices into their bus right when we create them,
> like this:
> 
>     dev = qdev_create(bus, type_name);
> 
> Note that @dev is a weak reference.  The reference from @bus to @dev
> is the only strong one.
> 
> We realize at some later time, either with
> 
>     object_property_set_bool(OBJECT(dev), true, "realized", errp);
> 
> or its convenience wrapper
> 
>     qdev_init_nofail(dev);
> 
> If @dev still has no QOM parent then, realizing makes the
> /machine/unattached/ orphanage its QOM parent.
> 
> Note that the device returned by qdev_create() is plugged into a bus,
> but doesn't have a QOM parent, yet.  Until it acquires one,
> unrealizing the bus will hang in bus_unparent():
> 
>     while ((kid = QTAILQ_FIRST(&bus->children)) != NULL) {
>         DeviceState *dev = kid->child;
>         object_unparent(OBJECT(dev));
>     }
> 
> object_unparent() does nothing when its argument has no QOM parent,
> and the loop spins forever.
> 
> Device state "no QOM parent, but plugged into bus" is dangerous.
> 
> Paolo suggested to delay plugging into the bus until realize.  We need
> to plug into the parent bus before we call the device's realize
> method, in case it uses the parent bus.  So the dangerous state still
> exists, but only within realization, where we can manage it safely.
> 
> This commit creates infrastructure to do this:
> 
>     dev = qdev_new(type_name);
>     ...
>     qdev_realize_and_unref(dev, bus, errp)
> 
> Note that @dev becomes a strong reference here.
> qdev_realize_and_unref() drops it.  There is also plain
> qdev_realize(), which doesn't drop it.
> 
> The remainder of this series will convert all users to this new
> interface.
> 
> Cc: Michael S. Tsirkin <mst@redhat.com>
> Cc: Marcel Apfelbaum <marcel.apfelbaum@gmail.com>
> Cc: Alistair Francis <alistair@alistair23.me>
> Cc: Gerd Hoffmann <kraxel@redhat.com>
> Cc: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> Cc: David Gibson <david@gibson.dropbear.id.au>
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> Acked-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
>  include/hw/qdev-core.h | 11 +++++-
>  hw/core/bus.c          | 14 +++++++
>  hw/core/qdev.c         | 90 ++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 114 insertions(+), 1 deletion(-)
> 
> diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h
> index b870b27966..fba29308f7 100644
> --- a/include/hw/qdev-core.h
> +++ b/include/hw/qdev-core.h
> @@ -57,7 +57,7 @@ typedef void (*BusUnrealize)(BusState *bus);
>   * After successful realization, setting static properties will fail.
>   *
>   * As an interim step, the #DeviceState:realized property can also be
> - * set with qdev_init_nofail().
> + * set with qdev_realize() or qdev_init_nofail().
>   * In the future, devices will propagate this state change to their children
>   * and along busses they expose.
>   * The point in time will be deferred to machine creation, so that values
> @@ -322,7 +322,13 @@ compat_props_add(GPtrArray *arr,
>  
>  DeviceState *qdev_create(BusState *bus, const char *name);
>  DeviceState *qdev_try_create(BusState *bus, const char *name);
> +DeviceState *qdev_new(const char *name);
> +DeviceState *qdev_try_new(const char *name);
>  void qdev_init_nofail(DeviceState *dev);
> +bool qdev_realize(DeviceState *dev, BusState *bus, Error **errp);
> +bool qdev_realize_and_unref(DeviceState *dev, BusState *bus, Error **errp);
> +void qdev_unrealize(DeviceState *dev);
> +
>  void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id,
>                                   int required_for_version);
>  HotplugHandler *qdev_get_bus_hotplug_handler(DeviceState *dev);
> @@ -411,6 +417,9 @@ typedef int (qdev_walkerfn)(DeviceState *dev, void *opaque);
>  void qbus_create_inplace(void *bus, size_t size, const char *typename,
>                           DeviceState *parent, const char *name);
>  BusState *qbus_create(const char *typename, DeviceState *parent, const char *name);
> +bool qbus_realize(BusState *bus, Error **errp);
> +void qbus_unrealize(BusState *bus);
> +
>  /* Returns > 0 if either devfn or busfn skip walk somewhere in cursion,
>   *         < 0 if either devfn or busfn terminate walk somewhere in cursion,
>   *           0 otherwise. */
> diff --git a/hw/core/bus.c b/hw/core/bus.c
> index 33a4443217..6f6071f5fa 100644
> --- a/hw/core/bus.c
> +++ b/hw/core/bus.c
> @@ -164,6 +164,20 @@ BusState *qbus_create(const char *typename, DeviceState *parent, const char *nam
>      return bus;
>  }
>  
> +bool qbus_realize(BusState *bus, Error **errp)
> +{
> +    Error *err = NULL;
> +
> +    object_property_set_bool(OBJECT(bus), true, "realized", &err);
> +    error_propagate(errp, err);
> +    return !err;
> +}
> +
> +void qbus_unrealize(BusState *bus)
> +{
> +    object_property_set_bool(OBJECT(bus), false, "realized", &error_abort);
> +}
> +
>  static bool bus_get_realized(Object *obj, Error **errp)
>  {
>      BusState *bus = BUS(obj);
> diff --git a/hw/core/qdev.c b/hw/core/qdev.c
> index a68ba674db..f2c5cee278 100644
> --- a/hw/core/qdev.c
> +++ b/hw/core/qdev.c
> @@ -176,6 +176,32 @@ DeviceState *qdev_try_create(BusState *bus, const char *type)
>      return dev;
>  }
>  
> +/*
> + * Create a device on the heap.
> + * A type @name must exist.
> + * This only initializes the device state structure and allows
> + * properties to be set.  The device still needs to be realized.  See
> + * qdev-core.h.
> + */
> +DeviceState *qdev_new(const char *name)
> +{
> +    return DEVICE(object_new(name));
> +}
> +
> +/*
> + * Try to create a device on the heap.
> + * This is like qdev_new(), except it returns %NULL when type @name
> + * does not exist.
> + */
> +DeviceState *qdev_try_new(const char *name)
> +{
> +    if (!object_class_by_name(name)) {
> +        return NULL;
> +    }
> +
> +    return DEVICE(object_new(name));

Or:

       return qdev_new(name);
> +}
> +
>  static QTAILQ_HEAD(, DeviceListener) device_listeners
>      = QTAILQ_HEAD_INITIALIZER(device_listeners);
>  
> @@ -427,6 +453,66 @@ void qdev_init_nofail(DeviceState *dev)
>      object_unref(OBJECT(dev));
>  }
>  
> +/*
> + * Realize @dev.
> + * @dev must not be plugged into a bus.
> + * Plug @dev into @bus if non-null, else into the main system bus.

So this is the historical part...

> + * This takes a reference to @dev.
> + * If @dev has no QOM parent, make one up, taking another reference.
> + * On success, return true.
> + * On failure, store an error through @errp and return false.
> + */
> +bool qdev_realize(DeviceState *dev, BusState *bus, Error **errp)
> +{
> +    Error *err = NULL;
> +
> +    assert(!dev->realized && !dev->parent_bus);
> +
> +    if (!bus) {
> +        /*
> +         * Assert that the device really is a SysBusDevice before we
> +         * put it onto the sysbus.  Non-sysbus devices which aren't
> +         * being put onto a bus should be realized with
> +         * object_property_set_bool(OBJECT(dev), true, "realized",
> +         * errp);
> +         */
> +        g_assert(object_dynamic_cast(OBJECT(dev), TYPE_SYS_BUS_DEVICE));
> +        bus = sysbus_get_default();

OK, so we take a QDEV argument.

If we have a BUS argument, we use it as parent bus.

If we don't have a BUS argument, we expect the device is a SYSBUSDEV and
use sysbus_get_default as parent bus.

So we can not use this function realize a QDEV which is not a SYSBUSDEV.
For that, we have to use 'object_property_set_bool(OBJECT(QDEV), true,
"realized")'.

IOW:
- to realize a QDEV, we have to use the OBJECT API,
- to realize a SYSBUSDEV, we have to use the QDEV API.

I'm not suggesting you to clean that now, I'm simply taking notes about
future improvements, because this is really not clear for new contributors.

> +    }
> +
> +    qdev_set_parent_bus(dev, bus);
> +
> +    object_property_set_bool(OBJECT(dev), true, "realized", &err);
> +    if (err) {
> +        error_propagate(errp, err);
> +    }
> +    return !err;
> +}
> +
> +/*
> + * Realize @dev and drop a reference.
> + * This is like qdev_realize(), except the caller must hold a
> + * (private) reference, which is dropped on return regardless of
> + * success or failure.  Intended use:
> + *     dev = qdev_new();
> + *     [...]
> + *     qdev_realize_and_unref(dev, bus, errp);
> + * Now @dev can go away without further ado.
> + */
> +bool qdev_realize_and_unref(DeviceState *dev, BusState *bus, Error **errp)
> +{
> +    bool ret;
> +
> +    ret = qdev_realize(dev, bus, errp);
> +    object_unref(OBJECT(dev));
> +    return ret;
> +}
> +
> +void qdev_unrealize(DeviceState *dev)
> +{
> +    object_property_set_bool(OBJECT(dev), false, "realized", &error_abort);
> +}
> +
>  static int qdev_assert_realized_properly(Object *obj, void *opaque)
>  {
>      DeviceState *dev = DEVICE(object_dynamic_cast(obj, TYPE_DEVICE));
> @@ -1002,6 +1088,10 @@ post_realize_fail:
>  fail:
>      error_propagate(errp, local_err);
>      if (unattached_parent) {
> +        /*
> +         * Beware, this doesn't just revert
> +         * object_property_add_child(), it also runs bus_remove()!
> +         */
>          object_unparent(OBJECT(dev));
>          unattached_count--;
>      }
> 

Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>



  parent reply	other threads:[~2020-06-09  8:01 UTC|newest]

Thread overview: 88+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-05-29 13:44 [PATCH v2 00/58] qdev: Rework how we plug into the parent bus Markus Armbruster
2020-05-29 13:44 ` [PATCH v2 01/58] qdev: Rename qbus_realize() to qbus_init() Markus Armbruster
2020-05-30  7:53   ` Philippe Mathieu-Daudé
2020-05-29 13:44 ` [PATCH v2 02/58] Revert "hw/prep: realize the PCI root bus as part of the prep init" Markus Armbruster
2020-05-29 13:44 ` [PATCH v2 03/58] Revert "hw/versatile: realize the PCI root bus as part of the versatile init" Markus Armbruster
2020-05-29 13:44 ` [PATCH v2 04/58] qdev: New qdev_new(), qdev_realize(), etc Markus Armbruster
2020-05-29 19:04   ` Alistair Francis
2020-06-09  7:59   ` Philippe Mathieu-Daudé [this message]
2020-06-09  9:52     ` Markus Armbruster
2020-05-29 13:44 ` [PATCH v2 05/58] qdev: Put qdev_new() to use with Coccinelle Markus Armbruster
2020-06-09  7:45   ` Philippe Mathieu-Daudé
2020-05-29 13:44 ` [PATCH v2 06/58] qdev: Convert to qbus_realize(), qbus_unrealize() Markus Armbruster
2020-06-09  8:13   ` Philippe Mathieu-Daudé
2020-05-29 13:44 ` [PATCH v2 07/58] qdev: Convert to qdev_unrealize() with Coccinelle Markus Armbruster
2020-06-09  8:03   ` Philippe Mathieu-Daudé
2020-05-29 13:44 ` [PATCH v2 08/58] qdev: Convert to qdev_unrealize() manually Markus Armbruster
2020-06-09  8:04   ` Philippe Mathieu-Daudé
2020-05-29 13:44 ` [PATCH v2 09/58] qdev: Convert uses of qdev_create() with Coccinelle Markus Armbruster
2020-05-29 13:44 ` [PATCH v2 10/58] qdev: Convert uses of qdev_create() manually Markus Armbruster
2020-05-29 13:44 ` [PATCH v2 11/58] qdev: Convert uses of qdev_set_parent_bus() with Coccinelle Markus Armbruster
2020-06-09  8:08   ` Philippe Mathieu-Daudé
2020-05-29 13:44 ` [PATCH v2 12/58] qdev: Convert uses of qdev_set_parent_bus() manually Markus Armbruster
2020-06-09  8:12   ` Philippe Mathieu-Daudé
2020-06-09 10:00     ` Markus Armbruster
2020-05-29 13:44 ` [PATCH v2 13/58] pci: New pci_new(), pci_realize_and_unref() etc Markus Armbruster
2020-05-29 13:44 ` [PATCH v2 14/58] hw/ppc: Eliminate two superfluous QOM casts Markus Armbruster
2020-05-29 13:44 ` [PATCH v2 15/58] pci: Convert uses of pci_create() etc. with Coccinelle Markus Armbruster
2020-05-29 13:44 ` [PATCH v2 16/58] pci: Convert uses of pci_create() etc. manually Markus Armbruster
2020-05-29 13:44 ` [PATCH v2 17/58] pci: pci_create(), pci_create_multifunction() are now unused, drop Markus Armbruster
2020-05-29 13:44 ` [PATCH v2 18/58] isa: New isa_new(), isa_realize_and_unref() etc Markus Armbruster
2020-06-09  8:19   ` Philippe Mathieu-Daudé
2020-06-09  8:26     ` Philippe Mathieu-Daudé
2020-05-29 13:44 ` [PATCH v2 19/58] isa: Convert uses of isa_create() with Coccinelle Markus Armbruster
2020-05-30  5:07   ` Markus Armbruster
2020-05-29 13:44 ` [PATCH v2 20/58] isa: Convert uses of isa_create(), isa_try_create() manually Markus Armbruster
2020-05-29 13:44 ` [PATCH v2 21/58] isa: isa_create(), isa_try_create() are now unused, drop Markus Armbruster
2020-05-29 13:44 ` [PATCH v2 22/58] ssi: ssi_auto_connect_slaves() never does anything, drop Markus Armbruster
2020-05-29 13:44 ` [PATCH v2 23/58] ssi: Convert uses of ssi_create_slave_no_init() with Coccinelle Markus Armbruster
2020-05-29 13:44 ` [PATCH v2 24/58] ssi: Convert last use of ssi_create_slave_no_init() manually Markus Armbruster
2020-05-29 13:44 ` [PATCH v2 25/58] ssi: ssi_create_slave_no_init() is now unused, drop Markus Armbruster
2020-05-29 13:44 ` [PATCH v2 26/58] usb: New usb_new(), usb_realize_and_unref() Markus Armbruster
2020-06-09  8:21   ` Philippe Mathieu-Daudé
2020-05-29 13:44 ` [PATCH v2 27/58] usb: Convert uses of usb_create() Markus Armbruster
2020-05-29 13:44 ` [PATCH v2 28/58] usb: usb_create() is now unused, drop Markus Armbruster
2020-05-29 13:44 ` [PATCH v2 29/58] usb: Eliminate usb_try_create_simple() Markus Armbruster
2020-05-29 13:44 ` [PATCH v2 30/58] qdev: qdev_create(), qdev_try_create() are now unused, drop Markus Armbruster
2020-05-29 13:44 ` [PATCH v2 31/58] auxbus: Rename aux_init_bus() to aux_bus_init() Markus Armbruster
2020-05-29 13:44 ` [PATCH v2 32/58] auxbus: New aux_bus_realize(), pairing with aux_bus_init() Markus Armbruster
2020-05-29 13:44 ` [PATCH v2 33/58] auxbus: Convert a use of qdev_set_parent_bus() Markus Armbruster
2020-06-09  8:31   ` Philippe Mathieu-Daudé
2020-05-29 13:44 ` [PATCH v2 34/58] auxbus: Eliminate aux_create_slave() Markus Armbruster
2020-05-29 13:45 ` [PATCH v2 35/58] qom: Tidy up a few object_initialize_child() calls Markus Armbruster
2020-05-29 13:45 ` [PATCH v2 36/58] qom: Less verbose object_initialize_child() Markus Armbruster
2020-05-29 13:45 ` [PATCH v2 37/58] macio: Convert use of qdev_set_parent_bus() Markus Armbruster
2020-06-09  8:33   ` Philippe Mathieu-Daudé
2020-05-29 13:45 ` [PATCH v2 38/58] macio: Eliminate macio_init_child_obj() Markus Armbruster
2020-05-29 13:45 ` [PATCH v2 39/58] sysbus: Drop useless OBJECT() in sysbus_init_child_obj() calls Markus Armbruster
2020-05-29 13:45 ` [PATCH v2 40/58] microbit: Tidy up sysbus_init_child_obj() @child argument Markus Armbruster
2020-05-29 13:45 ` [PATCH v2 41/58] sysbus: Tidy up sysbus_init_child_obj()'s @childsize arg, part 1 Markus Armbruster
2020-05-29 13:45 ` [PATCH v2 42/58] hw/arm/armsse: Pass correct child size to sysbus_init_child_obj() Markus Armbruster
2020-05-29 13:45 ` [PATCH v2 43/58] sysbus: Tidy up sysbus_init_child_obj()'s @childsize arg, part 2 Markus Armbruster
2020-05-29 13:45 ` [PATCH v2 44/58] sysbus: New sysbus_realize(), sysbus_realize_and_unref() Markus Armbruster
2020-06-09  8:35   ` Philippe Mathieu-Daudé
2020-05-29 13:45 ` [PATCH v2 45/58] sysbus: Convert to sysbus_realize() etc. with Coccinelle Markus Armbruster
2020-06-09  8:41   ` Philippe Mathieu-Daudé
2020-05-29 13:45 ` [PATCH v2 46/58] qdev: Drop qdev_realize() support for null bus Markus Armbruster
2020-06-09  8:45   ` Philippe Mathieu-Daudé
2020-06-09 10:05     ` Markus Armbruster
2020-05-29 13:45 ` [PATCH v2 47/58] sysbus: Convert qdev_set_parent_bus() use with Coccinelle, part 1 Markus Armbruster
2020-05-29 13:45 ` [PATCH v2 48/58] sysbus: Convert qdev_set_parent_bus() use with Coccinelle, part 2 Markus Armbruster
2020-05-29 13:45 ` [PATCH v2 49/58] sysbus: Convert qdev_set_parent_bus() use with Coccinelle, part 3 Markus Armbruster
2020-05-29 13:45 ` [PATCH v2 50/58] sysbus: Convert qdev_set_parent_bus() use with Coccinelle, part 4 Markus Armbruster
2020-05-29 13:45 ` [PATCH v2 51/58] sysbus: sysbus_init_child_obj() is now unused, drop Markus Armbruster
2020-05-29 13:45 ` [PATCH v2 52/58] microbit: Eliminate two local variables in microbit_init() Markus Armbruster
2020-05-29 13:45 ` [PATCH v2 53/58] s390x/event-facility: Simplify creation of SCLP event devices Markus Armbruster
2020-05-29 13:45 ` [PATCH v2 54/58] qdev: Make qdev_realize() support bus-less devices Markus Armbruster
2020-05-30  7:59   ` Philippe Mathieu-Daudé
2020-05-29 13:45 ` [PATCH v2 55/58] qdev: Use qdev_realize() in qdev_device_add() Markus Armbruster
2020-05-29 13:45 ` [PATCH v2 56/58] qdev: Convert bus-less devices to qdev_realize() with Coccinelle Markus Armbruster
2020-05-29 13:45 ` [PATCH v2 57/58] qdev: qdev_init_nofail() is now unused, drop Markus Armbruster
2020-05-29 13:45 ` [PATCH v2 58/58] MAINTAINERS: Make section QOM cover hw/core/*bus.c as well Markus Armbruster
2020-05-30  7:56   ` Philippe Mathieu-Daudé
2020-05-29 13:48 ` [PATCH v2 00/58] qdev: Rework how we plug into the parent bus Markus Armbruster
2020-05-29 23:58 ` no-reply
2020-05-30  4:18 ` no-reply
2020-05-30  4:28 ` no-reply
2020-05-30  5:43 ` no-reply
2020-05-30  6:15 ` no-reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=a82f8ad1-0c53-b9e7-c837-3c05e8b96193@redhat.com \
    --to=philmd@redhat.com \
    --cc=alistair@alistair23.me \
    --cc=armbru@redhat.com \
    --cc=david@gibson.dropbear.id.au \
    --cc=jsnow@redhat.com \
    --cc=kraxel@redhat.com \
    --cc=mark.cave-ayland@ilande.co.uk \
    --cc=mst@redhat.com \
    --cc=peter.maydell@linaro.org \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).