[PATCH 17/17] signal: Always set SIGNAL_GROUP_EXIT on process exit
From: Eric W. Biederman <hidden>
Date: 2022-01-03 21:34:39
Also in:
linux-arch, lkml
Subsystem:
exec & binfmt api, elf, filesystems (vfs and infrastructure), memory management - core, scheduler, the rest · Maintainers:
Kees Cook, Alexander Viro, Christian Brauner, Andrew Morton, David Hildenbrand, Ingo Molnar, Peter Zijlstra, Juri Lelli, Vincent Guittot, Linus Torvalds
Track how many threads have not started exiting and when the last thread starts exiting set SIGNAL_GROUP_EXIT. Signed-off-by: "Eric W. Biederman" <redacted> --- fs/coredump.c | 4 ---- include/linux/sched/signal.h | 1 + kernel/exit.c | 8 +------- kernel/fork.c | 2 ++ kernel/signal.c | 10 +++++++--- 5 files changed, 11 insertions(+), 14 deletions(-)
diff --git a/fs/coredump.c b/fs/coredump.c
index c54b502bf648..029d0f98aa90 100644
--- a/fs/coredump.c
+++ b/fs/coredump.c@@ -352,10 +352,6 @@ static int zap_process(struct task_struct *start, int exit_code) struct task_struct *t; int nr = 0; - start->signal->flags = SIGNAL_GROUP_EXIT; - start->signal->group_exit_code = exit_code; - start->signal->group_stop_count = 0; - for_each_thread(start, t) { schedule_task_exit_locked(t, exit_code); if (t != current && !(t->flags & PF_POSTCOREDUMP))
diff --git a/include/linux/sched/signal.h b/include/linux/sched/signal.h
index e8034ecaee84..bd9435e934a1 100644
--- a/include/linux/sched/signal.h
+++ b/include/linux/sched/signal.h@@ -94,6 +94,7 @@ struct signal_struct { refcount_t sigcnt; atomic_t live; int nr_threads; + int quick_threads; struct list_head thread_head; wait_queue_head_t wait_chldexit; /* for wait4() */
diff --git a/kernel/exit.c b/kernel/exit.c
index e95500e2d27c..be867a12de65 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c@@ -924,14 +924,8 @@ do_group_exit(int exit_code) else { struct task_struct *t; - sig->group_exit_code = exit_code; - sig->flags = SIGNAL_GROUP_EXIT; - sig->group_stop_count = 0; - __for_each_thread(sig, t) { - if (t == current) - continue; + __for_each_thread(sig, t) schedule_task_exit_locked(t, exit_code); - } } spin_unlock_irq(&sighand->siglock); }
diff --git a/kernel/fork.c b/kernel/fork.c
index 6f0293cb29c9..d973189a4014 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c@@ -1644,6 +1644,7 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk) return -ENOMEM; sig->nr_threads = 1; + sig->quick_threads = 1; atomic_set(&sig->live, 1); refcount_set(&sig->sigcnt, 1);
@@ -2383,6 +2384,7 @@ static __latent_entropy struct task_struct *copy_process( __this_cpu_inc(process_counts); } else { current->signal->nr_threads++; + current->signal->quick_threads++; atomic_inc(¤t->signal->live); refcount_inc(¤t->signal->sigcnt); task_join_group_stop(p);
diff --git a/kernel/signal.c b/kernel/signal.c
index e8fac8a3c935..9bd835fcb1dc 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c@@ -1052,9 +1052,6 @@ static void complete_signal(int sig, struct task_struct *p, enum pid_type type) * running and doing things after a slower * thread has the fatal signal pending. */ - signal->flags = SIGNAL_GROUP_EXIT; - signal->group_exit_code = sig; - signal->group_stop_count = 0; t = p; do { schedule_task_exit_locked(t, sig);
@@ -1365,10 +1362,17 @@ int force_sig_info(struct kernel_siginfo *info) void schedule_task_exit_locked(struct task_struct *task, int exit_code) { if (!(task->jobctl & JOBCTL_WILL_EXIT)) { + struct signal_struct *signal = task->signal; task_clear_jobctl_pending(task, JOBCTL_PENDING_MASK); task->jobctl |= JOBCTL_WILL_EXIT; task->exit_code = exit_code; signal_wake_up(task, 1); + signal->quick_threads--; + if (signal->quick_threads == 0) { + signal->flags = SIGNAL_GROUP_EXIT; + signal->group_exit_code = exit_code; + signal->group_stop_count = 0; + } } }
--
2.29.2