]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
pidfs: cleanup the usage of do_notify_pidfd()
authorOleg Nesterov <oleg@redhat.com>
Sun, 23 Mar 2025 17:19:55 +0000 (18:19 +0100)
committerChristian Brauner <brauner@kernel.org>
Tue, 25 Mar 2025 13:59:05 +0000 (14:59 +0100)
If a single-threaded process exits do_notify_pidfd() will be called twice,
from exit_notify() and right after that from do_notify_parent().

1. Change exit_notify() to call do_notify_pidfd() if the exiting task is
   not ptraced and it is not a group leader.

2. Change do_notify_parent() to call do_notify_pidfd() unconditionally.

   If tsk is not ptraced, do_notify_parent() will only be called when it
   is a group-leader and thread_group_empty() is true.

This means that if tsk is ptraced, do_notify_pidfd() will be called from
do_notify_parent() even if tsk is a delay_group_leader(). But this case is
less common, and apart from the unnecessary __wake_up() is harmless.

Granted, this unnecessary __wake_up() can be avoided, but I don't want to
do it in this patch because it's just a consequence of another historical
oddity: we notify the tracer even if !thread_group_empty(), but do_wait()
from debugger can't work until all other threads exit. With or without this
patch we should either eliminate do_notify_parent() in this case, or change
do_wait(WEXITED) to untrace the ptraced delay_group_leader() at least when
ptrace_reparented().

Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Link: https://lore.kernel.org/r/20250323171955.GA834@redhat.com
Signed-off-by: Christian Brauner <brauner@kernel.org>
kernel/exit.c
kernel/signal.c

index c2e6c7b7779ff6a034e48d569d7be91900a7a7af..5d1226fdfadccaf136b537df0899bb0c1167057f 100644 (file)
@@ -756,12 +756,6 @@ static void exit_notify(struct task_struct *tsk, int group_dead)
                kill_orphaned_pgrp(tsk->group_leader, NULL);
 
        tsk->exit_state = EXIT_ZOMBIE;
-       /*
-        * Ignore thread-group leaders that exited before all
-        * subthreads did.
-        */
-       if (!delay_group_leader(tsk))
-               do_notify_pidfd(tsk);
 
        if (unlikely(tsk->ptrace)) {
                int sig = thread_group_leader(tsk) &&
@@ -774,6 +768,8 @@ static void exit_notify(struct task_struct *tsk, int group_dead)
                        do_notify_parent(tsk, tsk->exit_signal);
        } else {
                autoreap = true;
+               /* untraced sub-thread */
+               do_notify_pidfd(tsk);
        }
 
        if (autoreap) {
index 027ad9e9741782960bd287d6e2ebd8f01b14e008..1d8db0dabb71204e14901d7f0455ab78344090e2 100644 (file)
@@ -2179,11 +2179,9 @@ bool do_notify_parent(struct task_struct *tsk, int sig)
 
        WARN_ON_ONCE(!tsk->ptrace &&
               (tsk->group_leader != tsk || !thread_group_empty(tsk)));
-       /*
-        * Notify for thread-group leaders without subthreads.
-        */
-       if (thread_group_empty(tsk))
-               do_notify_pidfd(tsk);
+
+       /* ptraced, or group-leader without sub-threads */
+       do_notify_pidfd(tsk);
 
        if (sig != SIGCHLD) {
                /*