diff mbox

[04/10] qdev: introduce new interface to remove composite sub-tree

Message ID 1345801763-24227-5-git-send-email-qemulist@gmail.com
State New
Headers show

Commit Message

pingfan liu Aug. 24, 2012, 9:49 a.m. UTC
From: Liu Ping Fan <pingfank@linux.vnet.ibm.com>

When a bridge device removed, all the children bebind it should be
removed. Using qdev_delete_subtree(dev) to emulate this event.
And it is achieved by iterated laughed by qdev_walk_children()

Signed-off-by: Liu Ping Fan <pingfank@linux.vnet.ibm.com>
---
 hw/qdev.c |   44 ++++++++++++++++++++++++++++++++++++++++++++
 hw/qdev.h |    1 +
 2 files changed, 45 insertions(+), 0 deletions(-)
diff mbox

Patch

diff --git a/hw/qdev.c b/hw/qdev.c
index ad618dd..570f0bf 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -239,6 +239,50 @@  void qbus_reset_all_fn(void *opaque)
     qbus_walk_children(bus, qdev_reset_one, qbus_reset_one, NULL, 0);
 }
 
+static int qdev_device_delete(DeviceState *dev, void *opaque)
+{
+    Object *obj = OBJECT(dev);
+    BusState *b = dev->parent_bus;
+
+    dev->parent_bus = NULL;
+    /* removed from list and bus->dev link */
+    bus_remove_child(b, dev);
+    /* remove bus<-dev link */
+    object_property_del(OBJECT(dev), "parent_bus", NULL);
+
+    /* when mmio-dispatch out of big lock, remove it!
+         * refcnt hold by
+         * object_property_add_child(qdev_get_peripheral(), ., OBJECT(qdev),..)
+         * should be released before here.
+         */
+    g_assert(obj->ref == 1);
+    object_unref(OBJECT(dev));
+
+    return 0;
+}
+
+static int qdev_bus_delete(BusState *bus, void *opaque)
+{
+    Object *obj = OBJECT(bus);
+    DeviceState *d = bus->parent;
+
+    bus->parent = NULL;
+    QLIST_REMOVE(bus, sibling);
+    d->num_child_bus--;
+    object_property_del_child(OBJECT(d), OBJECT(bus), NULL);
+    /* when mmio-dispatch out of big lock, remove it!*/
+    g_assert(obj->ref == 1);
+    object_unref(obj);
+
+    return 0;
+}
+
+/* Delete the composite tree which starts from @dev */
+void qdev_delete_subtree(DeviceState *dev)
+{
+    qdev_walk_children(dev, qdev_device_delete, qdev_bus_delete, NULL, 1);
+}
+
 /* can be used as ->unplug() callback for the simple cases */
 int qdev_simple_unplug_cb(DeviceState *dev)
 {
diff --git a/hw/qdev.h b/hw/qdev.h
index 9fc8b46..6f97990 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -162,6 +162,7 @@  void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id,
                                  int required_for_version);
 void qdev_unplug(DeviceState *dev, Error **errp);
 void qdev_free(DeviceState *dev);
+void qdev_delete_subtree(DeviceState *dev);
 int qdev_simple_unplug_cb(DeviceState *dev);
 void qdev_machine_creation_done(void);
 bool qdev_machine_modified(void);