Index | Thread | Search

From:
Kirill A. Korinsky <kirill@korins.ky>
Subject:
sys/vfs: protect vfs_syncwait() bufhead traversal
To:
OpenBSD tech <tech@openbsd.org>
Date:
Mon, 03 Aug 2026 00:51:46 +0200

Download raw body.

Thread
  • Kirill A. Korinsky:

    sys/vfs: protect vfs_syncwait() bufhead traversal

tech@,

vfs_syncwait() traverses bufhead without splbio(), allowing I/O completion
to release the current buffer before LIST_FOREACH() reads its next pointer;
protect the traversal, drop the priority before bawrite(), then restart
because synchronous completion may release the acquired buffer.

Have I missed something?

Index: sys/kern/vfs_subr.c
===================================================================
RCS file: /home/cvs/src/sys/kern/vfs_subr.c,v
diff -u -p -r1.335 vfs_subr.c
--- sys/kern/vfs_subr.c	30 Jun 2026 14:04:03 -0000	1.335
+++ sys/kern/vfs_subr.c	2 Aug 2026 22:43:13 -0000
@@ -1839,7 +1839,9 @@ vfs_syncwait(struct proc *p, int verbose
 	/* Wait for sync to finish. */
 	dcount = 10000;
 	for (iter = 0; iter < 20; iter++) {
+ restart:
 		nbusy = 0;
+		s = splbio();
 		LIST_FOREACH(bp, &bufhead, b_list) {
 			if ((bp->b_flags & (B_BUSY|B_INVAL|B_READ)) == B_BUSY)
 				nbusy++;
@@ -1853,19 +1855,19 @@ vfs_syncwait(struct proc *p, int verbose
 			 * own with testing.. XXX
 			 */
 			if (bp->b_flags & B_DELWRI) {
-				s = splbio();
 				bufcache_take(bp);
 				buf_acquire(bp);
 				splx(s);
-				nbusy++;
 				bawrite(bp);
 				if (dcount-- <= 0) {
 					if (verbose)
 						printf("softdep ");
 					return 1;
 				}
+				goto restart;
 			}
 		}
+		splx(s);
 		if (nbusy == 0)
 			break;
 		if (verbose)


-- 
wbr, Kirill