Re: end_dirop() can unlock the i_rwsem of a re-parented dentry on PREEMPT_RT (DEBUG_LOCKS_WARN_ON in filename_symlinkat)

From: Shuai Liu

Date: Fri Nov 06 2026 - 01:47:29 EST


Hi Al, Neil, Christian, Jan,

Adding you to Cc on this -- my first mail in this thread only reached
the list address due to a sendmail mishap on my side.

In short: on PREEMPT_RT, syzbot reports DEBUG_LOCKS_WARN_ON
(rt_mutex_owner != current) from inode_unlock() called by end_dirop()
via filename_symlinkat -> end_creating_path() -> end_creating()
(syzbot dashboard: https://syzkaller.appspot.com/bug?extid=2ed46b6b748df855347f).

end_dirop() re-derives the directory to unlock from the current
de->d_parent, while start_dirop() locked the parent it was given
*before* the lookup. The warning therefore implies the dentry was
re-parented between the two.

I audited the candidates that could move a held dentry
(lookup_one_qstr_excl/d_lookup; d_splice_alias_ops() both branches --
IS_ROOT __d_move under rename_lock, and the __d_unalias path with its
s_vfs_rename_mutex + inode_trylock_shared()/-ESTALE fallback) and
could not construct an interleaving that re-parents the dirop dentry
while the exclusive parent lock is held. Runtime instrumentation at
both ends (owner check in end_dirop(), parent-identity check in
end_creating_path()) ran ~48k iterations of the C reproducer with
zero hits and zero false positives.

The full analysis and my questions (Q1: should start_dirop() capture
the locked inode explicitly for end_dirop() to unlock; Q2: which
d_move() callers do you suspect; Q3: could the divergence originate
at start time) are in my previous mail in this thread. I'd greatly
appreciate your insight, Neil especially given the start_dirop()/
end_dirop() rework.

Thanks,
Shuai Liu (刘帅)