[GH-ISSUE #74] ext2fs: check ext2fs_valloc for the inode-reuse vnode bug fixed in ffs by #67 #67

Closed
opened 2026-11-03 22:03:40 -07:00 by gitea-mirror · 1 comment
Owner

Originally created by @raynorpat on GitHub (Oct 20, 2026).
Original GitHub issue: https://github.com/RhapsodiOS/RhapsodiOS/issues/74

#67 (fix 0a354086c) showed that ufs_inactive frees an inode in the bitmap before the vnode is recycled, so ffs_valloc could reallocate the inode and get back the old fifo's or device's vnode, keeping fifo/spec ops on a new regular file.

ext2fs_valloc (bsd/ext2fs/ext2fs_alloc.c ~158, via ext2fs_vget_alloc) and ext2fs_inactive have the same shape and were not checked. Determine whether the same reuse can happen there (fifo or device node deleted, new file created in the same directory), reproduce it if so, and apply the equivalent fix.

Found by the #67 investigation.

Originally created by @raynorpat on GitHub (Oct 20, 2026). Original GitHub issue: https://github.com/RhapsodiOS/RhapsodiOS/issues/74 #67 (fix 0a354086c) showed that `ufs_inactive` frees an inode in the bitmap before the vnode is recycled, so `ffs_valloc` could reallocate the inode and get back the old fifo's or device's vnode, keeping fifo/spec ops on a new regular file. `ext2fs_valloc` (`bsd/ext2fs/ext2fs_alloc.c` ~158, via `ext2fs_vget_alloc`) and `ext2fs_inactive` have the same shape and were not checked. Determine whether the same reuse can happen there (fifo or device node deleted, new file created in the same directory), reproduce it if so, and apply the equivalent fix. Found by the #67 investigation.
Author
Owner

@raynorpat commented on GitHub (Oct 20, 2026):

Real on ext2 too. Fixed by 9b61bbd22, merged into ffs-perf in 10295357f.

Root cause (same shape as #67):

  • ext2fs_inactive (ext2fs_inode.c :118) frees the inode with VOP_VFREE, then calls VOP_UPDATE (:124), which can sleep, before it unlocks and recycles the vnode (:128-134).
  • In that gap ext2fs_valloc can reallocate the inode. ext2fs_vget_alloc (ext2fs_vfsops.c :1594-1601) finds the old vnode in the hash, and vget takes a use count, so vrecycle leaves the vnode alone.
  • An old fifo's or device's vnode keeps those ops and its v_un. The new regular file's write then goes vn_write → mapfs_io → vmp_get on the stale fifo data and spins.

Reproducer: vm/work/issue-74/reuse.c on a fresh WSL-mke2fs volume. Each process loops: mkfifo, open nonblocking, unlink, close (closing after the unlink is what opens the race), then create a regular file, write and read back 4 KB, unlink.

  • On the base kernel (#67 fix, cksum 606865771) the guest hung in 2 of 2 runs within 2-5 minutes.
  • In both hangs, gdbstub showed a writer in vmp_get whose new regular file's vnode had v_op == ext2fs_fifoop_p.

Fix: the same as the ffs one. If the vnode ext2fs_vget_alloc returns doesn't have ext2fs_vnodeop_p, vput it and look the inode up again. Its dtime is already set, so ext2fs_inactive recycles it.

Verified on the fixed kernel (cksum 385197266):

  • reuse.c at 8 and 16 processes for 1200 s each passed: 33,835 and 18,307 iterations, WSL e2fsck -fn clean.
  • ffsbench stress --fs ext2 passed fs 12/12 and mmap 18/18, fsck clean.
<!-- gh-comment-id:6292150904 --> @raynorpat commented on GitHub (Oct 20, 2026): Real on ext2 too. Fixed by 9b61bbd22, merged into ffs-perf in 10295357f. **Root cause** (same shape as #67): - `ext2fs_inactive` (`ext2fs_inode.c` :118) frees the inode with `VOP_VFREE`, then calls `VOP_UPDATE` (:124), which can sleep, before it unlocks and recycles the vnode (:128-134). - In that gap `ext2fs_valloc` can reallocate the inode. `ext2fs_vget_alloc` (`ext2fs_vfsops.c` :1594-1601) finds the old vnode in the hash, and `vget` takes a use count, so `vrecycle` leaves the vnode alone. - An old fifo's or device's vnode keeps those ops and its `v_un`. The new regular file's write then goes `vn_write` → `mapfs_io` → `vmp_get` on the stale fifo data and spins. **Reproducer:** `vm/work/issue-74/reuse.c` on a fresh WSL-mke2fs volume. Each process loops: mkfifo, open nonblocking, unlink, close (closing after the unlink is what opens the race), then create a regular file, write and read back 4 KB, unlink. - On the base kernel (#67 fix, cksum 606865771) the guest hung in 2 of 2 runs within 2-5 minutes. - In both hangs, gdbstub showed a writer in `vmp_get` whose new regular file's vnode had `v_op == ext2fs_fifoop_p`. **Fix:** the same as the ffs one. If the vnode `ext2fs_vget_alloc` returns doesn't have `ext2fs_vnodeop_p`, `vput` it and look the inode up again. Its dtime is already set, so `ext2fs_inactive` recycles it. **Verified** on the fixed kernel (cksum 385197266): - `reuse.c` at 8 and 16 processes for 1200 s each passed: 33,835 and 18,307 iterations, WSL `e2fsck -fn` clean. - `ffsbench stress --fs ext2` passed fs 12/12 and mmap 18/18, fsck clean.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
github-starred/RhapsodiOS#67
No description provided.