Patch-mainline: v5.14-rc7
Git-commit: 0e566c8f0f2e8325e35f6f97e13cde5356b41814
References: git-fixes
From: Parav Pandit <parav@nvidia.com>
Date: Wed, 21 Jul 2021 17:26:47 +0300
Subject: [PATCH] virtio: Protect vqs list access
VQs may be accessed to mark the device broken while they are
created/destroyed. Hence protect the access to the vqs list.
[ jgross: preserve kABI by using config_lock instead ]
Fixes: e2dcdfe95c0b ("virtio: virtio_break_device() to mark all virtqueues broken.")
Signed-off-by: Parav Pandit <parav@nvidia.com>
Link: https://lore.kernel.org/r/20210721142648.1525924-4-parav@nvidia.com
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Juergen Gross <jgross@suse.com>
---
drivers/virtio/virtio.c | 1 +
drivers/virtio/virtio_ring.c | 8 ++++++++
include/linux/virtio.h | 1 +
3 files changed, 10 insertions(+)
diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index d5934c2e5a89..c2aaa0eff6df 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -971,6 +971,7 @@ struct virtqueue *__vring_new_virtqueue(unsigned int index,
{
unsigned int i;
struct vring_virtqueue *vq;
+ unsigned long flags;
vq = kmalloc(sizeof(*vq) + vring.num * sizeof(struct vring_desc_state),
GFP_KERNEL);
@@ -993,7 +994,9 @@ struct virtqueue *__vring_new_virtqueue(unsigned int index,
vq->avail_flags_shadow = 0;
vq->avail_idx_shadow = 0;
vq->num_added = 0;
+ spin_lock_irqsave(&vdev->config_lock, flags);
list_add_tail(&vq->vq.list, &vdev->vqs);
+ spin_unlock_irqrestore(&vdev->config_lock, flags);
#ifdef DEBUG
vq->in_use = false;
vq->last_add_time_valid = false;
@@ -1159,12 +1162,15 @@ void vring_del_virtqueue(struct virtqueue *_vq)
void vring_del_virtqueue(struct virtqueue *_vq)
{
struct vring_virtqueue *vq = to_vvq(_vq);
+ unsigned long flags;
if (vq->we_own_ring) {
vring_free_queue(vq->vq.vdev, vq->queue_size_in_bytes,
vq->vring.desc, vq->queue_dma_addr);
}
+ spin_lock_irqsave(&vq->vq.vdev->config_lock, flags);
list_del(&_vq->list);
+ spin_unlock_irqrestore(&vq->vq.vdev->config_lock, flags);
kfree(vq);
}
EXPORT_SYMBOL_GPL(vring_del_virtqueue);
@@ -1223,13 +1229,16 @@ void virtio_break_device(struct virtio_device *dev)
void virtio_break_device(struct virtio_device *dev)
{
struct virtqueue *_vq;
+ unsigned long flags;
+ spin_lock_irqsave(&dev->config_lock, flags);
list_for_each_entry(_vq, &dev->vqs, list) {
struct vring_virtqueue *vq = to_vvq(_vq);
/* Pairs with READ_ONCE() in virtqueue_is_broken(). */
WRITE_ONCE(vq->broken, true);
}
+ spin_unlock_irqrestore(&dev->config_lock, flags);
}
EXPORT_SYMBOL_GPL(virtio_break_device);
--
2.35.3