From nobody Sun Feb 8 20:52:25 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1537956482232283.0998243798033; Wed, 26 Sep 2018 03:08:02 -0700 (PDT) Received: from localhost ([::1]:57434 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1g56jg-00071q-Tu for importer@patchew.org; Wed, 26 Sep 2018 06:08:01 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44833) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1g56N1-0003Zx-89 for qemu-devel@nongnu.org; Wed, 26 Sep 2018 05:44:37 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1g56Mz-0005DO-J0 for qemu-devel@nongnu.org; Wed, 26 Sep 2018 05:44:35 -0400 Received: from mx1.redhat.com ([209.132.183.28]:62288) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1g56Mz-0005D5-Ar; Wed, 26 Sep 2018 05:44:33 -0400 Received: from smtp.corp.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.25]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 9B95F30001DA; Wed, 26 Sep 2018 09:44:32 +0000 (UTC) Received: from t460s.redhat.com (ovpn-117-98.ams2.redhat.com [10.36.117.98]) by smtp.corp.redhat.com (Postfix) with ESMTP id 3BAC72010D97; Wed, 26 Sep 2018 09:44:29 +0000 (UTC) From: David Hildenbrand To: qemu-devel@nongnu.org Date: Wed, 26 Sep 2018 11:42:13 +0200 Message-Id: <20180926094219.20322-19-david@redhat.com> In-Reply-To: <20180926094219.20322-1-david@redhat.com> References: <20180926094219.20322-1-david@redhat.com> X-Scanned-By: MIMEDefang 2.84 on 10.5.11.25 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.46]); Wed, 26 Sep 2018 09:44:32 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v4 18/24] qdev: hotplug: provide do_unplug handler X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Pankaj Gupta , Eduardo Habkost , "Michael S . Tsirkin" , Xiao Guangrong , David Hildenbrand , "Dr . David Alan Gilbert" , Markus Armbruster , Alexander Graf , qemu-ppc@nongnu.org, Paolo Bonzini , Igor Mammedov , Luiz Capitulino , David Gibson , Richard Henderson Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RDMRC_1 RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" The unplug and unplug_request handlers are special: They are not executed when unrealizing a device, but rather trigger the removal of a device from device_del() via object_unparent() - to effectively unrealize a device. If such a device has a child bus and another device attached to that bus (e.g. how virtio devices are created with their proxy device), we will not get a call to the unplug handler. As we want to support hotplug handlers (and especially also some unplug logic to undo resource assignment) for such devices, we cannot simply call the unplug handler when unrealizing - it has a different semantic ("trigger removal"). To handle this scenario, we need a do_unplug handler, that will be executed for all devices with a hotplug handler. While at it, introduce hotplug_fn_nofail and fix a spelling mistake in a comment. Signed-off-by: David Hildenbrand --- hw/core/hotplug.c | 10 ++++++++++ hw/core/qdev.c | 6 ++++++ include/hw/hotplug.h | 26 ++++++++++++++++++++++++-- 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/hw/core/hotplug.c b/hw/core/hotplug.c index 2253072d0e..e7a68d5160 100644 --- a/hw/core/hotplug.c +++ b/hw/core/hotplug.c @@ -45,6 +45,16 @@ void hotplug_handler_post_plug(HotplugHandler *plug_hand= ler, } } =20 +void hotplug_handler_do_unplug(HotplugHandler *plug_handler, + DeviceState *plugged_dev) +{ + HotplugHandlerClass *hdc =3D HOTPLUG_HANDLER_GET_CLASS(plug_handler); + + if (hdc->do_unplug) { + hdc->do_unplug(plug_handler, plugged_dev); + } +} + void hotplug_handler_unplug_request(HotplugHandler *plug_handler, DeviceState *plugged_dev, Error **errp) diff --git a/hw/core/qdev.c b/hw/core/qdev.c index 36b788a66b..dde2726099 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -873,6 +873,12 @@ static void device_set_realized(Object *obj, bool valu= e, Error **errp) } } else if (!value && dev->realized) { Error **local_errp =3D NULL; + + hotplug_ctrl =3D qdev_get_hotplug_handler(dev); + if (hotplug_ctrl) { + hotplug_handler_do_unplug(hotplug_ctrl, dev); + } + QLIST_FOREACH(bus, &dev->child_bus, sibling) { local_errp =3D local_err ? NULL : &local_err; object_property_set_bool(OBJECT(bus), false, "realized", diff --git a/include/hw/hotplug.h b/include/hw/hotplug.h index 51541d63e1..2fa5833cf1 100644 --- a/include/hw/hotplug.h +++ b/include/hw/hotplug.h @@ -31,13 +31,21 @@ typedef struct HotplugHandler { =20 /** * hotplug_fn: - * @plug_handler: a device performing plug/uplug action + * @plug_handler: a device performing (un)plug action * @plugged_dev: a device that has been (un)plugged * @errp: returns an error if this function fails */ typedef void (*hotplug_fn)(HotplugHandler *plug_handler, DeviceState *plugged_dev, Error **errp); =20 +/** + * hotplug_fn_nofail: + * @plug_handler: a device performing un(plug) action + * @plugged_dev: a device that has been (un)plugged + */ +typedef void (*hotplug_fn_nofail)(HotplugHandler *plug_handler, + DeviceState *plugged_dev); + /** * HotplugDeviceClass: * @@ -49,12 +57,17 @@ typedef void (*hotplug_fn)(HotplugHandler *plug_handler, * @plug: plug callback called at end of device.realize(true). * @post_plug: post plug callback called after device.realize(true) and de= vice * reset + * @do_unplug: unplug callback called at start of device.realize(false) * @unplug_request: unplug request callback. * Used as a means to initiate device unplug for devices = that * require asynchronous unplug handling. * @unplug: unplug callback. * Used for device removal with devices that implement * asynchronous and synchronous (surprise) removal. + * Note: unplug_request and unplug are only called for devices to initiate + * unplug of a device hierarchy (e.g. triggered by device_del). For + * devices that will be removed along with this device hierarchy only + * do_unplug will be called (e.g. to unassign resources). */ typedef struct HotplugHandlerClass { /* */ @@ -63,7 +76,8 @@ typedef struct HotplugHandlerClass { /* */ hotplug_fn pre_plug; hotplug_fn plug; - void (*post_plug)(HotplugHandler *plug_handler, DeviceState *plugged_d= ev); + hotplug_fn_nofail post_plug; + hotplug_fn_nofail do_unplug; hotplug_fn unplug_request; hotplug_fn unplug; } HotplugHandlerClass; @@ -94,6 +108,14 @@ void hotplug_handler_pre_plug(HotplugHandler *plug_hand= ler, void hotplug_handler_post_plug(HotplugHandler *plug_handler, DeviceState *plugged_dev); =20 +/** + * hotplug_handler_do_unplug: + * + * Call #HotplugHandlerClass.do_unplug callback of @plug_handler. + */ +void hotplug_handler_do_unplug(HotplugHandler *plug_handler, + DeviceState *plugged_dev); + /** * hotplug_handler_unplug_request: * --=20 2.17.1