From nobody Mon Feb 9 19:05:59 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.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; Authentication-Results: mx.zohomail.com; spf=pass (zoho.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=1572390717; cv=none; d=zoho.com; s=zohoarc; b=ECx1BiP2cGIPkME/UR/NhJN1oEEBA54xJHaxjydtSVX5VjsZ/YBYZgy69hSTz9b4EeJjhWpKDM5QYYBYftnEcj2wqC7Ukhl6cJXCdRYFDwCrWjWsyEznSbdUnzK5FFydfaaoVjdCxWvvmR/qr9gFF7Owss+XnuSFAUmRVtMP2i8= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1572390717; h=Content-Type: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=01Fs1jey86esNNGNv7ScP/Az7KLeObzFJh8m27qruq0=; b=aCBy0SHAxKlrb62QhJbKuh4Kt7xO1IGrRpEJry3AMdWXQqLyVBHGvFYwnFTD/1WNlSZqtQOIy02an2W5DW4ppTasn8FNAYijgOf7OiEpuKbkeCVX9hIdBzOfC0bcuerz1Ea24BfgiEbU0qkP3BL4DJsCwxnLbaz6hZR0VLce+U4= ARC-Authentication-Results: i=1; mx.zoho.com; spf=pass (zoho.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 157239071747721.22503062900978; Tue, 29 Oct 2019 16:11:57 -0700 (PDT) Received: from localhost ([::1]:34942 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iPaeZ-0001kF-R8 for importer@patchew.org; Tue, 29 Oct 2019 19:11:55 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:42769) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iPaTO-00081Y-AW for qemu-devel@nongnu.org; Tue, 29 Oct 2019 19:00:24 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iPaTI-0003Ag-3N for qemu-devel@nongnu.org; Tue, 29 Oct 2019 19:00:20 -0400 Received: from mx1.redhat.com ([209.132.183.28]:37482) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1iPaTG-00036k-1Q for qemu-devel@nongnu.org; Tue, 29 Oct 2019 19:00:15 -0400 Received: from mail-qt1-f199.google.com (mail-qt1-f199.google.com [209.85.160.199]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id E50A32A09B7 for ; Tue, 29 Oct 2019 23:00:11 +0000 (UTC) Received: by mail-qt1-f199.google.com with SMTP id w6so531335qte.5 for ; Tue, 29 Oct 2019 16:00:11 -0700 (PDT) Received: from redhat.com (94.222.26.109.rev.sfr.net. [109.26.222.94]) by smtp.gmail.com with ESMTPSA id g7sm380776qki.75.2019.10.29.16.00.07 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 29 Oct 2019 16:00:09 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:references :mime-version:content-disposition:in-reply-to; bh=01Fs1jey86esNNGNv7ScP/Az7KLeObzFJh8m27qruq0=; b=BpvsUkkOWg7JD7ylp6MO7IGPS1si8l1JqMR9lMjnV7InAFOD35bLZF1WOm+pH2G0oq 4oDGMsUBLsjZ58qhx7lmp0WWrbpzlljO7O/wqgky0X10lJZ1VPCzA63oVChxlnPXdrIJ 6RxSPRczjBZNMwDzoqQs5O9r12qISnCLYBIo+VnsDpc0SCXEzl++HfwAnjmPln3R/4GZ ik3P9iR6EE6xBDmyvmWOG9dyzO9AzO4mVp5KXWjOmpXpf6UAREwazFtk52R84hD/JmmK etTemgWhp+HKWyv2Ts1aCAbI/uZdpjS/2Fb8IxtPhUjXmPyzrfVPKvU1uwbHitRpLjYb Mzcw== X-Gm-Message-State: APjAAAWxgYIayVOPUdF8jEHhHorvNAvafmWOPXOS491CkALFgh8YvJ4P g2ZkIbBmzE45gJ7fx8friRzqBgFGTWuDJdx/9GdjKJmtGf+sxq88EMCxx4Go2BUGSAJEa5aGt2k N4vRyLON3HpBAkY4= X-Received: by 2002:ac8:701e:: with SMTP id x30mr1784899qtm.203.1572390010496; Tue, 29 Oct 2019 16:00:10 -0700 (PDT) X-Google-Smtp-Source: APXvYqxnePi/t76Pwk14BSFFyIh6tOx7lRZP9ASPgqfMuvaYamd/RqGVnP4c11rIgMBUm3uMOmBSFw== X-Received: by 2002:ac8:701e:: with SMTP id x30mr1784827qtm.203.1572390009832; Tue, 29 Oct 2019 16:00:09 -0700 (PDT) Date: Tue, 29 Oct 2019 19:00:00 -0400 From: "Michael S. Tsirkin" To: qemu-devel@nongnu.org Subject: [PULL 01/14] qdev/qbus: add hidden device support Message-ID: <20191029225932.14585-2-mst@redhat.com> References: <20191029225932.14585-1-mst@redhat.com> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <20191029225932.14585-1-mst@redhat.com> X-Mailer: git-send-email 2.22.0.678.g13338e74b8 X-Mutt-Fcc: =sent X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 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: Peter Maydell , Jens Freimann , Daniel =?utf-8?B?UC4gQmVycmFuZ8Op?= , Eduardo Habkost , Paolo Bonzini Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Jens Freimann This adds support for hiding a device to the qbus and qdev APIs. The first user of this will be the virtio-net failover feature but the API introduced with this patch could be used to implement other features as well, for example hiding pci devices when a pci bus is powered off. qdev_device_add() is modified to check for a failover_pair_id argument in the option string. A DeviceListener callback should_be_hidden() is added. It can be used by a standby device to inform qdev that this device should not be added now. The standby device handler can store the device options to plug the device in at a later point in time. One reason for hiding the device is that we don't want to expose both devices to the guest kernel until the respective virtio feature bit VIRTIO_NET_F_STANDBY was negotiated and we know that the devices will be handled correctly by the guest. More information on the kernel feature this is using: https://www.kernel.org/doc/html/latest/networking/net_failover.html An example where the primary device is a vfio-pci device and the standby device is a virtio-net device: A device is hidden when it has an "failover_pair_id" option, e.g. -device virtio-net-pci,...,failover=3Don,... -device vfio-pci,...,failover_pair_id=3Dnet1,... Signed-off-by: Jens Freimann Message-Id: <20191029114905.6856-2-jfreimann@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/core/qdev.c | 24 ++++++++++++++++++++++++ include/hw/qdev-core.h | 29 +++++++++++++++++++++++++++++ qdev-monitor.c | 41 +++++++++++++++++++++++++++++++++++++---- vl.c | 6 ++++-- 4 files changed, 94 insertions(+), 6 deletions(-) diff --git a/hw/core/qdev.c b/hw/core/qdev.c index cbad6c1d55..3b8d43d0fd 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -212,6 +212,30 @@ void device_listener_unregister(DeviceListener *listen= er) QTAILQ_REMOVE(&device_listeners, listener, link); } =20 +bool qdev_should_hide_device(QemuOpts *opts) +{ + int rc =3D -1; + DeviceListener *listener; + + QTAILQ_FOREACH(listener, &device_listeners, link) { + if (listener->should_be_hidden) { + /* + * should_be_hidden_will return + * 1 if device matches opts and it should be hidden + * 0 if device matches opts and should not be hidden + * -1 if device doesn't match ops + */ + rc =3D listener->should_be_hidden(listener, opts); + } + + if (rc > 0) { + break; + } + } + + return rc > 0; +} + void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id, int required_for_version) { diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h index aa123f88cb..710981af36 100644 --- a/include/hw/qdev-core.h +++ b/include/hw/qdev-core.h @@ -78,6 +78,19 @@ typedef void (*BusUnrealize)(BusState *bus, Error **errp= ); * respective parent types. * * + * + * # Hiding a device # + * To hide a device, a DeviceListener function should_be_hidden() needs to + * be registered. + * It can be used to defer adding a device and therefore hide it from the + * guest. The handler registering to this DeviceListener can save the QOpts + * passed to it for re-using it later and must return that it wants the de= vice + * to be/remain hidden or not. When the handler function decides the device + * shall not be hidden it will be added in qdev_device_add() and + * realized as any other device. Otherwise qdev_device_add() will return e= arly + * without adding the device. The guest will not see a "hidden" device + * until it was marked don't hide and qdev_device_add called again. + * */ typedef struct DeviceClass { /*< private >*/ @@ -154,6 +167,12 @@ struct DeviceState { struct DeviceListener { void (*realize)(DeviceListener *listener, DeviceState *dev); void (*unrealize)(DeviceListener *listener, DeviceState *dev); + /* + * This callback is called upon init of the DeviceState and allows to + * inform qdev that a device should be hidden, depending on the device + * opts, for example, to hide a standby device. + */ + int (*should_be_hidden)(DeviceListener *listener, QemuOpts *device_opt= s); QTAILQ_ENTRY(DeviceListener) link; }; =20 @@ -451,4 +470,14 @@ static inline bool qbus_is_hotpluggable(BusState *bus) void device_listener_register(DeviceListener *listener); void device_listener_unregister(DeviceListener *listener); =20 +/** + * @qdev_should_hide_device: + * @opts: QemuOpts as passed on cmdline. + * + * Check if a device should be added. + * When a device is added via qdev_device_add() this will be called, + * and return if the device should be added now or not. + */ +bool qdev_should_hide_device(QemuOpts *opts); + #endif diff --git a/qdev-monitor.c b/qdev-monitor.c index 148df9cacf..ffa08c670f 100644 --- a/qdev-monitor.c +++ b/qdev-monitor.c @@ -32,9 +32,11 @@ #include "qemu/help_option.h" #include "qemu/option.h" #include "qemu/qemu-print.h" +#include "qemu/option_int.h" #include "sysemu/block-backend.h" #include "sysemu/sysemu.h" #include "migration/misc.h" +#include "migration/migration.h" =20 /* * Aliases were a bad idea from the start. Let's keep them @@ -562,13 +564,36 @@ void qdev_set_id(DeviceState *dev, const char *id) } } =20 +static int is_failover_device(void *opaque, const char *name, const char *= value, + Error **errp) +{ + if (strcmp(name, "failover_pair_id") =3D=3D 0) { + QemuOpts *opts =3D (QemuOpts *)opaque; + + if (qdev_should_hide_device(opts)) { + return 1; + } + } + + return 0; +} + +static bool should_hide_device(QemuOpts *opts) +{ + if (qemu_opt_foreach(opts, is_failover_device, opts, NULL) =3D=3D 0) { + return false; + } + return true; +} + DeviceState *qdev_device_add(QemuOpts *opts, Error **errp) { DeviceClass *dc; const char *driver, *path; - DeviceState *dev; + DeviceState *dev =3D NULL; BusState *bus =3D NULL; Error *err =3D NULL; + bool hide; =20 driver =3D qemu_opt_get(opts, "driver"); if (!driver) { @@ -602,11 +627,17 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **= errp) return NULL; } } - if (qdev_hotplug && bus && !qbus_is_hotpluggable(bus)) { + hide =3D should_hide_device(opts); + + if ((hide || qdev_hotplug) && bus && !qbus_is_hotpluggable(bus)) { error_setg(errp, QERR_BUS_NO_HOTPLUG, bus->name); return NULL; } =20 + if (hide) { + return NULL; + } + if (!migration_is_idle()) { error_setg(errp, "device_add not allowed while migrating"); return NULL; @@ -648,8 +679,10 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **e= rrp) =20 err_del_dev: error_propagate(errp, err); - object_unparent(OBJECT(dev)); - object_unref(OBJECT(dev)); + if (dev) { + object_unparent(OBJECT(dev)); + object_unref(OBJECT(dev)); + } return NULL; } =20 diff --git a/vl.c b/vl.c index 49778e7399..c389d24b2c 100644 --- a/vl.c +++ b/vl.c @@ -2207,10 +2207,12 @@ static int device_init_func(void *opaque, QemuOpts = *opts, Error **errp) DeviceState *dev; =20 dev =3D qdev_device_add(opts, errp); - if (!dev) { + if (!dev && *errp) { + error_report_err(*errp); return -1; + } else if (dev) { + object_unref(OBJECT(dev)); } - object_unref(OBJECT(dev)); return 0; } =20 --=20 MST