From 0b22bd0ba0d500ab40e7673c591c594ec5447342 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Thu, 22 Oct 2009 15:06:06 +0200 Subject: [PATCH 1/2] virtio-pci: fix per-vq MSI-X request logic Commit f68d24082e22ccee3077d11aeb6dc5354f0ca7f1 in 2.6.32-rc1 broke requesting IRQs for per-VQ MSI-X vectors: - vector number was used instead of the vector itself - we try to request an IRQ for VQ which does not have a callback handler This is a regression that causes warnings in kernel log, potentially lower performance as we need to scan vq list, and might cause system failure if the interrupt requested is in fact needed by another system. This was not noticed earlier because in most cases we were falling back on shared interrupt for all vqs. The warnings often look like this: virtio-pci 0000:00:03.0: irq 26 for MSI/MSI-X virtio-pci 0000:00:03.0: irq 27 for MSI/MSI-X virtio-pci 0000:00:03.0: irq 28 for MSI/MSI-X IRQ handler type mismatch for IRQ 1 current handler: i8042 Pid: 2400, comm: modprobe Tainted: G W 2.6.32-rc3-11952-gf3ed8d8-dirty #1 Call Trace: [] ? __setup_irq+0x299/0x304 [] ? request_threaded_irq+0x144/0x1c1 [] ? vring_interrupt+0x0/0x30 [] ? vp_try_to_find_vqs+0x583/0x5c7 [] ? skb_recv_done+0x0/0x34 [virtio_net] [] ? vp_find_vqs+0x2d/0x83 [] ? vp_get+0x3c/0x4e [] ? virtnet_probe+0x2f1/0x428 [virtio_net] [] ? skb_recv_done+0x0/0x34 [virtio_net] [] ? skb_xmit_done+0x0/0x39 [virtio_net] [] ? sysfs_do_create_link+0xcb/0x116 [] ? vp_get_status+0x14/0x16 [] ? virtio_dev_probe+0xa9/0xc8 [] ? driver_probe_device+0x8d/0x128 [] ? __driver_attach+0x4f/0x6f [] ? __driver_attach+0x0/0x6f [] ? bus_for_each_dev+0x43/0x74 [] ? bus_add_driver+0xea/0x22d [] ? driver_register+0xa7/0x111 [] ? init+0x0/0xc [virtio_net] [] ? do_one_initcall+0x50/0x148 [] ? sys_init_module+0xc5/0x21a [] ? system_call_fastpath+0x16/0x1b virtio-pci 0000:00:03.0: irq 26 for MSI/MSI-X virtio-pci 0000:00:03.0: irq 27 for MSI/MSI-X Reported-by: Marcelo Tosatti Reported-by: Shirley Ma Signed-off-by: Michael S. Tsirkin Signed-off-by: Rusty Russell --- drivers/virtio/virtio_pci.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/drivers/virtio/virtio_pci.c b/drivers/virtio/virtio_pci.c index 4a1f1ebff7b..28d9cf7cf72 100644 --- a/drivers/virtio/virtio_pci.c +++ b/drivers/virtio/virtio_pci.c @@ -530,19 +530,22 @@ static int vp_try_to_find_vqs(struct virtio_device *vdev, unsigned nvqs, err = PTR_ERR(vqs[i]); goto error_find; } + + if (!vp_dev->per_vq_vectors || msix_vec == VIRTIO_MSI_NO_VECTOR) + continue; + /* allocate per-vq irq if available and necessary */ - if (vp_dev->per_vq_vectors) { - snprintf(vp_dev->msix_names[msix_vec], - sizeof *vp_dev->msix_names, - "%s-%s", - dev_name(&vp_dev->vdev.dev), names[i]); - err = request_irq(msix_vec, vring_interrupt, 0, - vp_dev->msix_names[msix_vec], - vqs[i]); - if (err) { - vp_del_vq(vqs[i]); - goto error_find; - } + snprintf(vp_dev->msix_names[msix_vec], + sizeof *vp_dev->msix_names, + "%s-%s", + dev_name(&vp_dev->vdev.dev), names[i]); + err = request_irq(vp_dev->msix_entries[msix_vec].vector, + vring_interrupt, 0, + vp_dev->msix_names[msix_vec], + vqs[i]); + if (err) { + vp_del_vq(vqs[i]); + goto error_find; } } return 0; From 2d61ba95034f1abbdec7729d52c740870a5eddb6 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Sun, 25 Oct 2009 15:28:53 +0200 Subject: [PATCH 2/2] virtio: order used ring after used index read On SMP guests, reads from the ring might bypass used index reads. This causes guest crashes because host writes to used index to signal ring data readiness. Fix this by inserting rmb before used ring reads. Signed-off-by: Michael S. Tsirkin Signed-off-by: Rusty Russell Cc: stable@kernel.org --- drivers/virtio/virtio_ring.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c index f5360058072..fbd2ecde93e 100644 --- a/drivers/virtio/virtio_ring.c +++ b/drivers/virtio/virtio_ring.c @@ -285,6 +285,9 @@ static void *vring_get_buf(struct virtqueue *_vq, unsigned int *len) return NULL; } + /* Only get used array entries after they have been exposed by host. */ + rmb(); + i = vq->vring.used->ring[vq->last_used_idx%vq->vring.num].id; *len = vq->vring.used->ring[vq->last_used_idx%vq->vring.num].len;