mirror of https://github.com/xemu-project/xemu.git
qdev: device free fixups.
Two bug fixes: * When freeing a device we unregister even stuff we didn't register in the first place because the ->init() callback failed. * When freeing a device with child busses attached, we fail to zap the child bus (and the devices attached to it). Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
This commit is contained in:
parent
021f067459
commit
131ec1bd7d
27
hw/qdev.c
27
hw/qdev.c
|
@ -102,6 +102,7 @@ DeviceState *qdev_create(BusState *bus, const char *name)
|
||||||
qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
|
qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
|
||||||
qdev_prop_set_compat(dev);
|
qdev_prop_set_compat(dev);
|
||||||
QLIST_INSERT_HEAD(&bus->children, dev, sibling);
|
QLIST_INSERT_HEAD(&bus->children, dev, sibling);
|
||||||
|
dev->state = DEV_STATE_CREATED;
|
||||||
return dev;
|
return dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,6 +217,7 @@ int qdev_init(DeviceState *dev)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
assert(dev->state == DEV_STATE_CREATED);
|
||||||
rc = dev->info->init(dev, dev->info);
|
rc = dev->info->init(dev, dev->info);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -223,18 +225,27 @@ int qdev_init(DeviceState *dev)
|
||||||
qemu_register_reset(dev->info->reset, dev);
|
qemu_register_reset(dev->info->reset, dev);
|
||||||
if (dev->info->vmsd)
|
if (dev->info->vmsd)
|
||||||
vmstate_register(-1, dev->info->vmsd, dev);
|
vmstate_register(-1, dev->info->vmsd, dev);
|
||||||
|
dev->state = DEV_STATE_INITIALIZED;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Unlink device from bus and free the structure. */
|
/* Unlink device from bus and free the structure. */
|
||||||
void qdev_free(DeviceState *dev)
|
void qdev_free(DeviceState *dev)
|
||||||
{
|
{
|
||||||
|
BusState *bus;
|
||||||
|
|
||||||
|
if (dev->state == DEV_STATE_INITIALIZED) {
|
||||||
|
while (dev->num_child_bus) {
|
||||||
|
bus = QLIST_FIRST(&dev->child_bus);
|
||||||
|
qbus_free(bus);
|
||||||
|
}
|
||||||
#if 0 /* FIXME: need sane vmstate_unregister function */
|
#if 0 /* FIXME: need sane vmstate_unregister function */
|
||||||
if (dev->info->vmsd)
|
if (dev->info->vmsd)
|
||||||
vmstate_unregister(dev->info->vmsd, dev);
|
vmstate_unregister(dev->info->vmsd, dev);
|
||||||
#endif
|
#endif
|
||||||
if (dev->info->reset)
|
if (dev->info->reset)
|
||||||
qemu_unregister_reset(dev->info->reset, dev);
|
qemu_unregister_reset(dev->info->reset, dev);
|
||||||
|
}
|
||||||
QLIST_REMOVE(dev, sibling);
|
QLIST_REMOVE(dev, sibling);
|
||||||
qemu_free(dev);
|
qemu_free(dev);
|
||||||
}
|
}
|
||||||
|
@ -549,6 +560,22 @@ BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name)
|
||||||
return bus;
|
return bus;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void qbus_free(BusState *bus)
|
||||||
|
{
|
||||||
|
DeviceState *dev;
|
||||||
|
|
||||||
|
while ((dev = QLIST_FIRST(&bus->children)) != NULL) {
|
||||||
|
qdev_free(dev);
|
||||||
|
}
|
||||||
|
if (bus->parent) {
|
||||||
|
QLIST_REMOVE(bus, sibling);
|
||||||
|
bus->parent->num_child_bus--;
|
||||||
|
}
|
||||||
|
if (bus->qdev_allocated) {
|
||||||
|
qemu_free(bus);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
|
#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
|
||||||
static void qbus_print(Monitor *mon, BusState *bus, int indent);
|
static void qbus_print(Monitor *mon, BusState *bus, int indent);
|
||||||
|
|
||||||
|
|
|
@ -19,10 +19,16 @@ typedef struct BusState BusState;
|
||||||
|
|
||||||
typedef struct BusInfo BusInfo;
|
typedef struct BusInfo BusInfo;
|
||||||
|
|
||||||
|
enum DevState {
|
||||||
|
DEV_STATE_CREATED = 1,
|
||||||
|
DEV_STATE_INITIALIZED,
|
||||||
|
};
|
||||||
|
|
||||||
/* This structure should not be accessed directly. We declare it here
|
/* This structure should not be accessed directly. We declare it here
|
||||||
so that it can be embedded in individual device state structures. */
|
so that it can be embedded in individual device state structures. */
|
||||||
struct DeviceState {
|
struct DeviceState {
|
||||||
const char *id;
|
const char *id;
|
||||||
|
enum DevState state;
|
||||||
DeviceInfo *info;
|
DeviceInfo *info;
|
||||||
BusState *parent_bus;
|
BusState *parent_bus;
|
||||||
int num_gpio_out;
|
int num_gpio_out;
|
||||||
|
@ -149,6 +155,7 @@ BusState *qdev_get_parent_bus(DeviceState *dev);
|
||||||
void qbus_create_inplace(BusState *bus, BusInfo *info,
|
void qbus_create_inplace(BusState *bus, BusInfo *info,
|
||||||
DeviceState *parent, const char *name);
|
DeviceState *parent, const char *name);
|
||||||
BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name);
|
BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name);
|
||||||
|
void qbus_free(BusState *bus);
|
||||||
|
|
||||||
#define FROM_QBUS(type, dev) DO_UPCAST(type, qbus, dev)
|
#define FROM_QBUS(type, dev) DO_UPCAST(type, qbus, dev)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue