Skip to content

Commit 2678369

Browse files
committed
virtio_scsi: fix DMA cacheline issues for events
Current struct virtio_scsi_event_node layout has two problems: The event (DMA_FROM_DEVICE) and work (CPU-written via INIT_WORK/queue_work) fields share a cacheline. On non-cache-coherent platforms, CPU writes to work can corrupt device-written event data. If ARCH_DMA_MINALIGN is large enough, the 8 events in event_list share cachelines, triggering CONFIG_DMA_API_DEBUG warnings. Fix the corruption by moving event buffers to a separate array and aligning using __dma_from_device_group_begin()/end(). Suppress the (now spurious) DMA debug warnings using virtqueue_add_inbuf_cache_clean(). Message-ID: <8801aeef7576a155299f19b6887682dd3a272aba.1767601130.git.mst@redhat.com> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
1 parent 95c7b0a commit 2678369

1 file changed

Lines changed: 12 additions & 5 deletions

File tree

drivers/scsi/virtio_scsi.c

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include <scsi/scsi_tcq.h>
3030
#include <scsi/scsi_devinfo.h>
3131
#include <linux/seqlock.h>
32+
#include <linux/dma-mapping.h>
3233

3334
#include "sd.h"
3435

@@ -61,7 +62,7 @@ struct virtio_scsi_cmd {
6162

6263
struct virtio_scsi_event_node {
6364
struct virtio_scsi *vscsi;
64-
struct virtio_scsi_event event;
65+
struct virtio_scsi_event *event;
6566
struct work_struct work;
6667
};
6768

@@ -89,6 +90,11 @@ struct virtio_scsi {
8990

9091
struct virtio_scsi_vq ctrl_vq;
9192
struct virtio_scsi_vq event_vq;
93+
94+
__dma_from_device_group_begin();
95+
struct virtio_scsi_event events[VIRTIO_SCSI_EVENT_LEN];
96+
__dma_from_device_group_end();
97+
9298
struct virtio_scsi_vq req_vqs[];
9399
};
94100

@@ -237,12 +243,12 @@ static int virtscsi_kick_event(struct virtio_scsi *vscsi,
237243
unsigned long flags;
238244

239245
INIT_WORK(&event_node->work, virtscsi_handle_event);
240-
sg_init_one(&sg, &event_node->event, sizeof(struct virtio_scsi_event));
246+
sg_init_one(&sg, event_node->event, sizeof(struct virtio_scsi_event));
241247

242248
spin_lock_irqsave(&vscsi->event_vq.vq_lock, flags);
243249

244-
err = virtqueue_add_inbuf(vscsi->event_vq.vq, &sg, 1, event_node,
245-
GFP_ATOMIC);
250+
err = virtqueue_add_inbuf_cache_clean(vscsi->event_vq.vq, &sg, 1, event_node,
251+
GFP_ATOMIC);
246252
if (!err)
247253
virtqueue_kick(vscsi->event_vq.vq);
248254

@@ -257,6 +263,7 @@ static int virtscsi_kick_event_all(struct virtio_scsi *vscsi)
257263

258264
for (i = 0; i < VIRTIO_SCSI_EVENT_LEN; i++) {
259265
vscsi->event_list[i].vscsi = vscsi;
266+
vscsi->event_list[i].event = &vscsi->events[i];
260267
virtscsi_kick_event(vscsi, &vscsi->event_list[i]);
261268
}
262269

@@ -380,7 +387,7 @@ static void virtscsi_handle_event(struct work_struct *work)
380387
struct virtio_scsi_event_node *event_node =
381388
container_of(work, struct virtio_scsi_event_node, work);
382389
struct virtio_scsi *vscsi = event_node->vscsi;
383-
struct virtio_scsi_event *event = &event_node->event;
390+
struct virtio_scsi_event *event = event_node->event;
384391

385392
if (event->event &
386393
cpu_to_virtio32(vscsi->vdev, VIRTIO_SCSI_T_EVENTS_MISSED)) {

0 commit comments

Comments
 (0)