#include "qemu/error-report.h"
#include "hw/hotplug.h"
#include "hw/boards.h"
+#include "hw/sysbus.h"
#include "qapi-event.h"
+#include "migration/migration.h"
-int qdev_hotplug = 0;
+bool qdev_hotplug = false;
static bool qdev_hot_added = false;
-static bool qdev_hot_removed = false;
+bool qdev_hot_removed = false;
const VMStateDescription *qdev_get_vmsd(DeviceState *dev)
{
void qdev_set_parent_bus(DeviceState *dev, BusState *bus)
{
+ bool replugging = dev->parent_bus != NULL;
+
+ if (replugging) {
+ /* Keep a reference to the device while it's not plugged into
+ * any bus, to avoid it potentially evaporating when it is
+ * dereffed in bus_remove_child().
+ */
+ object_ref(OBJECT(dev));
+ bus_remove_child(dev->parent_bus, dev);
+ object_unref(OBJECT(dev->parent_bus));
+ }
dev->parent_bus = bus;
object_ref(OBJECT(bus));
bus_add_child(bus, dev);
+ if (replugging) {
+ object_unref(OBJECT(dev));
+ }
}
/* Create a new device. This only initializes the device state
}
if (!bus) {
+ /* Assert that the device really is a SysBusDevice before
+ * we put it onto the sysbus. Non-sysbus devices which aren't
+ * being put onto a bus should be created with object_new(TYPE_FOO),
+ * not qdev_create(NULL, TYPE_FOO).
+ */
+ g_assert(object_dynamic_cast(OBJECT(dev), TYPE_SYS_BUS_DEVICE));
bus = sysbus_get_default();
}
return hotplug_ctrl;
}
-void qdev_unplug(DeviceState *dev, Error **errp)
-{
- DeviceClass *dc = DEVICE_GET_CLASS(dev);
- HotplugHandler *hotplug_ctrl;
- HotplugHandlerClass *hdc;
-
- if (dev->parent_bus && !qbus_is_hotpluggable(dev->parent_bus)) {
- error_setg(errp, QERR_BUS_NO_HOTPLUG, dev->parent_bus->name);
- return;
- }
-
- if (!dc->hotpluggable) {
- error_setg(errp, QERR_DEVICE_NO_HOTPLUG,
- object_get_typename(OBJECT(dev)));
- return;
- }
-
- qdev_hot_removed = true;
-
- hotplug_ctrl = qdev_get_hotplug_handler(dev);
- /* hotpluggable device MUST have HotplugHandler, if it doesn't
- * then something is very wrong with it */
- g_assert(hotplug_ctrl);
-
- /* If device supports async unplug just request it to be done,
- * otherwise just remove it synchronously */
- hdc = HOTPLUG_HANDLER_GET_CLASS(hotplug_ctrl);
- if (hdc->unplug_request) {
- hotplug_handler_unplug_request(hotplug_ctrl, dev, errp);
- } else {
- hotplug_handler_unplug(hotplug_ctrl, dev, errp);
- }
-}
-
static int qdev_reset_one(DeviceState *dev, void *opaque)
{
device_reset(dev);
assert(!dev->realized);
+ object_ref(OBJECT(dev));
object_property_set_bool(OBJECT(dev), true, "realized", &err);
if (err) {
error_reportf_err(err, "Initialization of device %s failed: ",
object_get_typename(OBJECT(dev)));
exit(1);
}
+ object_unref(OBJECT(dev));
}
void qdev_machine_creation_done(void)
* ok, initial machine setup is done, starting from now we can
* only create hotpluggable devices
*/
- qdev_hotplug = 1;
+ qdev_hotplug = true;
}
bool qdev_machine_modified(void)
HotplugHandler *hotplug_ctrl;
BusState *bus;
Error *local_err = NULL;
+ bool unattached_parent = false;
+ static int unattached_count;
+ int ret;
if (dev->hotplugged && !dc->hotpluggable) {
error_setg(errp, QERR_DEVICE_NO_HOTPLUG, object_get_typename(obj));
}
if (value && !dev->realized) {
+ ret = check_migratable(obj, &local_err);
+ if (ret < 0) {
+ goto fail;
+ }
+
if (!obj->parent) {
- static int unattached_count;
gchar *name = g_strdup_printf("device[%d]", unattached_count++);
object_property_add_child(container_get(qdev_get_machine(),
"/unattached"),
name, obj, &error_abort);
+ unattached_parent = true;
g_free(name);
}
+ hotplug_ctrl = qdev_get_hotplug_handler(dev);
+ if (hotplug_ctrl) {
+ hotplug_handler_pre_plug(hotplug_ctrl, dev, &local_err);
+ if (local_err != NULL) {
+ goto fail;
+ }
+ }
+
if (dc->realize) {
dc->realize(dev, &local_err);
}
DEVICE_LISTENER_CALL(realize, Forward, dev);
- hotplug_ctrl = qdev_get_hotplug_handler(dev);
if (hotplug_ctrl) {
hotplug_handler_plug(hotplug_ctrl, dev, &local_err);
}
}
if (qdev_get_vmsd(dev)) {
- vmstate_register_with_alias_id(dev, -1, qdev_get_vmsd(dev), dev,
- dev->instance_id_alias,
- dev->alias_required_for_version);
+ if (vmstate_register_with_alias_id(dev, -1, qdev_get_vmsd(dev), dev,
+ dev->instance_id_alias,
+ dev->alias_required_for_version,
+ &local_err) < 0) {
+ goto post_realize_fail;
+ }
}
QLIST_FOREACH(bus, &dev->child_bus, sibling) {
fail:
error_propagate(errp, local_err);
+ if (unattached_parent) {
+ object_unparent(OBJECT(dev));
+ unattached_count--;
+ }
}
static bool device_get_hotpluggable(Object *obj, Error **errp)
return dev->hotplugged;
}
-static void device_set_hotplugged(Object *obj, bool value, Error **err)
-{
- DeviceState *dev = DEVICE(obj);
-
- dev->hotplugged = value;
-}
-
static void device_initfn(Object *obj)
{
DeviceState *dev = DEVICE(obj);
object_property_add_bool(obj, "hotpluggable",
device_get_hotpluggable, NULL, NULL);
object_property_add_bool(obj, "hotplugged",
- device_get_hotplugged, device_set_hotplugged,
+ device_get_hotplugged, NULL,
&error_abort);
class = object_get_class(OBJECT(dev));