Re: [RFC][PATCH] make sure that lock_for_kill() callers drop the locks in safe order

Calvin Owens
2026-04-10T21:13:14Z

On Friday 04/10 at 15:32 -0400, Jeff Layton wrote:
> Yep, not even with that. One thing that claude pointed out: doing an
> mdelay() might prevent it from making any progress freeing dentries.
> I'm experimenting now with one that only randomly does a delay, but so
> far that hasn't turned up anything. I'll let you know if that changes.

Hi Jeff,

I've been poking at this one too. With the attached reproducer, the
waiter will get stuck in an infinite loop apparently in d_walk() with a
stock 7.0-rc7 (in my case with PREEMPT_LAZY):

d_walk
list_empty (inlined)
shrink_dcache_tree
d_invalidate
proc_invalidate_siblings_dcache
release_task
wait_task_zombie (inlined)
wait_consider_task
do_wait_thread (inlined)
__do_wait
do_wait
kernel_wait4
__do_sys_wait4 (inlined)
__se_sys_wait4 (inlined)
__x64_sys_wait4
do_syscall_64
entry_SYSCALL_64_after_hwframe
__internal_syscall_cancel
__syscall_cancel
__wait4 (inlined)
os_wait_impl (inlined)
os_wait
_Py_LeaveRecursiveCallTstate (inlined)
cfunction_vectorcall_NOARGS
_PyObject_VectorcallTstate (inlined)
PyObject_Vectorcall

It doesn't happen 100% of the time, but it's never taken more than three
attempts on two different machines. I've SIGKILL'd it and waited over an
hour, it really never comes back. Making NR_FORKS larger than 3 was
counterproductive on my 32-thread machines, but YMMV of course.

I haven't had time to dig more yet, but wanted to share the reproducer,
hopefully it yields something useful on your end.

I don't think this is Al's livelock, because only one thread is
spinning on an otherwise idle machine... but I apologize if it is and
it's going over my head.

Cheers,
Calvin

---
#!/usr/bin/python3
# sudo prlimit --nofile=10000000:10000000 ./repro.py

import os

NR_FORKS = 3

for _ in range(NR_FORKS):
pid = os.fork()
if pid == 0:
break

for dirpath, _, filenames in os.walk("/proc"):
for fn in filenames:
try:
os.open(os.path.join(dirpath, fn), os.O_RDONLY)
except:
pass

if pid == 0:
os._exit(0)

while True:
try:
os.wait()
except ChildProcessError:
os._exit(0)