diff options
author | Stefan Fritsch <sf@cvs.openbsd.org> | 2014-06-15 11:18:40 +0000 |
---|---|---|
committer | Stefan Fritsch <sf@cvs.openbsd.org> | 2014-06-15 11:18:40 +0000 |
commit | d298da5848fd4950a16c8b5d273f299d3067eb32 (patch) | |
tree | 13f3297787fe52f1f75d9e100ee6af5ffc80489b /sys/dev | |
parent | db8fe6d3f09beef2aba9d0cfb56931f6d8aca034 (diff) |
Fix hang with virtio event_idx feature
When using the RING_EVENT_IDX feature, we must first call publish_avail_idx()
and then read VQ_AVAIL_EVENT(vq), or there is a race condition that may cause
us to miss that the host needs to be notified. This resulted in an occasional
hang of network in vio(4).
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/pci/virtio.c | 13 | ||||
-rw-r--r-- | sys/dev/pci/virtiovar.h | 3 |
2 files changed, 6 insertions, 10 deletions
diff --git a/sys/dev/pci/virtio.c b/sys/dev/pci/virtio.c index 933b7120467..72e8df48f23 100644 --- a/sys/dev/pci/virtio.c +++ b/sys/dev/pci/virtio.c @@ -1,4 +1,4 @@ -/* $OpenBSD: virtio.c,v 1.5 2013/03/10 21:58:02 sf Exp $ */ +/* $OpenBSD: virtio.c,v 1.6 2014/06/15 11:18:39 sf Exp $ */ /* $NetBSD: virtio.c,v 1.3 2011/11/02 23:05:52 njoly Exp $ */ /* @@ -277,7 +277,6 @@ virtio_init_vq(struct virtio_softc *sc, struct virtqueue *vq, int reinit) /* enqueue/dequeue status */ vq->vq_avail_idx = 0; - vq->vq_avail_signalled = 0xffff; vq->vq_used_idx = 0; vq_sync_aring(sc, vq, BUS_DMASYNC_PREWRITE); vq_sync_uring(sc, vq, BUS_DMASYNC_PREREAD); @@ -684,15 +683,13 @@ virtio_enqueue_commit(struct virtio_softc *sc, struct virtqueue *vq, notify: if (notifynow) { if (vq->vq_owner->sc_features & VIRTIO_F_RING_EVENT_IDX) { - uint16_t o = vq->vq_avail_signalled; + uint16_t o = vq->vq_avail->idx; uint16_t n = vq->vq_avail_idx; - uint16_t t = VQ_AVAIL_EVENT(vq) + 1; + uint16_t t; publish_avail_idx(sc, vq); - if ((o < n && o < t && t <= n) - || (o > n && (o < t || t <= n))) { + t = VQ_AVAIL_EVENT(vq) + 1; + if ((uint16_t)(n - t) < (uint16_t)(n - o)) sc->sc_ops->kick(sc, vq->vq_index); - vq->vq_avail_signalled = n; - } } else { publish_avail_idx(sc, vq); if (!(vq->vq_used->flags & VRING_USED_F_NO_NOTIFY)) diff --git a/sys/dev/pci/virtiovar.h b/sys/dev/pci/virtiovar.h index 5bd7f38c600..2e3094b01d3 100644 --- a/sys/dev/pci/virtiovar.h +++ b/sys/dev/pci/virtiovar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: virtiovar.h,v 1.4 2013/03/10 21:58:02 sf Exp $ */ +/* $OpenBSD: virtiovar.h,v 1.5 2014/06/15 11:18:39 sf Exp $ */ /* $NetBSD: virtiovar.h,v 1.1 2011/10/30 12:12:21 hannken Exp $ */ /* @@ -120,7 +120,6 @@ struct virtqueue { /* enqueue/dequeue status */ uint16_t vq_avail_idx; - uint16_t vq_avail_signalled; uint16_t vq_used_idx; int vq_queued; struct mutex *vq_aring_lock; |