From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([208.118.235.92]:50835) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1T5Alq-0006Bb-Li for qemu-devel@nongnu.org; Sat, 25 Aug 2012 03:27:03 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1T5Alm-0001Gn-RG for qemu-devel@nongnu.org; Sat, 25 Aug 2012 03:27:02 -0400 Received: from mail-pz0-f45.google.com ([209.85.210.45]:47345) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1T5Alm-0001GX-Hl for qemu-devel@nongnu.org; Sat, 25 Aug 2012 03:26:58 -0400 Received: by dadn15 with SMTP id n15so1293689dad.4 for ; Sat, 25 Aug 2012 00:26:57 -0700 (PDT) From: Liu Ping Fan Date: Sat, 25 Aug 2012 15:26:47 +0800 Message-Id: <1345879607-15650-1-git-send-email-qemulist@gmail.com> Subject: [Qemu-devel] [PATCH] qdev: unplug request will propagate and release item bottom-up List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: Paolo Bonzini , Avi Kivity , Anthony Liguori From: Liu Ping Fan To achieve uplug a sub tree, we propagate unplug event on the tree. Signed-off-by: Liu Ping Fan --- 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