From: Alexei Starovoitov <[email protected]> build_map_info() takes mm_users of every mm that maps the file and register_for_each_vma() drops it after the visit. When the process has exited meanwhile it's the last mmput(), and exit_mmap() of a large mm runs with dup_mmap_sem held for writing. Every fork() in the system waits for it. Use mmput_async().
Signed-off-by: Alexei Starovoitov <[email protected]> --- kernel/events/uprobes.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c index 7709ea882477..6792004be6fa 100644 --- a/kernel/events/uprobes.c +++ b/kernel/events/uprobes.c @@ -1250,7 +1250,7 @@ build_map_info(struct address_space *mapping, loff_t offset, bool is_register) prev = curr; while (curr) { - mmput(curr->mm); + mmput_async(curr->mm); curr = curr->next; } @@ -1324,7 +1324,8 @@ register_for_each_vma(struct uprobe *uprobe, struct uprobe_consumer *new) unlock: mmap_write_unlock(mm); free: - mmput(mm); + /* exit_mmap() of the last user must not run under dup_mmap_sem */ + mmput_async(mm); info = free_map_info(info); } out: -- 2.55.0
