pidfd_poll: report POLLHUP when pid_task() == NULL
authorOleg Nesterov <oleg@redhat.com>
Fri, 2 Feb 2024 13:12:26 +0000 (14:12 +0100)
committerChristian Brauner <brauner@kernel.org>
Fri, 2 Feb 2024 13:57:53 +0000 (14:57 +0100)
Add another wake_up_all(wait_pidfd) into __change_pid() and change
pidfd_poll() to include EPOLLHUP if task == NULL.

This allows to wait until the target process/thread is reaped.

TODO: change do_notify_pidfd() to use the keyed wakeups.

Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Link: https://lore.kernel.org/r/20240202131226.GA26018@redhat.com
Signed-off-by: Christian Brauner <brauner@kernel.org>
kernel/fork.c
kernel/pid.c

index 1a9b910559169c2bec683948c74475dcd77a5048..aa08193d124f922188a096f4c20f1f01d698fee8 100644 (file)
@@ -2071,20 +2071,6 @@ static void pidfd_show_fdinfo(struct seq_file *m, struct file *f)
 }
 #endif
 
-static bool pidfd_task_exited(struct pid *pid, bool thread)
-{
-       struct task_struct *task;
-       bool exited;
-
-       rcu_read_lock();
-       task = pid_task(pid, PIDTYPE_PID);
-       exited = !task ||
-               (READ_ONCE(task->exit_state) && (thread || thread_group_empty(task)));
-       rcu_read_unlock();
-
-       return exited;
-}
-
 /*
  * Poll support for process exit notification.
  */
@@ -2092,6 +2078,7 @@ static __poll_t pidfd_poll(struct file *file, struct poll_table_struct *pts)
 {
        struct pid *pid = file->private_data;
        bool thread = file->f_flags & PIDFD_THREAD;
+       struct task_struct *task;
        __poll_t poll_flags = 0;
 
        poll_wait(file, &pid->wait_pidfd, pts);
@@ -2099,8 +2086,13 @@ static __poll_t pidfd_poll(struct file *file, struct poll_table_struct *pts)
         * Depending on PIDFD_THREAD, inform pollers when the thread
         * or the whole thread-group exits.
         */
-       if (pidfd_task_exited(pid, thread))
+       rcu_read_lock();
+       task = pid_task(pid, PIDTYPE_PID);
+       if (!task)
+               poll_flags = EPOLLIN | EPOLLRDNORM | EPOLLHUP;
+       else if (task->exit_state && (thread || thread_group_empty(task)))
                poll_flags = EPOLLIN | EPOLLRDNORM;
+       rcu_read_unlock();
 
        return poll_flags;
 }
index e11144466828025268e777cb5b743831578adcd4..62461c7c82b8bf7c247e620f5234f9d9168f30b5 100644 (file)
@@ -349,6 +349,11 @@ static void __change_pid(struct task_struct *task, enum pid_type type,
        hlist_del_rcu(&task->pid_links[type]);
        *pid_ptr = new;
 
+       if (type == PIDTYPE_PID) {
+               WARN_ON_ONCE(pid_has_task(pid, PIDTYPE_PID));
+               wake_up_all(&pid->wait_pidfd);
+       }
+
        for (tmp = PIDTYPE_MAX; --tmp >= 0; )
                if (pid_has_task(pid, tmp))
                        return;