qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 00/15] qdev: Add JSON -device
@ 2021-10-08 13:34 Kevin Wolf
  2021-10-08 13:34 ` [PATCH v2 01/15] net: Introduce NetClientInfo.check_peer_type() Kevin Wolf
                   ` (17 more replies)
  0 siblings, 18 replies; 35+ messages in thread
From: Kevin Wolf @ 2021-10-08 13:34 UTC (permalink / raw)
  To: qemu-devel
  Cc: kwolf, damien.hedde, pkrempa, berrange, ehabkost, qemu-block,
	mst, libvir-list, jasowang, quintela, armbru, vsementsov,
	lvivier, its, pbonzini, eblake

It's still a long way until we'll have QAPIfied devices, but there are
some improvements that we can already make now to make the future switch
easier.

One important part of this is having code paths without QemuOpts, which
we want to get rid of and replace with the keyval parser in the long
run. This series adds support for JSON syntax to -device, which bypasses
QemuOpts.

While we're not using QAPI yet, devices are based on QOM, so we already
do have type checks and an implied schema. JSON syntax supported now can
be supported by QAPI later and regarding command line compatibility,
actually switching to it becomes an implementation detail this way (of
course, it will still add valuable user-visible features like
introspection and documentation).

Apart from making things more future proof, this also immediately adds
a way to do non-scalar properties on the command line. nvme could have
used list support recently, and the lack of it in -device led to some
rather unnatural solution in the first version (doing the relationship
between a device and objects backwards) and loss of features in the
following. With this series, using a list as a device property should be
possible without any weird tricks.

Unfortunately, even QMP device_add goes through QemuOpts before this
series, which destroys any type safety QOM provides and also can't
support non-scalar properties. This is a bug, but it turns out that
libvirt actually relies on it and passes only strings for everything.
So this series still leaves device_add alone until libvirt is fixed.

v2:
- Drop type safe QMP device_add because libvirt gets it wrong, too
- More network patches to eliminate dependencies on the legacy QemuOpts
  data structures which would not contain all devices any more after
  this series. Fix some bugs there as a side effect.
- Remove an unnecessary use of ERRP_GUARD()
- Replaced error handling patch for qdev_set_id() with Damien's
- Drop the deprecation patch until libvirt uses the new JSON syntax

Damien Hedde (1):
  softmmu/qdev-monitor: add error handling in qdev_set_id

Kevin Wolf (14):
  net: Introduce NetClientInfo.check_peer_type()
  net/vhost-user: Fix device compatibility check
  net/vhost-vdpa: Fix device compatibility check
  qom: Reduce use of error_propagate()
  iotests/245: Fix type for iothread property
  iotests/051: Fix typo
  qdev: Avoid using string visitor for properties
  qdev: Make DeviceState.id independent of QemuOpts
  qemu-option: Allow deleting opts during qemu_opts_foreach()
  qdev: Add Error parameter to hide_device() callbacks
  virtio-net: Store failover primary opts pointer locally
  virtio-net: Avoid QemuOpts in failover_find_primary_device()
  qdev: Base object creation on QDict rather than QemuOpts
  vl: Enable JSON syntax for -device

 qapi/qdev.json                      | 15 +++--
 include/hw/qdev-core.h              | 15 +++--
 include/hw/virtio/virtio-net.h      |  2 +
 include/monitor/qdev.h              | 27 +++++++-
 include/net/net.h                   |  2 +
 hw/arm/virt.c                       |  2 +-
 hw/core/qdev-properties-system.c    |  6 ++
 hw/core/qdev.c                      | 11 +++-
 hw/net/virtio-net.c                 | 85 ++++++++++++-------------
 hw/pci-bridge/pci_expander_bridge.c |  2 +-
 hw/ppc/e500.c                       |  2 +-
 hw/vfio/pci.c                       |  4 +-
 hw/xen/xen-legacy-backend.c         |  3 +-
 net/vhost-user.c                    | 41 ++++--------
 net/vhost-vdpa.c                    | 37 ++++-------
 qom/object.c                        |  7 +-
 qom/object_interfaces.c             | 19 ++----
 softmmu/qdev-monitor.c              | 99 +++++++++++++++++++----------
 softmmu/vl.c                        | 63 ++++++++++++++++--
 util/qemu-option.c                  |  4 +-
 tests/qemu-iotests/051              |  2 +-
 tests/qemu-iotests/051.pc.out       |  4 +-
 tests/qemu-iotests/245              |  4 +-
 23 files changed, 278 insertions(+), 178 deletions(-)

-- 
2.31.1



^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCH v2 01/15] net: Introduce NetClientInfo.check_peer_type()
  2021-10-08 13:34 [PATCH v2 00/15] qdev: Add JSON -device Kevin Wolf
@ 2021-10-08 13:34 ` Kevin Wolf
  2021-10-13 13:28   ` Damien Hedde
  2021-10-14  3:22   ` Jason Wang
  2021-10-08 13:34 ` [PATCH v2 02/15] net/vhost-user: Fix device compatibility check Kevin Wolf
                   ` (16 subsequent siblings)
  17 siblings, 2 replies; 35+ messages in thread
From: Kevin Wolf @ 2021-10-08 13:34 UTC (permalink / raw)
  To: qemu-devel
  Cc: kwolf, damien.hedde, pkrempa, berrange, ehabkost, qemu-block,
	mst, libvir-list, jasowang, quintela, armbru, vsementsov,
	lvivier, its, pbonzini, eblake

Some network backends (vhost-user and vhost-vdpa) work only with
specific devices. At startup, they second guess what the command line
option handling will do and error out if they think a non-virtio device
will attach to them.

This second guessing is not only ugly, it can lead to wrong error
messages ('-device floppy,netdev=foo' should complain about an unknown
property, not about the wrong kind of network device being attached) and
completely ignores hotplugging.

Add a callback where backends can check compatibility with a device when
it actually tries to attach, even on hotplug.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 include/net/net.h                | 2 ++
 hw/core/qdev-properties-system.c | 6 ++++++
 2 files changed, 8 insertions(+)

diff --git a/include/net/net.h b/include/net/net.h
index 5d1508081f..986288eb07 100644
--- a/include/net/net.h
+++ b/include/net/net.h
@@ -62,6 +62,7 @@ typedef struct SocketReadState SocketReadState;
 typedef void (SocketReadStateFinalize)(SocketReadState *rs);
 typedef void (NetAnnounce)(NetClientState *);
 typedef bool (SetSteeringEBPF)(NetClientState *, int);
+typedef bool (NetCheckPeerType)(NetClientState *, ObjectClass *, Error **);
 
 typedef struct NetClientInfo {
     NetClientDriver type;
@@ -84,6 +85,7 @@ typedef struct NetClientInfo {
     SetVnetBE *set_vnet_be;
     NetAnnounce *announce;
     SetSteeringEBPF *set_steering_ebpf;
+    NetCheckPeerType *check_peer_type;
 } NetClientInfo;
 
 struct NetClientState {
diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c
index e71f5d64d1..a91f60567a 100644
--- a/hw/core/qdev-properties-system.c
+++ b/hw/core/qdev-properties-system.c
@@ -431,6 +431,12 @@ static void set_netdev(Object *obj, Visitor *v, const char *name,
             goto out;
         }
 
+        if (peers[i]->info->check_peer_type) {
+            if (!peers[i]->info->check_peer_type(peers[i], obj->class, errp)) {
+                goto out;
+            }
+        }
+
         ncs[i] = peers[i];
         ncs[i]->queue_index = i;
     }
-- 
2.31.1



^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v2 02/15] net/vhost-user: Fix device compatibility check
  2021-10-08 13:34 [PATCH v2 00/15] qdev: Add JSON -device Kevin Wolf
  2021-10-08 13:34 ` [PATCH v2 01/15] net: Introduce NetClientInfo.check_peer_type() Kevin Wolf
@ 2021-10-08 13:34 ` Kevin Wolf
  2021-10-13 13:30   ` Damien Hedde
  2021-10-14  3:23   ` Jason Wang
  2021-10-08 13:34 ` [PATCH v2 03/15] net/vhost-vdpa: " Kevin Wolf
                   ` (15 subsequent siblings)
  17 siblings, 2 replies; 35+ messages in thread
From: Kevin Wolf @ 2021-10-08 13:34 UTC (permalink / raw)
  To: qemu-devel
  Cc: kwolf, damien.hedde, pkrempa, berrange, ehabkost, qemu-block,
	mst, libvir-list, jasowang, quintela, armbru, vsementsov,
	lvivier, its, pbonzini, eblake

vhost-user works only with specific devices. At startup, it second
guesses what the command line option handling will do and error out if
it thinks a non-virtio device will attach to them.

This second guessing is not only ugly, it can lead to wrong error
messages ('-device floppy,netdev=foo' should complain about an unknown
property, not about the wrong kind of network device being attached) and
completely ignores hotplugging.

Drop the old checks and implement .check_peer_type() instead to fix
this. As a nice side effect, it also removes one more dependency on the
legacy QemuOpts infrastructure and even reduces the code size.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 net/vhost-user.c | 41 ++++++++++++++---------------------------
 1 file changed, 14 insertions(+), 27 deletions(-)

diff --git a/net/vhost-user.c b/net/vhost-user.c
index 4a939124d2..b1a0247b59 100644
--- a/net/vhost-user.c
+++ b/net/vhost-user.c
@@ -198,6 +198,19 @@ static bool vhost_user_has_ufo(NetClientState *nc)
     return true;
 }
 
+static bool vhost_user_check_peer_type(NetClientState *nc, ObjectClass *oc,
+                                       Error **errp)
+{
+    const char *driver = object_class_get_name(oc);
+
+    if (!g_str_has_prefix(driver, "virtio-net-")) {
+        error_setg(errp, "vhost-user requires frontend driver virtio-net-*");
+        return false;
+    }
+
+    return true;
+}
+
 static NetClientInfo net_vhost_user_info = {
         .type = NET_CLIENT_DRIVER_VHOST_USER,
         .size = sizeof(NetVhostUserState),
@@ -207,6 +220,7 @@ static NetClientInfo net_vhost_user_info = {
         .has_ufo = vhost_user_has_ufo,
         .set_vnet_be = vhost_user_set_vnet_endianness,
         .set_vnet_le = vhost_user_set_vnet_endianness,
+        .check_peer_type = vhost_user_check_peer_type,
 };
 
 static gboolean net_vhost_user_watch(void *do_not_use, GIOCondition cond,
@@ -397,27 +411,6 @@ static Chardev *net_vhost_claim_chardev(
     return chr;
 }
 
-static int net_vhost_check_net(void *opaque, QemuOpts *opts, Error **errp)
-{
-    const char *name = opaque;
-    const char *driver, *netdev;
-
-    driver = qemu_opt_get(opts, "driver");
-    netdev = qemu_opt_get(opts, "netdev");
-
-    if (!driver || !netdev) {
-        return 0;
-    }
-
-    if (strcmp(netdev, name) == 0 &&
-        !g_str_has_prefix(driver, "virtio-net-")) {
-        error_setg(errp, "vhost-user requires frontend driver virtio-net-*");
-        return -1;
-    }
-
-    return 0;
-}
-
 int net_init_vhost_user(const Netdev *netdev, const char *name,
                         NetClientState *peer, Error **errp)
 {
@@ -433,12 +426,6 @@ int net_init_vhost_user(const Netdev *netdev, const char *name,
         return -1;
     }
 
-    /* verify net frontend */
-    if (qemu_opts_foreach(qemu_find_opts("device"), net_vhost_check_net,
-                          (char *)name, errp)) {
-        return -1;
-    }
-
     queues = vhost_user_opts->has_queues ? vhost_user_opts->queues : 1;
     if (queues < 1 || queues > MAX_QUEUE_NUM) {
         error_setg(errp,
-- 
2.31.1



^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v2 03/15] net/vhost-vdpa: Fix device compatibility check
  2021-10-08 13:34 [PATCH v2 00/15] qdev: Add JSON -device Kevin Wolf
  2021-10-08 13:34 ` [PATCH v2 01/15] net: Introduce NetClientInfo.check_peer_type() Kevin Wolf
  2021-10-08 13:34 ` [PATCH v2 02/15] net/vhost-user: Fix device compatibility check Kevin Wolf
@ 2021-10-08 13:34 ` Kevin Wolf
  2021-10-13 13:30   ` Damien Hedde
  2021-10-14  3:24   ` Jason Wang
  2021-10-08 13:34 ` [PATCH v2 04/15] qom: Reduce use of error_propagate() Kevin Wolf
                   ` (14 subsequent siblings)
  17 siblings, 2 replies; 35+ messages in thread
From: Kevin Wolf @ 2021-10-08 13:34 UTC (permalink / raw)
  To: qemu-devel
  Cc: kwolf, damien.hedde, pkrempa, berrange, ehabkost, qemu-block,
	mst, libvir-list, jasowang, quintela, armbru, vsementsov,
	lvivier, its, pbonzini, eblake

vhost-vdpa works only with specific devices. At startup, it second
guesses what the command line option handling will do and error out if
it thinks a non-virtio device will attach to them.

This second guessing is not only ugly, it can lead to wrong error
messages ('-device floppy,netdev=foo' should complain about an unknown
property, not about the wrong kind of network device being attached) and
completely ignores hotplugging.

Drop the old checks and implement .check_peer_type() instead to fix
this. As a nice side effect, it also removes one more dependency on the
legacy QemuOpts infrastructure and even reduces the code size.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 net/vhost-vdpa.c | 37 ++++++++++++++-----------------------
 1 file changed, 14 insertions(+), 23 deletions(-)

diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c
index 912686457c..6dc68d8677 100644
--- a/net/vhost-vdpa.c
+++ b/net/vhost-vdpa.c
@@ -147,12 +147,26 @@ static bool vhost_vdpa_has_ufo(NetClientState *nc)
 
 }
 
