Commit 43f0df54 authored by Oleg Nesterov's avatar Oleg Nesterov Committed by Christian Brauner
Browse files

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: default avatarOleg Nesterov <oleg@redhat.com>
Link: https://lore.kernel.org/r/20240202131226.GA26018@redhat.com


Signed-off-by: default avatarChristian Brauner <brauner@kernel.org>
parent 64bef697
Loading
Loading
Loading
Loading
+7 −15
Original line number Diff line number Diff line
@@ -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;
}
+5 −0
Original line number Diff line number Diff line
@@ -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;