mirror of
https://github.com/RhapsodiOS/RhapsodiOS.git
synced 2026-11-03 22:01:40 -07:00
[GH-ISSUE #78] nfs: unmount of the loopback NFS scratch mount is busy after a full stress run, and umount -f hangs #72
Labels
No labels
bug
documentation
enhancement
enhancement
good first issue
help wanted
help wanted
pull-request
question
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
github-starred/RhapsodiOS#72
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @raynorpat on GitHub (Oct 20, 2026).
Original GitHub issue: https://github.com/RhapsodiOS/RhapsodiOS/issues/78
In the combined retest of ffs-perf
f68d4802c, the first all-categoryffsbench stress --fs nfsrun ended withumountreturning "Device busy".umount -fthen hung until the harness killed it (vm/stress_fs.shlim 120).There is no earlier all-category NFS run to compare with. Earlier fs+mmap NFS runs unmounted cleanly.
Find what still holds the mount (leftover processes or cwd from the stress run, open or cached vnodes, a v_usecount leak in nfs from one of the categories), and why the forced unmount hangs instead of failing or succeeding.
Logs:
vm/work/ffsbench/runs/combined-nfsmsdos,vm/work/combined-retest/.@raynorpat commented on GitHub (Oct 21, 2026):
Fixed by
e9e67317fand249ceb8fb, merged into ffs-perf in5342b6d9e. Both causes were kernel bugs.What held the mount: a loopback NFS self-deadlock.
mapfs_io. When the mapfs map or file cache is full,remap_vnode(kern/mapfs.c~577) ormapfs_cache_trim(~937) frees the head of the shared LRU.vnode_pageout→nfs_asyncio("nfsaio",nfs_bio.c:1031), orvrele→nfs_inactive→nfs_vinvalbuf("vinvalbuf",nfs_node.c:265). The server is the nfsd itself, often holding the very file's lock.nfs_inactiveof a silly-renamed.nfsfile holds a root vnode reference, hence "Device busy".Fix
e9e67317f: a caller working on a local file never picks an NFS entry to free. For an NFS entry that still holds map space it frees only the map window (mapfs_window_free: no push, the object and its dirty pages stay cached).vmp_pushfalls back to the tracked dirty range when the window is gone.umount -f:
nfs_unmountreturned EBUSY on a busy root even with MNT_FORCE (nfs_vfsops.c:936). That was the second "Device busy". Fix249ceb8fbskips that check under MNT_FORCE.Verified on the fixed kernel (cksum 1353083474):
make check-fsandcheck-netpass on UFS and with-d /mnt/nfs.Left open:
dounmountcallsVFS_SYNC(MNT_WAIT)even under MNT_FORCE, and NFS requests can't be cancelled.mfs_files_maxuntil an NFS caller trims.@raynorpat commented on GitHub (Oct 22, 2026):
Reopened after the final retest of ffs-perf
966dc5243(kernel cksum 3569582201). Two problems remain.1. A kernel panic in
mapfs_sync, probably frome9e67317f.umount"Device busy", then a forced unmount succeeded. Shortly after, while msdosvmwas running,update(pid 45) faulted insync: trap 0xe, err=2, eip 0x1d0c98 (_mapfs_sync+0x94). That is the inlinedvmp_getdequeuing fromvm_info_queue, with a next pointer of 0x41140000.mapfs_window_freeleaves.mapfs_window_freedrops its locks and later re-enqueues the entry. It checksmapped,queuedanduse_count, but not that the entry is being freed, sovm_info_freecan run in the gap and a freed entry goes back on the queue.mapfs_syncalso reads an entry after unlocking without holding a reference.vm/work/final-retest/panic/(bt.txt,qback.txt,serial-final.log).2. The plain NFS unmount is still "Device busy" after a full all-category run. The forced unmount now succeeds. Something still holds a reference on the mount after the deadlock fix.
Runs:
vm/work/ffsbench/runs/final*.@raynorpat commented on GitHub (Oct 30, 2026):
The two problems from the reopen are fixed by
387d97d67anddc5864824, merged into ffs-perf in3d017f064. They share one root cause.Why the plain unmount was busy (line numbers from
966dc5243):unmap_vnodeholds a temporarymap_count++across a blockingVOP_GETATTRand push (mapfs.c:491-495, :510/:524).mapfs_truncdoes the same (:743/:749).vfs_vnops.c:285), but its close still decrements.t_sharedworker exits at once over NFS, one close takes another's temporary hold, and the count drops to -1 or -2.mapfs_cache_clearonly frees entries withmap_count == 0(:1028). These silly-renamed.nfsfiles therefore kept their vnode, and with it a root reference: root use 3, sonfs_unmountreturned EBUSY. gdbstub on the stock kernel showedmap -1andmap -2on two.nfsA…vnodes.dc5864824: the three temporary decrements never go below zero.Why
mapfs_syncpanicked:vm_info_free(:315-340) callsmapfs_uncache, which skipsmemfreewhenmap_count != 0, thenzfrees an entry that is still onvm_info_queue.e9e67317f;249ceb8fbonly letumount -fget past the busy root and reach it.mapfs_window_freere-enqueue was also a real hole, but it isn't what fired.387d97d67:vm_info_freedequeues the entry under the lock. If a holder still has it (use_count > 0), a neworphanbit leaves the free to that holder's lastvmp_put. Neithervmp_putnormapfs_window_freere-enqueues a dying entry.Verified on the kernel built from
dc5864824(cksum 1631582623):umount -f, then sync. It panicked in round 1 without the fix (vflush→vm_info_free) and passed 9/9 with it. A write+sync variant also passed 9/9.check-mmap -d /mnt/nfsthen a plain umount went from Device busy 3/3 to success 3/3.check-fs,check-mmapandcheck-vmpass on UFS and on/mnt/nfs.fs rwandproc ptyfailures, also seen on the stock kernel, plus a run-2 UFS phase that ran about 3x slow (likely host load).Left open:
unmap_vnodeacrossVOP_GETATTR,vmp_invalidate, andmapfs_syncbetween its unlock andvmp_get) can still touch a freed entry if a forced unmount races them.vmp_putthat dropsuse_countto 0:vm_info_freecan free the entry in the short gap before thatvmp_putreleasesvmp->lock.