summaryrefslogtreecommitdiff
path: root/tools/lib/python
diff options
context:
space:
mode:
authorChristian Brauner <brauner@kernel.org>2026-09-21 15:45:06 +0200
committerChristian Brauner <brauner@kernel.org>2026-10-05 13:11:50 +0200
commita019713118305c3d7a2c380590f7d206d25b21ae (patch)
tree58148994c44f82d35bc57a0cdb3801cc8ab9b2db /tools/lib/python
parentad016f0131ebfec250a3360ea75d35128b3f4aa8 (diff)
downloadlinux-next-a019713118305c3d7a2c380590f7d206d25b21ae.tar.gz
linux-next-a019713118305c3d7a2c380590f7d206d25b21ae.zip
fs: close files from the highest descriptor down
close_files(), __range_close() and close_cloexec_files() walk the descriptor table from the lowest descriptor up. They used to call filp_close(), which left the final __fput() to task work. task work is a LIFO list, so the releases ran after the walk had finished and in the opposite direction, highest descriptor first. This dumb ordering is relevant for a bunch of broken but long-standing cases. It matters whenever the ->flush() or ->release() of one file waits for something that only the release of another file of the same table provides. Then one of the two orders deadlocks and the other one doesn't: exit, fd 3 is one end of a pipe peer ------------------------------- ---- splice(socket -> pipe) pipe_lock() waits for data or EOF close_files() fd 3: pipe_release() mutex_lock(&pipe->mutex) held by the peer fd 5: the socket, not reached would be the peer's EOF Programs create the thing that guards or wakes another thing first. Hence, it gets the lower descriptor which is the layout that breaks: (1) a tap device released before the AF_LLC socket that holds a reference to it (2) an unlinked fsdax file evicted before the pipe that holds its vmspliced pages (3) an overlayfs directory whose release queues up behind an unlink that waits for a splice into the same directory The exiting task is unkillable in all of them. All of that crap can obviously also become a bug if you reorder the file descriptors. Continue walking all three tables from the highest descriptor down. That restores the order the deferred puts had. ->flush() moves with the release. So it now runs highest descriptor first as well. None of this fixes the underlying defects. For every one of these pairs the mirrored layout deadlocked before and deadlocks again now: (1') splice() holding pipe->mutex across unbounded socket and tty I/O (2') AF_LLC keeping a netdev reference without a NETDEV_UNREGISTER handler (3') uninterruptible wait in dax_break_layout_final() (4') ovl_splice_write() sleeping under the inode lock It all predates the synchronous close and each should really get fixed. Reported-by: Chris Mason <mason@kernel.org> Link: https://patch.msgid.link/20260921-work-coredump-fixes-v3-17-8e4adb1619e6@kernel.org Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
Diffstat (limited to 'tools/lib/python')
0 files changed, 0 insertions, 0 deletions