WSL2-Linux-Kernel/fs/proc
Zhihao Cheng 3336e7c076 proc: fix a dentry lock race between release_task and lookup
[ Upstream commit d919a1e79b ]

Commit 7bc3e6e55a ("proc: Use a list of inodes to flush from proc")
moved proc_flush_task() behind __exit_signal().  Then, process systemd can
take long period high cpu usage during releasing task in following
concurrent processes:

  systemd                                 ps
kernel_waitid                 stat(/proc/tgid)
  do_wait                       filename_lookup
    wait_consider_task            lookup_fast
      release_task
        __exit_signal
          __unhash_process
            detach_pid
              __change_pid // remove task->pid_links
                                     d_revalidate -> pid_revalidate  // 0
                                     d_invalidate(/proc/tgid)
                                       shrink_dcache_parent(/proc/tgid)
                                         d_walk(/proc/tgid)
                                           spin_lock_nested(/proc/tgid/fd)
                                           // iterating opened fd
        proc_flush_pid                                    |
           d_invalidate (/proc/tgid/fd)                   |
              shrink_dcache_parent(/proc/tgid/fd)         |
                shrink_dentry_list(subdirs)               ↓
                  shrink_lock_dentry(/proc/tgid/fd) --> race on dentry lock

Function d_invalidate() will remove dentry from hash firstly, but why does
proc_flush_pid() process dentry '/proc/tgid/fd' before dentry
'/proc/tgid'?  That's because proc_pid_make_inode() adds proc inode in
reverse order by invoking hlist_add_head_rcu().  But proc should not add
any inodes under '/proc/tgid' except '/proc/tgid/task/pid', fix it by
adding inode into 'pid->inodes' only if the inode is /proc/tgid or
/proc/tgid/task/pid.

Performance regression:
Create 200 tasks, each task open one file for 50,000 times. Kill all
tasks when opened files exceed 10,000,000 (cat /proc/sys/fs/file-nr).

Before fix:
$ time killall -wq aa
  real    4m40.946s   # During this period, we can see 'ps' and 'systemd'
			taking high cpu usage.

After fix:
$ time killall -wq aa
  real    1m20.732s   # During this period, we can see 'systemd' taking
			high cpu usage.

Link: https://lkml.kernel.org/r/20220713130029.4133533-1-chengzhihao1@huawei.com
Fixes: 7bc3e6e55a ("proc: Use a list of inodes to flush from proc")
Link: https://bugzilla.kernel.org/show_bug.cgi?id=216054
Signed-off-by: Zhihao Cheng <chengzhihao1@huawei.com>
Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
Suggested-by: Brian Foster <bfoster@redhat.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Alexey Dobriyan <adobriyan@gmail.com>
Cc: Eric Biederman <ebiederm@xmission.com>
Cc: Matthew Wilcox <willy@infradead.org>
Cc: Baoquan He <bhe@redhat.com>
Cc: Kalesh Singh <kaleshsingh@google.com>
Cc: Yu Kuai <yukuai3@huawei.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
2022-08-17 14:24:08 +02:00
..
Kconfig treewide: replace '---help---' in Kconfig files with 'help' 2020-06-14 01:57:21 +09:00
Makefile proc: bootconfig: Add /proc/bootconfig to show boot config list 2020-01-13 13:19:39 -05:00
array.c proc: stop using seq_get_buf in proc_task_name 2021-09-08 11:50:25 -07:00
base.c proc: fix a dentry lock race between release_task and lookup 2022-08-17 14:24:08 +02:00
bootconfig.c proc: bootconfig: Add null pointer check 2022-04-08 14:24:12 +02:00
cmdline.c proc: introduce proc_create_single{,_data} 2018-05-16 07:23:35 +02:00
consoles.c treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 191 2019-05-30 11:29:21 -07:00
cpuinfo.c proc/cpuinfo: switch to ->read_iter 2020-11-06 10:05:18 -08:00
devices.c block: move block-related definitions out of fs.h 2020-06-24 09:16:02 -06:00
fd.c procfs: prevent unprivileged processes accessing fdinfo dir 2022-05-18 10:26:50 +02:00
fd.h fs: make helpers idmap mount aware 2021-01-24 14:27:20 +01:00
generic.c proc: fix dentry/inode overinstantiating under /proc/${pid}/net 2022-06-09 10:23:10 +02:00
inode.c proc: delete redundant subset=pid check 2021-05-06 19:24:11 -07:00
internal.h fs: make helpers idmap mount aware 2021-01-24 14:27:20 +01:00
interrupts.c proc: introduce proc_create_seq{,_data} 2018-05-16 07:23:35 +02:00
kcore.c fs/proc/kcore: use page_offline_(freeze|thaw) 2021-06-30 20:47:28 -07:00
kmsg.c proc: faster open/read/close with "permanent" files 2020-04-07 10:43:42 -07:00
loadavg.c sched: Make nr_running() return 32-bit value 2021-05-12 21:34:14 +02:00
meminfo.c mm: memcontrol: convert NR_FILE_PMDMAPPED account to pages 2021-02-24 13:38:29 -08:00
namespaces.c Merge branch 'work.openat2' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs 2020-01-29 11:20:24 -08:00
nommu.c mm: don't include asm/pgtable.h if linux/mm.h is already included 2020-06-09 09:39:13 -07:00
page.c mm: Add PG_arch_2 page flag 2020-09-04 12:46:06 +01:00
proc_net.c proc: fix dentry/inode overinstantiating under /proc/${pid}/net 2022-06-09 10:23:10 +02:00
proc_sysctl.c sysctl: move some boundary constants from sysctl.c to sysctl_vals 2022-07-29 17:25:11 +02:00
proc_tty.c tty: replace ->proc_fops with ->proc_show 2018-05-16 07:24:30 +02:00
root.c fs: make helpers idmap mount aware 2021-01-24 14:27:20 +01:00
self.c Revert "proc: don't allow async path resolution of /proc/self components" 2021-02-23 20:32:11 -07:00
softirqs.c proc: introduce proc_create_single{,_data} 2018-05-16 07:23:35 +02:00
stat.c fs/proc/uptime.c: Fix idle time reporting in /proc/uptime 2021-11-18 19:16:13 +01:00
task_mmu.c proc: fix documentation and description of pagemap 2022-03-08 19:12:54 +01:00
task_nommu.c mmap locking API: use coccinelle to convert mmap_sem rwsem call sites 2020-06-09 09:39:14 -07:00
thread_self.c Revert "proc: don't allow async path resolution of /proc/thread-self components" 2021-02-23 20:32:11 -07:00
uptime.c fs/proc/uptime.c: Fix idle time reporting in /proc/uptime 2021-11-18 19:16:13 +01:00
util.c fs/proc/util.c: include fs/proc/internal.h for name_to_int() 2019-01-04 13:13:45 -08:00
version.c proc: introduce proc_create_single{,_data} 2018-05-16 07:23:35 +02:00
vmcore.c proc/vmcore: fix clearing user buffer by properly using clear_user() 2021-12-01 09:04:44 +01:00