qemu-devel
[Top][All Lists]
Advanced

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

[Qemu-devel] [PATCH] qdev: unplug request will propagate and release ite


From: Liu Ping Fan
Subject: [Qemu-devel] [PATCH] qdev: unplug request will propagate and release item bottom-up
Date: Sat, 25 Aug 2012 15:26:47 +0800

From: Liu Ping Fan <address@hidden>

To achieve uplug a sub tree, we propagate unplug event on the tree.

Signed-off-by: Liu Ping Fan <address@hidden>
---
 hw/acpi_piix4.c |   71 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 hw/qdev.c       |    7 ++++-
 hw/qdev.h       |    2 +
 3 files changed, 77 insertions(+), 3 deletions(-)

diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c
index 0aace60..49247c5 100644
--- a/hw/acpi_piix4.c
+++ b/hw/acpi_piix4.c
@@ -287,6 +287,74 @@ static const VMStateDescription vmstate_acpi = {
     }
 };
 
+static void check_release_bus(BusState *bus);
+
+static void check_release_device(DeviceState *dev)
+{
+    Object *obj = OBJECT(dev);
+    BusState *up_b = dev->parent_bus;
+    BusState *child;
+
+    if (dev->unplug_state == 1) {
+        /* a leaf device has no child bus, or empty child bus */
+        QLIST_FOREACH(child, &dev->child_bus, sibling) {
+            if (!QTAILQ_EMPTY(&child->children)) {
+                return;
+            }
+            child->parent = NULL;
+            QLIST_REMOVE(child, sibling);
+            dev->num_child_bus--;
+            object_property_del_child(OBJECT(dev), OBJECT(child), NULL);
+            /* when mmio-dispatch out of big lock, remove it!*/
+            g_assert(OBJECT(child)->ref == 1);
+            object_unref(OBJECT(child));
+        }
+
+        dev->parent_bus = NULL;
+        /* removed from list and bus->dev link */
+        bus_remove_child(up_b, dev);
+        /* remove bus<-dev link */
+        object_property_del(OBJECT(dev), "parent_bus", NULL);
+
+        /* when mmio-dispatch out of big lock, remove it! */
+        g_assert(obj->ref == 1);
+        object_unref(obj);
+        check_release_bus(up_b);
+    }
+}
+
+static void check_release_bus(BusState *bus)
+{
+    Object *obj = OBJECT(bus);
+    DeviceState *d = bus->parent;
+
+    if (bus->unplug_state == 1 && QTAILQ_EMPTY(&bus->children)) {
+        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);
+        check_release_device(d);
+    }
+}
+
+static void qdev_unplug_complete(DeviceState *qdev)
+{
+    BusState *child;
+
+    /* keep the child<> , until all of the children detached.
+    * Mark dev and its bus going.
+    */
+   qdev->unplug_state = 1;
+   QLIST_FOREACH(child, &qdev->child_bus, sibling) {
+       child->unplug_state = 1;
+   }
+   /* bottom-up through the release chain */
+   check_release_device(qdev);
+}
+
 static void acpi_piix_eject_slot(PIIX4PMState *s, unsigned slots)
 {
     BusChild *kid, *next;
@@ -305,8 +373,7 @@ static void acpi_piix_eject_slot(PIIX4PMState *s, unsigned 
slots)
             if (pc->no_hotplug) {
                 slot_free = false;
             } else {
-                object_unparent(OBJECT(dev));
-                qdev_free(qdev);
+                qdev_unplug_complete(qdev);
             }
         }
     }
diff --git a/hw/qdev.c b/hw/qdev.c
index b5b74b9..206e0eb 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -194,7 +194,7 @@ void qdev_set_legacy_instance_id(DeviceState *dev, int 
alias_id,
     dev->alias_required_for_version = required_for_version;
 }
 
-void qdev_unplug(DeviceState *dev, Error **errp)
+static void qdev_eject_unplug(DeviceState *dev, Error **errp)
 {
     DeviceClass *dc = DEVICE_GET_CLASS(dev);
 
@@ -212,6 +212,11 @@ void qdev_unplug(DeviceState *dev, Error **errp)
     }
 }
 
+void qdev_unplug(DeviceState *dev, Error **errp)
+{
+    qdev_walk_children(dev, qdev_eject_unplug, NULL, errp);
+}
+
 static int qdev_reset_one(DeviceState *dev, void *opaque)
 {
     device_reset(dev);
diff --git a/hw/qdev.h b/hw/qdev.h
index d699194..3c09ae7 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -67,6 +67,7 @@ struct DeviceState {
     enum DevState state;
     QemuOpts *opts;
     int hotplugged;
+    int unplug_state;
     BusState *parent_bus;
     int num_gpio_out;
     qemu_irq *gpio_out;
@@ -115,6 +116,7 @@ struct BusState {
     DeviceState *parent;
     const char *name;
     int allow_hotplug;
+    int unplug_state;
     bool qom_allocated;
     bool glib_allocated;
     int max_index;
-- 
1.7.4.4




reply via email to

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