From 12b2e9f30f978f26f35f9df5c2ef96fbc019bab6 Mon Sep 17 00:00:00 2001 From: Tony Krowiak Date: Mon, 17 Dec 2018 10:57:30 -0500 Subject: qdev/core: fix qbus_is_full() The qbus_is_full(BusState *bus) function (qdev_monitor.c) compares the max_index value of the BusState structure with the max_dev value of the BusClass structure to determine whether the maximum number of children has been reached for the bus. The problem is, the max_index field of the BusState structure does not necessarily reflect the number of devices that have been plugged into the bus. Whenever a child device is plugged into the bus, the bus's max_index value is assigned to the child device and then incremented. If the child is subsequently unplugged, the value of the max_index does not change and no longer reflects the number of children. When the bus's max_index value reaches the maximum number of devices allowed for the bus (i.e., the max_dev field in the BusClass structure), attempts to plug another device will be rejected claiming that the bus is full -- even if the bus is actually empty. To resolve the problem, a new 'num_children' field is being added to the BusState structure to keep track of the number of children plugged into the bus. It will be incremented when a child is plugged, and decremented when a child is unplugged. Signed-off-by: Tony Krowiak Reviewed-by: Pierre Morel Reviewed-by: Halil Pasic Message-Id: <1545062250-7573-1-git-send-email-akrowiak@linux.ibm.com> Reviewed-by: Igor Mammedov Signed-off-by: Eduardo Habkost --- include/hw/qdev-core.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h index e70a4bf..35b8154 100644 --- a/include/hw/qdev-core.h +++ b/include/hw/qdev-core.h @@ -206,6 +206,7 @@ struct BusState { HotplugHandler *hotplug_handler; int max_index; bool realized; + int num_children; QTAILQ_HEAD(, BusChild) children; QLIST_ENTRY(BusState) sibling; }; -- cgit v1.1 From 17cc0128da3d4a211731a79853ea81c7159b26af Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Thu, 28 Feb 2019 13:28:48 +0100 Subject: qdev: Let machine hotplug handler to override bus hotplug handler it will allow to return another hotplug handler than the default one for a specific bus based device type. Which is needed to handle non trivial plug/unplug sequences that need the access to resources configured outside of bus where device is attached. That will allow for returned hotplug handler to orchestrate wiring in arbitrary order, by chaining other hotplug handlers when it's needed. PS: It could be used for hybrid virtio-mem and virtio-pmem devices where it will return machine as hotplug handler which will do necessary wiring at machine level and then pass control down the chain to bus specific hotplug handler. Example of top level hotplug handler override and custom plug sequence: some_machine_get_hotplug_handler(machine){ if (object_dynamic_cast(OBJECT(dev), TYPE_SOME_BUS_DEVICE)) { return HOTPLUG_HANDLER(machine); } return NULL; } some_machine_device_plug(hotplug_dev, dev) { if (object_dynamic_cast(OBJECT(dev), TYPE_SOME_BUS_DEVICE)) { /* do machine specific initialization */ some_machine_init_special_device(dev) /* pass control to bus specific handler */ hotplug_handler_plug(dev->parent_bus->hotplug_handler, dev) } } Reviewed-by: David Gibson Signed-off-by: Igor Mammedov Signed-off-by: David Hildenbrand Message-Id: <20190228122849.4296-3-david@redhat.com> Signed-off-by: Eduardo Habkost --- include/hw/qdev-core.h | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'include') diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h index 35b8154..ea4c1f6 100644 --- a/include/hw/qdev-core.h +++ b/include/hw/qdev-core.h @@ -282,6 +282,17 @@ void qdev_init_nofail(DeviceState *dev); void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id, int required_for_version); HotplugHandler *qdev_get_machine_hotplug_handler(DeviceState *dev); +/** + * qdev_get_hotplug_handler: Get handler responsible for device wiring + * + * Find HOTPLUG_HANDLER for @dev that provides [pre|un]plug callbacks for it. + * + * Note: in case @dev has a parent bus, it will be returned as handler unless + * machine handler overrides it. + * + * Returns: pointer to object that implements TYPE_HOTPLUG_HANDLER interface + * or NULL if there aren't any. + */ HotplugHandler *qdev_get_hotplug_handler(DeviceState *dev); void qdev_unplug(DeviceState *dev, Error **errp); void qdev_simple_device_unplug_cb(HotplugHandler *hotplug_dev, -- cgit v1.1 From 14405c274e86e993e90198a49eecab3ca0ded8db Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Thu, 28 Feb 2019 13:28:49 +0100 Subject: qdev: Provide qdev_get_bus_hotplug_handler() Let's use a wrapper instead of looking it up manually. This function can than be reused when we explicitly want to have the bus hotplug handler (e.g. when the bus hotplug handler was overwritten by the machine hotplug handler). Reviewed-by: Igor Mammedov Signed-off-by: David Hildenbrand Message-Id: <20190228122849.4296-4-david@redhat.com> Signed-off-by: Eduardo Habkost --- include/hw/qdev-core.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h index ea4c1f6..17f09aa 100644 --- a/include/hw/qdev-core.h +++ b/include/hw/qdev-core.h @@ -281,6 +281,7 @@ DeviceState *qdev_try_create(BusState *bus, const char *name); void qdev_init_nofail(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); HotplugHandler *qdev_get_machine_hotplug_handler(DeviceState *dev); /** * qdev_get_hotplug_handler: Get handler responsible for device wiring -- cgit v1.1