Skip to content

Commit

Permalink
virtio_scsi: fix race on device removal
Browse files Browse the repository at this point in the history
We cancel event work on device removal, but an interrupt
could trigger immediately after this, and queue it
again.

To fix, set a flag.

Loosely based on patch by Paolo Bonzini

Signed-off-by: Paolo Bonzini <[email protected]>
Signed-off-by: Michael S. Tsirkin <[email protected]>
Signed-off-by: Rusty Russell <[email protected]>
  • Loading branch information
mstsirkin authored and rustyrussell committed Oct 14, 2014
1 parent 1fa5b2a commit e67423c
Showing 1 changed file with 10 additions and 1 deletion.
11 changes: 10 additions & 1 deletion drivers/scsi/virtio_scsi.c
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,9 @@ struct virtio_scsi {
/* CPU hotplug notifier */
struct notifier_block nb;

/* Protected by event_vq lock */
bool stop_events;

struct virtio_scsi_vq ctrl_vq;
struct virtio_scsi_vq event_vq;
struct virtio_scsi_vq req_vqs[];
Expand Down Expand Up @@ -303,6 +306,11 @@ static void virtscsi_cancel_event_work(struct virtio_scsi *vscsi)
{
int i;

/* Stop scheduling work before calling cancel_work_sync. */
spin_lock_irq(&vscsi->event_vq.vq_lock);
vscsi->stop_events = true;
spin_unlock_irq(&vscsi->event_vq.vq_lock);

for (i = 0; i < VIRTIO_SCSI_EVENT_LEN; i++)
cancel_work_sync(&vscsi->event_list[i].work);
}
Expand Down Expand Up @@ -390,7 +398,8 @@ static void virtscsi_complete_event(struct virtio_scsi *vscsi, void *buf)
{
struct virtio_scsi_event_node *event_node = buf;

queue_work(system_freezable_wq, &event_node->work);
if (!vscsi->stop_events)
queue_work(system_freezable_wq, &event_node->work);
}

static void virtscsi_event_done(struct virtqueue *vq)
Expand Down

0 comments on commit e67423c

Please sign in to comment.