[Bug 297976] Panic in the kern_symlinkat()->ffs_truncate()->flush_newblk_dep(): flush_newblk_dep: Bad newblk
Date: Sun, 04 Oct 2026 19:27:32 UTC
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=297976
--- Comment #5 from commit-hook@FreeBSD.org ---
A commit in branch main references this bug:
URL:
https://cgit.FreeBSD.org/src/commit/?id=479c98287ee63496bd44d8d64d63c9ec16323e33
commit 479c98287ee63496bd44d8d64d63c9ec16323e33
Author: Maxim Sobolev <sobomax@FreeBSD.org>
AuthorDate: 2026-10-04 19:24:39 +0000
Commit: Maxim Sobolev <sobomax@FreeBSD.org>
CommitDate: 2026-10-04 19:26:41 +0000
ffs: revalidate mkdir dependencies after vnode lookup
flush_pagedep_deps() drops the soft updates lock while obtaining the
vnode of a newly created directory with get_parent_vp(). The
MKDIR_BODY dependency may complete during this interval, invalidating
the diradd selected before the lock was dropped.
Once the directory's allocdirect is retired, the lookup of its first
block by block number in flush_newblk_dep() can find an older
dependency for a previous use of the same physical block. The newblk
hash is not unique by block number: when ffs_reallocblks() relocates a
cluster, the completed allocindirs of the old blocks stay on the
indirdep's ir_completehd until the indirect block pointer in the inode
is written, while the old blocks are already free and may be allocated
to a new directory. flush_newblk_dep() then finds a D_ALLOCINDIR where
it expects a D_ALLOCDIRECT and panics with "flush_newblk_dep: Bad
newblk".
Retain the vnode returned by get_parent_vp(), reacquire the soft
updates lock, and restart dependency selection. Use the retained vnode
only when the newly selected MKDIR_BODY dependency refers to the same
inode.
Enter flush_newblk_dep() with the soft updates lock held and pass it
the associated diradd. Recheck MKDIR_BODY after every operation that
may drop the lock, so that completion during the helper's retry loop
cannot result in another lookup of the retired allocation.
Keep the vnode handling in flush_pagedep_deps(), which owns the retained
vnode and the list of unfinished diradds, and move the dependency
selection into flush_pagedep_deps1(). The latter never acquires or
releases a vnode: it returns EJUSTRETURN with the inode number when it
needs one, or with 0 when the retained vnode must be released first,
and every call restarts the selection, so a vnode is only used for a
diradd found while it was held. This also merges the two
get_parent_vp() call sites. Every restart goes through that return:
obtaining or releasing a vnode, and continuing after jwait() or
getdirtybuf() had to wait with the softdep lock dropped. The diradds
deferred on the unfinished list are put back on the pagedep's list
before the lock is dropped for a restart, so that none are kept off it
while other threads can run. Assert that flush_newblk_dep() is called
with the vnode exclusively locked.
This preserves the original newblk dependency ordering and retains the
existing assertion for an active MKDIR_BODY dependency that resolves to
an unexpected dependency type.
PR: 297976
Reviewed by: kib
Tested by: pho
Sponsored by: Sippy Software, Inc.
Differential revision: https://reviews.freebsd.org/D59356
sys/ufs/ffs/ffs_softdep.c | 217 +++++++++++++++++++++++++++++++++++-----------
1 file changed, 166 insertions(+), 51 deletions(-)
--
You are receiving this mail because:
You are the assignee for the bug.