NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: kern/60795: LFS userland cleaner and umount can enter deadlock
> Date: Sat, 26 Sep 2026 06:18:19 +0000 (UTC)
> From: clare%csel.org@localhost
>
> the umount process
>
> db{0}> bt /a ffff9bff0365e000
> trace: pid 21479 lid 21479 at 0xffffcc094754cc00
> sleepq_block() at netbsd:sleepq_block+0xea
> turnstile_block() at netbsd:turnstile_block+0x24b
> rw_vector_enter() at netbsd:rw_vector_enter+0x161
> lfs_prelock() at netbsd:lfs_prelock+0x86
> lfs_seglock() at netbsd:lfs_seglock+0x16
> [...]
>
> the lfs_cleanerd (userland) process
>
> db{0}> bt /a ffff9bff0365e400
> trace: pid 22182 lid 22182 at 0xffffcc09486d4950
> sleepq_block() at netbsd:sleepq_block+0xea
> cv_wait() at netbsd:cv_wait+0xca
> fstrans_start() at netbsd:fstrans_start+0x14c
> [...]
> bread() at netbsd:bread+0x18
> [...]
> lfs_rewrite_segments() at netbsd:lfs_rewrite_segments+0x3f6
> lfs_fcntl() at netbsd:lfs_fcntl+0x15b3
- unmount suspends fs, waits for seglock.
- lfs_rewrite_segments takes seglock, tries block I/O which waits for
concurrent suspension to resume.
*deadlock*
Perhaps lfs_fcntl, or lfs_rewrite_segments, should start a lazy
fstrans on the file system before trying to do any work on it, so it
isn't blocked by a concurrent suspension for unmount?
fstrans_start_lazy(ap->a_vp->v_mount);
...
fstrans_done(ap->a_vp->v_mount);
Maybe the fstrans should be started before testing IMNT_SHUTDOWN?
1897 /* Avoid locking a draining lock */
1898 if (ap->a_vp->v_mount->mnt_iflag & IMNT_UNMOUNT) {
1899 return ESHUTDOWN;
1900 }
https://nxr.NetBSD.org/xref/src/sys/ufs/lfs/lfs_vnops.c#1897
Side note: How does one ensure v_mount is stable at this point in the
face of concurrent revoke? Seems like we need to do something like
for (;;) {
mp = atomic_load_consume(&v->v_mount);
fstrans_start_lazy(mp);
if (__predict_true(mp == atomic_load_consume(&v->v_mount)))
break;
fstrans_done(mp);
}
vn_lock(vp, LK_SHARED|LK_WAIT);
/*
* mp may be lfs or deadfs if the vnode was concurrently
* revoked; check for concurrent revoke before proceeding.
*/
mutex_enter(vp->v_interlock);
error = vdead_check(vp, 0);
mutex_exit(vp->v_interlock);
if (error)
goto out;
... check IMNT_SHUTDOWN, do the rest of lfs_fcntl ...
out: VOP_UNLOCK(vp);
fstrans_done(mp);
...feeling some deja vu about this question, looks like I was
wondering something similar a couple years ago too:
https://mail-index.NetBSD.org/tech-kern/2024/10/01/msg029758.html
Actually, maybe it doesn't need to be a lazy fstrans at all; maybe the
ordinary fstrans in vn_lock is enough. But then maybe we can't hold
vn_lock across the whole fcntl operation for other reasons -- that
leads to a lot of code paths that might try to take vnode locks.
Home |
Main Index |
Thread Index |
Old Index