Skip to content

Commit bcede51

Browse files
stefanhaRHkevmw
authored andcommitted
virtio-scsi: handle ctrl virtqueue in main loop
Previously the ctrl virtqueue was handled in the AioContext where SCSI requests are processed. When IOThread Virtqueue Mapping was added things become more complicated because SCSI requests could run in other AioContexts. Simplify by handling the ctrl virtqueue in the main loop where reset operations can be performed. Note that BHs are still used canceling SCSI requests in their AioContexts but at least the mean loop activity doesn't need BHs anymore. Signed-off-by: Stefan Hajnoczi <[email protected]> Message-ID: <[email protected]> Tested-by: Peter Krempa <[email protected]> Signed-off-by: Kevin Wolf <[email protected]>
1 parent 2e8e18c commit bcede51

File tree

3 files changed

+33
-125
lines changed

3 files changed

+33
-125
lines changed

hw/scsi/virtio-scsi-dataplane.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,12 @@ void virtio_scsi_dataplane_setup(VirtIOSCSI *s, Error **errp)
7373
s->vq_aio_context[i] = ctx;
7474
}
7575
}
76+
77+
/*
78+
* Always handle the ctrl virtqueue in the main loop thread where device
79+
* resets can be performed.
80+
*/
81+
s->vq_aio_context[0] = qemu_get_aio_context();
7682
}
7783

7884
/* Context: BQL held */

hw/scsi/virtio-scsi.c

Lines changed: 27 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -319,115 +319,6 @@ static void virtio_scsi_cancel_notify(Notifier *notifier, void *data)
319319
g_free(n);
320320
}
321321

322-
static void virtio_scsi_do_one_tmf_bh(VirtIOSCSIReq *req)
323-
{
324-
VirtIOSCSI *s = req->dev;
325-
SCSIDevice *d = virtio_scsi_device_get(s, req->req.tmf.lun);
326-
BusChild *kid;
327-
int target;
328-
329-
switch (req->req.tmf.subtype) {
330-
case VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET:
331-
if (!d) {
332-
req->resp.tmf.response = VIRTIO_SCSI_S_BAD_TARGET;
333-
goto out;
334-
}
335-
if (d->lun != virtio_scsi_get_lun(req->req.tmf.lun)) {
336-
req->resp.tmf.response = VIRTIO_SCSI_S_INCORRECT_LUN;
337-
goto out;
338-
}
339-
qatomic_inc(&s->resetting);
340-
device_cold_reset(&d->qdev);
341-
qatomic_dec(&s->resetting);
342-
break;
343-
344-
case VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET:
345-
target = req->req.tmf.lun[1];
346-
qatomic_inc(&s->resetting);
347-
348-
rcu_read_lock();
349-
QTAILQ_FOREACH_RCU(kid, &s->bus.qbus.children, sibling) {
350-
SCSIDevice *d1 = SCSI_DEVICE(kid->child);
351-
if (d1->channel == 0 && d1->id == target) {
352-
device_cold_reset(&d1->qdev);
353-
}
354-
}
355-
rcu_read_unlock();
356-
357-
qatomic_dec(&s->resetting);
358-
break;
359-
360-
default:
361-
g_assert_not_reached();
362-
}
363-
364-
out:
365-
object_unref(OBJECT(d));
366-
virtio_scsi_complete_req(req, &s->ctrl_lock);
367-
}
368-
369-
/* Some TMFs must be processed from the main loop thread */
370-
static void virtio_scsi_do_tmf_bh(void *opaque)
371-
{
372-
VirtIOSCSI *s = opaque;
373-
QTAILQ_HEAD(, VirtIOSCSIReq) reqs = QTAILQ_HEAD_INITIALIZER(reqs);
374-
VirtIOSCSIReq *req;
375-
VirtIOSCSIReq *tmp;
376-
377-
GLOBAL_STATE_CODE();
378-
379-
WITH_QEMU_LOCK_GUARD(&s->tmf_bh_lock) {
380-
QTAILQ_FOREACH_SAFE(req, &s->tmf_bh_list, next, tmp) {
381-
QTAILQ_REMOVE(&s->tmf_bh_list, req, next);
382-
QTAILQ_INSERT_TAIL(&reqs, req, next);
383-
}
384-
385-
qemu_bh_delete(s->tmf_bh);
386-
s->tmf_bh = NULL;
387-
}
388-
389-
QTAILQ_FOREACH_SAFE(req, &reqs, next, tmp) {
390-
QTAILQ_REMOVE(&reqs, req, next);
391-
virtio_scsi_do_one_tmf_bh(req);
392-
}
393-
}
394-
395-
static void virtio_scsi_reset_tmf_bh(VirtIOSCSI *s)
396-
{
397-
VirtIOSCSIReq *req;
398-
VirtIOSCSIReq *tmp;
399-
400-
GLOBAL_STATE_CODE();
401-
402-
/* Called after ioeventfd has been stopped, so tmf_bh_lock is not needed */
403-
if (s->tmf_bh) {
404-
qemu_bh_delete(s->tmf_bh);
405-
s->tmf_bh = NULL;
406-
}
407-
408-
QTAILQ_FOREACH_SAFE(req, &s->tmf_bh_list, next, tmp) {
409-
QTAILQ_REMOVE(&s->tmf_bh_list, req, next);
410-
411-
/* SAM-6 6.3.2 Hard reset */
412-
req->resp.tmf.response = VIRTIO_SCSI_S_TARGET_FAILURE;
413-
virtio_scsi_complete_req(req, &req->dev->ctrl_lock);
414-
}
415-
}
416-
417-
static void virtio_scsi_defer_tmf_to_main_loop(VirtIOSCSIReq *req)
418-
{
419-
VirtIOSCSI *s = req->dev;
420-
421-
WITH_QEMU_LOCK_GUARD(&s->tmf_bh_lock) {
422-
QTAILQ_INSERT_TAIL(&s->tmf_bh_list, req, next);
423-
424-
if (!s->tmf_bh) {
425-
s->tmf_bh = qemu_bh_new(virtio_scsi_do_tmf_bh, s);
426-
qemu_bh_schedule(s->tmf_bh);
427-
}
428-
}
429-
}
430-
431322
static void virtio_scsi_tmf_cancel_req(VirtIOSCSIReq *tmf, SCSIRequest *r)
432323
{
433324
VirtIOSCSICancelNotifier *notifier;
@@ -627,11 +518,35 @@ static int virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req)
627518
break;
628519

