summaryrefslogtreecommitdiffstats
path: root/hw/core/bus.c
diff options
context:
space:
mode:
authorMaxim Levitsky2020-10-06 14:38:59 +0200
committerPaolo Bonzini2020-10-12 17:50:50 +0200
commit2d24a64661549732fc77f632928318dd52f5bce5 (patch)
tree3e7f20a87ef9c2368db3f988fe331279cacf236a /hw/core/bus.c
parentdevice_core: use drain_call_rcu in in qmp_device_add (diff)
downloadqemu-2d24a64661549732fc77f632928318dd52f5bce5.tar.gz
qemu-2d24a64661549732fc77f632928318dd52f5bce5.tar.xz
qemu-2d24a64661549732fc77f632928318dd52f5bce5.zip
device-core: use RCU for list of children of a bus
This fixes the race between device emulation code that tries to find a child device to dispatch the request to (e.g a scsi disk), and hotplug of a new device to that bus. Note that this doesn't convert all the readers of the list but only these that might go over that list without BQL held. This is a very small first step to make this code thread safe. Suggested-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Maxim Levitsky <mlevitsk@redhat.com> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> Message-Id: <20200913160259.32145-5-mlevitsk@redhat.com> [Use RCU_READ_LOCK_GUARD in more places, adjust testcase now that the delay in DEVICE_DELETED due to RCU is more consistent. - Paolo] Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Message-Id: <20201006123904.610658-9-mlevitsk@redhat.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'hw/core/bus.c')
-rw-r--r--hw/core/bus.c28
1 files changed, 17 insertions, 11 deletions
diff --git a/hw/core/bus.c b/hw/core/bus.c
index 6b987b6946..a0483859ae 100644
--- a/hw/core/bus.c
+++ b/hw/core/bus.c
@@ -49,12 +49,14 @@ int qbus_walk_children(BusState *bus,
}
}
- QTAILQ_FOREACH(kid, &bus->children, sibling) {
- err = qdev_walk_children(kid->child,
- pre_devfn, pre_busfn,
- post_devfn, post_busfn, opaque);
- if (err < 0) {
- return err;
+ WITH_RCU_READ_LOCK_GUARD() {
+ QTAILQ_FOREACH_RCU(kid, &bus->children, sibling) {
+ err = qdev_walk_children(kid->child,
+ pre_devfn, pre_busfn,
+ post_devfn, post_busfn, opaque);
+ if (err < 0) {
+ return err;
+ }
}
}
@@ -90,8 +92,10 @@ static void bus_reset_child_foreach(Object *obj, ResettableChildCallback cb,
BusState *bus = BUS(obj);
BusChild *kid;
- QTAILQ_FOREACH(kid, &bus->children, sibling) {
- cb(OBJECT(kid->child), opaque, type);
+ WITH_RCU_READ_LOCK_GUARD() {
+ QTAILQ_FOREACH_RCU(kid, &bus->children, sibling) {
+ cb(OBJECT(kid->child), opaque, type);
+ }
}
}
@@ -194,9 +198,11 @@ static void bus_set_realized(Object *obj, bool value, Error **errp)
/* TODO: recursive realization */
} else if (!value && bus->realized) {
- QTAILQ_FOREACH(kid, &bus->children, sibling) {
- DeviceState *dev = kid->child;
- qdev_unrealize(dev);
+ WITH_RCU_READ_LOCK_GUARD() {
+ QTAILQ_FOREACH_RCU(kid, &bus->children, sibling) {
+ DeviceState *dev = kid->child;
+ qdev_unrealize(dev);
+ }
}
if (bc->unrealize) {
bc->unrealize(bus);