NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: kern/60144: virtio(4) cache coherence issue



At Thu, 2 Apr 2026 05:42:10 -0700,
Jason Thorpe wrote:
> If thatʼs the case, then Iʼd be concerned that thereʼs some other
> issue in the virtio code that could cause a problem on 68040 as
> well, because what it indicates is that, after the cache was
> invalidated, something accessed the relevant memory (or memory
> adjacent enough to the relevant memory) that caused a cache line
> fill to take place, thus putting data thatʼs about to be stale back
> into the cache.

Thank you for your suggestion.
I found it.

sys/dev/pci/virtio.c:
 1221 int
 1222 virtio_enqueue_commit(struct virtio_softc *sc, struct virtqueue *vq, int
 1222  slot,
 1223     bool notifynow)
 1224 {
  :
 1247         /*
 1248          * Prepare for `device->CPU' (host->guest) transfer
 1249          * into the buffer.  This must happen before we commit
 1250          * the vq->vq_avail->idx update to ensure we're not
 1251          * still using the buffer in case program-prior loads
 1252          * or stores in it get delayed past the store to
 1253          * vq->vq_avail->idx.
 1254          */
 1255         vq_sync_uring_all(sc, vq, BUS_DMASYNC_PREREAD);

   ^^-- Issues PREREAD.  On 68030/-current, it invalidates the data cache
        (containing vq->vq_used at least).

 1256
 1257         /* ensure payload is published, then avail idx */
 1258         vq_sync_aring_payload(sc, vq, BUS_DMASYNC_PREWRITE);
 1259         vq->vq_avail->idx = virtio_rw16(sc, vq->vq_avail_idx);
 1260         vq_sync_aring_header(sc, vq, BUS_DMASYNC_PREWRITE);
 1261         vq->vq_queued++;
 1262
 1263         /*
 1264          * Ensure we publish the avail idx _before_ we check whether
 1265          * the host needs to notified.
 1266          */
 1267         paravirt_membar_sync();
 1268
 1269         if (sc->sc_active_features & VIRTIO_F_RING_EVENT_IDX) {
 1270             vq_sync_uring_avail(sc, vq, BUS_DMASYNC_POSTREAD);
 1271             t = virtio_rw16(sc, *vq->vq_avail_event) + 1;
 1272             if ((uint16_t) (n - t) < (uint16_t) (n - o))
 1273                 sc->sc_ops->kick(sc, vq->vq_index);
 1274         } else {
 1275             vq_sync_uring_header(sc, vq, BUS_DMASYNC_POSTREAD);
 1276             flags = virtio_rw16(sc, vq->vq_used->flags);

   ^^-- Reads vq->vq_used region again(!!)
        See text below.

 1277             if (!(flags & VRING_USED_F_NO_NOTIFY))
 1278                 sc->sc_ops->kick(sc, vq->vq_index);

   ^^-- And then starts the virtio HW process.

 1279         }
 1280     }
 1281     mutex_exit(&vq->vq_aring_lock);
 1282
 1283     return 0;
 1284 }
 

vq->vq_used is shared region between the driver(CPU) and the device(HW),
and is defined as:

  struct vring_used {
        uint16_t flags;
        uint16_t idx;
        struct vring_used_elem ring[];
	/* trailed by uint16_t avail_event when VIRTIO_F_RING_EVENT_IDX */
  } __packed;

Reading vq->vq_used->flags here will also load the adjacent
vq->vq_used->idx into the cache (at least on the 68030 cache system).
This cached idx may still remain in the cache in the next interrupt
handler even though the virtio device has already updated idx in memory.
---
Tetsuya Isaki <isaki%pastel-flower.jp@localhost / isaki%NetBSD.org@localhost>



Home | Main Index | Thread Index | Old Index