Download raw body.
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
sys/vfs: protect vfs_syncwait() bufhead traversal