+static bool vhost_vdpa_check_peer_type(NetClientState *nc, ObjectClass *oc,
+                                       Error **errp)
+{
+    const char *driver = object_class_get_name(oc);
+
+    if (!g_str_has_prefix(driver, "virtio-net-")) {
+        error_setg(errp, "vhost-vdpa requires frontend driver virtio-net-*");
+        return false;
+    }
+
+    return true;
+}
+
 static NetClientInfo net_vhost_vdpa_info = {
         .type = NET_CLIENT_DRIVER_VHOST_VDPA,
         .size = sizeof(VhostVDPAState),
         .cleanup = vhost_vdpa_cleanup,
         .has_vnet_hdr = vhost_vdpa_has_vnet_hdr,
         .has_ufo = vhost_vdpa_has_ufo,
+        .check_peer_type = vhost_vdpa_check_peer_type,
 };
 
 static int net_vhost_vdpa_init(NetClientState *peer, const char *device,
@@ -179,24 +193,6 @@ static int net_vhost_vdpa_init(NetClientState *peer, const char *device,
     return ret;
 }
 
-static int net_vhost_check_net(void *opaque, QemuOpts *opts, Error **errp)
-{
-    const char *name = opaque;
-    const char *driver, *netdev;
-
-    driver = qemu_opt_get(opts, "driver");
-    netdev = qemu_opt_get(opts, "netdev");
-    if (!driver || !netdev) {
-        return 0;
-    }
-    if (strcmp(netdev, name) == 0 &&
-        !g_str_has_prefix(driver, "virtio-net-")) {
-        error_setg(errp, "vhost-vdpa requires frontend driver virtio-net-*");
-        return -1;
-    }
-    return 0;
-}
-
 int net_init_vhost_vdpa(const Netdev *netdev, const char *name,
                         NetClientState *peer, Error **errp)
 {
@@ -204,10 +200,5 @@ int net_init_vhost_vdpa(const Netdev *netdev, const char *name,
 
     assert(netdev->type == NET_CLIENT_DRIVER_VHOST_VDPA);
     opts = &netdev->u.vhost_vdpa;
-    /* verify net frontend */
-    if (qemu_opts_foreach(qemu_find_opts("device"), net_vhost_check_net,
-                          (char *)name, errp)) {
-        return -1;
-    }
     return net_vhost_vdpa_init(peer, TYPE_VHOST_VDPA, name, opts->vhostdev);
 }
-- 
2.31.1



^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v2 04/15] qom: Reduce use of error_propagate()
  2021-10-08 13:34 [PATCH v2 00/15] qdev: Add JSON -device Kevin Wolf
                   ` (2 preceding siblings ...)
  2021-10-08 13:34 ` [PATCH v2 03/15] net/vhost-vdpa: " Kevin Wolf
@ 2021-10-08 13:34 ` Kevin Wolf
  2021-10-11 15:07   ` Markus Armbruster
  2021-10-08 13:34 ` [PATCH v2 05/15] iotests/245: Fix type for iothread property Kevin Wolf
                   ` (13 subsequent siblings)
  17 siblings, 1 reply; 35+ messages in thread
From: Kevin Wolf @ 2021-10-08 13:34 UTC (permalink / raw)
  To: qemu-devel
  Cc: kwolf, damien.hedde, pkrempa, berrange, ehabkost, qemu-block,
	mst, libvir-list, jasowang, quintela, armbru, vsementsov,
	lvivier, its, pbonzini, eblake

ERRP_GUARD() makes debugging easier by making sure that &error_abort
still fails at the real origin of the error instead of
error_propagate().

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 qom/object.c            |  7 +++----
 qom/object_interfaces.c | 19 ++++++-------------
 2 files changed, 9 insertions(+), 17 deletions(-)

diff --git a/qom/object.c b/qom/object.c
index e86cb05b84..6be710bc40 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -1389,7 +1389,7 @@ bool object_property_get(Object *obj, const char *name, Visitor *v,
 bool object_property_set(Object *obj, const char *name, Visitor *v,
                          Error **errp)
 {
-    Error *err = NULL;
+    ERRP_GUARD();
     ObjectProperty *prop = object_property_find_err(obj, name, errp);
 
     if (prop == NULL) {
@@ -1400,9 +1400,8 @@ bool object_property_set(Object *obj, const char *name, Visitor *v,
         error_setg(errp, QERR_PERMISSION_DENIED);
         return false;
     }
-    prop->set(obj, v, name, prop->opaque, &err);
-    error_propagate(errp, err);
-    return !err;
+    prop->set(obj, v, name, prop->opaque, errp);
+    return !*errp;
 }
 
 bool object_property_set_str(Object *obj, const char *name,
diff --git a/qom/object_interfaces.c b/qom/object_interfaces.c
index ad9b56b59a..3b61c195c5 100644
--- a/qom/object_interfaces.c
+++ b/qom/object_interfaces.c
@@ -46,25 +46,18 @@ static void object_set_properties_from_qdict(Object *obj, const QDict *qdict,
                                              Visitor *v, Error **errp)
 {
     const QDictEntry *e;
-    Error *local_err = NULL;
 
-    if (!visit_start_struct(v, NULL, NULL, 0, &local_err)) {
-        goto out;
+    if (!visit_start_struct(v, NULL, NULL, 0, errp)) {
+        return;
     }
     for (e = qdict_first(qdict); e; e = qdict_next(qdict, e)) {
-        if (!object_property_set(obj, e->key, v, &local_err)) {
-            break;
+        if (!object_property_set(obj, e->key, v, errp)) {
+            goto out;
         }
     }
-    if (!local_err) {
-        visit_check_struct(v, &local_err);
-    }
-    visit_end_struct(v, NULL);
-
+    visit_check_struct(v, errp);
 out:
-    if (local_err) {
-        error_propagate(errp, local_err);
-    }
+    visit_end_struct(v, NULL);
 }
 
 void object_set_properties_from_keyval(Object *obj, const QDict *qdict,
-- 
2.31.1



^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v2 05/15] iotests/245: Fix type for iothread property
  2021-10-08 13:34 [PATCH v2 00/15] qdev: Add JSON -device Kevin Wolf
                   ` (3 preceding siblings ...)
  2021-10-08 13:34 ` [PATCH v2 04/15] qom: Reduce use of error_propagate() Kevin Wolf
@ 2021-10-08 13:34 ` Kevin Wolf
  2021-10-08 13:34 ` [PATCH v2 06/15] iotests/051: Fix typo Kevin Wolf
                   ` (12 subsequent siblings)
  17 siblings, 0 replies; 35+ messages in thread
From: Kevin Wolf @ 2021-10-08 13:34 UTC (permalink / raw)
  To: qemu-devel
  Cc: kwolf, damien.hedde, pkrempa, berrange, ehabkost, qemu-block,
	mst, libvir-list, jasowang, quintela, armbru, vsementsov,
	lvivier, its, pbonzini, eblake

iothread is a string property, so None (= JSON null) is not a valid
value for it. Pass the empty string instead to get the default iothread.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
---
 tests/qemu-iotests/245 | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/tests/qemu-iotests/245 b/tests/qemu-iotests/245
index bf8261eec0..9b12b42eed 100755
--- a/tests/qemu-iotests/245
+++ b/tests/qemu-iotests/245
@@ -1189,10 +1189,10 @@ class TestBlockdevReopen(iotests.QMPTestCase):
         self.run_test_iothreads('iothread0', 'iothread0')
 
     def test_iothreads_switch_backing(self):
-        self.run_test_iothreads('iothread0', None)
+        self.run_test_iothreads('iothread0', '')
 
     def test_iothreads_switch_overlay(self):
-        self.run_test_iothreads(None, 'iothread0')
+        self.run_test_iothreads('', 'iothread0')
 
 if __name__ == '__main__':
     iotests.activate_logging()
-- 
2.31.1



^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v2 06/15] iotests/051: Fix typo
  2021-10-08 13:34 [PATCH v2 00/15] qdev: Add JSON -device Kevin Wolf
                   ` (4 preceding siblings ...)
  2021-10-08 13:34 ` [PATCH v2 05/15] iotests/245: Fix type for iothread property Kevin Wolf
@ 2021-10-08 13:34 ` Kevin Wolf
  2021-10-08 13:34 ` [PATCH v2 07/15] qdev: Avoid using string visitor for properties Kevin Wolf
                   ` (11 subsequent siblings)
  17 siblings, 0 replies; 35+ messages in thread
From: Kevin Wolf @ 2021-10-08 13:34 UTC (permalink / raw)
  To: qemu-devel
  Cc: kwolf, damien.hedde, pkrempa, berrange, ehabkost, qemu-block,
	mst, libvir-list, jasowang, quintela, armbru, vsementsov,
	lvivier, its, pbonzini, eblake

The iothread isn't called 'iothread0', but 'thread0'. Depending on the
order that properties are parsed, the error message may change from the
expected one to another one saying that the iothread doesn't exist.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
---
 tests/qemu-iotests/051        | 2 +-
 tests/qemu-iotests/051.pc.out | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051
index 7bf29343d7..1d2fa93a11 100755
--- a/tests/qemu-iotests/051
+++ b/tests/qemu-iotests/051
@@ -199,7 +199,7 @@ case "$QEMU_DEFAULT_MACHINE" in
         # virtio-blk enables the iothread only when the driver initialises the
         # device, so a second virtio-blk device can't be added even with the
         # same iothread. virtio-scsi allows this.
-        run_qemu $iothread -device virtio-blk-pci,drive=disk,iothread=iothread0,share-rw=on
+        run_qemu $iothread -device virtio-blk-pci,drive=disk,iothread=thread0,share-rw=on
         run_qemu $iothread -device virtio-scsi,id=virtio-scsi1,iothread=thread0 -device scsi-hd,bus=virtio-scsi1.0,drive=disk,share-rw=on
         ;;
      *)
diff --git a/tests/qemu-iotests/051.pc.out b/tests/qemu-iotests/051.pc.out
index afe7632964..063e4fc584 100644
--- a/tests/qemu-iotests/051.pc.out
+++ b/tests/qemu-iotests/051.pc.out
@@ -183,9 +183,9 @@ Testing: -drive file=TEST_DIR/t.qcow2,if=none,node-name=disk -object iothread,id
 QEMU X.Y.Z monitor - type 'help' for more information
 (qemu) QEMU_PROG: -device scsi-hd,bus=virtio-scsi1.0,drive=disk,share-rw=on: Cannot change iothread of active block backend
 
-Testing: -drive file=TEST_DIR/t.qcow2,if=none,node-name=disk -object iothread,id=thread0 -device virtio-scsi,iothread=thread0,id=virtio-scsi0 -device scsi-hd,bus=virtio-scsi0.0,drive=disk,share-rw=on -device virtio-blk-pci,drive=disk,iothread=iothread0,share-rw=on
+Testing: -drive file=TEST_DIR/t.qcow2,if=none,node-name=disk -object iothread,id=thread0 -device virtio-scsi,iothread=thread0,id=virtio-scsi0 -device scsi-hd,bus=virtio-scsi0.0,drive=disk,share-rw=on -device virtio-blk-pci,drive=disk,iothread=thread0,share-rw=on
 QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) QEMU_PROG: -device virtio-blk-pci,drive=disk,iothread=iothread0,share-rw=on: Cannot change iothread of active block backend
+(qemu) QEMU_PROG: -device virtio-blk-pci,drive=disk,iothread=thread0,share-rw=on: Cannot change iothread of active block backend
 
 Testing: -drive file=TEST_DIR/t.qcow2,if=none,node-name=disk -object iothread,id=thread0 -device virtio-scsi,iothread=thread0,id=virtio-scsi0 -device scsi-hd,bus=virtio-scsi0.0,drive=disk,share-rw=on -device virtio-scsi,id=virtio-scsi1,iothread=thread0 -device scsi-hd,bus=virtio-scsi1.0,drive=disk,share-rw=on
 QEMU X.Y.Z monitor - type 'help' for more information
-- 
2.31.1



^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v2 07/15] qdev: Avoid using string visitor for properties
  2021-10-08 13:34 [PATCH v2 00/15] qdev: Add JSON -device Kevin Wolf
                   ` (5 preceding siblings ...)
  2021-10-08 13:34 ` [PATCH v2 06/15] iotests/051: Fix typo Kevin Wolf
@ 2021-10-08 13:34 ` Kevin Wolf
  2021-10-08 13:34 ` [PATCH v2 08/15] qdev: Make DeviceState.id independent of QemuOpts Kevin Wolf
                   ` (10 subsequent siblings)
  17 siblings, 0 replies; 35+ messages in thread
From: Kevin Wolf @ 2021-10-08 13:34 UTC (permalink / raw)
  To: qemu-devel
  Cc: kwolf, damien.hedde, pkrempa, berrange, ehabkost, qemu-block,
	mst, libvir-list, jasowang, quintela, armbru, vsementsov,
	lvivier, its, pbonzini, eblake

The only thing the string visitor adds compared to a keyval visitor is
list support. git grep for 'visit_start_list' and 'visit.*List' shows
that devices don't make use of this.

In a world with a QAPIfied command line interface, the keyval visitor is
used to parse the command line. In order to make sure that no devices
start using this feature that would make backwards compatibility harder,
just switch away from object_property_parse(), which internally uses the
string visitor, to a keyval visitor and object_property_set().

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 softmmu/qdev-monitor.c | 20 +++++++++++++++++---
 1 file changed, 17 insertions(+), 3 deletions(-)

diff --git a/softmmu/qdev-monitor.c b/softmmu/qdev-monitor.c
index 0705f00846..034b999401 100644
--- a/softmmu/qdev-monitor.c
+++ b/softmmu/qdev-monitor.c
@@ -28,6 +28,8 @@
 #include "qapi/qmp/dispatch.h"
 #include "qapi/qmp/qdict.h"
 #include "qapi/qmp/qerror.h"
+#include "qapi/qmp/qstring.h"
+#include "qapi/qobject-input-visitor.h"
 #include "qemu/config-file.h"
 #include "qemu/error-report.h"
 #include "qemu/help_option.h"
@@ -198,16 +200,28 @@ static int set_property(void *opaque, const char *name, const char *value,
                         Error **errp)
 {
     Object *obj = opaque;
+    QString *val;
+    Visitor *v;
+    int ret;
 
     if (strcmp(name, "driver") == 0)
         return 0;
     if (strcmp(name, "bus") == 0)
         return 0;
 
-    if (!object_property_parse(obj, name, value, errp)) {
-        return -1;
+    val = qstring_from_str(value);
+    v = qobject_input_visitor_new_keyval(QOBJECT(val));
+
+    if (!object_property_set(obj, name, v, errp)) {
+        ret = -1;
+        goto out;
     }
-    return 0;
+
+    ret = 0;
+out:
+    visit_free(v);
+    qobject_unref(val);
+    return ret;
 }
 
 static const char *find_typename_by_alias(const char *alias)
-- 
2.31.1



^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v2 08/15] qdev: Make DeviceState.id independent of QemuOpts
  2021-10-08 13:34 [PATCH v2 00/15] qdev: Add JSON -device Kevin Wolf
                   ` (6 preceding siblings ...)
  2021-10-08 13:34 ` [PATCH v2 07/15] qdev: Avoid using string visitor for properties Kevin Wolf
@ 2021-10-08 13:34 ` Kevin Wolf
  2021-10-13 13:41   ` Damien Hedde
  2021-10-08 13:34 ` [PATCH v2 09/15] softmmu/qdev-monitor: add error handling in qdev_set_id Kevin Wolf
                   ` (9 subsequent siblings)
  17 siblings, 1 reply; 35+ messages in thread
From: Kevin Wolf @ 2021-10-08 13:34 UTC (permalink / raw)
  To: qemu-devel
  Cc: kwolf, damien.hedde, pkrempa, berrange, ehabkost, qemu-block,
	mst, libvir-list, jasowang, quintela, armbru, vsementsov,
	lvivier, its, pbonzini, eblake

DeviceState.id is a pointer to a string that is stored in the QemuOpts
object DeviceState.opts and freed together with it. We want to create
devices without going through QemuOpts in the future, so make this a
separately allocated string.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
---
 include/hw/qdev-core.h              | 2 +-
 include/monitor/qdev.h              | 2 +-
 hw/arm/virt.c                       | 2 +-
 hw/core/qdev.c                      | 1 +
 hw/pci-bridge/pci_expander_bridge.c | 2 +-
 hw/ppc/e500.c                       | 2 +-
 softmmu/qdev-monitor.c              | 5 +++--
 7 files changed, 9 insertions(+), 7 deletions(-)

diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h
index 4ff19c714b..5a073fc368 100644
--- a/include/hw/qdev-core.h
+++ b/include/hw/qdev-core.h
@@ -176,7 +176,7 @@ struct DeviceState {
     Object parent_obj;
     /*< public >*/
 
-    const char *id;
+    char *id;
     char *canonical_path;
     bool realized;
     bool pending_deleted_event;
diff --git a/include/monitor/qdev.h b/include/monitor/qdev.h
index eaa947d73a..389287eb44 100644
--- a/include/monitor/qdev.h
+++ b/include/monitor/qdev.h
@@ -9,6 +9,6 @@ void qmp_device_add(QDict *qdict, QObject **ret_data, Error **errp);
 
 int qdev_device_help(QemuOpts *opts);
 DeviceState *qdev_device_add(QemuOpts *opts, Error **errp);
-void qdev_set_id(DeviceState *dev, const char *id);
+void qdev_set_id(DeviceState *dev, char *id);
 
 #endif
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 7170aaacd5..4160d49688 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -1459,7 +1459,7 @@ static void create_platform_bus(VirtMachineState *vms)
     MemoryRegion *sysmem = get_system_memory();
 
     dev = qdev_new(TYPE_PLATFORM_BUS_DEVICE);
-    dev->id = TYPE_PLATFORM_BUS_DEVICE;
+    dev->id = g_strdup(TYPE_PLATFORM_BUS_DEVICE);
     qdev_prop_set_uint32(dev, "num_irqs", PLATFORM_BUS_NUM_IRQS);
     qdev_prop_set_uint32(dev, "mmio_size", vms->memmap[VIRT_PLATFORM_BUS].size);
     sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
diff --git a/hw/core/qdev.c b/hw/core/qdev.c
index cefc5eaa0a..d918b50a1d 100644
--- a/hw/core/qdev.c
+++ b/hw/core/qdev.c
@@ -956,6 +956,7 @@ static void device_finalize(Object *obj)
     }
 
     qemu_opts_del(dev->opts);
+    g_free(dev->id);
 }
 
 static void device_class_base_init(ObjectClass *class, void *data)
diff --git a/hw/pci-bridge/pci_expander_bridge.c b/hw/pci-bridge/pci_expander_bridge.c
index 7112dc3062..10e6e7c2ab 100644
--- a/hw/pci-bridge/pci_expander_bridge.c
+++ b/hw/pci-bridge/pci_expander_bridge.c
@@ -245,7 +245,7 @@ static void pxb_dev_realize_common(PCIDevice *dev, bool pcie, Error **errp)
     } else {
         bus = pci_root_bus_new(ds, "pxb-internal", NULL, NULL, 0, TYPE_PXB_BUS);
         bds = qdev_new("pci-bridge");
-        bds->id = dev_name;
+        bds->id = g_strdup(dev_name);
         qdev_prop_set_uint8(bds, PCI_BRIDGE_DEV_PROP_CHASSIS_NR, pxb->bus_nr);
         qdev_prop_set_bit(bds, PCI_BRIDGE_DEV_PROP_SHPC, false);
     }
diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index 95451414dd..960e7efcd3 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -1006,7 +1006,7 @@ void ppce500_init(MachineState *machine)
     /* Platform Bus Device */
     if (pmc->has_platform_bus) {
         dev = qdev_new(TYPE_PLATFORM_BUS_DEVICE);
-        dev->id = TYPE_PLATFORM_BUS_DEVICE;
+        dev->id = g_strdup(TYPE_PLATFORM_BUS_DEVICE);
         qdev_prop_set_uint32(dev, "num_irqs", pmc->platform_bus_num_irqs);
         qdev_prop_set_uint32(dev, "mmio_size", pmc->platform_bus_size);
         sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
diff --git a/softmmu/qdev-monitor.c b/softmmu/qdev-monitor.c
index 034b999401..1207e57a46 100644
--- a/softmmu/qdev-monitor.c
+++ b/softmmu/qdev-monitor.c
@@ -592,7 +592,8 @@ static BusState *qbus_find(const char *path, Error **errp)
     return bus;
 }
 
-void qdev_set_id(DeviceState *dev, const char *id)
+/* Takes ownership of @id, will be freed when deleting the device */
+void qdev_set_id(DeviceState *dev, char *id)
 {
     if (id) {
         dev->id = id;
@@ -690,7 +691,7 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **errp)
         }
     }
 
-    qdev_set_id(dev, qemu_opts_id(opts));
+    qdev_set_id(dev, g_strdup(qemu_opts_id(opts)));
 
     /* set properties */
     if (qemu_opt_foreach(opts, set_property, dev, errp)) {
-- 
2.31.1



^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v2 09/15] softmmu/qdev-monitor: add error handling in qdev_set_id
  2021-10-08 13:34 [PATCH v2 00/15] qdev: Add JSON -device Kevin Wolf
                   ` (7 preceding siblings ...)
  2021-10-08 13:34 ` [PATCH v2 08/15] qdev: Make DeviceState.id independent of QemuOpts Kevin Wolf
@ 2021-10-08 13:34 ` Kevin Wolf
  2021-10-11 21:00   ` Eric Blake
  2021-10-08 13:34 ` [PATCH v2 10/15] qemu-option: Allow deleting opts during qemu_opts_foreach() Kevin Wolf
                   ` (8 subsequent siblings)
  17 siblings, 1 reply; 35+ messages in thread
From: Kevin Wolf @ 2021-10-08 13:34 UTC (permalink / raw)
  To: qemu-devel
  Cc: kwolf, damien.hedde, pkrempa, berrange, ehabkost, qemu-block,
	mst, libvir-list, jasowang, quintela, armbru, vsementsov,
	lvivier, its, pbonzini, eblake

From: Damien Hedde <damien.hedde@greensocs.com>

qdev_set_id() is mostly used when the user adds a device (using
-device cli option or device_add qmp command). This commit adds
an error parameter to handle the case where the given id is
already taken.

Also document the function and add a return value in order to
be able to capture success/failure: the function now returns the
id in case of success, or NULL in case of failure.

The commit modifies the 2 calling places (qdev-monitor and
xen-legacy-backend) to add the error object parameter.

Note that the id is, right now, guaranteed to be unique because
all ids came from the "device" QemuOptsList where the id is used
as key. This addition is a preparation for a future commit which
will relax the uniqueness.

Signed-off-by: Damien Hedde <damien.hedde@greensocs.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 include/monitor/qdev.h      | 25 +++++++++++++++++++++++-
 hw/xen/xen-legacy-backend.c |  3 ++-
 softmmu/qdev-monitor.c      | 38 +++++++++++++++++++++++++++----------
 3 files changed, 54 insertions(+), 12 deletions(-)

diff --git a/include/monitor/qdev.h b/include/monitor/qdev.h
index 389287eb44..74e6c55a2b 100644
--- a/include/monitor/qdev.h
+++ b/include/monitor/qdev.h
@@ -9,6 +9,29 @@ void qmp_device_add(QDict *qdict, QObject **ret_data, Error **errp);
 
 int qdev_device_help(QemuOpts *opts);
 DeviceState *qdev_device_add(QemuOpts *opts, Error **errp);
-void qdev_set_id(DeviceState *dev, char *id);
+
+/**
+ * qdev_set_id: parent the device and set its id if provided.
+ * @dev: device to handle
+ * @id: id to be given to the device, or NULL.
+ *
+ * Returns: the id of the device in case of success; otherwise NULL.
+ *
+ * @dev must be unrealized, unparented and must not have an id.
+ *
+ * If @id is non-NULL, this function tries to setup @dev qom path as
+ * "/peripheral/id". If @id is already taken, it fails. If it succeeds,
+ * the id field of @dev is set to @id (@dev now owns the given @id
+ * parameter).
+ *
+ * If @id is NULL, this function generates a unique name and setups @dev
+ * qom path as "/peripheral-anon/name". This name is not set as the id
+ * of @dev.
+ *
+ * Upon success, it returns the id/name (generated or provided). The
+ * returned string is owned by the corresponding child property and must
+ * not be freed by the caller.
+ */
+const char *qdev_set_id(DeviceState *dev, char *id, Error **errp);
 
 #endif
diff --git a/hw/xen/xen-legacy-backend.c b/hw/xen/xen-legacy-backend.c
index be3cf4a195..085fd31ef7 100644
--- a/hw/xen/xen-legacy-backend.c
+++ b/hw/xen/xen-legacy-backend.c
@@ -276,7 +276,8 @@ static struct XenLegacyDevice *xen_be_get_xendev(const char *type, int dom,
     xendev = g_malloc0(ops->size);
     object_initialize(&xendev->qdev, ops->size, TYPE_XENBACKEND);
     OBJECT(xendev)->free = g_free;
-    qdev_set_id(DEVICE(xendev), g_strdup_printf("xen-%s-%d", type, dev));
+    qdev_set_id(DEVICE(xendev), g_strdup_printf("xen-%s-%d", type, dev),
+                &error_fatal);
     qdev_realize(DEVICE(xendev), xen_sysbus, &error_fatal);
     object_unref(OBJECT(xendev));
 
diff --git a/softmmu/qdev-monitor.c b/softmmu/qdev-monitor.c
index 1207e57a46..feb15818e6 100644
--- a/softmmu/qdev-monitor.c
+++ b/softmmu/qdev-monitor.c
@@ -593,22 +593,34 @@ static BusState *qbus_find(const char *path, Error **errp)
 }
 
 /* Takes ownership of @id, will be freed when deleting the device */
-void qdev_set_id(DeviceState *dev, char *id)
+const char *qdev_set_id(DeviceState *dev, char *id, Error **errp)
 {
-    if (id) {
-        dev->id = id;
-    }
+    ObjectProperty *prop;
 
-    if (dev->id) {
-        object_property_add_child(qdev_get_peripheral(), dev->id,
-                                  OBJECT(dev));
+    assert(!dev->id && !dev->realized);
+
+    /*
+     * object_property_[try_]add_child() below will assert the device
+     * has no parent
+     */
+    if (id) {
+        prop = object_property_try_add_child(qdev_get_peripheral(), id,
+                                             OBJECT(dev), NULL);
+        if (prop) {
+            dev->id = id;
+        } else {
+            error_setg(errp, "Duplicate device ID '%s'", id);
+            return NULL;
+        }
     } else {
         static int anon_count;
         gchar *name = g_strdup_printf("device[%d]", anon_count++);
-        object_property_add_child(qdev_get_peripheral_anon(), name,
-                                  OBJECT(dev));
+        prop = object_property_add_child(qdev_get_peripheral_anon(), name,
+                                         OBJECT(dev));
         g_free(name);
     }
+
+    return prop->name;
 }
 
 DeviceState *qdev_device_add(QemuOpts *opts, Error **errp)
@@ -691,7 +703,13 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **errp)
         }
     }
 
-    qdev_set_id(dev, g_strdup(qemu_opts_id(opts)));
+    /*
+     * set dev's parent and register its id.
+     * If it fails it means the id is already taken.
+     */
+    if (!qdev_set_id(dev, g_strdup(qemu_opts_id(opts)), errp)) {
+        goto err_del_dev;
+    }
 
     /* set properties */
     if (qemu_opt_foreach(opts, set_property, dev, errp)) {
-- 
2.31.1



^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v2 10/15] qemu-option: Allow deleting opts during qemu_opts_foreach()
  2021-10-08 13:34 [PATCH v2 00/15] qdev: Add JSON -device Kevin Wolf
                   ` (8 preceding siblings ...)
  2021-10-08 13:34 ` [PATCH v2 09/15] softmmu/qdev-monitor: add error handling in qdev_set_id Kevin Wolf
@ 2021-10-08 13:34 ` Kevin Wolf
  2021-10-08 13:34 ` [PATCH v2 11/15] qdev: Add Error parameter to hide_device() callbacks Kevin Wolf
                   ` (7 subsequent siblings)
  17 siblings, 0 replies; 35+ messages in thread
From: Kevin Wolf @ 2021-10-08 13:34 UTC (permalink / raw)
  To: qemu-devel
  Cc: kwolf, damien.hedde, pkrempa, berrange, ehabkost, qemu-block,
	mst, libvir-list, jasowang, quintela, armbru, vsementsov,
	lvivier, its, pbonzini, eblake

Use QTAILQ_FOREACH_SAFE() so that the current QemuOpts can be deleted
while iterating through the whole list.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
---
 util/qemu-option.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/util/qemu-option.c b/util/qemu-option.c
index 61cb4a97bd..eedd08929b 100644
--- a/util/qemu-option.c
+++ b/util/qemu-option.c
@@ -1126,11 +1126,11 @@ int qemu_opts_foreach(QemuOptsList *list, qemu_opts_loopfunc func,
                       void *opaque, Error **errp)
 {
     Location loc;
-    QemuOpts *opts;
+    QemuOpts *opts, *next;
     int rc = 0;
 
     loc_push_none(&loc);
-    QTAILQ_FOREACH(opts, &list->head, next) {
+    QTAILQ_FOREACH_SAFE(opts, &list->head, next, next) {
         loc_restore(&opts->loc);
         rc = func(opaque, opts, errp);
         if (rc) {
-- 
2.31.1



^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v2 11/15] qdev: Add Error parameter to hide_device() callbacks
  2021-10-08 13:34 [PATCH v2 00/15] qdev: Add JSON -device Kevin Wolf
                   ` (9 preceding siblings ...)
  2021-10-08 13:34 ` [PATCH v2 10/15] qemu-option: Allow deleting opts during qemu_opts_foreach() Kevin Wolf
@ 2021-10-08 13:34 ` Kevin Wolf
  2021-10-08 13:34 ` [PATCH v2 12/15] virtio-net: Store failover primary opts pointer locally Kevin Wolf
                   ` (6 subsequent siblings)
  17 siblings, 0 replies; 35+ messages in thread
From: Kevin Wolf @ 2021-10-08 13:34 UTC (permalink / raw)
  To: qemu-devel
  Cc: kwolf, damien.hedde, pkrempa, berrange, ehabkost, qemu-block,
	mst, libvir-list, jasowang, quintela, armbru, vsementsov,
	lvivier, its, pbonzini, eblake

hide_device() is used for virtio-net failover, where the standby virtio
device delays creation of the primary device. It only makes sense to
have a single primary device for each standby device. Adding a second
one should result in an error instead of hiding it and never using it
afterwards.

Prepare for this by adding an Error parameter to the hide_device()
callback where virtio-net is informed about adding a primary device.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 include/hw/qdev-core.h | 8 ++++++--
 hw/core/qdev.c         | 7 +++++--
 hw/net/virtio-net.c    | 2 +-
 softmmu/qdev-monitor.c | 5 ++++-
 4 files changed, 16 insertions(+), 6 deletions(-)

diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h
index 5a073fc368..74d8b614a7 100644
--- a/include/hw/qdev-core.h
+++ b/include/hw/qdev-core.h
@@ -201,8 +201,12 @@ struct DeviceListener {
      * informs qdev if a device should be visible or hidden.  We can
      * hide a failover device depending for example on the device
      * opts.
+     *
+     * On errors, it returns false and errp is set. Device creation
+     * should fail in this case.
      */
-    bool (*hide_device)(DeviceListener *listener, QemuOpts *device_opts);
+    bool (*hide_device)(DeviceListener *listener, QemuOpts *device_opts,
+                        Error **errp);
     QTAILQ_ENTRY(DeviceListener) link;
 };
 
@@ -837,7 +841,7 @@ void device_listener_unregister(DeviceListener *listener);
  * 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);
+bool qdev_should_hide_device(QemuOpts *opts, Error **errp);
 
 typedef enum MachineInitPhase {
     /* current_machine is NULL.  */
diff --git a/hw/core/qdev.c b/hw/core/qdev.c
index d918b50a1d..c3a021c444 100644
--- a/hw/core/qdev.c
+++ b/hw/core/qdev.c
@@ -211,14 +211,17 @@ void device_listener_unregister(DeviceListener *listener)
     QTAILQ_REMOVE(&device_listeners, listener, link);
 }
 
-bool qdev_should_hide_device(QemuOpts *opts)
+bool qdev_should_hide_device(QemuOpts *opts, Error **errp)
 {
+    ERRP_GUARD();
     DeviceListener *listener;
 
     QTAILQ_FOREACH(listener, &device_listeners, link) {
         if (listener->hide_device) {
-            if (listener->hide_device(listener, opts)) {
+            if (listener->hide_device(listener, opts, errp)) {
                 return true;
+            } else if (*errp) {
+                return false;
             }
         }
     }
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index f205331dcf..a17d5739fc 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -3304,7 +3304,7 @@ static void virtio_net_migration_state_notifier(Notifier *notifier, void *data)
 }
 
 static bool failover_hide_primary_device(DeviceListener *listener,
-                                         QemuOpts *device_opts)
+                                         QemuOpts *device_opts, Error **errp)
 {
     VirtIONet *n = container_of(listener, VirtIONet, primary_listener);
     const char *standby_id;
diff --git a/softmmu/qdev-monitor.c b/softmmu/qdev-monitor.c
index feb15818e6..ccc3c11563 100644
--- a/softmmu/qdev-monitor.c
+++ b/softmmu/qdev-monitor.c
@@ -625,6 +625,7 @@ const char *qdev_set_id(DeviceState *dev, char *id, Error **errp)
 
 DeviceState *qdev_device_add(QemuOpts *opts, Error **errp)
 {
+    ERRP_GUARD();
     DeviceClass *dc;
     const char *driver, *path;
     DeviceState *dev = NULL;
@@ -668,11 +669,13 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **errp)
             error_setg(errp, "Device with failover_pair_id don't have id");
             return NULL;
         }
-        if (qdev_should_hide_device(opts)) {
+        if (qdev_should_hide_device(opts, errp)) {
             if (bus && !qbus_is_hotpluggable(bus)) {
                 error_setg(errp, QERR_BUS_NO_HOTPLUG, bus->name);
             }
             return NULL;
+        } else if (*errp) {
+            return NULL;
         }
     }
 
-- 
2.31.1



^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v2 12/15] virtio-net: Store failover primary opts pointer locally
  2021-10-08 13:34 [PATCH v2 00/15] qdev: Add JSON -device Kevin Wolf
                   ` (10 preceding siblings ...)
  2021-10-08 13:34 ` [PATCH v2 11/15] qdev: Add Error parameter to hide_device() callbacks Kevin Wolf
@ 2021-10-08 13:34 ` Kevin Wolf
  2021-10-19  8:06   ` Laurent Vivier
  2021-10-08 13:34 ` [PATCH v2 13/15] virtio-net: Avoid QemuOpts in failover_find_primary_device() Kevin Wolf
                   ` (5 subsequent siblings)
  17 siblings, 1 reply; 35+ messages in thread
From: Kevin Wolf @ 2021-10-08 13:34 UTC (permalink / raw)
  To: qemu-devel
  Cc: kwolf, damien.hedde, pkrempa, berrange, ehabkost, qemu-block,
	mst, libvir-list, jasowang, quintela, armbru, vsementsov,
	lvivier, its, pbonzini, eblake

Instead of accessing the global QemuOptsList, which really belong to the
command line parser and shouldn't be accessed from devices, store a
pointer to the QemuOpts in a new VirtIONet field.

This is not the final state, but just an intermediate step to get rid of
QemuOpts in devices. It will later be replaced with an options QDict.

Before this patch, two "primary" devices could be hidden for the same
standby device, but only one of them would actually be enabled and the
other one would be kept hidden forever, so this doesn't make sense.
After this patch, configuring a second primary device is an error.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 include/hw/virtio/virtio-net.h |  1 +
 hw/net/virtio-net.c            | 26 ++++++++++++++++++--------
 2 files changed, 19 insertions(+), 8 deletions(-)

diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h
index 824a69c23f..d118c95f69 100644
--- a/include/hw/virtio/virtio-net.h
+++ b/include/hw/virtio/virtio-net.h
@@ -209,6 +209,7 @@ struct VirtIONet {
     bool failover_primary_hidden;
     bool failover;
     DeviceListener primary_listener;
+    QemuOpts *primary_opts;
     Notifier migration_state;
     VirtioNetRssData rss_data;
     struct NetRxPkt *rx_pkt;
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index a17d5739fc..ed9a9012e9 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -858,27 +858,24 @@ static DeviceState *failover_find_primary_device(VirtIONet *n)
 static void failover_add_primary(VirtIONet *n, Error **errp)
 {
     Error *err = NULL;
-    QemuOpts *opts;
-    char *id;
     DeviceState *dev = failover_find_primary_device(n);
 
     if (dev) {
         return;
     }
 
-    id = failover_find_primary_device_id(n);
-    if (!id) {
+    if (!n->primary_opts) {
         error_setg(errp, "Primary device not found");
         error_append_hint(errp, "Virtio-net failover will not work. Make "
                           "sure primary device has parameter"
                           " failover_pair_id=%s\n", n->netclient_name);
         return;
     }
-    opts = qemu_opts_find(qemu_find_opts("device"), id);
-    g_assert(opts); /* cannot be NULL because id was found using opts list */
-    dev = qdev_device_add(opts, &err);
+
+    dev = qdev_device_add(n->primary_opts, &err);
     if (err) {
-        qemu_opts_del(opts);
+        qemu_opts_del(n->primary_opts);
+        n->primary_opts = NULL;
     } else {
         object_unref(OBJECT(dev));
     }
@@ -3317,6 +3314,19 @@ static bool failover_hide_primary_device(DeviceListener *listener,
         return false;
     }
 
+    if (n->primary_opts) {
+        error_setg(errp, "Cannot attach more than one primary device to '%s'",
+                   n->netclient_name);
+        return false;
+    }
+
+    /*
+     * Having a weak reference here should be okay because a device can't be
+     * deleted while it's hidden. This will be replaced soon with a QDict that
+     * has a clearer ownership model.
+     */
+    n->primary_opts = device_opts;
+
     /* failover_primary_hidden is set during feature negotiation */
     return qatomic_read(&n->failover_primary_hidden);
 }
-- 
2.31.1



^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v2 13/15] virtio-net: Avoid QemuOpts in failover_find_primary_device()
  2021-10-08 13:34 [PATCH v2 00/15] qdev: Add JSON -device Kevin Wolf
                   ` (11 preceding siblings ...)
  2021-10-08 13:34 ` [PATCH v2 12/15] virtio-net: Store failover primary opts pointer locally Kevin Wolf
@ 2021-10-08 13:34 ` Kevin Wolf
  2021-10-08 13:34 ` [PATCH v2 14/15] qdev: Base object creation on QDict rather than QemuOpts Kevin Wolf
                   ` (4 subsequent siblings)
  17 siblings, 0 replies; 35+ messages in thread
From: Kevin Wolf @ 2021-10-08 13:34 UTC (permalink / raw)
  To: qemu-devel
  Cc: kwolf, damien.hedde, pkrempa, berrange, ehabkost, qemu-block,
	mst, libvir-list, jasowang, quintela, armbru, vsementsov,
	lvivier, its, pbonzini, eblake

Don't go through the global QemuOptsList, it is state of the legacy
command line parser and we will create devices that are not contained
in it. It is also just the command line configuration and not
necessarily the current runtime state.

Instead, look at the qdev device tree which has the current state of all
existing devices.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 hw/net/virtio-net.c | 52 +++++++++++++++++----------------------------
 1 file changed, 19 insertions(+), 33 deletions(-)

diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index ed9a9012e9..f503f28c00 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -796,48 +796,34 @@ static inline uint64_t virtio_net_supported_guest_offloads(VirtIONet *n)
 
 typedef struct {
     VirtIONet *n;
-    char *id;
-} FailoverId;
+    DeviceState *dev;
+} FailoverDevice;
 
 /**
- * Set the id of the failover primary device
+ * Set the failover primary device
  *
  * @opaque: FailoverId to setup
  * @opts: opts for device we are handling
  * @errp: returns an error if this function fails
  */
-static int failover_set_primary(void *opaque, QemuOpts *opts, Error **errp)
+static int failover_set_primary(DeviceState *dev, void *opaque)
 {
-    FailoverId *fid = opaque;
-    const char *standby_id = qemu_opt_get(opts, "failover_pair_id");
+    FailoverDevice *fdev = opaque;
+    PCIDevice *pci_dev = (PCIDevice *)
+        object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE);
 
-    if (g_strcmp0(standby_id, fid->n->netclient_name) == 0) {
-        fid->id = g_strdup(opts->id);
+    if (!pci_dev) {
+        return 0;
+    }
+
+    if (!g_strcmp0(pci_dev->failover_pair_id, fdev->n->netclient_name)) {
+        fdev->dev = dev;
         return 1;
     }
 
     return 0;
 }
 
-/**
- * Find the primary device id for this failover virtio-net
- *
- * @n: VirtIONet device
- * @errp: returns an error if this function fails
- */
-static char *failover_find_primary_device_id(VirtIONet *n)
-{
-    Error *err = NULL;
-    FailoverId fid;
-
-    fid.n = n;
-    if (!qemu_opts_foreach(qemu_find_opts("device"),
-                           failover_set_primary, &fid, &err)) {
-        return NULL;
-    }
-    return fid.id;
-}
-
 /**
  * Find the primary device for this failover virtio-net
  *
@@ -846,13 +832,13 @@ static char *failover_find_primary_device_id(VirtIONet *n)
  */
 static DeviceState *failover_find_primary_device(VirtIONet *n)
 {
-    char *id = failover_find_primary_device_id(n);
-
-    if (!id) {
-        return NULL;
-    }
+    FailoverDevice fdev = {
+        .n = n,
+    };
 
-    return qdev_find_recursive(sysbus_get_default(), id);
+    qbus_walk_children(sysbus_get_default(), failover_set_primary, NULL,
+                       NULL, NULL, &fdev);
+    return fdev.dev;
 }
 
 static void failover_add_primary(VirtIONet *n, Error **errp)
-- 
2.31.1



^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v2 14/15] qdev: Base object creation on QDict rather than QemuOpts
  2021-10-08 13:34 [PATCH v2 00/15] qdev: Add JSON -device Kevin Wolf
                   ` (12 preceding siblings ...)
  2021-10-08 13:34 ` [PATCH v2 13/15] virtio-net: Avoid QemuOpts in failover_find_primary_device() Kevin Wolf
@ 2021-10-08 13:34 ` Kevin Wolf
  2021-10-08 15:17   ` Laurent Vivier
  2021-10-08 13:34 ` [PATCH v2 15/15] vl: Enable JSON syntax for -device Kevin Wolf
                   ` (3 subsequent siblings)
  17 siblings, 1 reply; 35+ messages in thread
From: Kevin Wolf @ 2021-10-08 13:34 UTC (permalink / raw)
  To: qemu-devel
  Cc: kwolf, damien.hedde, pkrempa, berrange, ehabkost, qemu-block,
	mst, libvir-list, jasowang, quintela, armbru, vsementsov,
	lvivier, its, pbonzini, eblake

QDicts are both what QMP natively uses and what the keyval parser
produces. Going through QemuOpts isn't useful for either one, so switch
the main device creation function to QDicts. By sharing more code with
the -object/object-add code path, we can even reduce the code size a
bit.

This commit doesn't remove the detour through QemuOpts from any code
path yet, but it allows the following commits to do so.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 include/hw/qdev-core.h         | 11 +++---
 include/hw/virtio/virtio-net.h |  3 +-
 include/monitor/qdev.h         |  2 +
 hw/core/qdev.c                 |  7 ++--
 hw/net/virtio-net.c            | 23 +++++++-----
 hw/vfio/pci.c                  |  4 +-
 softmmu/qdev-monitor.c         | 69 +++++++++++++++-------------------
 7 files changed, 60 insertions(+), 59 deletions(-)

diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h
index 74d8b614a7..910042c650 100644
--- a/include/hw/qdev-core.h
+++ b/include/hw/qdev-core.h
@@ -180,7 +180,7 @@ struct DeviceState {
     char *canonical_path;
     bool realized;
     bool pending_deleted_event;
-    QemuOpts *opts;
+    QDict *opts;
     int hotplugged;
     bool allow_unplug_during_migration;
     BusState *parent_bus;
@@ -205,8 +205,8 @@ struct DeviceListener {
      * On errors, it returns false and errp is set. Device creation
      * should fail in this case.
      */
-    bool (*hide_device)(DeviceListener *listener, QemuOpts *device_opts,
-                        Error **errp);
+    bool (*hide_device)(DeviceListener *listener, const QDict *device_opts,
+                        bool from_json, Error **errp);
     QTAILQ_ENTRY(DeviceListener) link;
 };
 
@@ -835,13 +835,14 @@ void device_listener_unregister(DeviceListener *listener);
 
 /**
  * @qdev_should_hide_device:
- * @opts: QemuOpts as passed on cmdline.
+ * @opts: options QDict
+ * @from_json: true if @opts entries are typed, false for all strings
  *
  * 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, Error **errp);
+bool qdev_should_hide_device(const QDict *opts, bool from_json, Error **errp);
 
 typedef enum MachineInitPhase {
     /* current_machine is NULL.  */
diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h
index d118c95f69..74a10ebe85 100644
--- a/include/hw/virtio/virtio-net.h
+++ b/include/hw/virtio/virtio-net.h
@@ -209,7 +209,8 @@ struct VirtIONet {
     bool failover_primary_hidden;
     bool failover;
     DeviceListener primary_listener;
-    QemuOpts *primary_opts;
+    QDict *primary_opts;
+    bool primary_opts_from_json;
     Notifier migration_state;
     VirtioNetRssData rss_data;
     struct NetRxPkt *rx_pkt;
diff --git a/include/monitor/qdev.h b/include/monitor/qdev.h
index 74e6c55a2b..1d57bf6577 100644
--- a/include/monitor/qdev.h
+++ b/include/monitor/qdev.h
@@ -9,6 +9,8 @@ void qmp_device_add(QDict *qdict, QObject **ret_data, Error **errp);
 
 int qdev_device_help(QemuOpts *opts);
 DeviceState *qdev_device_add(QemuOpts *opts, Error **errp);
+DeviceState *qdev_device_add_from_qdict(const QDict *opts,
+                                        bool from_json, Error **errp);
 
 /**
  * qdev_set_id: parent the device and set its id if provided.
diff --git a/hw/core/qdev.c b/hw/core/qdev.c
index c3a021c444..7f06403752 100644
--- a/hw/core/qdev.c
+++ b/hw/core/qdev.c
@@ -28,6 +28,7 @@
 #include "qemu/osdep.h"
 #include "qapi/error.h"
 #include "qapi/qapi-events-qdev.h"
+#include "qapi/qmp/qdict.h"
 #include "qapi/qmp/qerror.h"
 #include "qapi/visitor.h"
 #include "qemu/error-report.h"
@@ -211,14 +212,14 @@ void device_listener_unregister(DeviceListener *listener)
     QTAILQ_REMOVE(&device_listeners, listener, link);
 }
 
-bool qdev_should_hide_device(QemuOpts *opts, Error **errp)
+bool qdev_should_hide_device(const QDict *opts, bool from_json, Error **errp)
 {
     ERRP_GUARD();
     DeviceListener *listener;
 
     QTAILQ_FOREACH(listener, &device_listeners, link) {
         if (listener->hide_device) {
-            if (listener->hide_device(listener, opts, errp)) {
+            if (listener->hide_device(listener, opts, from_json, errp)) {
                 return true;
             } else if (*errp) {
                 return false;
@@ -958,7 +959,7 @@ static void device_finalize(Object *obj)
         dev->canonical_path = NULL;
     }
 
-    qemu_opts_del(dev->opts);
+    qobject_unref(dev->opts);
     g_free(dev->id);
 }
 
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index f503f28c00..09e173a558 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -858,9 +858,11 @@ static void failover_add_primary(VirtIONet *n, Error **errp)
         return;
     }
 
-    dev = qdev_device_add(n->primary_opts, &err);
+    dev = qdev_device_add_from_qdict(n->primary_opts,
+                                     n->primary_opts_from_json,
+                                     &err);
     if (err) {
-        qemu_opts_del(n->primary_opts);
+        qobject_unref(n->primary_opts);
         n->primary_opts = NULL;
     } else {
         object_unref(OBJECT(dev));
@@ -3287,7 +3289,9 @@ static void virtio_net_migration_state_notifier(Notifier *notifier, void *data)
 }
 
 static bool failover_hide_primary_device(DeviceListener *listener,
-                                         QemuOpts *device_opts, Error **errp)
+                                         const QDict *device_opts,
+                                         bool from_json,
+                                         Error **errp)
 {
     VirtIONet *n = container_of(listener, VirtIONet, primary_listener);
     const char *standby_id;
@@ -3295,7 +3299,7 @@ static bool failover_hide_primary_device(DeviceListener *listener,
     if (!device_opts) {
         return false;
     }
-    standby_id = qemu_opt_get(device_opts, "failover_pair_id");
+    standby_id = qdict_get_try_str(device_opts, "failover_pair_id");
     if (g_strcmp0(standby_id, n->netclient_name) != 0) {
         return false;
     }
@@ -3306,12 +3310,8 @@ static bool failover_hide_primary_device(DeviceListener *listener,
         return false;
     }
 
-    /*
-     * Having a weak reference here should be okay because a device can't be
-     * deleted while it's hidden. This will be replaced soon with a QDict that
-     * has a clearer ownership model.
-     */
-    n->primary_opts = device_opts;
+    n->primary_opts = qdict_clone_shallow(device_opts);
+    n->primary_opts_from_json = from_json;
 
     /* failover_primary_hidden is set during feature negotiation */
     return qatomic_read(&n->failover_primary_hidden);
@@ -3502,8 +3502,11 @@ static void virtio_net_device_unrealize(DeviceState *dev)
     g_free(n->vlans);
 
     if (n->failover) {
+        qobject_unref(n->primary_opts);
         device_listener_unregister(&n->primary_listener);
         remove_migration_state_change_notifier(&n->migration_state);
+    } else {
+        assert(n->primary_opts == NULL);
     }
 
     max_queues = n->multiqueue ? n->max_queues : 1;
diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
index 4feaa1cb68..5cdf1d4298 100644
--- a/hw/vfio/pci.c
+++ b/hw/vfio/pci.c
@@ -29,10 +29,10 @@
 #include "hw/qdev-properties.h"
 #include "hw/qdev-properties-system.h"
 #include "migration/vmstate.h"
+#include "qapi/qmp/qdict.h"
 #include "qemu/error-report.h"
 #include "qemu/main-loop.h"
 #include "qemu/module.h"
-#include "qemu/option.h"
 #include "qemu/range.h"
 #include "qemu/units.h"
 #include "sysemu/kvm.h"
@@ -941,7 +941,7 @@ static void vfio_pci_size_rom(VFIOPCIDevice *vdev)
     }
 
     if (vfio_opt_rom_in_denylist(vdev)) {
-        if (dev->opts && qemu_opt_get(dev->opts, "rombar")) {
+        if (dev->opts && qdict_haskey(dev->opts, "rombar")) {
             warn_report("Device at %s is known to cause system instability"
                         " issues during option rom execution",
                         vdev->vbasedev.name);
diff --git a/softmmu/qdev-monitor.c b/softmmu/qdev-monitor.c
index ccc3c11563..90882f1571 100644
--- a/softmmu/qdev-monitor.c
+++ b/softmmu/qdev-monitor.c
@@ -196,34 +196,6 @@ static void qdev_print_devinfos(bool show_no_user)
     g_slist_free(list);
 }
 
-static int set_property(void *opaque, const char *name, const char *value,
-                        Error **errp)
-{
-    Object *obj = opaque;
-    QString *val;
-    Visitor *v;
-    int ret;
-
-    if (strcmp(name, "driver") == 0)
-        return 0;
-    if (strcmp(name, "bus") == 0)
-        return 0;
-
-    val = qstring_from_str(value);
-    v = qobject_input_visitor_new_keyval(QOBJECT(val));
-
-    if (!object_property_set(obj, name, v, errp)) {
-        ret = -1;
-        goto out;
-    }
-
-    ret = 0;
-out:
-    visit_free(v);
-    qobject_unref(val);
-    return ret;
-}
-
 static const char *find_typename_by_alias(const char *alias)
 {
     int i;
@@ -623,15 +595,17 @@ const char *qdev_set_id(DeviceState *dev, char *id, Error **errp)
     return prop->name;
 }
 
-DeviceState *qdev_device_add(QemuOpts *opts, Error **errp)
+DeviceState *qdev_device_add_from_qdict(const QDict *opts,
+                                        bool from_json, Error **errp)
 {
     ERRP_GUARD();
     DeviceClass *dc;
     const char *driver, *path;
+    char *id;
     DeviceState *dev = NULL;
     BusState *bus = NULL;
 
-    driver = qemu_opt_get(opts, "driver");
+    driver = qdict_get_try_str(opts, "driver");
     if (!driver) {
         error_setg(errp, QERR_MISSING_PARAMETER, "driver");
         return NULL;
@@ -644,7 +618,7 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **errp)
     }
 
     /* find bus */
-    path = qemu_opt_get(opts, "bus");
+    path = qdict_get_try_str(opts, "bus");
     if (path != NULL) {
         bus = qbus_find(path, errp);
         if (!bus) {
@@ -664,12 +638,12 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **errp)
         }
     }
 
-    if (qemu_opt_get(opts, "failover_pair_id")) {
-        if (!opts->id) {
+    if (qdict_haskey(opts, "failover_pair_id")) {
+        if (!qdict_haskey(opts, "id")) {
             error_setg(errp, "Device with failover_pair_id don't have id");
             return NULL;
         }
-        if (qdev_should_hide_device(opts, errp)) {
+        if (qdev_should_hide_device(opts, from_json, errp)) {
             if (bus && !qbus_is_hotpluggable(bus)) {
                 error_setg(errp, QERR_BUS_NO_HOTPLUG, bus->name);
             }
@@ -710,18 +684,24 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **errp)
      * set dev's parent and register its id.
      * If it fails it means the id is already taken.
      */
-    if (!qdev_set_id(dev, g_strdup(qemu_opts_id(opts)), errp)) {
+    id = g_strdup(qdict_get_try_str(opts, "id"));
+    if (!qdev_set_id(dev, id, errp)) {
         goto err_del_dev;
     }
 
     /* set properties */
-    if (qemu_opt_foreach(opts, set_property, dev, errp)) {
+    dev->opts = qdict_clone_shallow(opts);
+    qdict_del(dev->opts, "driver");
+    qdict_del(dev->opts, "bus");
+    qdict_del(dev->opts, "id");
+
+    object_set_properties_from_keyval(&dev->parent_obj, dev->opts, from_json,
+                                      errp);
+    if (*errp) {
         goto err_del_dev;
     }
 
-    dev->opts = opts;
     if (!qdev_realize(DEVICE(dev), bus, errp)) {
-        dev->opts = NULL;
         goto err_del_dev;
     }
     return dev;
@@ -734,6 +714,19 @@ err_del_dev:
     return NULL;
 }
 
+/* Takes ownership of @opts on success */
+DeviceState *qdev_device_add(QemuOpts *opts, Error **errp)
+{
+    QDict *qdict = qemu_opts_to_qdict(opts, NULL);
+    DeviceState *ret;
+
+    ret = qdev_device_add_from_qdict(qdict, false, errp);
+    if (ret) {
+        qemu_opts_del(opts);
+    }
+    qobject_unref(qdict);
+    return ret;
+}
 
 #define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
 static void qbus_print(Monitor *mon, BusState *bus, int indent);
-- 
2.31.1



^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v2 15/15] vl: Enable JSON syntax for -device
  2021-10-08 13:34 [PATCH v2 00/15] qdev: Add JSON -device Kevin Wolf
                   ` (13 preceding siblings ...)
  2021-10-08 13:34 ` [PATCH v2 14/15] qdev: Base object creation on QDict rather than QemuOpts Kevin Wolf
@ 2021-10-08 13:34 ` Kevin Wolf
  2021-10-13 15:30 ` [PATCH v2 00/15] qdev: Add JSON -device Michael S. Tsirkin
                   ` (2 subsequent siblings)
  17 siblings, 0 replies; 35+ messages in thread
From: Kevin Wolf @ 2021-10-08 13:34 UTC (permalink / raw)
  To: qemu-devel
  Cc: kwolf, damien.hedde, pkrempa, berrange, ehabkost, qemu-block,
	mst, libvir-list, jasowang, quintela, armbru, vsementsov,
	lvivier, its, pbonzini, eblake

Like we already do for -object, introduce support for JSON syntax in
-device, which can be kept stable in the long term and guarantees that a
single code path with identical behaviour is used for both QMP and the
command line. Compared to the QemuOpts based code, the parser contains
less surprises and has support for non-scalar options (lists and
structs). Switching management tools to JSON means that we can more
easily change the "human" CLI syntax from QemuOpts to the keyval parser
later.

In the QAPI schema, a feature flag is added to the device-add command to
allow management tools to detect support for this.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 qapi/qdev.json | 15 ++++++++----
 softmmu/vl.c   | 63 ++++++++++++++++++++++++++++++++++++++++++++------
 2 files changed, 67 insertions(+), 11 deletions(-)

diff --git a/qapi/qdev.json b/qapi/qdev.json
index d75e68908b..69656b14df 100644
--- a/qapi/qdev.json
+++ b/qapi/qdev.json
@@ -32,17 +32,23 @@
 ##
 # @device_add:
 #
+# Add a device.
+#
 # @driver: the name of the new device's driver
 #
 # @bus: the device's parent bus (device tree path)
 #
 # @id: the device's ID, must be unique
 #
-# Additional arguments depend on the type.
-#
-# Add a device.
+# Features:
+# @json-cli: If present, the "-device" command line option supports JSON
+#            syntax with a structure identical to the arguments of this
+#            command.
 #
 # Notes:
+#
+# Additional arguments depend on the type.
+#
 # 1. For detailed information about this command, please refer to the
 #    'docs/qdev-device-use.txt' file.
 #
@@ -67,7 +73,8 @@
 ##
 { 'command': 'device_add',
   'data': {'driver': 'str', '*bus': 'str', '*id': 'str'},
-  'gen': false } # so we can get the additional arguments
+  'gen': false, # so we can get the additional arguments
+  'features': ['json-cli'] }
 
 ##
 # @device_del:
diff --git a/softmmu/vl.c b/softmmu/vl.c
index 55ab70eb97..af0c4cbd99 100644
--- a/softmmu/vl.c
+++ b/softmmu/vl.c
@@ -144,6 +144,12 @@ typedef struct ObjectOption {
     QTAILQ_ENTRY(ObjectOption) next;
 } ObjectOption;
 
+typedef struct DeviceOption {
+    QDict *opts;
+    Location loc;
+    QTAILQ_ENTRY(DeviceOption) next;
+} DeviceOption;
+
 static const char *cpu_option;
 static const char *mem_path;
 static const char *incoming;
@@ -151,6 +157,7 @@ static const char *loadvm;
 static const char *accelerators;
 static QDict *machine_opts_dict;
 static QTAILQ_HEAD(, ObjectOption) object_opts = QTAILQ_HEAD_INITIALIZER(object_opts);
+static QTAILQ_HEAD(, DeviceOption) device_opts = QTAILQ_HEAD_INITIALIZER(device_opts);
 static ram_addr_t maxram_size;
 static uint64_t ram_slots;
 static int display_remote;
@@ -494,21 +501,39 @@ const char *qemu_get_vm_name(void)
     return qemu_name;
 }
 
-static int default_driver_check(void *opaque, QemuOpts *opts, Error **errp)
+static void default_driver_disable(const char *driver)
 {
-    const char *driver = qemu_opt_get(opts, "driver");
     int i;
 
-    if (!driver)
-        return 0;
+    if (!driver) {
+        return;
+    }
+
     for (i = 0; i < ARRAY_SIZE(default_list); i++) {
         if (strcmp(default_list[i].driver, driver) != 0)
             continue;
         *(default_list[i].flag) = 0;
     }
+}
+
+static int default_driver_check(void *opaque, QemuOpts *opts, Error **errp)
+{
+    const char *driver = qemu_opt_get(opts, "driver");
+
+    default_driver_disable(driver);
     return 0;
 }
 
+static void default_driver_check_json(void)
+{
+    DeviceOption *opt;
+
+    QTAILQ_FOREACH(opt, &device_opts, next) {
+        const char *driver = qdict_get_try_str(opt->opts, "driver");
+        default_driver_disable(driver);
+    }
+}
+
 static int parse_name(void *opaque, QemuOpts *opts, Error **errp)
 {
     const char *proc_name;
@@ -1311,6 +1336,7 @@ static void qemu_disable_default_devices(void)
 {
     MachineClass *machine_class = MACHINE_GET_CLASS(current_machine);
 
+    default_driver_check_json();
     qemu_opts_foreach(qemu_find_opts("device"),
                       default_driver_check, NULL, NULL);
     qemu_opts_foreach(qemu_find_opts("global"),
@@ -2637,6 +2663,8 @@ static void qemu_init_board(void)
 
 static void qemu_create_cli_devices(void)
 {
+    DeviceOption *opt;
+
     soundhw_init();
 
     qemu_opts_foreach(qemu_find_opts("fw_cfg"),
@@ -2652,6 +2680,18 @@ static void qemu_create_cli_devices(void)
     rom_set_order_override(FW_CFG_ORDER_OVERRIDE_DEVICE);
     qemu_opts_foreach(qemu_find_opts("device"),
                       device_init_func, NULL, &error_fatal);
+    QTAILQ_FOREACH(opt, &device_opts, next) {
+        loc_push_restore(&opt->loc);
+        /*
+         * TODO Eventually we should call qmp_device_add() here to make sure it
+         * behaves the same, but QMP still has to accept incorrectly typed
+         * options until libvirt is fixed and we want to be strict on the CLI
+         * from the start, so call qdev_device_add_from_qdict() directly for
+         * now.
+         */
+        qdev_device_add_from_qdict(opt->opts, true, &error_fatal);
+        loc_pop(&opt->loc);
+    }
     rom_reset_order_override();
 }
 
@@ -3352,9 +3392,18 @@ void qemu_init(int argc, char **argv, char **envp)
                 add_device_config(DEV_USB, optarg);
                 break;
             case QEMU_OPTION_device:
-                if (!qemu_opts_parse_noisily(qemu_find_opts("device"),
-                                             optarg, true)) {
-                    exit(1);
+                if (optarg[0] == '{') {
+                    QObject *obj = qobject_from_json(optarg, &error_fatal);
+                    DeviceOption *opt = g_new0(DeviceOption, 1);
+                    opt->opts = qobject_to(QDict, obj);
+                    loc_save(&opt->loc);
+                    assert(opt->opts != NULL);
+                    QTAILQ_INSERT_TAIL(&device_opts, opt, next);
+                } else {
+                    if (!qemu_opts_parse_noisily(qemu_find_opts("device"),
+                                                 optarg, true)) {
+                        exit(1);
+                    }
                 }
                 break;
             case QEMU_OPTION_smp:
-- 
2.31.1



^ permalink raw reply related	[flat|nested] 35+ messages in thread

* Re: [PATCH v2 14/15] qdev: Base object creation on QDict rather than QemuOpts
  2021-10-08 13:34 ` [PATCH v2 14/15] qdev: Base object creation on QDict rather than QemuOpts Kevin Wolf
@ 2021-10-08 15:17   ` Laurent Vivier
  0 siblings, 0 replies; 35+ messages in thread
From: Laurent Vivier @ 2021-10-08 15:17 UTC (permalink / raw)
  To: Kevin Wolf, qemu-devel
  Cc: damien.hedde, pkrempa, berrange, ehabkost, qemu-block, mst,
	libvir-list, jasowang, quintela, armbru, vsementsov, its,
	pbonzini, eblake

On 08/10/2021 15:34, Kevin Wolf wrote:
> QDicts are both what QMP natively uses and what the keyval parser
> produces. Going through QemuOpts isn't useful for either one, so switch
> the main device creation function to QDicts. By sharing more code with
> the -object/object-add code path, we can even reduce the code size a
> bit.
> 
> This commit doesn't remove the detour through QemuOpts from any code
> path yet, but it allows the following commits to do so.
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>   include/hw/qdev-core.h         | 11 +++---
>   include/hw/virtio/virtio-net.h |  3 +-
>   include/monitor/qdev.h         |  2 +
>   hw/core/qdev.c                 |  7 ++--
>   hw/net/virtio-net.c            | 23 +++++++-----
>   hw/vfio/pci.c                  |  4 +-
>   softmmu/qdev-monitor.c         | 69 +++++++++++++++-------------------
>   7 files changed, 60 insertions(+), 59 deletions(-)
> 
> diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h
> index 74d8b614a7..910042c650 100644
> --- a/include/hw/qdev-core.h
> +++ b/include/hw/qdev-core.h
> @@ -180,7 +180,7 @@ struct DeviceState {
>       char *canonical_path;
>       bool realized;
>       bool pending_deleted_event;
> -    QemuOpts *opts;
> +    QDict *opts;
>       int hotplugged;
>       bool allow_unplug_during_migration;
>       BusState *parent_bus;
> @@ -205,8 +205,8 @@ struct DeviceListener {
>        * On errors, it returns false and errp is set. Device creation
>        * should fail in this case.
>        */
> -    bool (*hide_device)(DeviceListener *listener, QemuOpts *device_opts,
> -                        Error **errp);
> +    bool (*hide_device)(DeviceListener *listener, const QDict *device_opts,
> +                        bool from_json, Error **errp);
>       QTAILQ_ENTRY(DeviceListener) link;
>   };
>   
> @@ -835,13 +835,14 @@ void device_listener_unregister(DeviceListener *listener);
>   
>   /**
>    * @qdev_should_hide_device:
> - * @opts: QemuOpts as passed on cmdline.
> + * @opts: options QDict > + * @from_json: true if @opts entries are typed, false for all strings

Add the errp here too:

     * @errp: pointer to error object

>    *
>    * 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, Error **errp);
> +bool qdev_should_hide_device(const QDict *opts, bool from_json, Error **errp);
>   
>   typedef enum MachineInitPhase {
>       /* current_machine is NULL.  */

Thank you to have added the errp pointer in the hide_device helpers, it helps in my series.

Laurent



^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v2 04/15] qom: Reduce use of error_propagate()
  2021-10-08 13:34 ` [PATCH v2 04/15] qom: Reduce use of error_propagate() Kevin Wolf
@ 2021-10-11 15:07   ` Markus Armbruster
  0 siblings, 0 replies; 35+ messages in thread
From: Markus Armbruster @ 2021-10-11 15:07 UTC (permalink / raw)
  To: Kevin Wolf
  Cc: damien.hedde, lvivier, pkrempa, berrange, ehabkost, qemu-block,
	mst, libvir-list, jasowang, quintela, qemu-devel, vsementsov,
	its, pbonzini, eblake

Kevin Wolf <kwolf@redhat.com> writes:

> ERRP_GUARD() makes debugging easier by making sure that &error_abort
> still fails at the real origin of the error instead of
> error_propagate().
>
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>

Yes, please!

Reviewed-by: Markus Armbruster <armbru@redhat.com>



^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v2 09/15] softmmu/qdev-monitor: add error handling in qdev_set_id
  2021-10-08 13:34 ` [PATCH v2 09/15] softmmu/qdev-monitor: add error handling in qdev_set_id Kevin Wolf
@ 2021-10-11 21:00   ` Eric Blake
  2021-10-13 13:10     ` Damien Hedde
  0 siblings, 1 reply; 35+ messages in thread
From: Eric Blake @ 2021-10-11 21:00 UTC (permalink / raw)
  To: Kevin Wolf
  Cc: damien.hedde, lvivier, pkrempa, berrange, ehabkost, qemu-block,
	mst, libvir-list, jasowang, quintela, qemu-devel, armbru,
	vsementsov, its, pbonzini

On Fri, Oct 08, 2021 at 03:34:36PM +0200, Kevin Wolf wrote:
> From: Damien Hedde <damien.hedde@greensocs.com>
> 
> qdev_set_id() is mostly used when the user adds a device (using
> -device cli option or device_add qmp command). This commit adds
> an error parameter to handle the case where the given id is
> already taken.
> 
> Also document the function and add a return value in order to
> be able to capture success/failure: the function now returns the
> id in case of success, or NULL in case of failure.
> 
> The commit modifies the 2 calling places (qdev-monitor and
> xen-legacy-backend) to add the error object parameter.
> 
> Note that the id is, right now, guaranteed to be unique because
> all ids came from the "device" QemuOptsList where the id is used
> as key. This addition is a preparation for a future commit which
> will relax the uniqueness.
> 
> Signed-off-by: Damien Hedde <damien.hedde@greensocs.com>
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---

> +++ b/softmmu/qdev-monitor.c
> @@ -593,22 +593,34 @@ static BusState *qbus_find(const char *path, Error **errp)
>  }
>  
>  /* Takes ownership of @id, will be freed when deleting the device */
> -void qdev_set_id(DeviceState *dev, char *id)
> +const char *qdev_set_id(DeviceState *dev, char *id, Error **errp)
>  {
> -    if (id) {
> -        dev->id = id;
> -    }
> +    ObjectProperty *prop;
>  
> -    if (dev->id) {
> -        object_property_add_child(qdev_get_peripheral(), dev->id,
> -                                  OBJECT(dev));
> +    assert(!dev->id && !dev->realized);
> +
> +    /*
> +     * object_property_[try_]add_child() below will assert the device
> +     * has no parent
> +     */
> +    if (id) {
> +        prop = object_property_try_add_child(qdev_get_peripheral(), id,
> +                                             OBJECT(dev), NULL);
> +        if (prop) {
> +            dev->id = id;
> +        } else {
> +            error_setg(errp, "Duplicate device ID '%s'", id);
> +            return NULL;

id is not freed on this error path...

> +        }
>      } else {
>          static int anon_count;
>          gchar *name = g_strdup_printf("device[%d]", anon_count++);
> -        object_property_add_child(qdev_get_peripheral_anon(), name,
> -                                  OBJECT(dev));
> +        prop = object_property_add_child(qdev_get_peripheral_anon(), name,
> +                                         OBJECT(dev));
>          g_free(name);
>      }
> +
> +    return prop->name;
>  }
>  
>  DeviceState *qdev_device_add(QemuOpts *opts, Error **errp)
> @@ -691,7 +703,13 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **errp)
>          }
>      }
>  
> -    qdev_set_id(dev, g_strdup(qemu_opts_id(opts)));
> +    /*
> +     * set dev's parent and register its id.
> +     * If it fails it means the id is already taken.
> +     */
> +    if (!qdev_set_id(dev, g_strdup(qemu_opts_id(opts)), errp)) {
> +        goto err_del_dev;

...nor on this, which means the g_strdup() leaks on failure.

> +    }
>  
>      /* set properties */
>      if (qemu_opt_foreach(opts, set_property, dev, errp)) {
> -- 
> 2.31.1
> 

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org



^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v2 09/15] softmmu/qdev-monitor: add error handling in qdev_set_id
  2021-10-11 21:00   ` Eric Blake
@ 2021-10-13 13:10     ` Damien Hedde
  2021-10-13 21:37       ` Eric Blake
  0 siblings, 1 reply; 35+ messages in thread
From: Damien Hedde @ 2021-10-13 13:10 UTC (permalink / raw)
  To: Eric Blake, Kevin Wolf
  Cc: lvivier, pkrempa, berrange, ehabkost, qemu-block, mst,
	libvir-list, jasowang, quintela, qemu-devel, armbru, vsementsov,
	its, pbonzini



On 10/11/21 23:00, Eric Blake wrote:
> On Fri, Oct 08, 2021 at 03:34:36PM +0200, Kevin Wolf wrote:
>> From: Damien Hedde <damien.hedde@greensocs.com>
>>
>> qdev_set_id() is mostly used when the user adds a device (using
>> -device cli option or device_add qmp command). This commit adds
>> an error parameter to handle the case where the given id is
>> already taken.
>>
>> Also document the function and add a return value in order to
>> be able to capture success/failure: the function now returns the
>> id in case of success, or NULL in case of failure.
>>
>> The commit modifies the 2 calling places (qdev-monitor and
>> xen-legacy-backend) to add the error object parameter.
>>
>> Note that the id is, right now, guaranteed to be unique because
>> all ids came from the "device" QemuOptsList where the id is used
>> as key. This addition is a preparation for a future commit which
>> will relax the uniqueness.
>>
>> Signed-off-by: Damien Hedde <damien.hedde@greensocs.com>
>> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
>> ---
> 
>> +        } else {
>> +            error_setg(errp, "Duplicate device ID '%s'", id);
>> +            return NULL;
> 
> id is not freed on this error path...
> 

>>   
>>   DeviceState *qdev_device_add(QemuOpts *opts, Error **errp)
>> @@ -691,7 +703,13 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **errp)
>>           }
>>       }
>>   
>> -    qdev_set_id(dev, g_strdup(qemu_opts_id(opts)));
>> +    /*
>> +     * set dev's parent and register its id.
>> +     * If it fails it means the id is already taken.
>> +     */
>> +    if (!qdev_set_id(dev, g_strdup(qemu_opts_id(opts)), errp)) {
>> +        goto err_del_dev;
> 
> ...nor on this, which means the g_strdup() leaks on failure.
> 

Since we strdup the id just before calling qdev_set_id.
Maybe we should do the the strdup in qdev_set_id (and free things on 
error there too). It seems simplier than freeing things on the callee 
side just in case of an error.


Damien






^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v2 01/15] net: Introduce NetClientInfo.check_peer_type()
  2021-10-08 13:34 ` [PATCH v2 01/15] net: Introduce NetClientInfo.check_peer_type() Kevin Wolf
@ 2021-10-13 13:28   ` Damien Hedde
  2021-10-14  3:22   ` Jason Wang
  1 sibling, 0 replies; 35+ messages in thread
From: Damien Hedde @ 2021-10-13 13:28 UTC (permalink / raw)
  To: Kevin Wolf, qemu-devel
  Cc: lvivier, pkrempa, berrange, ehabkost, qemu-block, mst,
	libvir-list, jasowang, quintela, armbru, vsementsov, its,
	pbonzini, eblake



On 10/8/21 15:34, Kevin Wolf wrote:
> Some network backends (vhost-user and vhost-vdpa) work only with
> specific devices. At startup, they second guess what the command line
> option handling will do and error out if they think a non-virtio device
> will attach to them.
> 
> This second guessing is not only ugly, it can lead to wrong error
> messages ('-device floppy,netdev=foo' should complain about an unknown
> property, not about the wrong kind of network device being attached) and
> completely ignores hotplugging.
> 
> Add a callback where backends can check compatibility with a device when
> it actually tries to attach, even on hotplug.
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>

Reviewed-by: Damien Hedde <damien.hedde@greensocs.com>
> ---
>   include/net/net.h                | 2 ++
>   hw/core/qdev-properties-system.c | 6 ++++++
>   2 files changed, 8 insertions(+)
> 
> diff --git a/include/net/net.h b/include/net/net.h
> index 5d1508081f..986288eb07 100644
> --- a/include/net/net.h
> +++ b/include/net/net.h
> @@ -62,6 +62,7 @@ typedef struct SocketReadState SocketReadState;
>   typedef void (SocketReadStateFinalize)(SocketReadState *rs);
>   typedef void (NetAnnounce)(NetClientState *);
>   typedef bool (SetSteeringEBPF)(NetClientState *, int);
> +typedef bool (NetCheckPeerType)(NetClientState *, ObjectClass *, Error **);
>   
>   typedef struct NetClientInfo {
>       NetClientDriver type;
> @@ -84,6 +85,7 @@ typedef struct NetClientInfo {
>       SetVnetBE *set_vnet_be;
>       NetAnnounce *announce;
>       SetSteeringEBPF *set_steering_ebpf;
> +    NetCheckPeerType *check_peer_type;
>   } NetClientInfo;
>   
>   struct NetClientState {
> diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c
> index e71f5d64d1..a91f60567a 100644
> --- a/hw/core/qdev-properties-system.c
> +++ b/hw/core/qdev-properties-system.c
> @@ -431,6 +431,12 @@ static void set_netdev(Object *obj, Visitor *v, const char *name,
>               goto out;
>           }
>   
> +        if (peers[i]->info->check_peer_type) {
> +            if (!peers[i]->info->check_peer_type(peers[i], obj->class, errp)) {
> +                goto out;
> +            }
> +        }
> +
>           ncs[i] = peers[i];
>           ncs[i]->queue_index = i;
>       }
> 


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v2 02/15] net/vhost-user: Fix device compatibility check
  2021-10-08 13:34 ` [PATCH v2 02/15] net/vhost-user: Fix device compatibility check Kevin Wolf
@ 2021-10-13 13:30   ` Damien Hedde
  2021-10-14  3:23   ` Jason Wang
  1 sibling, 0 replies; 35+ messages in thread
From: Damien Hedde @ 2021-10-13 13:30 UTC (permalink / raw)
  To: Kevin Wolf, qemu-devel
  Cc: lvivier, pkrempa, berrange, ehabkost, qemu-block, mst,
	libvir-list, jasowang, quintela, armbru, vsementsov, its,
	pbonzini, eblake



On 10/8/21 15:34, Kevin Wolf wrote:
> vhost-user works only with specific devices. At startup, it second
> guesses what the command line option handling will do and error out if
> it thinks a non-virtio device will attach to them.
> 
> This second guessing is not only ugly, it can lead to wrong error
> messages ('-device floppy,netdev=foo' should complain about an unknown
> property, not about the wrong kind of network device being attached) and
> completely ignores hotplugging.
> 
> Drop the old checks and implement .check_peer_type() instead to fix
> this. As a nice side effect, it also removes one more dependency on the
> legacy QemuOpts infrastructure and even reduces the code size.
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>

Reviewed-by: Damien Hedde <damien.hedde@greensocs.com>


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v2 03/15] net/vhost-vdpa: Fix device compatibility check
  2021-10-08 13:34 ` [PATCH v2 03/15] net/vhost-vdpa: " Kevin Wolf
@ 2021-10-13 13:30   ` Damien Hedde
  2021-10-14  3:24   ` Jason Wang
  1 sibling, 0 replies; 35+ messages in thread
From: Damien Hedde @ 2021-10-13 13:30 UTC (permalink / raw)
  To: Kevin Wolf, qemu-devel
  Cc: lvivier, pkrempa, berrange, ehabkost, qemu-block, mst,
	libvir-list, jasowang, quintela, armbru, vsementsov, its,
	pbonzini, eblake



On 10/8/21 15:34, Kevin Wolf wrote:
> vhost-vdpa works only with specific devices. At startup, it second
> guesses what the command line option handling will do and error out if
> it thinks a non-virtio device will attach to them.
> 
> This second guessing is not only ugly, it can lead to wrong error
> messages ('-device floppy,netdev=foo' should complain about an unknown
> property, not about the wrong kind of network device being attached) and
> completely ignores hotplugging.
> 
> Drop the old checks and implement .check_peer_type() instead to fix
> this. As a nice side effect, it also removes one more dependency on the
> legacy QemuOpts infrastructure and even reduces the code size.
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>

Reviewed-by: Damien Hedde <damien.hedde@greensocs.com>


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v2 08/15] qdev: Make DeviceState.id independent of QemuOpts
  2021-10-08 13:34 ` [PATCH v2 08/15] qdev: Make DeviceState.id independent of QemuOpts Kevin Wolf
@ 2021-10-13 13:41   ` Damien Hedde
  0 siblings, 0 replies; 35+ messages in thread
From: Damien Hedde @ 2021-10-13 13:41 UTC (permalink / raw)
  To: Kevin Wolf, qemu-devel
  Cc: lvivier, pkrempa, berrange, ehabkost, qemu-block, mst,
	libvir-list, jasowang, quintela, armbru, vsementsov, its,
	pbonzini, eblake



On 10/8/21 15:34, Kevin Wolf wrote:
> DeviceState.id is a pointer to a string that is stored in the QemuOpts
> object DeviceState.opts and freed together with it. We want to create
> devices without going through QemuOpts in the future, so make this a
> separately allocated string.
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>


Reviewed-by: Damien Hedde <damien.hedde@greensocs.com>


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v2 00/15] qdev: Add JSON -device
  2021-10-08 13:34 [PATCH v2 00/15] qdev: Add JSON -device Kevin Wolf
                   ` (14 preceding siblings ...)
  2021-10-08 13:34 ` [PATCH v2 15/15] vl: Enable JSON syntax for -device Kevin Wolf
@ 2021-10-13 15:30 ` Michael S. Tsirkin
  2021-10-13 16:53   ` Kevin Wolf
  2021-10-15 13:24 ` Peter Krempa
  2021-10-15 14:38 ` Kevin Wolf
  17 siblings, 1 reply; 35+ messages in thread
From: Michael S. Tsirkin @ 2021-10-13 15:30 UTC (permalink / raw)
  To: Kevin Wolf
  Cc: damien.hedde, lvivier, pkrempa, berrange, ehabkost, qemu-block,
	quintela, libvir-list, jasowang, qemu-devel, armbru, vsementsov,
	its, pbonzini, eblake

On Fri, Oct 08, 2021 at 03:34:27PM +0200, Kevin Wolf wrote:
> It's still a long way until we'll have QAPIfied devices, but there are
> some improvements that we can already make now to make the future switch
> easier.
> 
> One important part of this is having code paths without QemuOpts, which
> we want to get rid of and replace with the keyval parser in the long
> run. This series adds support for JSON syntax to -device, which bypasses
> QemuOpts.
> 
> While we're not using QAPI yet, devices are based on QOM, so we already
> do have type checks and an implied schema. JSON syntax supported now can
> be supported by QAPI later and regarding command line compatibility,
> actually switching to it becomes an implementation detail this way (of
> course, it will still add valuable user-visible features like
> introspection and documentation).
> 
> Apart from making things more future proof, this also immediately adds
> a way to do non-scalar properties on the command line. nvme could have
> used list support recently, and the lack of it in -device led to some
> rather unnatural solution in the first version (doing the relationship
> between a device and objects backwards) and loss of features in the
> following. With this series, using a list as a device property should be
> possible without any weird tricks.
> 
> Unfortunately, even QMP device_add goes through QemuOpts before this
> series, which destroys any type safety QOM provides and also can't
> support non-scalar properties. This is a bug, but it turns out that
> libvirt actually relies on it and passes only strings for everything.
> So this series still leaves device_add alone until libvirt is fixed.


Reviewed-by: Michael S. Tsirkin <mst@redhat.com>

I assume you are merging this?

> v2:
> - Drop type safe QMP device_add because libvirt gets it wrong, too
> - More network patches to eliminate dependencies on the legacy QemuOpts
>   data structures which would not contain all devices any more after
>   this series. Fix some bugs there as a side effect.
> - Remove an unnecessary use of ERRP_GUARD()
> - Replaced error handling patch for qdev_set_id() with Damien's
> - Drop the deprecation patch until libvirt uses the new JSON syntax
> 
> Damien Hedde (1):
>   softmmu/qdev-monitor: add error handling in qdev_set_id
> 
> Kevin Wolf (14):
>   net: Introduce NetClientInfo.check_peer_type()
>   net/vhost-user: Fix device compatibility check
>   net/vhost-vdpa: Fix device compatibility check
>   qom: Reduce use of error_propagate()
>   iotests/245: Fix type for iothread property
>   iotests/051: Fix typo
>   qdev: Avoid using string visitor for properties
>   qdev: Make DeviceState.id independent of QemuOpts
>   qemu-option: Allow deleting opts during qemu_opts_foreach()
>   qdev: Add Error parameter to hide_device() callbacks
>   virtio-net: Store failover primary opts pointer locally
>   virtio-net: Avoid QemuOpts in failover_find_primary_device()
>   qdev: Base object creation on QDict rather than QemuOpts
>   vl: Enable JSON syntax for -device
> 
>  qapi/qdev.json                      | 15 +++--
>  include/hw/qdev-core.h              | 15 +++--
>  include/hw/virtio/virtio-net.h      |  2 +
>  include/monitor/qdev.h              | 27 +++++++-
>  include/net/net.h                   |  2 +
>  hw/arm/virt.c                       |  2 +-
>  hw/core/qdev-properties-system.c    |  6 ++
>  hw/core/qdev.c                      | 11 +++-
>  hw/net/virtio-net.c                 | 85 ++++++++++++-------------
>  hw/pci-bridge/pci_expander_bridge.c |  2 +-
>  hw/ppc/e500.c                       |  2 +-
>  hw/vfio/pci.c                       |  4 +-
>  hw/xen/xen-legacy-backend.c         |  3 +-
>  net/vhost-user.c                    | 41 ++++--------
>  net/vhost-vdpa.c                    | 37 ++++-------
>  qom/object.c                        |  7 +-
>  qom/object_interfaces.c             | 19 ++----
>  softmmu/qdev-monitor.c              | 99 +++++++++++++++++++----------
>  softmmu/vl.c                        | 63 ++++++++++++++++--
>  util/qemu-option.c                  |  4 +-
>  tests/qemu-iotests/051              |  2 +-
>  tests/qemu-iotests/051.pc.out       |  4 +-
>  tests/qemu-iotests/245              |  4 +-
>  23 files changed, 278 insertions(+), 178 deletions(-)
> 
> -- 
> 2.31.1



^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v2 00/15] qdev: Add JSON -device
  2021-10-13 15:30 ` [PATCH v2 00/15] qdev: Add JSON -device Michael S. Tsirkin
@ 2021-10-13 16:53   ` Kevin Wolf
  0 siblings, 0 replies; 35+ messages in thread
From: Kevin Wolf @ 2021-10-13 16:53 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: damien.hedde, lvivier, pkrempa, berrange, ehabkost, qemu-block,
	quintela, libvir-list, jasowang, qemu-devel, armbru, vsementsov,
	its, pbonzini, eblake

Am 13.10.2021 um 17:30 hat Michael S. Tsirkin geschrieben:
> On Fri, Oct 08, 2021 at 03:34:27PM +0200, Kevin Wolf wrote:
> > It's still a long way until we'll have QAPIfied devices, but there are
> > some improvements that we can already make now to make the future switch
> > easier.
> > 
> > One important part of this is having code paths without QemuOpts, which
> > we want to get rid of and replace with the keyval parser in the long
> > run. This series adds support for JSON syntax to -device, which bypasses
> > QemuOpts.
> > 
> > While we're not using QAPI yet, devices are based on QOM, so we already
> > do have type checks and an implied schema. JSON syntax supported now can
> > be supported by QAPI later and regarding command line compatibility,
> > actually switching to it becomes an implementation detail this way (of
> > course, it will still add valuable user-visible features like
> > introspection and documentation).
> > 
> > Apart from making things more future proof, this also immediately adds
> > a way to do non-scalar properties on the command line. nvme could have
> > used list support recently, and the lack of it in -device led to some
> > rather unnatural solution in the first version (doing the relationship
> > between a device and objects backwards) and loss of features in the
> > following. With this series, using a list as a device property should be
> > possible without any weird tricks.
> > 
> > Unfortunately, even QMP device_add goes through QemuOpts before this
> > series, which destroys any type safety QOM provides and also can't
> > support non-scalar properties. This is a bug, but it turns out that
> > libvirt actually relies on it and passes only strings for everything.
> > So this series still leaves device_add alone until libvirt is fixed.
> 
> 
> Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
> 
> I assume you are merging this?

Yes, I can merge it through my tree. Thanks for the review!

Kevin



^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v2 09/15] softmmu/qdev-monitor: add error handling in qdev_set_id
  2021-10-13 13:10     ` Damien Hedde
@ 2021-10-13 21:37       ` Eric Blake
  2021-10-15  7:24         ` Kevin Wolf
  0 siblings, 1 reply; 35+ messages in thread
From: Eric Blake @ 2021-10-13 21:37 UTC (permalink / raw)
  To: Damien Hedde
  Cc: Kevin Wolf, lvivier, pkrempa, berrange, ehabkost, qemu-block,
	mst, libvir-list, jasowang, quintela, qemu-devel, armbru,
	vsementsov, its, pbonzini

On Wed, Oct 13, 2021 at 03:10:38PM +0200, Damien Hedde wrote:
> > > @@ -691,7 +703,13 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **errp)
> > >           }
> > >       }
> > > -    qdev_set_id(dev, g_strdup(qemu_opts_id(opts)));
> > > +    /*
> > > +     * set dev's parent and register its id.
> > > +     * If it fails it means the id is already taken.
> > > +     */
> > > +    if (!qdev_set_id(dev, g_strdup(qemu_opts_id(opts)), errp)) {
> > > +        goto err_del_dev;
> > 
> > ...nor on this, which means the g_strdup() leaks on failure.
> > 
> 
> Since we strdup the id just before calling qdev_set_id.
> Maybe we should do the the strdup in qdev_set_id (and free things on error
> there too). It seems simplier than freeing things on the callee side just in
> case of an error.

Indeed.  If we expected qdev_set_id() to be passed something that it
can later free, we would have used 'char *'; but because we used
'const char *' for that parameter, it really does make more sense for
the callers to pass in any string and for qdev_set_id() to do the
necessary strdup()ing, as well as clean up on error.

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org



^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v2 01/15] net: Introduce NetClientInfo.check_peer_type()
  2021-10-08 13:34 ` [PATCH v2 01/15] net: Introduce NetClientInfo.check_peer_type() Kevin Wolf
  2021-10-13 13:28   ` Damien Hedde
@ 2021-10-14  3:22   ` Jason Wang
  1 sibling, 0 replies; 35+ messages in thread
From: Jason Wang @ 2021-10-14  3:22 UTC (permalink / raw)
  To: Kevin Wolf, qemu-devel
  Cc: damien.hedde, lvivier, pkrempa, berrange, ehabkost, qemu-block,
	mst, libvir-list, quintela, armbru, vsementsov, its, pbonzini,
	eblake


在 2021/10/8 下午9:34, Kevin Wolf 写道:
> Some network backends (vhost-user and vhost-vdpa) work only with
> specific devices. At startup, they second guess what the command line
> option handling will do and error out if they think a non-virtio device
> will attach to them.
>
> This second guessing is not only ugly, it can lead to wrong error
> messages ('-device floppy,netdev=foo' should complain about an unknown
> property, not about the wrong kind of network device being attached) and
> completely ignores hotplugging.
>
> Add a callback where backends can check compatibility with a device when
> it actually tries to attach, even on hotplug.
>
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>


Acked-by: Jason Wang <jasowang@redhat.com>


> ---
>   include/net/net.h                | 2 ++
>   hw/core/qdev-properties-system.c | 6 ++++++
>   2 files changed, 8 insertions(+)
>
> diff --git a/include/net/net.h b/include/net/net.h
> index 5d1508081f..986288eb07 100644
> --- a/include/net/net.h
> +++ b/include/net/net.h
> @@ -62,6 +62,7 @@ typedef struct SocketReadState SocketReadState;
>   typedef void (SocketReadStateFinalize)(SocketReadState *rs);
>   typedef void (NetAnnounce)(NetClientState *);
>   typedef bool (SetSteeringEBPF)(NetClientState *, int);
> +typedef bool (NetCheckPeerType)(NetClientState *, ObjectClass *, Error **);
>   
>   typedef struct NetClientInfo {
>       NetClientDriver type;
> @@ -84,6 +85,7 @@ typedef struct NetClientInfo {
>       SetVnetBE *set_vnet_be;
>       NetAnnounce *announce;
>       SetSteeringEBPF *set_steering_ebpf;
> +    NetCheckPeerType *check_peer_type;
>   } NetClientInfo;
>   
>   struct NetClientState {
> diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c
> index e71f5d64d1..a91f60567a 100644
> --- a/hw/core/qdev-properties-system.c
> +++ b/hw/core/qdev-properties-system.c
> @@ -431,6 +431,12 @@ static void set_netdev(Object *obj, Visitor *v, const char *name,
>               goto out;
>           }
>   
> +        if (peers[i]->info->check_peer_type) {
> +            if (!peers[i]->info->check_peer_type(peers[i], obj->class, errp)) {
> +                goto out;
> +            }
> +        }
> +
>           ncs[i] = peers[i];
>           ncs[i]->queue_index = i;
>       }



^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v2 02/15] net/vhost-user: Fix device compatibility check
  2021-10-08 13:34 ` [PATCH v2 02/15] net/vhost-user: Fix device compatibility check Kevin Wolf
  2021-10-13 13:30   ` Damien Hedde
@ 2021-10-14  3:23   ` Jason Wang
  1 sibling, 0 replies; 35+ messages in thread
From: Jason Wang @ 2021-10-14  3:23 UTC (permalink / raw)
  To: Kevin Wolf, qemu-devel
  Cc: damien.hedde, lvivier, pkrempa, berrange, ehabkost, qemu-block,
	mst, libvir-list, quintela, armbru, vsementsov, its, pbonzini,
	eblake


在 2021/10/8 下午9:34, Kevin Wolf 写道:
> vhost-user works only with specific devices. At startup, it second
> guesses what the command line option handling will do and error out if
> it thinks a non-virtio device will attach to them.
>
> This second guessing is not only ugly, it can lead to wrong error
> messages ('-device floppy,netdev=foo' should complain about an unknown
> property, not about the wrong kind of network device being attached) and
> completely ignores hotplugging.
>
> Drop the old checks and implement .check_peer_type() instead to fix
> this. As a nice side effect, it also removes one more dependency on the
> legacy QemuOpts infrastructure and even reduces the code size.
>
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>


Acked-by: Jason Wang <jasowang@redhat.com>


> ---
>   net/vhost-user.c | 41 ++++++++++++++---------------------------
>   1 file changed, 14 insertions(+), 27 deletions(-)
>
> diff --git a/net/vhost-user.c b/net/vhost-user.c
> index 4a939124d2..b1a0247b59 100644
> --- a/net/vhost-user.c
> +++ b/net/vhost-user.c
> @@ -198,6 +198,19 @@ static bool vhost_user_has_ufo(NetClientState *nc)
>       return true;
>   }
>   
> +static bool vhost_user_check_peer_type(NetClientState *nc, ObjectClass *oc,
> +                                       Error **errp)
> +{
> +    const char *driver = object_class_get_name(oc);
> +
> +    if (!g_str_has_prefix(driver, "virtio-net-")) {
> +        error_setg(errp, "vhost-user requires frontend driver virtio-net-*");
> +        return false;
> +    }
> +
> +    return true;
> +}
> +
>   static NetClientInfo net_vhost_user_info = {
>           .type = NET_CLIENT_DRIVER_VHOST_USER,
>           .size = sizeof(NetVhostUserState),
> @@ -207,6 +220,7 @@ static NetClientInfo net_vhost_user_info = {
>           .has_ufo = vhost_user_has_ufo,
>           .set_vnet_be = vhost_user_set_vnet_endianness,
>           .set_vnet_le = vhost_user_set_vnet_endianness,
> +        .check_peer_type = vhost_user_check_peer_type,
>   };
>   
>   static gboolean net_vhost_user_watch(void *do_not_use, GIOCondition cond,
> @@ -397,27 +411,6 @@ static Chardev *net_vhost_claim_chardev(
>       return chr;
>   }
>   
> -static int net_vhost_check_net(void *opaque, QemuOpts *opts, Error **errp)
> -{
> -    const char *name = opaque;
> -    const char *driver, *netdev;
> -
> -    driver = qemu_opt_get(opts, "driver");
> -    netdev = qemu_opt_get(opts, "netdev");
> -
> -    if (!driver || !netdev) {
> -        return 0;
> -    }
> -
> -    if (strcmp(netdev, name) == 0 &&
> -        !g_str_has_prefix(driver, "virtio-net-")) {
> -        error_setg(errp, "vhost-user requires frontend driver virtio-net-*");
> -        return -1;
> -    }
> -
> -    return 0;
> -}
> -
>   int net_init_vhost_user(const Netdev *netdev, const char *name,
>                           NetClientState *peer, Error **errp)
>   {
> @@ -433,12 +426,6 @@ int net_init_vhost_user(const Netdev *netdev, const char *name,
>           return -1;
>       }
>   
> -    /* verify net frontend */
> -    if (qemu_opts_foreach(qemu_find_opts("device"), net_vhost_check_net,
> -                          (char *)name, errp)) {
> -        return -1;
> -    }
> -
>       queues = vhost_user_opts->has_queues ? vhost_user_opts->queues : 1;
>       if (queues < 1 || queues > MAX_QUEUE_NUM) {
>           error_setg(errp,



^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v2 03/15] net/vhost-vdpa: Fix device compatibility check
  2021-10-08 13:34 ` [PATCH v2 03/15] net/vhost-vdpa: " Kevin Wolf
  2021-10-13 13:30   ` Damien Hedde
@ 2021-10-14  3:24   ` Jason Wang
  1 sibling, 0 replies; 35+ messages in thread
From: Jason Wang @ 2021-10-14  3:24 UTC (permalink / raw)
  To: Kevin Wolf, qemu-devel
  Cc: damien.hedde, lvivier, pkrempa, berrange, ehabkost, qemu-block,
	mst, libvir-list, quintela, armbru, vsementsov, its, pbonzini,
	eblake


在 2021/10/8 下午9:34, Kevin Wolf 写道:
> vhost-vdpa works only with specific devices. At startup, it second
> guesses what the command line option handling will do and error out if
> it thinks a non-virtio device will attach to them.
>
> This second guessing is not only ugly, it can lead to wrong error
> messages ('-device floppy,netdev=foo' should complain about an unknown
> property, not about the wrong kind of network device being attached) and
> completely ignores hotplugging.
>
> Drop the old checks and implement .check_peer_type() instead to fix
> this. As a nice side effect, it also removes one more dependency on the
> legacy QemuOpts infrastructure and even reduces the code size.
>
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>


Acked-by: Jason Wang <jasowang@redhat.com>


> ---
>   net/vhost-vdpa.c | 37 ++++++++++++++-----------------------
>   1 file changed, 14 insertions(+), 23 deletions(-)
>
> diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c
> index 912686457c..6dc68d8677 100644
> --- a/net/vhost-vdpa.c
> +++ b/net/vhost-vdpa.c
> @@ -147,12 +147,26 @@ static bool vhost_vdpa_has_ufo(NetClientState *nc)
>   
>   }
>   
> +static bool vhost_vdpa_check_peer_type(NetClientState *nc, ObjectClass *oc,
> +                                       Error **errp)
> +{
> +    const char *driver = object_class_get_name(oc);
> +
> +    if (!g_str_has_prefix(driver, "virtio-net-")) {
> +        error_setg(errp, "vhost-vdpa requires frontend driver virtio-net-*");
> +        return false;
> +    }
> +
> +    return true;
> +}
> +
>   static NetClientInfo net_vhost_vdpa_info = {
>           .type = NET_CLIENT_DRIVER_VHOST_VDPA,
>           .size = sizeof(VhostVDPAState),
>           .cleanup = vhost_vdpa_cleanup,
>           .has_vnet_hdr = vhost_vdpa_has_vnet_hdr,
>           .has_ufo = vhost_vdpa_has_ufo,
> +        .check_peer_type = vhost_vdpa_check_peer_type,
>   };
>   
>   static int net_vhost_vdpa_init(NetClientState *peer, const char *device,
> @@ -179,24 +193,6 @@ static int net_vhost_vdpa_init(NetClientState *peer, const char *device,
>       return ret;
>   }
>   
> -static int net_vhost_check_net(void *opaque, QemuOpts *opts, Error **errp)
> -{
> -    const char *name = opaque;
> -    const char *driver, *netdev;
> -
> -    driver = qemu_opt_get(opts, "driver");
> -    netdev = qemu_opt_get(opts, "netdev");
> -    if (!driver || !netdev) {
> -        return 0;
> -    }
> -    if (strcmp(netdev, name) == 0 &&
> -        !g_str_has_prefix(driver, "virtio-net-")) {
> -        error_setg(errp, "vhost-vdpa requires frontend driver virtio-net-*");
> -        return -1;
> -    }
> -    return 0;
> -}
> -
>   int net_init_vhost_vdpa(const Netdev *netdev, const char *name,
>                           NetClientState *peer, Error **errp)
>   {
> @@ -204,10 +200,5 @@ int net_init_vhost_vdpa(const Netdev *netdev, const char *name,
>   
>       assert(netdev->type == NET_CLIENT_DRIVER_VHOST_VDPA);
>       opts = &netdev->u.vhost_vdpa;
> -    /* verify net frontend */
> -    if (qemu_opts_foreach(qemu_find_opts("device"), net_vhost_check_net,
> -                          (char *)name, errp)) {
> -        return -1;
> -    }
>       return net_vhost_vdpa_init(peer, TYPE_VHOST_VDPA, name, opts->vhostdev);
>   }



^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v2 09/15] softmmu/qdev-monitor: add error handling in qdev_set_id
  2021-10-13 21:37       ` Eric Blake
@ 2021-10-15  7:24         ` Kevin Wolf
  0 siblings, 0 replies; 35+ messages in thread
From: Kevin Wolf @ 2021-10-15  7:24 UTC (permalink / raw)
  To: Eric Blake
  Cc: Damien Hedde, lvivier, pkrempa, berrange, ehabkost, qemu-block,
	mst, libvir-list, jasowang, quintela, qemu-devel, armbru,
	vsementsov, its, pbonzini

Am 13.10.2021 um 23:37 hat Eric Blake geschrieben:
> On Wed, Oct 13, 2021 at 03:10:38PM +0200, Damien Hedde wrote:
> > > > @@ -691,7 +703,13 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **errp)
> > > >           }
> > > >       }
> > > > -    qdev_set_id(dev, g_strdup(qemu_opts_id(opts)));
> > > > +    /*
> > > > +     * set dev's parent and register its id.
> > > > +     * If it fails it means the id is already taken.
> > > > +     */
> > > > +    if (!qdev_set_id(dev, g_strdup(qemu_opts_id(opts)), errp)) {
> > > > +        goto err_del_dev;
> > > 
> > > ...nor on this, which means the g_strdup() leaks on failure.
> > > 
> > 
> > Since we strdup the id just before calling qdev_set_id.
> > Maybe we should do the the strdup in qdev_set_id (and free things on error
> > there too). It seems simplier than freeing things on the callee side just in
> > case of an error.
> 
> Indeed.  If we expected qdev_set_id() to be passed something that it
> can later free, we would have used 'char *'; but because we used
> 'const char *' for that parameter, it really does make more sense for
> the callers to pass in any string and for qdev_set_id() to do the
> necessary strdup()ing, as well as clean up on error.

Since this seems to be the only thing in the series that needs to be
addressed, I'll do the minimal fix while applying (adding g_free() to
the error path in qemu_opts_id()) and then we can clean up on top.

