Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

+12 -5
+12 -5
drivers/scsi/virtio_scsi.c
··· 29 29 #include <scsi/scsi_tcq.h> 30 30 #include <scsi/scsi_devinfo.h> 31 31 #include <linux/seqlock.h> 32 + #include <linux/dma-mapping.h> 32 33 33 34 #include "sd.h" 34 35 ··· 62 61 63 62 struct virtio_scsi_event_node { 64 63 struct virtio_scsi *vscsi; 65 - struct virtio_scsi_event event; 64 + struct virtio_scsi_event *event; 66 65 struct work_struct work; 67 66 }; 68 67 ··· 90 89 91 90 struct virtio_scsi_vq ctrl_vq; 92 91 struct virtio_scsi_vq event_vq; 92 + 93 + __dma_from_device_group_begin(); 94 + struct virtio_scsi_event events[VIRTIO_SCSI_EVENT_LEN]; 95 + __dma_from_device_group_end(); 96 + 93 97 struct virtio_scsi_vq req_vqs[]; 94 98 }; 95 99 ··· 243 237 unsigned long flags; 244 238 245 239 INIT_WORK(&event_node->work, virtscsi_handle_event); 246 - sg_init_one(&sg, &event_node->event, sizeof(struct virtio_scsi_event)); 240 + sg_init_one(&sg, event_node->event, sizeof(struct virtio_scsi_event)); 247 241 248 242 spin_lock_irqsave(&vscsi->event_vq.vq_lock, flags); 249 243 250 - err = virtqueue_add_inbuf(vscsi->event_vq.vq, &sg, 1, event_node, 251 - GFP_ATOMIC); 244 + err = virtqueue_add_inbuf_cache_clean(vscsi->event_vq.vq, &sg, 1, event_node, 245 + GFP_ATOMIC); 252 246 if (!err) 253 247 virtqueue_kick(vscsi->event_vq.vq); 254 248 ··· 263 257 264 258 for (i = 0; i < VIRTIO_SCSI_EVENT_LEN; i++) { 265 259 vscsi->event_list[i].vscsi = vscsi; 260 + vscsi->event_list[i].event = &vscsi->events[i]; 266 261 virtscsi_kick_event(vscsi, &vscsi->event_list[i]); 267 262 } 268 263 ··· 387 380 struct virtio_scsi_event_node *event_node = 388 381 container_of(work, struct virtio_scsi_event_node, work); 389 382 struct virtio_scsi *vscsi = event_node->vscsi; 390 - struct virtio_scsi_event *event = &event_node->event; 383 + struct virtio_scsi_event *event = event_node->event; 391 384 392 385 if (event->event & 393 386 cpu_to_virtio32(vscsi->vdev, VIRTIO_SCSI_T_EVENTS_MISSED)) {