Hi, When traversing the mount list, the current mount point is locked with vfs_busy(). When a FOREACH_SAFE macro is used, the next pointer is not locked and could be freed by another process.
I remember that someone showed me a panic that ended in one of these functions, but I have lost the bug report. Anyway, the fix is easy in most places, do not use _SAFE as it is unsafe. In vfs_unmountall() the current pointer is actullay freed. I have added a comment and will think about it again after my other dounmount() fix has been commited. The problem has been introduced in 2013 with this commit message. > Change 'mountlist' from CIRCLEQ to TAILQ. Be paranoid and > use TAILQ_*_SAFE more than might be needed. ok? bluhm Index: kern/vfs_subr.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/kern/vfs_subr.c,v retrieving revision 1.256 diff -u -p -r1.256 vfs_subr.c --- kern/vfs_subr.c 10 Jan 2017 19:56:34 -0000 1.256 +++ kern/vfs_subr.c 12 Jan 2017 15:52:51 -0000 @@ -1251,12 +1251,12 @@ vprint(char *label, struct vnode *vp) void printlockedvnodes(void) { - struct mount *mp, *nmp; + struct mount *mp; struct vnode *vp; printf("Locked vnodes\n"); - TAILQ_FOREACH_SAFE(mp, &mountlist, mnt_list, nmp) { + TAILQ_FOREACH(mp, &mountlist, mnt_list) { if (vfs_busy(mp, VB_READ|VB_NOWAIT)) continue; LIST_FOREACH(vp, &mp->mnt_vnodelist, v_mntvnodes) { @@ -1574,8 +1574,9 @@ vfs_unmountall(void) retry: allerror = 0; TAILQ_FOREACH_REVERSE_SAFE(mp, &mountlist, mntlist, mnt_list, nmp) { - if ((vfs_busy(mp, VB_WRITE|VB_NOWAIT)) != 0) + if (vfs_busy(mp, VB_WRITE|VB_NOWAIT)) continue; + /* XXX Here is a race, the next pointer is not locked. */ if ((error = dounmount(mp, MNT_FORCE, curproc)) != 0) { printf("unmount of %s failed with error %d\n", mp->mnt_stat.f_mntonname, error); Index: kern/vfs_syscalls.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/kern/vfs_syscalls.c,v retrieving revision 1.267 diff -u -p -r1.267 vfs_syscalls.c --- kern/vfs_syscalls.c 10 Jan 2017 20:13:17 -0000 1.267 +++ kern/vfs_syscalls.c 12 Jan 2017 15:44:37 -0000 @@ -425,10 +425,10 @@ struct ctldebug debug0 = { "syncprt", &s int sys_sync(struct proc *p, void *v, register_t *retval) { - struct mount *mp, *nmp; + struct mount *mp; int asyncflag; - TAILQ_FOREACH_REVERSE_SAFE(mp, &mountlist, mntlist, mnt_list, nmp) { + TAILQ_FOREACH_REVERSE(mp, &mountlist, mntlist, mnt_list) { if (vfs_busy(mp, VB_READ|VB_NOWAIT)) continue; if ((mp->mnt_flag & MNT_RDONLY) == 0) { @@ -570,7 +570,7 @@ sys_getfsstat(struct proc *p, void *v, r syscallarg(size_t) bufsize; syscallarg(int) flags; } */ *uap = v; - struct mount *mp, *nmp; + struct mount *mp; struct statfs *sp; struct statfs *sfsp; size_t count, maxcount; @@ -580,7 +580,7 @@ sys_getfsstat(struct proc *p, void *v, r sfsp = SCARG(uap, buf); count = 0; - TAILQ_FOREACH_SAFE(mp, &mountlist, mnt_list, nmp) { + TAILQ_FOREACH(mp, &mountlist, mnt_list) { if (vfs_busy(mp, VB_READ|VB_NOWAIT)) continue; if (sfsp && count < maxcount) {