From patchwork Sat Aug 25 07:26:47 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: pingfan liu X-Patchwork-Id: 179953 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id DD0F72C010F for ; Sat, 25 Aug 2012 17:27:12 +1000 (EST) Received: from localhost ([::1]:55442 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1T5Alx-0006Gg-Lp for incoming@patchwork.ozlabs.org; Sat, 25 Aug 2012 03:27:09 -0400 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) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:x-mailer; bh=hB5BhIUGrsWe6omQio1zl0GCxXliypHXN0zunynbeAA=; b=vCo6SMb15iWBj2f9vYD/gzbf95bUhR8XxiHlWAcmSqKH9p7Hhg+OoQL0wvB2AnBEJM pgumCIVHDlvfHv1O+kiLA/u/rNfvZijZonujGkpUjQfjTT4DHZKAc3fpDc8JBGiKjELG fqxxnbUOtMHfAFLl2gIXBQXpIxsQRI4Kd9nJu2cJSn9vwlSNzantuiBRMIrbP/bgG5Yy w+KVSzAxo9P+WNmTjUl5QzAUkrvjgslX8iuIrayhb/qZaqFOaAtsNcdSWbYt4aKQvBHK oLZX67VHQKYhBkhclcckZFtX1bE+EpEVKkhKKLd1+18fL92bach/1bitghW5b4asg4oT OQhg== Received: by 10.68.191.134 with SMTP id gy6mr18383264pbc.136.1345879617699; Sat, 25 Aug 2012 00:26:57 -0700 (PDT) Received: from localhost ([221.223.240.212]) by mx.google.com with ESMTPS id qx8sm9988863pbc.63.2012.08.25.00.26.52 (version=TLSv1/SSLv3 cipher=OTHER); Sat, 25 Aug 2012 00:26:56 -0700 (PDT) From: Liu Ping Fan To: qemu-devel@nongnu.org Date: Sat, 25 Aug 2012 15:26:47 +0800 Message-Id: <1345879607-15650-1-git-send-email-qemulist@gmail.com> X-Mailer: git-send-email 1.7.4.4 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 209.85.210.45 Cc: Paolo Bonzini , Avi Kivity , Anthony Liguori Subject: [Qemu-devel] [PATCH] qdev: unplug request will propagate and release item bottom-up X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org 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;