NetBSD-Bugs archive

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

Re: kern/60182: ld@virtio sometimes hangs up



Can you please try the attached patch?
# HG changeset patch
# User Taylor R Campbell <riastradh%NetBSD.org@localhost>
# Date 1775664088 0
#      Wed Apr 08 16:01:28 2026 +0000
# Branch trunk
# Node ID e970b3afe31985e3cad7f63c90d2c597a34e3d31
# Parent  ae9c36e69b645ddfc9547c15bc10f8ee5f7d8f8d
# EXP-Topic riastradh-pr60182-ldvirtiopollsync
ld@virtio: Guard virtio_dequeue by virtio_vq_is_enqueued.

After triggering the DMA operation, or any previous virtio_dequeue,
virtio_vq_is_enqueued issues the necessary bus_dmamap_sync for
virtio_dequeue to observe any potential (new) result.

Normally this happens inside virtio(4) (in virtio_vq_intr) between
interrupt delivery and calling the virtqueue's done callback.  But
polling mode I/O operations (and dump operations) don't take that
path, so it is necessary to call virtio_vq_is_enqueued explicitly.

PR kern/60182: ld@virtio sometimes hangs up

diff -r ae9c36e69b64 -r e970b3afe319 sys/dev/pci/ld_virtio.c
--- a/sys/dev/pci/ld_virtio.c	Tue Feb 24 03:50:28 2026 +0000
+++ b/sys/dev/pci/ld_virtio.c	Wed Apr 08 16:01:28 2026 +0000
@@ -492,7 +492,8 @@ ld_virtio_info(struct ld_softc *ld, bool
 	while (sc->sc_sync_use != SYNC_FREE) {
 		if (poll) {
 			mutex_exit(&sc->sc_sync_wait_lock);
-			ld_virtio_vq_done(vq);
+			if (virtio_vq_is_enqueued(vq))
+				ld_virtio_vq_done(vq);
 			mutex_enter(&sc->sc_sync_wait_lock);
 			continue;
 		}
@@ -558,7 +559,8 @@ done:
 	while (sc->sc_sync_use != SYNC_DONE) {
 		if (poll) {
 			mutex_exit(&sc->sc_sync_wait_lock);
-			ld_virtio_vq_done(vq);
+			if (virtio_vq_is_enqueued(vq))
+				ld_virtio_vq_done(vq);
 			mutex_enter(&sc->sc_sync_wait_lock);
 			continue;
 		}
@@ -767,7 +769,8 @@ ld_virtio_dump(struct ld_softc *ld, void
 	r = virtio_enqueue_prep(vsc, vq, &slot);
 	if (r != 0) {
 		if (r == EAGAIN) { /* no free slot; dequeue first */
-			delay(100);
+			while (!virtio_vq_is_enqueued(vq))
+				delay(100);
 			ld_virtio_vq_done(vq);
 			r = virtio_enqueue_prep(vsc, vq, &slot);
 			if (r != 0)
@@ -820,6 +823,8 @@ ld_virtio_dump(struct ld_softc *ld, void
 	for ( ; ; ) {
 		int dslot;
 
+		while (!virtio_vq_is_enqueued(vq))
+			continue;
 		r = virtio_dequeue(vsc, vq, &dslot, NULL);
 		if (r != 0)
 			continue;
@@ -905,7 +910,8 @@ ld_virtio_flush(struct ld_softc *ld, boo
 	while (sc->sc_sync_use != SYNC_FREE) {
 		if (poll) {
 			mutex_exit(&sc->sc_sync_wait_lock);
-			ld_virtio_vq_done(vq);
+			if (virtio_vq_is_enqueued(vq))
+				ld_virtio_vq_done(vq);
 			mutex_enter(&sc->sc_sync_wait_lock);
 			continue;
 		}
@@ -953,7 +959,8 @@ ld_virtio_flush(struct ld_softc *ld, boo
 	while (sc->sc_sync_use != SYNC_DONE) {
 		if (poll) {
 			mutex_exit(&sc->sc_sync_wait_lock);
-			ld_virtio_vq_done(vq);
+			if (virtio_vq_is_enqueued(vq))
+				ld_virtio_vq_done(vq);
 			mutex_enter(&sc->sc_sync_wait_lock);
 			continue;
 		}


Home | Main Index | Thread Index | Old Index