Kevin



^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v2 00/15] qdev: Add JSON -device
  2021-10-08 13:34 [PATCH v2 00/15] qdev: Add JSON -device Kevin Wolf
                   ` (15 preceding siblings ...)
  2021-10-13 15:30 ` [PATCH v2 00/15] qdev: Add JSON -device Michael S. Tsirkin
@ 2021-10-15 13:24 ` Peter Krempa
  2021-10-15 14:38 ` Kevin Wolf
  17 siblings, 0 replies; 35+ messages in thread
From: Peter Krempa @ 2021-10-15 13:24 UTC (permalink / raw)
  To: Kevin Wolf
  Cc: damien.hedde, lvivier, vsementsov, berrange, ehabkost,
	qemu-block, mst, libvir-list, jasowang, quintela, qemu-devel,
	armbru, its, pbonzini, eblake

On Fri, Oct 08, 2021 at 15:34:27 +0200, Kevin Wolf wrote:
> It's still a long way until we'll have QAPIfied devices, but there are
> some improvements that we can already make now to make the future switch
> easier.
> 
> One important part of this is having code paths without QemuOpts, which
> we want to get rid of and replace with the keyval parser in the long
> run. This series adds support for JSON syntax to -device, which bypasses
> QemuOpts.
> 
> While we're not using QAPI yet, devices are based on QOM, so we already
> do have type checks and an implied schema. JSON syntax supported now can
> be supported by QAPI later and regarding command line compatibility,
> actually switching to it becomes an implementation detail this way (of
> course, it will still add valuable user-visible features like
> introspection and documentation).
> 
> Apart from making things more future proof, this also immediately adds
> a way to do non-scalar properties on the command line. nvme could have
> used list support recently, and the lack of it in -device led to some
> rather unnatural solution in the first version (doing the relationship
> between a device and objects backwards) and loss of features in the
> following. With this series, using a list as a device property should be
> possible without any weird tricks.
> 
> Unfortunately, even QMP device_add goes through QemuOpts before this
> series, which destroys any type safety QOM provides and also can't
> support non-scalar properties. This is a bug, but it turns out that
> libvirt actually relies on it and passes only strings for everything.
> So this series still leaves device_add alone until libvirt is fixed.

