From nobody Fri Nov 14 20:38:08 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1589901176; cv=none; d=zohomail.com; s=zohoarc; b=YbLIHHVBeKvqoBiO21HPn559P2Js+GWjXNgjqA+jVLrTv4RHvLWxeP9wCU0MU0bkQyGjjL9CwT4Z7M9Q1XoKSS3/cHUM+JzdFux/yTMLAlXQ/MSRPzce2thc2GnJ6SREERKN0ruzMehHZqKcbU3gzVGRcITLsUbx/Yr3yQvmsL8= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1589901176; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=baz+wijb/5/Ov6sUxxfXHuI6tIYKPNLIcHpW7/PUksY=; b=LLE9GttAkCjM01RrP0R8E78XfL9giJfHFWeX8+r9gT8DLV5dzDwVU5ZMAliBXsn8Tg/yBanqeNg4D06qCkTG0ROkNB2d2TP/fDgIYNYbDMszdb6XyZeDwi4ZIfoJ00aWsPeyQEMmI9JWHERNFy6K/9QQiGcFzNfst1NF715WVLM= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1589901176788210.410498202697; Tue, 19 May 2020 08:12:56 -0700 (PDT) Received: from localhost ([::1]:39958 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jb3vL-0002R8-9c for importer@patchew.org; Tue, 19 May 2020 11:12:55 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:45080) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1jb3fA-0001Yx-5H for qemu-devel@nongnu.org; Tue, 19 May 2020 10:56:12 -0400 Received: from us-smtp-delivery-1.mimecast.com ([207.211.31.120]:20557 helo=us-smtp-1.mimecast.com) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.90_1) (envelope-from ) id 1jb3f2-0003WU-3e for qemu-devel@nongnu.org; Tue, 19 May 2020 10:56:11 -0400 Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-195-PFYrWBKNMjeDlT3mU7SkPQ-1; Tue, 19 May 2020 10:56:01 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id EB3E71009613; Tue, 19 May 2020 14:55:59 +0000 (UTC) Received: from blackfin.pond.sub.org (ovpn-112-32.ams2.redhat.com [10.36.112.32]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 3A2945D9CD; Tue, 19 May 2020 14:55:53 +0000 (UTC) Received: by blackfin.pond.sub.org (Postfix, from userid 1000) id B988C11358BF; Tue, 19 May 2020 16:55:51 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1589900163; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=baz+wijb/5/Ov6sUxxfXHuI6tIYKPNLIcHpW7/PUksY=; b=ROer8r+yG7XaYK/dSJNil4HS4Eswz1IgqMyGEEmkJWLnjgzltRQjIkvJaQcKbpTKl1Knk0 4OvdbaEbOQphEV3w2N8Rcdna8YWjEEEjOu9wlC7SrEYdjB8Px1WtshqUFHC9mjsoh8wDiH xJry6EKOjDHaN9OW4sFJsereg3kSqoQ= X-MC-Unique: PFYrWBKNMjeDlT3mU7SkPQ-1 From: Markus Armbruster To: qemu-devel@nongnu.org Subject: [PATCH 03/55] qdev: New qdev_new(), qdev_realize(), etc. Date: Tue, 19 May 2020 16:54:59 +0200 Message-Id: <20200519145551.22836-4-armbru@redhat.com> In-Reply-To: <20200519145551.22836-1-armbru@redhat.com> References: <20200519145551.22836-1-armbru@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.14 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=207.211.31.120; envelope-from=armbru@redhat.com; helo=us-smtp-1.mimecast.com X-detected-operating-system: by eggs.gnu.org: First seen = 2020/05/19 09:19:26 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x [generic] [fuzzy] X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_PASS=-0.001, URIBL_BLOCKED=0.001 autolearn=_AUTOLEARN X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: berrange@redhat.com, ehabkost@redhat.com, "Michael S . Tsirkin" , Alistair Francis , Mark Cave-Ayland , Gerd Hoffmann , pbonzini@redhat.com, David Gibson Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) Content-Type: text/plain; charset="utf-8" We commonly plug devices into their bus right when we create them, like this: dev =3D qdev_create(bus, type_name); Note that @dev is a weak reference. The reference from @bus to @dev is the only strong one. We realize at some later time, either with object_property_set_bool(OBJECT(dev), true, "realized", errp); or its convenience wrapper qdev_init_nofail(dev); If @dev still has no QOM parent then, realizing makes the /machine/unattached/ orphanage its QOM parent. Note that the device returned by qdev_create() is plugged into a bus, but doesn't have a QOM parent, yet. Until it acquires one, unrealizing the bus will hang in bus_unparent(): while ((kid =3D QTAILQ_FIRST(&bus->children)) !=3D NULL) { DeviceState *dev =3D kid->child; object_unparent(OBJECT(dev)); } object_unparent() does nothing when its argument has no QOM parent, and the loop spins forever. Device state "no QOM parent, but plugged into bus" is dangerous. Paolo suggested to delay plugging into the bus until realize. We need to plug into the parent bus before we call the device's realize method, in case it uses the parent bus. So the dangerous state still exists, but only within realization, where we can manage it safely. This commit creates infrastructure to do this: dev =3D qdev_new(type_name); ... qdev_realize_and_unref(dev, bus, errp) Note that @dev becomes a strong reference here. qdev_realize_and_unref() drops it. There is also plain qdev_realize(), which doesn't drop it. The remainder of this series will convert all users to this new interface. Cc: Michael S. Tsirkin Cc: Marcel Apfelbaum Cc: Alistair Francis Cc: Gerd Hoffmann Cc: Mark Cave-Ayland Cc: David Gibson Signed-off-by: Markus Armbruster Acked-by: Gerd Hoffmann --- include/hw/qdev-core.h | 11 ++++- hw/core/bus.c | 14 +++++++ hw/core/qdev.c | 94 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 118 insertions(+), 1 deletion(-) diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h index b870b27966..fba29308f7 100644 --- a/include/hw/qdev-core.h +++ b/include/hw/qdev-core.h @@ -57,7 +57,7 @@ typedef void (*BusUnrealize)(BusState *bus); * After successful realization, setting static properties will fail. * * As an interim step, the #DeviceState:realized property can also be - * set with qdev_init_nofail(). + * set with qdev_realize() or qdev_init_nofail(). * In the future, devices will propagate this state change to their childr= en * and along busses they expose. * The point in time will be deferred to machine creation, so that values @@ -322,7 +322,13 @@ compat_props_add(GPtrArray *arr, =20 DeviceState *qdev_create(BusState *bus, const char *name); DeviceState *qdev_try_create(BusState *bus, const char *name); +DeviceState *qdev_new(const char *name); +DeviceState *qdev_try_new(const char *name); void qdev_init_nofail(DeviceState *dev); +bool qdev_realize(DeviceState *dev, BusState *bus, Error **errp); +bool qdev_realize_and_unref(DeviceState *dev, BusState *bus, Error **errp); +void qdev_unrealize(DeviceState *dev); + void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id, int required_for_version); HotplugHandler *qdev_get_bus_hotplug_handler(DeviceState *dev); @@ -411,6 +417,9 @@ typedef int (qdev_walkerfn)(DeviceState *dev, void *opa= que); void qbus_create_inplace(void *bus, size_t size, const char *typename, DeviceState *parent, const char *name); BusState *qbus_create(const char *typename, DeviceState *parent, const cha= r *name); +bool qbus_realize(BusState *bus, Error **errp); +void qbus_unrealize(BusState *bus); + /* Returns > 0 if either devfn or busfn skip walk somewhere in cursion, * < 0 if either devfn or busfn terminate walk somewhere in cursio= n, * 0 otherwise. */ diff --git a/hw/core/bus.c b/hw/core/bus.c index 08c5eab24a..bf622604a3 100644 --- a/hw/core/bus.c +++ b/hw/core/bus.c @@ -169,6 +169,20 @@ BusState *qbus_create(const char *typename, DeviceStat= e *parent, const char *nam return bus; } =20 +bool qbus_realize(BusState *bus, Error **errp) +{ + Error *err =3D NULL; + + object_property_set_bool(OBJECT(bus), true, "realized", &err); + error_propagate(errp, err); + return !err; +} + +void qbus_unrealize(BusState *bus) +{ + object_property_set_bool(OBJECT(bus), true, "realized", &error_abort); +} + static bool bus_get_realized(Object *obj, Error **errp) { BusState *bus =3D BUS(obj); diff --git a/hw/core/qdev.c b/hw/core/qdev.c index a68ba674db..82deeb7841 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -176,6 +176,32 @@ DeviceState *qdev_try_create(BusState *bus, const char= *type) return dev; } =20 +/* + * Create a device on the heap. + * A type @name must exist. + * This only initializes the device state structure and allows + * properties to be set. The device still needs to be realized. See + * qdev-core.h. + */ +DeviceState *qdev_new(const char *name) +{ + return DEVICE(object_new(name)); +} + +/* + * Try to create a device on the heap. + * This is like qdev_new(), except it returns %NULL when type @name + * does not exist. + */ +DeviceState *qdev_try_new(const char *name) +{ + if (!object_class_by_name(name)) { + return NULL; + } + + return DEVICE(object_new(name)); +} + static QTAILQ_HEAD(, DeviceListener) device_listeners =3D QTAILQ_HEAD_INITIALIZER(device_listeners); =20 @@ -427,6 +453,70 @@ void qdev_init_nofail(DeviceState *dev) object_unref(OBJECT(dev)); } =20 +/* + * Realize @dev. + * @dev must not be plugged into a bus. + * Plug @dev into @bus if non-null, else into the main system bus. + * This takes a reference to @dev. + * If @dev has no QOM parent, make one up, taking another reference. + * On success, return true. + * On failure, store an error through @errp and return false. + */ +bool qdev_realize(DeviceState *dev, BusState *bus, Error **errp) +{ + Error *err =3D NULL; + + assert(!dev->realized && !dev->parent_bus); + + if (!bus) { + /* + * Assert that the device really is a SysBusDevice before we + * put it onto the sysbus. Non-sysbus devices which aren't + * being put onto a bus should be realized with + * object_property_set_bool(OBJECT(dev), true, "realized", + * errp); + */ + g_assert(object_dynamic_cast(OBJECT(dev), TYPE_SYS_BUS_DEVICE)); + bus =3D sysbus_get_default(); + } + + qdev_set_parent_bus(dev, bus); + + object_ref(OBJECT(dev)); + object_property_set_bool(OBJECT(dev), true, "realized", &err); + if (err) { + error_propagate_prepend(errp, err, + "Initialization of device %s failed: ", + object_get_typename(OBJECT(dev))); + } + object_unref(OBJECT(dev)); + return !err; +} + +/* + * Realize @dev and drop a reference. + * This is like qdev_realize(), except it steals a reference rather + * than take one to plug @dev into @bus. On failure, it drops that + * reference instead. Intended use: + * dev =3D qdev_new(); + * [...] + * qdev_realize_and_unref(dev, bus, errp); + * Now @dev can go away without further ado. + */ +bool qdev_realize_and_unref(DeviceState *dev, BusState *bus, Error **errp) +{ + bool ret; + + ret =3D qdev_realize(dev, bus, errp); + object_unref(OBJECT(dev)); + return ret; +} + +void qdev_unrealize(DeviceState *dev) +{ + object_property_set_bool(OBJECT(dev), false, "realized", &error_abort); +} + static int qdev_assert_realized_properly(Object *obj, void *opaque) { DeviceState *dev =3D DEVICE(object_dynamic_cast(obj, TYPE_DEVICE)); @@ -1002,6 +1092,10 @@ post_realize_fail: fail: error_propagate(errp, local_err); if (unattached_parent) { + /* + * Beware, this doesn't just revert + * object_property_add_child(), it also runs bus_remove()! + */ object_unparent(OBJECT(dev)); unattached_count--; } --=20 2.21.1