Skip to content

Commit 43f0df5

Browse files
oleg-nesterovbrauner
authored andcommitted
pidfd_poll: report POLLHUP when pid_task() == NULL
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>
1 parent 64bef69 commit 43f0df5

2 files changed

Lines changed: 12 additions & 15 deletions

File tree

kernel/fork.c

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2071,36 +2071,28 @@ static void pidfd_show_fdinfo(struct seq_file *m, struct file *f)
20712071
}
20722072
#endif
20732073

2074-
static bool pidfd_task_exited(struct pid *pid, bool thread)
2075-
{
2076-
struct task_struct *task;
2077-
bool exited;
2078-
2079-
rcu_read_lock();
2080-
task = pid_task(pid, PIDTYPE_PID);
2081-
exited = !task ||
2082-
(READ_ONCE(task->exit_state) && (thread || thread_group_empty(task)));
2083-
rcu_read_unlock();
2084-
2085-
return exited;
2086-
}
2087-
20882074
/*
20892075
* Poll support for process exit notification.
20902076
*/
20912077
static __poll_t pidfd_poll(struct file *file, struct poll_table_struct *pts)
20922078
{
20932079
struct pid *pid = file->private_data;
20942080
bool thread = file->f_flags & PIDFD_THREAD;
2081+
struct task_struct *task;
20952082
__poll_t poll_flags = 0;
20962083

20972084
poll_wait(file, &pid->wait_pidfd, pts);
20982085
/*
20992086
* Depending on PIDFD_THREAD, inform pollers when the thread
21002087
* or the whole thread-group exits.
21012088
*/
2102-
if (pidfd_task_exited(pid, thread))
2089+
rcu_read_lock();
2090+
task = pid_task(pid, PIDTYPE_PID);
2091+
if (!task)
2092+
poll_flags = EPOLLIN | EPOLLRDNORM | EPOLLHUP;
2093+
else if (task->exit_state && (thread || thread_group_empty(task)))
21032094
poll_flags = EPOLLIN | EPOLLRDNORM;
2095+
rcu_read_unlock();
21042096

21052097
return poll_flags;
21062098
}

kernel/pid.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,11 @@ static void __change_pid(struct task_struct *task, enum pid_type type,
349349
hlist_del_rcu(&task->pid_links[type]);
350350
*pid_ptr = new;
351351

352+
if (type == PIDTYPE_PID) {
353+
WARN_ON_ONCE(pid_has_task(pid, PIDTYPE_PID));
354+
wake_up_all(&pid->wait_pidfd);
355+
}
356+
352357
for (tmp = PIDTYPE_MAX; --tmp >= 0; )
353358
if (pid_has_task(pid, tmp))
354359
return;

0 commit comments

Comments
 (0)