I've tested hotplug and standard -device with many (not all) devices
libvirt uses and seems that both '-device JSON' and monitor work
properly.

I'll enable '-device JSON' in libvirt once this hits upstream.

> 
> v2:
> - Drop type safe QMP device_add because libvirt gets it wrong, too

I've actually applied this patch too to make sure that libvirt is
working properly in both modes. It works now well with this too.

I'm not sure about the compatibility promise here, but libvirt is now
prepared even for teh strict version of 'device_add'. Libvirt's
requirements state that new libvirt needs to be used with new qemu and
thus from our view it's okay to do it even now.

> - More network patches to eliminate dependencies on the legacy QemuOpts
>   data structures which would not contain all devices any more after
>   this series. Fix some bugs there as a side effect.
> - Remove an unnecessary use of ERRP_GUARD()
> - Replaced error handling patch for qdev_set_id() with Damien's
> - Drop the deprecation patch until libvirt uses the new JSON syntax

Series:

Tested-by: Peter Krempa <pkrempa@redhat.com>



^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v2 00/15] qdev: Add JSON -device
  2021-10-08 13:34 [PATCH v2 00/15] qdev: Add JSON -device Kevin Wolf
                   ` (16 preceding siblings ...)
  2021-10-15 13:24 ` Peter Krempa
