aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorRusty Russell <rusty@rustcorp.com.au>2008-02-04 23:50:04 -0500
committerRusty Russell <rusty@rustcorp.com.au>2008-02-04 07:50:04 -0500
commit81a8deab1ce3816c6a89e3429e234e7d3686da94 (patch)
treed62e7dcc09dddd0edc6d507e7b219c16e66d3b02 /drivers
parent6e5aa7efb27aec7e55b6463fa2c8db594c4226fa (diff)
virtio: handle interrupts after callbacks turned off
Anthony Liguori found double interrupt suppression in the virtio_net driver, triggered by two skb_recv_done's in a row. This is because virtio_ring's interrupt suppression is a best-effort optimization: it contains no synchronization so the host can miss it and still send interrupts. But it's certainly nicer for virtio users if calling disable_cb actually disables callbacks, so we check for the race in the interrupt routine. Note: SMP guests might require syncronization here, but since disable_cb is actually called from interrupt context, there has to be some form of synchronization before the next same interrupt handler is called (Linux guarantees that the same device's irq handler will never run simultanously on multiple CPUs). Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/virtio/virtio_ring.c7
1 files changed, 7 insertions, 0 deletions
diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index 9849babd6b37..9859213aa658 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -255,6 +255,13 @@ irqreturn_t vring_interrupt(int irq, void *_vq)
255 if (unlikely(vq->broken)) 255 if (unlikely(vq->broken))
256 return IRQ_HANDLED; 256 return IRQ_HANDLED;
257 257
258 /* Other side may have missed us turning off the interrupt,
259 * but we should preserve disable semantic for virtio users. */
260 if (unlikely(vq->vring.avail->flags & VRING_AVAIL_F_NO_INTERRUPT)) {
261 pr_debug("virtqueue interrupt after disable for %p\n", vq);
262 return IRQ_HANDLED;
263 }
264
258 pr_debug("virtqueue callback for %p (%p)\n", vq, vq->vq.callback); 265 pr_debug("virtqueue callback for %p (%p)\n", vq, vq->vq.callback);
259 if (vq->vq.callback) 266 if (vq->vq.callback)
260 vq->vq.callback(&vq->vq); 267 vq->vq.callback(&vq->vq);