629520
case VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET:
630-
case VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET:
631-
virtio_scsi_defer_tmf_to_main_loop(req);
632-
ret = -EINPROGRESS;
521+
if (!d) {
522+
goto fail;
523+
}
524+
if (d->lun != virtio_scsi_get_lun(req->req.tmf.lun)) {
525+
goto incorrect_lun;
526+
}
527+
qatomic_inc(&s->resetting);
528+
device_cold_reset(&d->qdev);
529+
qatomic_dec(&s->resetting);
633530
break;
634531

532+
case VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET: {
533+
BusChild *kid;
534+
int target = req->req.tmf.lun[1];
535+
qatomic_inc(&s->resetting);
536+
537+
rcu_read_lock();
538+
QTAILQ_FOREACH_RCU(kid, &s->bus.qbus.children, sibling) {
539+
SCSIDevice *d1 = SCSI_DEVICE(kid->child);
540+
if (d1->channel == 0 && d1->id == target) {
541+
device_cold_reset(&d1->qdev);
542+
}
543+
}
544+
rcu_read_unlock();
545+
546+
qatomic_dec(&s->resetting);
547+
break;
548+
}
549+
635550
case VIRTIO_SCSI_T_TMF_ABORT_TASK_SET:
636551
case VIRTIO_SCSI_T_TMF_CLEAR_TASK_SET: {
637552
g_autoptr(GHashTable) aio_contexts = g_hash_table_new(NULL, NULL);
@@ -1087,7 +1002,6 @@ static void virtio_scsi_reset(VirtIODevice *vdev)
10871002

10881003
assert(!s->dataplane_started);
10891004

1090-
virtio_scsi_reset_tmf_bh(s);
10911005
virtio_scsi_flush_defer_tmf_to_aio_context(s);
10921006

10931007
qatomic_inc(&s->resetting);
@@ -1402,10 +1316,8 @@ static void virtio_scsi_device_realize(DeviceState *dev, Error **errp)
14021316
VirtIOSCSI *s = VIRTIO_SCSI(dev);
14031317
Error *err = NULL;
14041318

1405-
QTAILQ_INIT(&s->tmf_bh_list);
14061319
qemu_mutex_init(&s->ctrl_lock);
14071320
qemu_mutex_init(&s->event_lock);
1408-
qemu_mutex_init(&s->tmf_bh_lock);
14091321

14101322
virtio_scsi_common_realize(dev,
14111323
virtio_scsi_handle_ctrl,
@@ -1445,11 +1357,9 @@ static void virtio_scsi_device_unrealize(DeviceState *dev)
14451357
{
14461358
VirtIOSCSI *s = VIRTIO_SCSI(dev);
14471359

1448-
virtio_scsi_reset_tmf_bh(s);
14491360
virtio_scsi_dataplane_cleanup(s);
14501361
qbus_set_hotplug_handler(BUS(&s->bus), NULL);
14511362
virtio_scsi_common_unrealize(dev);
1452-
qemu_mutex_destroy(&s->tmf_bh_lock);
14531363
qemu_mutex_destroy(&s->event_lock);
14541364
qemu_mutex_destroy(&s->ctrl_lock);
14551365
}

include/hw/virtio/virtio-scsi.h

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -90,14 +90,6 @@ struct VirtIOSCSI {
9090

9191
QemuMutex ctrl_lock; /* protects ctrl_vq */
9292

93-
/*
94-
* TMFs deferred to main loop BH. These fields are protected by
95-
* tmf_bh_lock.
96-
*/
97-
QemuMutex tmf_bh_lock;
98-
QEMUBH *tmf_bh;
99-
QTAILQ_HEAD(, VirtIOSCSIReq) tmf_bh_list;
100-
10193
/* Fields for dataplane below */
10294
AioContext **vq_aio_context; /* per-virtqueue AioContext pointer */
10395

0 commit comments

Comments
 (0)