@ 2021-10-15 14:38 ` Kevin Wolf
  17 siblings, 0 replies; 35+ messages in thread
From: Kevin Wolf @ 2021-10-15 14:38 UTC (permalink / raw)
  To: qemu-devel
  Cc: damien.hedde, lvivier, pkrempa, berrange, ehabkost, qemu-block,
	mst, libvir-list, jasowang, quintela, armbru, vsementsov, its,
	pbonzini, eblake

Am 08.10.2021 um 15:34 hat Kevin Wolf geschrieben:
> It's still a long way until we'll have QAPIfied devices, but there are
> some improvements that we can already make now to make the future switch
> easier.
> 
> One important part of this is having code paths without QemuOpts, which
> we want to get rid of and replace with the keyval parser in the long
> run. This series adds support for JSON syntax to -device, which bypasses
> QemuOpts.
> 
> While we're not using QAPI yet, devices are based on QOM, so we already
> do have type checks and an implied schema. JSON syntax supported now can
> be supported by QAPI later and regarding command line compatibility,
> actually switching to it becomes an implementation detail this way (of
> course, it will still add valuable user-visible features like
> introspection and documentation).
> 
> Apart from making things more future proof, this also immediately adds
> a way to do non-scalar properties on the command line. nvme could have
> used list support recently, and the lack of it in -device led to some
> rather unnatural solution in the first version (doing the relationship
> between a device and objects backwards) and loss of features in the
> following. With this series, using a list as a device property should be
> possible without any weird tricks.
> 
> Unfortunately, even QMP device_add goes through QemuOpts before this
> series, which destroys any type safety QOM provides and also can't
> support non-scalar properties. This is a bug, but it turns out that
> libvirt actually relies on it and passes only strings for everything.
> So this series still leaves device_add alone until libvirt is fixed.

Thanks for the review and testing, applied to my tree.

Kevin



^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v2 12/15] virtio-net: Store failover primary opts pointer locally
  2021-10-08 13:34 ` [PATCH v2 12/15] virtio-net: Store failover primary opts pointer locally Kevin Wolf
