#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"
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;
dev->canonical_path = NULL;
}
- qemu_opts_del(dev->opts);
+ qobject_unref(dev->opts);
g_free(dev->id);
}
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));
}
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;
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;
}
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);
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;
#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"
}
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);
char *canonical_path;
bool realized;
bool pending_deleted_event;
- QemuOpts *opts;
+ QDict *opts;
int hotplugged;
bool allow_unplug_during_migration;
BusState *parent_bus;
* 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;
};
/**
* @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
+ * @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. */
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;
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.
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;
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;
}
/* 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) {
}
}
- 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);
}
* 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;
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);