mirror of
https://github.com/RhapsodiOS/RhapsodiOS.git
synced 2026-11-03 22:01:40 -07:00
[GH-ISSUE #66] nfs: loopback client loses O_APPEND data, returns ESTALE/EEXIST after local renames, and gives no SIGBUS past a truncated mapping #58
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#58
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 19, 2026).
Original GitHub issue: https://github.com/RhapsodiOS/RhapsodiOS/issues/66
Symptom
A loopback NFS mount fails several stress tests with only one client and only local processes:
nfsd/mountdon the same guest;/mnt1/nfsexpon UFS, published through NetInfo/exports;mount_nfs localhost:/mnt1/nfsexp /mnt/nfs.Results in two runs (
p4-nfs2on the issue58 kernel,p4-accepton the #60 kernel):fs append, wrong size:FAIL what=size off=0xc31f8/0xc3200. Four processesO_APPEND-write to one file on the same client, and the final size is short.fs tree/rename/link:unlink: ESTALE,open: ESTALE;open: EEXISTon a name the test had just removed;rename ... short-read.mmap trunc, no SIGBUS:FAIL reason=no-sigbus. Afterftruncateshrinks a mapped NFS file, touching the mapping past the new EOF does not fault.mmap regrow, stale data:what=zero off=0x5000(issue58 kernel), the #59 symptom on NFS. Recheck it on a kernel with the #59 fix.21 pass, 9 fail on the #60 kernel.
Reproduce
This uses branch
stress-phase4'svm/stress_fs.shNFS target, which does the NetInfo export, startsmountdandnfsd -tu -n 4, and mountslocalhost. Evidence:vm/work/ffsbench/runs/p4-nfs2/stress-0/andp4-accept/stress-0/(nfs.*.out).Where to look
O_APPENDpath (nfs_write). The offset is taken from cached attributes (np->n_size) without serialising against other local writers, or without refreshing the size.rename/unlink(nfs_lookup,cache_purgeon the client side).nfs_setattrwith a smaller size must callvnode_pager_setsize/the mapfs truncate the wayffs_truncatedoes;vno_flush_eoftreatment may be needed for NFS's mapped vnodes.Related: #41, #59. Found by stress suite phase 4's
--fs nfstarget.@raynorpat commented on GitHub (Oct 20, 2026):
Fixed on ffs-perf (merge
b37bece0dof branch issue-66, five commits).Not #71: every symptom reproduced on a kernel with the FSAVE workaround (ffs-perf
4fd6d07b6).Fixes:
161d8004f, O_APPEND size loss (client bug). NFS has no vnode lock (nfs_lock is vop_nolock), so two O_APPEND writers could read the same size and write at the same end.nfs_write(nfs_bio.c) now runs appenders one at a time, in arrival order (a ticket queue; its counters reuse a union member regular files don't use, sonfsnodestays 256 bytes).7aae56e80, no SIGBUS past a truncated mapping, and regrow stale data (client bug).nfs_setattr(nfs_vnops.c~727) calledmapfs_trunconly when MapFS had a window open, so a user mapping kept its pages past the new end and #59'svno_flush_eofnever ran for NFS. It now truncates the wayffs_truncatedoes.be0ad837d, EEXIST after a retried exclusive create (server side).nfsrv_createstores the client's verifier in atime, butufs_setattr(ufs_vnops.c~484) dropped the nanoseconds. A retry that missed the 64-entry reply cache then got EEXIST; 6-13 retries were seen per run.84e363177, EIO on create or mkdir in a removed directory (server quirk). UFS's ENOENT was mapped to IO bynfsrv_errmap(nfs_subs.c~2219). It now answers STALE.c0bc4e524, ESTALE is inherent, not a bug. Another process removes the object between a lookup and the call that uses its file handle; without vnode locks the client can't prevent that. The stress fs tests now end UNSUP withreason="ESTALE: object removed by another worker"(README updated).Verified on a kernel with these fixes (cksum 3567260633):
--fs nfsseed 4: 29 PASS, 1 UNSUP, 0 FAIL.check-fsandcheck-mmappass.Left open:
umount: /mnt/nfs: Device busyeven with-f. It did not recur in five later runs; cause unknown.treeusually ends UNSUP on NFS, so it says little about NFS.