Skip to content

Commit f3558b1

Browse files
committed
qdev: Base object creation on QDict rather than QemuOpts
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 <[email protected]> Message-Id: <[email protected]> Reviewed-by: Michael S. Tsirkin <[email protected]> Tested-by: Peter Krempa <[email protected]> Signed-off-by: Kevin Wolf <[email protected]>
1 parent 12b2fad commit f3558b1

File tree

7 files changed

+61
-59
lines changed

7 files changed

+61
-59
lines changed

hw/core/qdev.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "qemu/osdep.h"
2929
#include "qapi/error.h"
3030
#include "qapi/qapi-events-qdev.h"
31+
#include "qapi/qmp/qdict.h"
3132
#include "qapi/qmp/qerror.h"
3233
#include "qapi/visitor.h"
3334
#include "qemu/error-report.h"
@@ -211,14 +212,14 @@ void device_listener_unregister(DeviceListener *listener)
211212
QTAILQ_REMOVE(&device_listeners, listener, link);
212213
}
213214

214-
bool qdev_should_hide_device(QemuOpts *opts, Error **errp)
215+
bool qdev_should_hide_device(const QDict *opts, bool from_json, Error **errp)
215216
{
216217
ERRP_GUARD();
217218
DeviceListener *listener;
218219

219220
QTAILQ_FOREACH(listener, &device_listeners, link) {
220221
if (listener->hide_device) {
221-
if (listener->hide_device(listener, opts, errp)) {
222+
if (listener->hide_device(listener, opts, from_json, errp)) {
222223
return true;
223224
} else if (*errp) {
224225
return false;
@@ -958,7 +959,7 @@ static void device_finalize(Object *obj)
958959
dev->canonical_path = NULL;
959960
}
960961

961-
qemu_opts_del(dev->opts);
962+
qobject_unref(dev->opts);
962963
g_free(dev->id);
963964
}
964965

hw/net/virtio-net.c

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -858,9 +858,11 @@ static void failover_add_primary(VirtIONet *n, Error **errp)
858858
return;
859859
}
860860

861-
dev = qdev_device_add(n->primary_opts, &err);
861+
dev = qdev_device_add_from_qdict(n->primary_opts,
862+
n->primary_opts_from_json,
863+
&err);
862864
if (err) {
863-
qemu_opts_del(n->primary_opts);
865+
qobject_unref(n->primary_opts);
864866
n->primary_opts = NULL;
865867
} else {
866868
object_unref(OBJECT(dev));
@@ -3287,15 +3289,17 @@ static void virtio_net_migration_state_notifier(Notifier *notifier, void *data)
32873289
}
32883290

32893291
static bool failover_hide_primary_device(DeviceListener *listener,
3290-
QemuOpts *device_opts, Error **errp)
3292+
const QDict *device_opts,
3293+
bool from_json,
3294+
Error **errp)
32913295
{
32923296
VirtIONet *n = container_of(listener, VirtIONet, primary_listener);
32933297
const char *standby_id;
32943298

32953299
if (!device_opts) {
32963300
return false;
32973301
}
3298-
standby_id = qemu_opt_get(device_opts, "failover_pair_id");
3302+
standby_id = qdict_get_try_str(device_opts, "failover_pair_id");
32993303
if (g_strcmp0(standby_id, n->netclient_name) != 0) {
33003304
return false;
33013305
}
@@ -3306,12 +3310,8 @@ static bool failover_hide_primary_device(DeviceListener *listener,
33063310
return false;
33073311
}
33083312

3309-
/*
3310-
* Having a weak reference here should be okay because a device can't be
3311-
* deleted while it's hidden. This will be replaced soon with a QDict that
3312-
* has a clearer ownership model.
3313-
*/
3314-
n->primary_opts = device_opts;
3313+
n->primary_opts = qdict_clone_shallow(device_opts);
3314+
n->primary_opts_from_json = from_json;
33153315

33163316
/* failover_primary_hidden is set during feature negotiation */
33173317
return qatomic_read(&n->failover_primary_hidden);
@@ -3502,8 +3502,11 @@ static void virtio_net_device_unrealize(DeviceState *dev)
35023502
g_free(n->vlans);
35033503

35043504
if (n->failover) {
3505+
qobject_unref(n->primary_opts);
35053506
device_listener_unregister(&n->primary_listener);
35063507
remove_migration_state_change_notifier(&n->migration_state);
3508+
} else {
3509+
assert(n->primary_opts == NULL);
35073510
}
35083511

35093512
max_queues = n->multiqueue ? n->max_queues : 1;

hw/vfio/pci.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,10 @@
2929
#include "hw/qdev-properties.h"
3030
#include "hw/qdev-properties-system.h"
3131
#include "migration/vmstate.h"
32+
#include "qapi/qmp/qdict.h"
3233
#include "qemu/error-report.h"
3334
#include "qemu/main-loop.h"
3435
#include "qemu/module.h"
35-
#include "qemu/option.h"
3636
#include "qemu/range.h"
3737
#include "qemu/units.h"
3838
#include "sysemu/kvm.h"
@@ -941,7 +941,7 @@ static void vfio_pci_size_rom(VFIOPCIDevice *vdev)
941941
}
942942

943943
if (vfio_opt_rom_in_denylist(vdev)) {
944-
if (dev->opts && qemu_opt_get(dev->opts, "rombar")) {
944+
if (dev->opts && qdict_haskey(dev->opts, "rombar")) {
945945
warn_report("Device at %s is known to cause system instability"
946946
" issues during option rom execution",
947947
vdev->vbasedev.name);

include/hw/qdev-core.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ struct DeviceState {
180180
char *canonical_path;
181181
bool realized;
182182
bool pending_deleted_event;
183-
QemuOpts *opts;
183+
QDict *opts;
184184
int hotplugged;
185185
bool allow_unplug_during_migration;
186186
BusState *parent_bus;
@@ -205,8 +205,8 @@ struct DeviceListener {
205205
* On errors, it returns false and errp is set. Device creation
206206
* should fail in this case.
207207
*/
208-
bool (*hide_device)(DeviceListener *listener, QemuOpts *device_opts,
209-
Error **errp);
208+
bool (*hide_device)(DeviceListener *listener, const QDict *device_opts,
209+
bool from_json, Error **errp);
210210
QTAILQ_ENTRY(DeviceListener) link;
211211
};
212212

@@ -835,13 +835,15 @@ void device_listener_unregister(DeviceListener *listener);
835835

836836
/**
837837
* @qdev_should_hide_device:
838-
* @opts: QemuOpts as passed on cmdline.
838+
* @opts: options QDict
839+
* @from_json: true if @opts entries are typed, false for all strings
840+
* @errp: pointer to error object
839841
*
840842
* Check if a device should be added.
841843
* When a device is added via qdev_device_add() this will be called,
842844
* and return if the device should be added now or not.
843845
*/
844-
bool qdev_should_hide_device(QemuOpts *opts, Error **errp);
846+
bool qdev_should_hide_device(const QDict *opts, bool from_json, Error **errp);
845847

846848
typedef enum MachineInitPhase {
847849
/* current_machine is NULL. */

include/hw/virtio/virtio-net.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,8 @@ struct VirtIONet {
209209
bool failover_primary_hidden;
210210
bool failover;
211211
DeviceListener primary_listener;
212-
QemuOpts *primary_opts;
212+
QDict *primary_opts;
213+
bool primary_opts_from_json;
213214
Notifier migration_state;
214215
VirtioNetRssData rss_data;
215216
struct NetRxPkt *rx_pkt;

include/monitor/qdev.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ void qmp_device_add(QDict *qdict, QObject **ret_data, Error **errp);
99

1010
int qdev_device_help(QemuOpts *opts);
1111
DeviceState *qdev_device_add(QemuOpts *opts, Error **errp);
12+
DeviceState *qdev_device_add_from_qdict(const QDict *opts,
13+
bool from_json, Error **errp);
1214

1315
/**
1416
* qdev_set_id: parent the device and set its id if provided.

softmmu/qdev-monitor.c

Lines changed: 31 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -196,34 +196,6 @@ static void qdev_print_devinfos(bool show_no_user)
196196
g_slist_free(list);
197197
}
198198

199-
static int set_property(void *opaque, const char *name, const char *value,
200-
Error **errp)
201-
{
202-
Object *obj = opaque;
203-
QString *val;
204-
Visitor *v;
205-
int ret;
206-
207-
if (strcmp(name, "driver") == 0)
208-
return 0;
209-
if (strcmp(name, "bus") == 0)
210-
return 0;
211-
212-
val = qstring_from_str(value);
213-
v = qobject_input_visitor_new_keyval(QOBJECT(val));
214-
215-
if (!object_property_set(obj, name, v, errp)) {
216-
ret = -1;
217-
goto out;
218-
}
219-
220-
ret = 0;
221-
out:
222-
visit_free(v);
223-
qobject_unref(val);
224-
return ret;
225-
}
226-
227199
static const char *find_typename_by_alias(const char *alias)
228200
{
229201
int i;
@@ -624,15 +596,17 @@ const char *qdev_set_id(DeviceState *dev, char *id, Error **errp)
624596
return prop->name;
625597
}
626598

627-
DeviceState *qdev_device_add(QemuOpts *opts, Error **errp)
599+
DeviceState *qdev_device_add_from_qdict(const QDict *opts,
600+
bool from_json, Error **errp)
628601
{
629602
ERRP_GUARD();
630603
DeviceClass *dc;
631604
const char *driver, *path;
605+
char *id;
632606
DeviceState *dev = NULL;
633607
BusState *bus = NULL;
634608

635-
driver = qemu_opt_get(opts, "driver");
609+
driver = qdict_get_try_str(opts, "driver");
636610
if (!driver) {
637611
error_setg(errp, QERR_MISSING_PARAMETER, "driver");
638612
return NULL;
@@ -645,7 +619,7 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **errp)
645619
}
646620

647621
/* find bus */
648-
path = qemu_opt_get(opts, "bus");
622+
path = qdict_get_try_str(opts, "bus");
649623
if (path != NULL) {
650624
bus = qbus_find(path, errp);
651625
if (!bus) {
@@ -665,12 +639,12 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **errp)
665639
}
666640
}
667641

668-
if (qemu_opt_get(opts, "failover_pair_id")) {
669-
if (!opts->id) {
642+
if (qdict_haskey(opts, "failover_pair_id")) {
643+
if (!qdict_haskey(opts, "id")) {
670644
error_setg(errp, "Device with failover_pair_id don't have id");
671645
return NULL;
672646
}
673-
if (qdev_should_hide_device(opts, errp)) {
647+
if (qdev_should_hide_device(opts, from_json, errp)) {
674648
if (bus && !qbus_is_hotpluggable(bus)) {
675649
error_setg(errp, QERR_BUS_NO_HOTPLUG, bus->name);
676650
}
@@ -711,18 +685,24 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **errp)
711685
* set dev's parent and register its id.
712686
* If it fails it means the id is already taken.
713687
*/
714-
if (!qdev_set_id(dev, g_strdup(qemu_opts_id(opts)), errp)) {
688+
id = g_strdup(qdict_get_try_str(opts, "id"));
689+
if (!qdev_set_id(dev, id, errp)) {
715690
goto err_del_dev;
716691
}
717692

718693
/* set properties */
719-
if (qemu_opt_foreach(opts, set_property, dev, errp)) {
694+
dev->opts = qdict_clone_shallow(opts);
695+
qdict_del(dev->opts, "driver");
696+
qdict_del(dev->opts, "bus");
697+
qdict_del(dev->opts, "id");
698+
699+
object_set_properties_from_keyval(&dev->parent_obj, dev->opts, from_json,
700+
errp);
701+
if (*errp) {
720702
goto err_del_dev;
721703
}
722704

723-
dev->opts = opts;
724705
if (!qdev_realize(DEVICE(dev), bus, errp)) {
725-
dev->opts = NULL;
726706
goto err_del_dev;
727707
}
728708
return dev;
@@ -735,6 +715,19 @@ DeviceState *qdev_device_add(QemuOpts *opts, Error **errp)
735715
return NULL;
736716
}
737717

718+
/* Takes ownership of @opts on success */
719+
DeviceState *qdev_device_add(QemuOpts *opts, Error **errp)
720+
{
721+
QDict *qdict = qemu_opts_to_qdict(opts, NULL);
722+
DeviceState *ret;
723+
724+
ret = qdev_device_add_from_qdict(qdict, false, errp);
725+
if (ret) {
726+
qemu_opts_del(opts);
727+
}
728+
qobject_unref(qdict);
729+
return ret;
730+
}
738731

739732
#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
740733
static void qbus_print(Monitor *mon, BusState *bus, int indent);

0 commit comments

Comments
 (0)