mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-09 02:24:58 -06:00
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>
This commit is contained in:
parent
7bed89958b
commit
2d24a64661
5 changed files with 63 additions and 29 deletions
|
@ -400,7 +400,10 @@ static bool scsi_target_emulate_report_luns(SCSITargetReq *r)
|
|||
id = r->req.dev->id;
|
||||
found_lun0 = false;
|
||||
n = 0;
|
||||
QTAILQ_FOREACH(kid, &r->req.bus->qbus.children, sibling) {
|
||||
|
||||
RCU_READ_LOCK_GUARD();
|
||||
|
||||
QTAILQ_FOREACH_RCU(kid, &r->req.bus->qbus.children, sibling) {
|
||||
DeviceState *qdev = kid->child;
|
||||
SCSIDevice *dev = SCSI_DEVICE(qdev);
|
||||
|
||||
|
@ -421,7 +424,7 @@ static bool scsi_target_emulate_report_luns(SCSITargetReq *r)
|
|||
memset(r->buf, 0, len);
|
||||
stl_be_p(&r->buf[0], n);
|
||||
i = found_lun0 ? 8 : 16;
|
||||
QTAILQ_FOREACH(kid, &r->req.bus->qbus.children, sibling) {
|
||||
QTAILQ_FOREACH_RCU(kid, &r->req.bus->qbus.children, sibling) {
|
||||
DeviceState *qdev = kid->child;
|
||||
SCSIDevice *dev = SCSI_DEVICE(qdev);
|
||||
|
||||
|
@ -430,6 +433,7 @@ static bool scsi_target_emulate_report_luns(SCSITargetReq *r)
|
|||
i += 8;
|
||||
}
|
||||
}
|
||||
|
||||
assert(i == n + 8);
|
||||
r->len = len;
|
||||
return true;
|
||||
|
@ -1572,7 +1576,8 @@ SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int id, int lun)
|
|||
BusChild *kid;
|
||||
SCSIDevice *target_dev = NULL;
|
||||
|
||||
QTAILQ_FOREACH(kid, &bus->qbus.children, sibling) {
|
||||
RCU_READ_LOCK_GUARD();
|
||||
QTAILQ_FOREACH_RCU(kid, &bus->qbus.children, sibling) {
|
||||
DeviceState *qdev = kid->child;
|
||||
SCSIDevice *dev = SCSI_DEVICE(qdev);
|
||||
|
||||
|
@ -1591,6 +1596,7 @@ SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int id, int lun)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
return target_dev;
|
||||
}
|
||||
|
||||
|
|
|
@ -367,12 +367,16 @@ static int 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(kid, &s->bus.qbus.children, sibling) {
|
||||
|
||||
rcu_read_lock();
|
||||
QTAILQ_FOREACH_RCU(kid, &s->bus.qbus.children, sibling) {
|
||||
d = SCSI_DEVICE(kid->child);
|
||||
if (d->channel == 0 && d->id == target) {
|
||||
qdev_reset_all(&d->qdev);
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
s->resetting--;
|
||||
break;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue