There are currently three types of object_property_add_link() callers: 1. The link property may be set at any time. 2. The link property of a DeviceState instance may only be set before realize. 3. The link property may never be set, it is read-only.
Something similar can already be achieved with object_property_add_str()'s set() argument. Follow its example and add a set() argument to object_property_add_link(). Also provide default set() functions for case #1 and #2. Case #3 is covered by passing a NULL function pointer. Cc: "Andreas Färber" <afaer...@suse.de> Cc: Peter Crosthwaite <peter.crosthwa...@petalogix.com> Cc: Paolo Bonzini <pbonz...@redhat.com> Cc: Alexander Graf <ag...@suse.de> Cc: Anthony Liguori <aligu...@amazon.com> Cc: "Michael S. Tsirkin" <m...@redhat.com> Signed-off-by: Stefan Hajnoczi <stefa...@redhat.com> --- hw/core/qdev-properties.c | 12 ++++++++++++ hw/core/qdev.c | 4 +++- hw/dma/xilinx_axidma.c | 4 ++++ hw/net/xilinx_axienet.c | 4 ++++ hw/pcmcia/pxa2xx.c | 1 + hw/s390x/s390-virtio-bus.c | 1 + hw/s390x/virtio-ccw.c | 1 + hw/virtio/virtio-pci.c | 1 + hw/virtio/virtio-rng.c | 1 + include/hw/qdev-properties.h | 11 +++++++++++ include/qom/object.h | 12 ++++++++++++ qom/object.c | 18 ++++++++++++++++++ ui/console.c | 1 + 13 files changed, 70 insertions(+), 1 deletion(-) diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c index 77d0c66..2858f11 100644 --- a/hw/core/qdev-properties.c +++ b/hw/core/qdev-properties.c @@ -21,6 +21,18 @@ void qdev_prop_set_after_realize(DeviceState *dev, const char *name, } } +void qdev_prop_default_set_link(Object *obj, const char *name, + Object *val, Error **errp) +{ + DeviceState *dev = DEVICE(obj); + + if (dev->realized) { + error_setg(errp, "Attempt to set link property '%s' on device '%s' " + "(type '%s') after it was realized", + name, dev->id, object_get_typename(obj)); + } +} + void *qdev_get_prop_ptr(DeviceState *dev, Property *prop) { void *ptr = dev; diff --git a/hw/core/qdev.c b/hw/core/qdev.c index 273c737..c40fd8b 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -98,6 +98,7 @@ static void bus_add_child(BusState *bus, DeviceState *child) object_property_add_link(OBJECT(bus), name, object_get_typename(OBJECT(child)), (Object **)&kid->child, + NULL, /* read-only property */ false, /* return ownership on prop deletion */ NULL); } @@ -762,7 +763,7 @@ static void device_initfn(Object *obj) } while (class != object_class_by_name(TYPE_DEVICE)); object_property_add_link(OBJECT(dev), "parent_bus", TYPE_BUS, - (Object **)&dev->parent_bus, false, + (Object **)&dev->parent_bus, NULL, false, &error_abort); } @@ -884,6 +885,7 @@ static void qbus_initfn(Object *obj) object_property_add_link(obj, QDEV_HOTPLUG_HANDLER_PROPERTY, TYPE_HOTPLUG_HANDLER, (Object **)&bus->hotplug_handler, + object_property_default_set_link, true, NULL); } diff --git a/hw/dma/xilinx_axidma.c b/hw/dma/xilinx_axidma.c index cc5826d..a0da529 100644 --- a/hw/dma/xilinx_axidma.c +++ b/hw/dma/xilinx_axidma.c @@ -538,9 +538,11 @@ static void xilinx_axidma_realize(DeviceState *dev, Error **errp) object_property_add_link(OBJECT(ds), "dma", TYPE_XILINX_AXI_DMA, (Object **)&ds->dma, + object_property_default_set_link, true, &local_errp); object_property_add_link(OBJECT(cs), "dma", TYPE_XILINX_AXI_DMA, (Object **)&cs->dma, + object_property_default_set_link, true, &local_errp); if (local_errp) { goto xilinx_axidma_realize_fail; @@ -574,10 +576,12 @@ static void xilinx_axidma_init(Object *obj) object_property_add_link(obj, "axistream-connected", TYPE_STREAM_SLAVE, (Object **)&s->tx_data_dev, + qdev_prop_default_set_link, true, &error_abort); object_property_add_link(obj, "axistream-control-connected", TYPE_STREAM_SLAVE, (Object **)&s->tx_control_dev, + qdev_prop_default_set_link, true, &error_abort); object_initialize(&s->rx_data_dev, sizeof(s->rx_data_dev), diff --git a/hw/net/xilinx_axienet.c b/hw/net/xilinx_axienet.c index 385e059..4e139b7 100644 --- a/hw/net/xilinx_axienet.c +++ b/hw/net/xilinx_axienet.c @@ -946,9 +946,11 @@ static void xilinx_enet_realize(DeviceState *dev, Error **errp) object_property_add_link(OBJECT(ds), "enet", "xlnx.axi-ethernet", (Object **) &ds->enet, + object_property_default_set_link, true, &local_errp); object_property_add_link(OBJECT(cs), "enet", "xlnx.axi-ethernet", (Object **) &cs->enet, + object_property_default_set_link, true, &local_errp); if (local_errp) { goto xilinx_enet_realize_fail; @@ -985,10 +987,12 @@ static void xilinx_enet_init(Object *obj) object_property_add_link(obj, "axistream-connected", TYPE_STREAM_SLAVE, (Object **) &s->tx_data_dev, + qdev_prop_default_set_link, true, &error_abort); object_property_add_link(obj, "axistream-control-connected", TYPE_STREAM_SLAVE, (Object **) &s->tx_control_dev, + qdev_prop_default_set_link, true, &error_abort); object_initialize(&s->rx_data_dev, sizeof(s->rx_data_dev), diff --git a/hw/pcmcia/pxa2xx.c b/hw/pcmcia/pxa2xx.c index f55a806..ee113e1 100644 --- a/hw/pcmcia/pxa2xx.c +++ b/hw/pcmcia/pxa2xx.c @@ -199,6 +199,7 @@ static void pxa2xx_pcmcia_initfn(Object *obj) object_property_add_link(obj, "card", TYPE_PCMCIA_CARD, (Object **)&s->card, + NULL, /* read-only property */ false, /* don't unref on prop deletion */ NULL); } diff --git a/hw/s390x/s390-virtio-bus.c b/hw/s390x/s390-virtio-bus.c index 0c9ff92..027558b 100644 --- a/hw/s390x/s390-virtio-bus.c +++ b/hw/s390x/s390-virtio-bus.c @@ -314,6 +314,7 @@ static void s390_virtio_rng_instance_init(Object *obj) object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); object_property_add_link(obj, "rng", TYPE_RNG_BACKEND, (Object **)&dev->vdev.conf.rng, + qdev_prop_default_set_link, true, NULL); } diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index 2fe782b..53fa86e 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -1185,6 +1185,7 @@ static void virtio_ccw_rng_instance_init(Object *obj) object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); object_property_add_link(obj, "rng", TYPE_RNG_BACKEND, (Object **)&dev->vdev.conf.rng, + qdev_prop_default_set_link, true, NULL); } diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index e91de26..2b3c93f 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -1518,6 +1518,7 @@ static void virtio_rng_initfn(Object *obj) object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); object_property_add_link(obj, "rng", TYPE_RNG_BACKEND, (Object **)&dev->vdev.conf.rng, + qdev_prop_default_set_link, true, NULL); } diff --git a/hw/virtio/virtio-rng.c b/hw/virtio/virtio-rng.c index 54ae848..8efe0aa 100644 --- a/hw/virtio/virtio-rng.c +++ b/hw/virtio/virtio-rng.c @@ -224,6 +224,7 @@ static void virtio_rng_initfn(Object *obj) object_property_add_link(obj, "rng", TYPE_RNG_BACKEND, (Object **)&vrng->conf.rng, + qdev_prop_default_set_link, true, NULL); } diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h index 0c0babf..da35cb3 100644 --- a/include/hw/qdev-properties.h +++ b/include/hw/qdev-properties.h @@ -201,4 +201,15 @@ void qdev_property_add_static(DeviceState *dev, Property *prop, Error **errp); */ void qdev_prop_set_after_realize(DeviceState *dev, const char *name, Error **errp); + +/** + * @qdev_prop_default_set_link: + * + * Set the Error object if an attempt is made to set the link after realize. + * This function should be used as the set() argument to + * object_property_add_link(). + */ +void qdev_prop_default_set_link(Object *obj, const char *name, + Object *val, Error **errp); + #endif diff --git a/include/qom/object.h b/include/qom/object.h index 276d02e..fc25888 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -1060,11 +1060,21 @@ void object_property_add_child(Object *obj, const char *name, Object *child, Error **errp); /** + * object_property_default_set_link: + * + * The default implementation of the object_property_add_link() set callback + * function. It allows the link property to be set and never returns an error. + */ +void object_property_default_set_link(Object *, const char *, + Object *, Error **); + +/** * object_property_add_link: * @obj: the object to add a property to * @name: the name of the property * @type: the qobj type of the link * @child: a pointer to where the link object reference is stored + * @set: the setter or NULL if the property is read-only * @unref_on_release: whether to release the link object reference when * the property is deleted * @errp: if an error occurs, a pointer to an area to store the area @@ -1084,6 +1094,8 @@ void object_property_add_child(Object *obj, const char *name, */ void object_property_add_link(Object *obj, const char *name, const char *type, Object **child, + void (*set)(Object *obj, const char *name, + Object *val, Error **errp), bool unref_on_release, Error **errp); diff --git a/qom/object.c b/qom/object.c index 89c5358..c430286 100644 --- a/qom/object.c +++ b/qom/object.c @@ -1023,9 +1023,16 @@ out: g_free(type); } +void object_property_default_set_link(Object *obj, const char *name, + Object *val, Error **errp) +{ + /* Allow the link to be set, always */ +} + typedef struct { Object **child; bool unref_on_release; + void (*set)(Object *, const char *, Object *, Error **); } LinkProperty; static void object_get_link_property(Object *obj, Visitor *v, void *opaque, @@ -1100,6 +1107,14 @@ static void object_set_link_property(Object *obj, Visitor *v, void *opaque, return; } + if (prop->set) { + prop->set(obj, name, new_target, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + } + if (new_target) { object_ref(new_target); } @@ -1122,6 +1137,8 @@ static void object_release_link_property(Object *obj, const char *name, void object_property_add_link(Object *obj, const char *name, const char *type, Object **child, + void (*set)(Object *, const char *, + Object *, Error **), bool unref_on_release, Error **errp) { @@ -1130,6 +1147,7 @@ void object_property_add_link(Object *obj, const char *name, gchar *full_type; prop->child = child; + prop->set = set; prop->unref_on_release = unref_on_release; full_type = g_strdup_printf("link<%s>", type); diff --git a/ui/console.c b/ui/console.c index af2d617..6220654 100644 --- a/ui/console.c +++ b/ui/console.c @@ -1179,6 +1179,7 @@ static QemuConsole *new_console(DisplayState *ds, console_type_t console_type) s = QEMU_CONSOLE(obj); object_property_add_link(obj, "device", TYPE_DEVICE, (Object **)&s->device, + object_property_default_set_link, true, &local_err); if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) && -- 1.8.5.3