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/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/softmmu/qdev-monitor.c b/softmmu/qdev-monitor.c index b7c2d69207..0b6833cc57 100644 --- a/softmmu/qdev-monitor.c +++ b/softmmu/qdev-monitor.c @@ -593,22 +593,35 @@ 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 { + g_free(id); + 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 +704,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)) {