qbus: Make child devices links

Make qbus children show up as link<> properties.  There is no stable
addressing for qbus children so we use an unstable naming convention.

This is okay in QOM though because the composition name is expected to
be what's stable.

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
This commit is contained in:
Anthony Liguori 2011-12-23 15:34:39 -06:00 committed by Andreas Färber
parent f968fc6892
commit 0866aca1de
15 changed files with 159 additions and 83 deletions

View File

@ -284,7 +284,7 @@ static const VMStateDescription vmstate_acpi = {
static void acpi_piix_eject_slot(PIIX4PMState *s, unsigned slots)
{
DeviceState *qdev, *next;
BusChild *kid, *next;
BusState *bus = qdev_get_parent_bus(&s->dev.qdev);
int slot = ffs(slots) - 1;
bool slot_free = true;
@ -292,7 +292,8 @@ static void acpi_piix_eject_slot(PIIX4PMState *s, unsigned slots)
/* Mark request as complete */
s->pci0_status.down &= ~(1U << slot);
QTAILQ_FOREACH_SAFE(qdev, &bus->children, sibling, next) {
QTAILQ_FOREACH_SAFE(kid, &bus->children, sibling, next) {
DeviceState *qdev = kid->child;
PCIDevice *dev = PCI_DEVICE(qdev);
PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
if (PCI_SLOT(dev->devfn) == slot) {
@ -313,7 +314,7 @@ static void piix4_update_hotplug(PIIX4PMState *s)
{
PCIDevice *dev = &s->dev;
BusState *bus = qdev_get_parent_bus(&dev->qdev);
DeviceState *qdev, *next;
BusChild *kid, *next;
/* Execute any pending removes during reset */
while (s->pci0_status.down) {
@ -323,7 +324,8 @@ static void piix4_update_hotplug(PIIX4PMState *s)
s->pci0_hotplug_enable = ~0;
s->pci0_slot_device_present = 0;
QTAILQ_FOREACH_SAFE(qdev, &bus->children, sibling, next) {
QTAILQ_FOREACH_SAFE(kid, &bus->children, sibling, next) {
DeviceState *qdev = kid->child;
PCIDevice *pdev = PCI_DEVICE(qdev);
PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pdev);
int slot = PCI_SLOT(pdev->devfn);

View File

@ -86,11 +86,12 @@ int i2c_bus_busy(i2c_bus *bus)
/* TODO: Make this handle multiple masters. */
int i2c_start_transfer(i2c_bus *bus, uint8_t address, int recv)
{
DeviceState *qdev;
BusChild *kid;
I2CSlave *slave = NULL;
I2CSlaveClass *sc;
QTAILQ_FOREACH(qdev, &bus->qbus.children, sibling) {
QTAILQ_FOREACH(kid, &bus->qbus.children, sibling) {
DeviceState *qdev = kid->child;
I2CSlave *candidate = I2C_SLAVE_FROM_QDEV(qdev);
if (candidate->address == address) {
slave = candidate;

View File

@ -78,10 +78,11 @@ static int hda_codec_dev_exit(DeviceState *qdev)
HDACodecDevice *hda_codec_find(HDACodecBus *bus, uint32_t cad)
{
DeviceState *qdev;
BusChild *kid;
HDACodecDevice *cdev;
QTAILQ_FOREACH(qdev, &bus->qbus.children, sibling) {
QTAILQ_FOREACH(kid, &bus->qbus.children, sibling) {
DeviceState *qdev = kid->child;
cdev = DO_UPCAST(HDACodecDevice, qdev, qdev);
if (cdev->cad == cad) {
return cdev;
@ -483,10 +484,11 @@ static void intel_hda_parse_bdl(IntelHDAState *d, IntelHDAStream *st)
static void intel_hda_notify_codecs(IntelHDAState *d, uint32_t stream, bool running, bool output)
{
DeviceState *qdev;
BusChild *kid;
HDACodecDevice *cdev;
QTAILQ_FOREACH(qdev, &d->codecs.qbus.children, sibling) {
QTAILQ_FOREACH(kid, &d->codecs.qbus.children, sibling) {
DeviceState *qdev = kid->child;
HDACodecDeviceClass *cdc;
cdev = DO_UPCAST(HDACodecDevice, qdev, qdev);
@ -1105,15 +1107,16 @@ static const MemoryRegionOps intel_hda_mmio_ops = {
static void intel_hda_reset(DeviceState *dev)
{
BusChild *kid;
IntelHDAState *d = DO_UPCAST(IntelHDAState, pci.qdev, dev);
DeviceState *qdev;
HDACodecDevice *cdev;
intel_hda_regs_reset(d);
d->wall_base_ns = qemu_get_clock_ns(vm_clock);
/* reset codecs */
QTAILQ_FOREACH(qdev, &d->codecs.qbus.children, sibling) {
QTAILQ_FOREACH(kid, &d->codecs.qbus.children, sibling) {
DeviceState *qdev = kid->child;
cdev = DO_UPCAST(HDACodecDevice, qdev, qdev);
device_reset(DEVICE(cdev));
d->state_sts |= (1 << cdev->cad);

View File

@ -1677,9 +1677,10 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val)
}
if (val & LSI_SCNTL1_RST) {
if (!(s->sstat0 & LSI_SSTAT0_RST)) {
DeviceState *dev;
BusChild *kid;
QTAILQ_FOREACH(dev, &s->bus.qbus.children, sibling) {
QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
DeviceState *dev = kid->child;
device_reset(dev);
}
s->sstat0 |= LSI_SSTAT0_RST;

View File

@ -205,11 +205,12 @@ static void qbus_list_bus(DeviceState *dev)
static void qbus_list_dev(BusState *bus)
{
DeviceState *dev;
BusChild *kid;
const char *sep = " ";
error_printf("devices at \"%s\":", bus->name);
QTAILQ_FOREACH(dev, &bus->children, sibling) {
QTAILQ_FOREACH(kid, &bus->children, sibling) {
DeviceState *dev = kid->child;
error_printf("%s\"%s\"", sep, object_get_typename(OBJECT(dev)));
if (dev->id)
error_printf("/\"%s\"", dev->id);
@ -232,7 +233,7 @@ static BusState *qbus_find_bus(DeviceState *dev, char *elem)
static DeviceState *qbus_find_dev(BusState *bus, char *elem)
{
DeviceState *dev;
BusChild *kid;
/*
* try to match in order:
@ -240,17 +241,20 @@ static DeviceState *qbus_find_dev(BusState *bus, char *elem)
* (2) driver name
* (3) driver alias, if present
*/
QTAILQ_FOREACH(dev, &bus->children, sibling) {
QTAILQ_FOREACH(kid, &bus->children, sibling) {
DeviceState *dev = kid->child;
if (dev->id && strcmp(dev->id, elem) == 0) {
return dev;
}
}
QTAILQ_FOREACH(dev, &bus->children, sibling) {
QTAILQ_FOREACH(kid, &bus->children, sibling) {
DeviceState *dev = kid->child;
if (strcmp(object_get_typename(OBJECT(dev)), elem) == 0) {
return dev;
}
}
QTAILQ_FOREACH(dev, &bus->children, sibling) {
QTAILQ_FOREACH(kid, &bus->children, sibling) {
DeviceState *dev = kid->child;
DeviceClass *dc = DEVICE_GET_CLASS(dev);
if (qdev_class_has_alias(dc) &&
@ -264,7 +268,7 @@ static DeviceState *qbus_find_dev(BusState *bus, char *elem)
static BusState *qbus_find_recursive(BusState *bus, const char *name,
const char *bus_typename)
{
DeviceState *dev;
BusChild *kid;
BusState *child, *ret;
int match = 1;
@ -279,7 +283,8 @@ static BusState *qbus_find_recursive(BusState *bus, const char *name,
return bus;
}
QTAILQ_FOREACH(dev, &bus->children, sibling) {
QTAILQ_FOREACH(kid, &bus->children, sibling) {
DeviceState *dev = kid->child;
QLIST_FOREACH(child, &dev->child_bus, sibling) {
ret = qbus_find_recursive(child, name, bus_typename);
if (ret) {
@ -533,12 +538,13 @@ static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
static void qbus_print(Monitor *mon, BusState *bus, int indent)
{
struct DeviceState *dev;
BusChild *kid;
qdev_printf("bus: %s\n", bus->name);
indent += 2;
qdev_printf("type %s\n", object_get_typename(OBJECT(bus)));
QTAILQ_FOREACH(dev, &bus->children, sibling) {
QTAILQ_FOREACH(kid, &bus->children, sibling) {
DeviceState *dev = kid->child;
qdev_print(mon, dev, indent);
}
}

View File

@ -60,14 +60,48 @@ bool qdev_exists(const char *name)
static void qdev_property_add_legacy(DeviceState *dev, Property *prop,
Error **errp);
void qdev_set_parent_bus(DeviceState *dev, BusState *bus)
static void bus_remove_child(BusState *bus, DeviceState *child)
{
BusChild *kid;
QTAILQ_FOREACH(kid, &bus->children, sibling) {
if (kid->child == child) {
char name[32];
snprintf(name, sizeof(name), "child[%d]", kid->index);
QTAILQ_REMOVE(&bus->children, kid, sibling);
object_property_del(OBJECT(bus), name, NULL);
g_free(kid);
return;
}
}
}
static void bus_add_child(BusState *bus, DeviceState *child)
{
char name[32];
BusChild *kid = g_malloc0(sizeof(*kid));
if (qdev_hotplug) {
assert(bus->allow_hotplug);
}
kid->index = bus->max_index++;
kid->child = child;
QTAILQ_INSERT_HEAD(&bus->children, kid, sibling);
snprintf(name, sizeof(name), "child[%d]", kid->index);
object_property_add_link(OBJECT(bus), name,
object_get_typename(OBJECT(child)),
(Object **)&kid->child,
NULL);
}
void qdev_set_parent_bus(DeviceState *dev, BusState *bus)
{
dev->parent_bus = bus;
QTAILQ_INSERT_HEAD(&bus->children, dev, sibling);
bus_add_child(bus, dev);
}
/* Create a new device. This only initializes the device state structure
@ -310,7 +344,7 @@ BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
int qbus_walk_children(BusState *bus, qdev_walkerfn *devfn,
qbus_walkerfn *busfn, void *opaque)
{
DeviceState *dev;
BusChild *kid;
int err;
if (busfn) {
@ -320,8 +354,8 @@ int qbus_walk_children(BusState *bus, qdev_walkerfn *devfn,
}
}
QTAILQ_FOREACH(dev, &bus->children, sibling) {
err = qdev_walk_children(dev, devfn, busfn, opaque);
QTAILQ_FOREACH(kid, &bus->children, sibling) {
err = qdev_walk_children(kid->child, devfn, busfn, opaque);
if (err < 0) {
return err;
}
@ -355,12 +389,17 @@ int qdev_walk_children(DeviceState *dev, qdev_walkerfn *devfn,
DeviceState *qdev_find_recursive(BusState *bus, const char *id)
{
DeviceState *dev, *ret;
BusChild *kid;
DeviceState *ret;
BusState *child;
QTAILQ_FOREACH(dev, &bus->children, sibling) {
if (dev->id && strcmp(dev->id, id) == 0)
QTAILQ_FOREACH(kid, &bus->children, sibling) {
DeviceState *dev = kid->child;
if (dev->id && strcmp(dev->id, id) == 0) {
return dev;
}
QLIST_FOREACH(child, &dev->child_bus, sibling) {
ret = qdev_find_recursive(child, id);
if (ret) {
@ -431,9 +470,10 @@ BusState *qbus_create(const char *typename, DeviceState *parent, const char *nam
void qbus_free(BusState *bus)
{
DeviceState *dev;
BusChild *kid;
while ((dev = QTAILQ_FIRST(&bus->children)) != NULL) {
while ((kid = QTAILQ_FIRST(&bus->children)) != NULL) {
DeviceState *dev = kid->child;
qdev_free(dev);
}
if (bus->parent) {
@ -684,7 +724,9 @@ static void device_finalize(Object *obj)
qemu_opts_del(dev->opts);
}
}
QTAILQ_REMOVE(&dev->parent_bus->children, dev, sibling);
if (dev->parent_bus) {
bus_remove_child(dev->parent_bus, dev);
}
}
static void device_class_base_init(ObjectClass *class, void *data)

View File

@ -74,7 +74,6 @@ struct DeviceState {
qemu_irq *gpio_in;
QLIST_HEAD(, BusState) child_bus;
int num_child_bus;
QTAILQ_ENTRY(DeviceState) sibling;
int instance_id_alias;
int alias_required_for_version;
};
@ -100,6 +99,12 @@ struct BusClass {
int (*reset)(BusState *bus);
};
typedef struct BusChild {
DeviceState *child;
int index;
QTAILQ_ENTRY(BusChild) sibling;
} BusChild;
/**
* BusState:
* @qom_allocated: Indicates whether the object was allocated by QOM.
@ -113,7 +118,8 @@ struct BusState {
int allow_hotplug;
bool qom_allocated;
bool glib_allocated;
QTAILQ_HEAD(ChildrenHead, DeviceState) children;
int max_index;
QTAILQ_HEAD(ChildrenHead, BusChild) children;
QLIST_ENTRY(BusState) sibling;
};

View File

@ -315,20 +315,20 @@ VirtIOS390Device *s390_virtio_bus_find_vring(VirtIOS390Bus *bus,
ram_addr_t mem,
int *vq_num)
{
VirtIOS390Device *_dev;
DeviceState *dev;
BusChild *kid;
int i;
QTAILQ_FOREACH(dev, &bus->bus.children, sibling) {
_dev = (VirtIOS390Device *)dev;
QTAILQ_FOREACH(kid, &bus->bus.children, sibling) {
VirtIOS390Device *dev = (VirtIOS390Device *)kid->child;
for(i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) {
if (!virtio_queue_get_addr(_dev->vdev, i))
if (!virtio_queue_get_addr(dev->vdev, i))
break;
if (virtio_queue_get_addr(_dev->vdev, i) == mem) {
if (virtio_queue_get_addr(dev->vdev, i) == mem) {
if (vq_num) {
*vq_num = i;
}
return _dev;
return dev;
}
}
}
@ -339,13 +339,12 @@ VirtIOS390Device *s390_virtio_bus_find_vring(VirtIOS390Bus *bus,
/* Find a device by device descriptor location */
VirtIOS390Device *s390_virtio_bus_find_mem(VirtIOS390Bus *bus, ram_addr_t mem)
{
VirtIOS390Device *_dev;
DeviceState *dev;
BusChild *kid;
QTAILQ_FOREACH(dev, &bus->bus.children, sibling) {
_dev = (VirtIOS390Device *)dev;
if (_dev->dev_offs == mem) {
return _dev;
QTAILQ_FOREACH(kid, &bus->bus.children, sibling) {
VirtIOS390Device *dev = (VirtIOS390Device *)kid->child;
if (dev->dev_offs == mem) {
return dev;
}
}

View File

@ -315,7 +315,7 @@ static void store_lun(uint8_t *outbuf, int lun)
static bool scsi_target_emulate_report_luns(SCSITargetReq *r)
{
DeviceState *qdev;
BusChild *kid;
int i, len, n;
int channel, id;
bool found_lun0;
@ -330,7 +330,8 @@ static bool scsi_target_emulate_report_luns(SCSITargetReq *r)
id = r->req.dev->id;
found_lun0 = false;
n = 0;
QTAILQ_FOREACH(qdev, &r->req.bus->qbus.children, sibling) {
QTAILQ_FOREACH(kid, &r->req.bus->qbus.children, sibling) {
DeviceState *qdev = kid->child;
SCSIDevice *dev = SCSI_DEVICE(qdev);
if (dev->channel == channel && dev->id == id) {
@ -352,7 +353,8 @@ static bool scsi_target_emulate_report_luns(SCSITargetReq *r)
memset(r->buf, 0, len);
stl_be_p(&r->buf, n);
i = found_lun0 ? 8 : 16;
QTAILQ_FOREACH(qdev, &r->req.bus->qbus.children, sibling) {
QTAILQ_FOREACH(kid, &r->req.bus->qbus.children, sibling) {
DeviceState *qdev = kid->child;
SCSIDevice *dev = SCSI_DEVICE(qdev);
if (dev->channel == channel && dev->id == id) {
@ -1487,10 +1489,11 @@ static char *scsibus_get_fw_dev_path(DeviceState *dev)
SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int id, int lun)
{
DeviceState *qdev;
BusChild *kid;
SCSIDevice *target_dev = NULL;
QTAILQ_FOREACH_REVERSE(qdev, &bus->qbus.children, ChildrenHead, sibling) {
QTAILQ_FOREACH_REVERSE(kid, &bus->qbus.children, ChildrenHead, sibling) {
DeviceState *qdev = kid->child;
SCSIDevice *dev = SCSI_DEVICE(qdev);
if (dev->channel == channel && dev->id == id) {

View File

@ -35,17 +35,18 @@
static PCIDevice *find_dev(sPAPREnvironment *spapr,
uint64_t buid, uint32_t config_addr)
{
DeviceState *qdev;
int devfn = (config_addr >> 8) & 0xFF;
sPAPRPHBState *phb;
QLIST_FOREACH(phb, &spapr->phbs, list) {
BusChild *kid;
if (phb->buid != buid) {
continue;
}
QTAILQ_FOREACH(qdev, &phb->host_state.bus->qbus.children, sibling) {
PCIDevice *dev = (PCIDevice *)qdev;
QTAILQ_FOREACH(kid, &phb->host_state.bus->qbus.children, sibling) {
PCIDevice *dev = (PCIDevice *)kid->child;
if (dev->devfn == devfn) {
return dev;
}

View File

@ -62,11 +62,11 @@ static const TypeInfo spapr_vio_bus_info = {
VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg)
{
DeviceState *qdev;
BusChild *kid;
VIOsPAPRDevice *dev = NULL;
QTAILQ_FOREACH(qdev, &bus->bus.children, sibling) {
dev = (VIOsPAPRDevice *)qdev;
QTAILQ_FOREACH(kid, &bus->bus.children, sibling) {
dev = (VIOsPAPRDevice *)kid->child;
if (dev->reg == reg) {
return dev;
}
@ -606,7 +606,7 @@ static void rtas_quiesce(sPAPREnvironment *spapr, uint32_t token,
uint32_t nret, target_ulong rets)
{
VIOsPAPRBus *bus = spapr->vio_bus;
DeviceState *qdev;
BusChild *kid;
VIOsPAPRDevice *dev = NULL;
if (nargs != 0) {
@ -614,8 +614,8 @@ static void rtas_quiesce(sPAPREnvironment *spapr, uint32_t token,
return;
}
QTAILQ_FOREACH(qdev, &bus->bus.children, sibling) {
dev = (VIOsPAPRDevice *)qdev;
QTAILQ_FOREACH(kid, &bus->bus.children, sibling) {
dev = (VIOsPAPRDevice *)kid->child;
spapr_vio_quiesce_one(dev);
}
@ -625,7 +625,7 @@ static void rtas_quiesce(sPAPREnvironment *spapr, uint32_t token,
static VIOsPAPRDevice *reg_conflict(VIOsPAPRDevice *dev)
{
VIOsPAPRBus *bus = DO_UPCAST(VIOsPAPRBus, bus, dev->qdev.parent_bus);
DeviceState *qdev;
BusChild *kid;
VIOsPAPRDevice *other;
/*
@ -633,8 +633,8 @@ static VIOsPAPRDevice *reg_conflict(VIOsPAPRDevice *dev)
* using the requested address. We have to open code this because
* the given dev might already be in the list.
*/
QTAILQ_FOREACH(qdev, &bus->bus.children, sibling) {
other = DO_UPCAST(VIOsPAPRDevice, qdev, qdev);
QTAILQ_FOREACH(kid, &bus->bus.children, sibling) {
other = DO_UPCAST(VIOsPAPRDevice, qdev, kid->child);
if (other != dev && other->reg == dev->reg) {
return other;
@ -840,19 +840,20 @@ static int compare_reg(const void *p1, const void *p2)
int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt)
{
DeviceState *qdev, **qdevs;
BusChild *kid;
int i, num, ret = 0;
/* Count qdevs on the bus list */
num = 0;
QTAILQ_FOREACH(qdev, &bus->bus.children, sibling) {
QTAILQ_FOREACH(kid, &bus->bus.children, sibling) {
num++;
}
/* Copy out into an array of pointers */
qdevs = g_malloc(sizeof(qdev) * num);
num = 0;
QTAILQ_FOREACH(qdev, &bus->bus.children, sibling) {
qdevs[num++] = qdev;
QTAILQ_FOREACH(kid, &bus->bus.children, sibling) {
qdevs[num++] = kid->child;
}
/* Sort the array */

View File

@ -160,7 +160,7 @@ static TypeInfo spapr_vty_info = {
VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus)
{
VIOsPAPRDevice *sdev, *selected;
DeviceState *iter;
BusChild *kid;
/*
* To avoid the console bouncing around we want one VTY to be
@ -169,7 +169,9 @@ VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus)
*/
selected = NULL;
QTAILQ_FOREACH(iter, &bus->bus.children, sibling) {
QTAILQ_FOREACH(kid, &bus->bus.children, sibling) {
DeviceState *iter = kid->child;
/* Only look at VTY devices */
if (!object_dynamic_cast(OBJECT(iter), "spapr-vty")) {
continue;

View File

@ -30,10 +30,11 @@ static int ssi_slave_init(DeviceState *dev)
SSISlave *s = SSI_SLAVE(dev);
SSISlaveClass *ssc = SSI_SLAVE_GET_CLASS(s);
SSIBus *bus;
BusChild *kid;
bus = FROM_QBUS(SSIBus, qdev_get_parent_bus(dev));
if (QTAILQ_FIRST(&bus->qbus.children) != dev
|| QTAILQ_NEXT(dev, sibling) != NULL) {
kid = QTAILQ_FIRST(&bus->qbus.children);
if (kid->child != dev || QTAILQ_NEXT(kid, sibling) != NULL) {
hw_error("Too many devices on SSI bus");
}
@ -72,14 +73,15 @@ SSIBus *ssi_create_bus(DeviceState *parent, const char *name)
uint32_t ssi_transfer(SSIBus *bus, uint32_t val)
{
DeviceState *dev;
BusChild *kid;
SSISlave *slave;
SSISlaveClass *ssc;
dev = QTAILQ_FIRST(&bus->qbus.children);
if (!dev) {
kid = QTAILQ_FIRST(&bus->qbus.children);
if (!kid) {
return 0;
}
slave = SSI_SLAVE(dev);
slave = SSI_SLAVE(kid->child);
ssc = SSI_SLAVE_GET_CLASS(slave);
return ssc->transfer(slave, val);
}

View File

@ -275,7 +275,7 @@ static void virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req)
{
SCSIDevice *d = virtio_scsi_device_find(s, req->req.tmf->lun);
SCSIRequest *r, *next;
DeviceState *qdev;
BusChild *kid;
int target;
/* Here VIRTIO_SCSI_S_OK means "FUNCTION COMPLETE". */
@ -346,8 +346,8 @@ static void virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req)
case VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET:
target = req->req.tmf->lun[1];
s->resetting++;
QTAILQ_FOREACH(qdev, &s->bus.qbus.children, sibling) {
d = DO_UPCAST(SCSIDevice, qdev, qdev);
QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
d = DO_UPCAST(SCSIDevice, qdev, kid->child);
if (d->channel == 0 && d->id == target) {
qdev_reset_all(&d->qdev);
}

View File

@ -689,9 +689,16 @@ void object_property_del(Object *obj, const char *name, Error **errp)
{
ObjectProperty *prop = object_property_find(obj, name);
QTAILQ_REMOVE(&obj->properties, prop, node);
if (prop == NULL) {
error_set(errp, QERR_PROPERTY_NOT_FOUND, "", name);
return;
}
prop->release(obj, prop->name, prop->opaque);
if (prop->release) {
prop->release(obj, name, prop->opaque);
}
QTAILQ_REMOVE(&obj->properties, prop, node);
g_free(prop->name);
g_free(prop->type);