virtio: Improve vq->broken access to avoid any compiler optimization
[ Upstream commit 60f0779862 ]
Currently vq->broken field is read by virtqueue_is_broken() in busy
loop in one context by virtnet_send_command().
vq->broken is set to true in other process context by
virtio_break_device(). Reader and writer are accessing it without any
synchronization. This may lead to a compiler optimization which may
result to optimize reading vq->broken only once.
Hence, force reading vq->broken on each invocation of
virtqueue_is_broken() and also force writing it so that such
update is visible to the readers.
It is a theoretical fix that isn't yet encountered in the field.
Signed-off-by: Parav Pandit <parav@nvidia.com>
Link: https://lore.kernel.org/r/20210721142648.1525924-2-parav@nvidia.com
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
f41c7462d8
commit
065a13c299
@@ -2268,7 +2268,7 @@ bool virtqueue_is_broken(struct virtqueue *_vq)
|
|||||||
{
|
{
|
||||||
struct vring_virtqueue *vq = to_vvq(_vq);
|
struct vring_virtqueue *vq = to_vvq(_vq);
|
||||||
|
|
||||||
return vq->broken;
|
return READ_ONCE(vq->broken);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(virtqueue_is_broken);
|
EXPORT_SYMBOL_GPL(virtqueue_is_broken);
|
||||||
|
|
||||||
@@ -2283,7 +2283,9 @@ void virtio_break_device(struct virtio_device *dev)
|
|||||||
spin_lock(&dev->vqs_list_lock);
|
spin_lock(&dev->vqs_list_lock);
|
||||||
list_for_each_entry(_vq, &dev->vqs, list) {
|
list_for_each_entry(_vq, &dev->vqs, list) {
|
||||||
struct vring_virtqueue *vq = to_vvq(_vq);
|
struct vring_virtqueue *vq = to_vvq(_vq);
|
||||||
vq->broken = true;
|
|
||||||
|
/* Pairs with READ_ONCE() in virtqueue_is_broken(). */
|
||||||
|
WRITE_ONCE(vq->broken, true);
|
||||||
}
|
}
|
||||||
spin_unlock(&dev->vqs_list_lock);
|
spin_unlock(&dev->vqs_list_lock);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user