@ 2021-10-19  8:06   ` Laurent Vivier
  2021-10-19 10:57     ` Kevin Wolf
  0 siblings, 1 reply; 35+ messages in thread
From: Laurent Vivier @ 2021-10-19  8:06 UTC (permalink / raw)
  To: Kevin Wolf, qemu-devel
  Cc: damien.hedde, pkrempa, berrange, ehabkost, qemu-block, mst,
	libvir-list, jasowang, quintela, armbru, vsementsov, its,
	pbonzini, eblake

On 08/10/2021 15:34, Kevin Wolf wrote:
> Instead of accessing the global QemuOptsList, which really belong to the
> command line parser and shouldn't be accessed from devices, store a
> pointer to the QemuOpts in a new VirtIONet field.
> 
> This is not the final state, but just an intermediate step to get rid of
> QemuOpts in devices. It will later be replaced with an options QDict.
> 
> Before this patch, two "primary" devices could be hidden for the same
> standby device, but only one of them would actually be enabled and the
> other one would be kept hidden forever, so this doesn't make sense.
> After this patch, configuring a second primary device is an error.
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>   include/hw/virtio/virtio-net.h |  1 +
>   hw/net/virtio-net.c            | 26 ++++++++++++++++++--------
>   2 files changed, 19 insertions(+), 8 deletions(-)
> 
> diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h
> index 824a69c23f..d118c95f69 100644
> --- a/include/hw/virtio/virtio-net.h
> +++ b/include/hw/virtio/virtio-net.h
> @@ -209,6 +209,7 @@ struct VirtIONet {
>       bool failover_primary_hidden;
>       bool failover;
>       DeviceListener primary_listener;
> +    QemuOpts *primary_opts;
>       Notifier migration_state;
>       VirtioNetRssData rss_data;
>       struct NetRxPkt *rx_pkt;
> diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
> index a17d5739fc..ed9a9012e9 100644
> --- a/hw/net/virtio-net.c
> +++ b/hw/net/virtio-net.c
> @@ -858,27 +858,24 @@ static DeviceState *failover_find_primary_device(VirtIONet *n)
>   static void failover_add_primary(VirtIONet *n, Error **errp)
>   {
>       Error *err = NULL;
> -    QemuOpts *opts;
> -    char *id;
>       DeviceState *dev = failover_find_primary_device(n);
>   
>       if (dev) {
>           return;
>       }
>   
> -    id = failover_find_primary_device_id(n);
> -    if (!id) {
> +    if (!n->primary_opts) {
>           error_setg(errp, "Primary device not found");
>           error_append_hint(errp, "Virtio-net failover will not work. Make "
>                             "sure primary device has parameter"
>                             " failover_pair_id=%s\n", n->netclient_name);
>           return;
>       }
> -    opts = qemu_opts_find(qemu_find_opts("device"), id);
> -    g_assert(opts); /* cannot be NULL because id was found using opts list */
> -    dev = qdev_device_add(opts, &err);
> +
> +    dev = qdev_device_add(n->primary_opts, &err);
>       if (err) {
> -        qemu_opts_del(opts);
> +        qemu_opts_del(n->primary_opts);
> +        n->primary_opts = NULL;
>       } else {
>           object_unref(OBJECT(dev));
>       }
> @@ -3317,6 +3314,19 @@ static bool failover_hide_primary_device(DeviceListener *listener,
>           return false;
>       }
>   
> +    if (n->primary_opts) {
> +        error_setg(errp, "Cannot attach more than one primary device to '%s'",
> +                   n->netclient_name);
> +        return false;
> +    }
> +

This part has introduced a regression, I've sent a patch to fix that.

https://patchew.org/QEMU/20211019071532.682717-1-lvivier@redhat.com/

Thanks,
Laurent



^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v2 12/15] virtio-net: Store failover primary opts pointer locally
  2021-10-19  8:06   ` Laurent Vivier
@ 2021-10-19 10:57     ` Kevin Wolf
  0 siblings, 0 replies; 35+ messages in thread
From: Kevin Wolf @ 2021-10-19 10:57 UTC (permalink / raw)
  To: Laurent Vivier
  Cc: damien.hedde, pkrempa, berrange, ehabkost, qemu-block, mst,
	libvir-list, jasowang, quintela, qemu-devel, armbru, vsementsov,
	its, pbonzini, eblake

Am 19.10.2021 um 10:06 hat Laurent Vivier geschrieben:
> On 08/10/2021 15:34, Kevin Wolf wrote:
> > Instead of accessing the global QemuOptsList, which really belong to the
> > command line parser and shouldn't be accessed from devices, store a
> > pointer to the QemuOpts in a new VirtIONet field.
> > 
> > This is not the final state, but just an intermediate step to get rid of
> > QemuOpts in devices. It will later be replaced with an options QDict.
> > 
> > Before this patch, two "primary" devices could be hidden for the same
> > standby device, but only one of them would actually be enabled and the
> > other one would be kept hidden forever, so this doesn't make sense.
> > After this patch, configuring a second primary device is an error.
> > 
> > Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> > ---
> >   include/hw/virtio/virtio-net.h |  1 +
> >   hw/net/virtio-net.c            | 26 ++++++++++++++++++--------
> >   2 files changed, 19 insertions(+), 8 deletions(-)
> > 
> > diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h
> > index 824a69c23f..d118c95f69 100644
> > --- a/include/hw/virtio/virtio-net.h
> > +++ b/include/hw/virtio/virtio-net.h
> > @@ -209,6 +209,7 @@ struct VirtIONet {
> >       bool failover_primary_hidden;
> >       bool failover;
> >       DeviceListener primary_listener;
> > +    QemuOpts *primary_opts;
> >       Notifier migration_state;
> >       VirtioNetRssData rss_data;
> >       struct NetRxPkt *rx_pkt;
> > diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
> > index a17d5739fc..ed9a9012e9 100644
> > --- a/hw/net/virtio-net.c
> > +++ b/hw/net/virtio-net.c
> > @@ -858,27 +858,24 @@ static DeviceState *failover_find_primary_device(VirtIONet *n)
> >   static void failover_add_primary(VirtIONet *n, Error **errp)
> >   {
> >       Error *err = NULL;
> > -    QemuOpts *opts;
> > -    char *id;
> >       DeviceState *dev = failover_find_primary_device(n);
> >       if (dev) {
> >           return;
> >       }
> > -    id = failover_find_primary_device_id(n);
> > -    if (!id) {
> > +    if (!n->primary_opts) {
> >           error_setg(errp, "Primary device not found");
> >           error_append_hint(errp, "Virtio-net failover will not work. Make "
> >                             "sure primary device has parameter"
> >                             " failover_pair_id=%s\n", n->netclient_name);
> >           return;
> >       }
> > -    opts = qemu_opts_find(qemu_find_opts("device"), id);
> > -    g_assert(opts); /* cannot be NULL because id was found using opts list */
> > -    dev = qdev_device_add(opts, &err);
> > +
> > +    dev = qdev_device_add(n->primary_opts, &err);
> >       if (err) {
> > -        qemu_opts_del(opts);
> > +        qemu_opts_del(n->primary_opts);
> > +        n->primary_opts = NULL;
> >       } else {
> >           object_unref(OBJECT(dev));
> >       }
> > @@ -3317,6 +3314,19 @@ static bool failover_hide_primary_device(DeviceListener *listener,
> >           return false;
> >       }
> > +    if (n->primary_opts) {
> > +        error_setg(errp, "Cannot attach more than one primary device to '%s'",
> > +                   n->netclient_name);
> > +        return false;
> > +    }
> > +
> 
> This part has introduced a regression, I've sent a patch to fix that.
> 
> https://patchew.org/QEMU/20211019071532.682717-1-lvivier@redhat.com/

Thanks for catching this! The fix looks good to me.

Kevin



^ permalink raw reply	[flat|nested] 35+ messages in thread

end of thread, other threads:[~2021-10-19 10:59 UTC | newest]

Thread overview: 35+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-10-08 13:34 [PATCH v2 00/15] qdev: Add JSON -device Kevin Wolf
2021-10-08 13:34 ` [PATCH v2 01/15] net: Introduce NetClientInfo.check_peer_type() Kevin Wolf
2021-10-13 13:28   ` Damien Hedde
2021-10-14  3:22   ` Jason Wang
2021-10-08 13:34 ` [PATCH v2 02/15] net/vhost-user: Fix device compatibility check Kevin Wolf
2021-10-13 13:30   ` Damien Hedde
2021-10-14  3:23   ` Jason Wang
2021-10-08 13:34 ` [PATCH v2 03/15] net/vhost-vdpa: " Kevin Wolf
2021-10-13 13:30   ` Damien Hedde
2021-10-14  3:24   ` Jason Wang
2021-10-08 13:34 ` [PATCH v2 04/15] qom: Reduce use of error_propagate() Kevin Wolf
2021-10-11 15:07   ` Markus Armbruster
2021-10-08 13:34 ` [PATCH v2 05/15] iotests/245: Fix type for iothread property Kevin Wolf
2021-10-08 13:34 ` [PATCH v2 06/15] iotests/051: Fix typo Kevin Wolf
2021-10-08 13:34 ` [PATCH v2 07/15] qdev: Avoid using string visitor for properties Kevin Wolf
2021-10-08 13:34 ` [PATCH v2 08/15] qdev: Make DeviceState.id independent of QemuOpts Kevin Wolf
2021-10-13 13:41   ` Damien Hedde
2021-10-08 13:34 ` [PATCH v2 09/15] softmmu/qdev-monitor: add error handling in qdev_set_id Kevin Wolf
2021-10-11 21:00   ` Eric Blake
2021-10-13 13:10     ` Damien Hedde
2021-10-13 21:37       ` Eric Blake
2021-10-15  7:24         ` Kevin Wolf
2021-10-08 13:34 ` [PATCH v2 10/15] qemu-option: Allow deleting opts during qemu_opts_foreach() Kevin Wolf
2021-10-08 13:34 ` [PATCH v2 11/15] qdev: Add Error parameter to hide_device() callbacks Kevin Wolf
2021-10-08 13:34 ` [PATCH v2 12/15] virtio-net: Store failover primary opts pointer locally Kevin Wolf
2021-10-19  8:06   ` Laurent Vivier
2021-10-19 10:57     ` Kevin Wolf
2021-10-08 13:34 ` [PATCH v2 13/15] virtio-net: Avoid QemuOpts in failover_find_primary_device() Kevin Wolf
2021-10-08 13:34 ` [PATCH v2 14/15] qdev: Base object creation on QDict rather than QemuOpts Kevin Wolf
2021-10-08 15:17   ` Laurent Vivier
2021-10-08 13:34 ` [PATCH v2 15/15] vl: Enable JSON syntax for -device Kevin Wolf
2021-10-13 15:30 ` [PATCH v2 00/15] qdev: Add JSON -device Michael S. Tsirkin
2021-10-13 16:53   ` Kevin Wolf
2021-10-15 13:24 ` Peter Krempa
2021-10-15 14:38 ` Kevin Wolf

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).