All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 1/2] Add polling support to pidfd
@ 2019-04-30 16:21 ` joel
  0 siblings, 0 replies; 33+ messages in thread
From: Joel Fernandes (Google) @ 2019-04-30 16:21 UTC (permalink / raw)
  To: linux-kernel
  Cc: Joel Fernandes (Google),
	Andy Lutomirski, Steven Rostedt, Daniel Colascione,
	Christian Brauner, Jann Horn, Tim Murray, Jonathan Kowalski,
	Linus Torvalds, Al Viro, Kees Cook, David Howells, Oleg Nesterov,
	kernel-team, Andrew Morton, Arnd Bergmann, Eric W. Biederman,
	Greg Kroah-Hartman, Ingo Molnar, KJ Tsanaktsidis,
	linux-kselftest, Michal Hocko, Nadav Amit, Peter Zijlstra (Intel),
	Serge Hallyn, Shuah Khan, Thomas Gleixner, Tycho Andersen

Android low memory killer (LMK) needs to know when a process dies once
it is sent the kill signal. It does so by checking for the existence of
/proc/pid which is both racy and slow. For example, if a PID is reused
between when LMK sends a kill signal and checks for existence of the
PID, since the wrong PID is now possibly checked for existence.

This patch adds polling support to pidfd. Using the polling support, LMK
will be able to get notified when a process exists in race-free and fast
way, and allows the LMK to do other things (such as by polling on other
fds) while awaiting the process being killed to die.

For notification to polling processes, we follow the same existing
mechanism in the kernel used when the parent of the task group is to be
notified of a child's death (do_notify_parent).  This is precisely when
the tasks waiting on a poll of pidfd are also awakened in this patch.

We have decided to include the waitqueue in struct pid for the following
reasons:
1. The wait queue has to survive for the lifetime of the poll. Including
it in task_struct would not be option in this case because the task can
be reaped and destroyed before the poll returns.

2. By including the struct pid for the waitqueue means that during
de_thread(), the new thread group leader automatically gets the new
waitqueue/pid even though its task_struct is different.

Appropriate test cases are added in the second patch to provide coverage
of all the cases the patch is handling.

Andy had a similar patch [1] in the past which was a good reference
however this patch tries to handle different situations properly related
to thread group existence, and how/where it notifies. And also solves
other bugs (waitqueue lifetime).  Daniel had a similar patch [2]
recently which this patch supercedes.

[1] https://lore.kernel.org/patchwork/patch/345098/
[2] https://lore.kernel.org/lkml/20181029175322.189042-1-dancol@google.com/

Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Daniel Colascione <dancol@google.com>
Cc: Christian Brauner <christian@brauner.io>
Cc: Jann Horn <jannh@google.com>
Cc: Tim Murray <timmurray@google.com>
Cc: Jonathan Kowalski <bl0pbl33p@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Kees Cook <keescook@chromium.org>
Cc: David Howells <dhowells@redhat.com>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: kernel-team@android.com
(Oleg improved the code by showing how to avoid tasklist_lock)
Suggested-by: Oleg Nesterov <oleg@redhat.com>
Co-developed-by: Daniel Colascione <dancol@google.com>
Signed-off-by: Daniel Colascione <dancol@google.com>
Signed-off-by: Joel Fernandes (Google) <joel@joelfernandes.org>

---

v1 -> v2:
* Restructure poll code to avoid tasklist_lock (Oleg)
* use task_pid instead of get_pid_task in notify_pidfd (Oleg)
* Added comments to code, commit message nits (Christian)
* Test case nits/improvements (Christian)

RFC -> v1:
* Based on CLONE_PIDFD patches: https://lwn.net/Articles/786244/
* Updated selftests.
* Renamed poll wake function to do_notify_pidfd.
* Removed depending on EXIT flags
* Removed POLLERR flag since semantics are controversial and
  we don't have usecases for it right now (later we can add if there's
  a need for it).

 include/linux/pid.h |  3 +++
 kernel/fork.c       | 29 +++++++++++++++++++++++++++++
 kernel/pid.c        |  2 ++
 kernel/signal.c     | 11 +++++++++++
 4 files changed, 45 insertions(+)

diff --git a/include/linux/pid.h b/include/linux/pid.h
index 3c8ef5a199ca..1484db6ca8d1 100644
--- a/include/linux/pid.h
+++ b/include/linux/pid.h
@@ -3,6 +3,7 @@
 #define _LINUX_PID_H
 
 #include <linux/rculist.h>
+#include <linux/wait.h>
 
 enum pid_type
 {
@@ -60,6 +61,8 @@ struct pid
 	unsigned int level;
 	/* lists of tasks that use this pid */
 	struct hlist_head tasks[PIDTYPE_MAX];
+	/* wait queue for pidfd notifications */
+	wait_queue_head_t wait_pidfd;
 	struct rcu_head rcu;
 	struct upid numbers[1];
 };
diff --git a/kernel/fork.c b/kernel/fork.c
index 5525837ed80e..721f8c9d2921 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1685,8 +1685,37 @@ static void pidfd_show_fdinfo(struct seq_file *m, struct file *f)
 }
 #endif
 
+/*
+ * Poll support for process exit notification.
+ */
+static unsigned int pidfd_poll(struct file *file, struct poll_table_struct *pts)
+{
+	struct task_struct *task;
+	struct pid *pid = file->private_data;
+	int poll_flags = 0;
+
+	poll_wait(file, &pid->wait_pidfd, pts);
+
+	rcu_read_lock();
+	task = pid_task(pid, PIDTYPE_PID);
+	WARN_ON_ONCE(task && !thread_group_leader(task));
+
+	/*
+	 * Inform pollers only when the whole thread group exits, if thread
+	 * group leader exits before all other threads in the group, then
+	 * poll(2) should block, similar to the wait(2) family.
+	 */
+	if (!task || (task->exit_state && thread_group_empty(task)))
+		poll_flags = POLLIN | POLLRDNORM;
+	rcu_read_unlock();
+
+	return poll_flags;
+}
+
+
 const struct file_operations pidfd_fops = {
 	.release = pidfd_release,
+	.poll = pidfd_poll,
 #ifdef CONFIG_PROC_FS
 	.show_fdinfo = pidfd_show_fdinfo,
 #endif
diff --git a/kernel/pid.c b/kernel/pid.c
index 20881598bdfa..5c90c239242f 100644
--- a/kernel/pid.c
+++ b/kernel/pid.c
@@ -214,6 +214,8 @@ struct pid *alloc_pid(struct pid_namespace *ns)
 	for (type = 0; type < PIDTYPE_MAX; ++type)
 		INIT_HLIST_HEAD(&pid->tasks[type]);
 
+	init_waitqueue_head(&pid->wait_pidfd);
+
 	upid = pid->numbers + ns->level;
 	spin_lock_irq(&pidmap_lock);
 	if (!(ns->pid_allocated & PIDNS_ADDING))
diff --git a/kernel/signal.c b/kernel/signal.c
index 1581140f2d99..a17fff073c3d 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -1800,6 +1800,14 @@ int send_sigqueue(struct sigqueue *q, struct pid *pid, enum pid_type type)
 	return ret;
 }
 
+static void do_notify_pidfd(struct task_struct *task)
+{
+	struct pid *pid;
+
+	pid = task_pid(task);
+	wake_up_all(&pid->wait_pidfd);
+}
+
 /*
  * Let a parent know about the death of a child.
  * For a stopped/continued status change, use do_notify_parent_cldstop instead.
@@ -1823,6 +1831,9 @@ bool do_notify_parent(struct task_struct *tsk, int sig)
 	BUG_ON(!tsk->ptrace &&
 	       (tsk->group_leader != tsk || !thread_group_empty(tsk)));
 
+	/* Wake up all pidfd waiters */
+	do_notify_pidfd(tsk);
+
 	if (sig != SIGCHLD) {
 		/*
 		 * This is only possible if parent == real_parent.
-- 
2.21.0.593.g511ec345e18-goog

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v2 1/2] Add polling support to pidfd
@ 2019-04-30 16:21 ` joel
  0 siblings, 0 replies; 33+ messages in thread
From: joel @ 2019-04-30 16:21 UTC (permalink / raw)


Android low memory killer (LMK) needs to know when a process dies once
it is sent the kill signal. It does so by checking for the existence of
/proc/pid which is both racy and slow. For example, if a PID is reused
between when LMK sends a kill signal and checks for existence of the
PID, since the wrong PID is now possibly checked for existence.

This patch adds polling support to pidfd. Using the polling support, LMK
will be able to get notified when a process exists in race-free and fast
way, and allows the LMK to do other things (such as by polling on other
fds) while awaiting the process being killed to die.

For notification to polling processes, we follow the same existing
mechanism in the kernel used when the parent of the task group is to be
notified of a child's death (do_notify_parent).  This is precisely when
the tasks waiting on a poll of pidfd are also awakened in this patch.

We have decided to include the waitqueue in struct pid for the following
reasons:
1. The wait queue has to survive for the lifetime of the poll. Including
it in task_struct would not be option in this case because the task can
be reaped and destroyed before the poll returns.

2. By including the struct pid for the waitqueue means that during
de_thread(), the new thread group leader automatically gets the new
waitqueue/pid even though its task_struct is different.

Appropriate test cases are added in the second patch to provide coverage
of all the cases the patch is handling.

Andy had a similar patch [1] in the past which was a good reference
however this patch tries to handle different situations properly related
to thread group existence, and how/where it notifies. And also solves
other bugs (waitqueue lifetime).  Daniel had a similar patch [2]
recently which this patch supercedes.

[1] https://lore.kernel.org/patchwork/patch/345098/
[2] https://lore.kernel.org/lkml/20181029175322.189042-1-dancol at google.com/

Cc: Andy Lutomirski <luto at amacapital.net>
Cc: Steven Rostedt <rostedt at goodmis.org>
Cc: Daniel Colascione <dancol at google.com>
Cc: Christian Brauner <christian at brauner.io>
Cc: Jann Horn <jannh at google.com>
Cc: Tim Murray <timmurray at google.com>
Cc: Jonathan Kowalski <bl0pbl33p at gmail.com>
Cc: Linus Torvalds <torvalds at linux-foundation.org>
Cc: Al Viro <viro at zeniv.linux.org.uk>
Cc: Kees Cook <keescook at chromium.org>
Cc: David Howells <dhowells at redhat.com>
Cc: Oleg Nesterov <oleg at redhat.com>
Cc: kernel-team at android.com
(Oleg improved the code by showing how to avoid tasklist_lock)
Suggested-by: Oleg Nesterov <oleg at redhat.com>
Co-developed-by: Daniel Colascione <dancol at google.com>
Signed-off-by: Daniel Colascione <dancol at google.com>
Signed-off-by: Joel Fernandes (Google) <joel at joelfernandes.org>

---

v1 -> v2:
* Restructure poll code to avoid tasklist_lock (Oleg)
* use task_pid instead of get_pid_task in notify_pidfd (Oleg)
* Added comments to code, commit message nits (Christian)
* Test case nits/improvements (Christian)

RFC -> v1:
* Based on CLONE_PIDFD patches: https://lwn.net/Articles/786244/
* Updated selftests.
* Renamed poll wake function to do_notify_pidfd.
* Removed depending on EXIT flags
* Removed POLLERR flag since semantics are controversial and
  we don't have usecases for it right now (later we can add if there's
  a need for it).

 include/linux/pid.h |  3 +++
 kernel/fork.c       | 29 +++++++++++++++++++++++++++++
 kernel/pid.c        |  2 ++
 kernel/signal.c     | 11 +++++++++++
 4 files changed, 45 insertions(+)

diff --git a/include/linux/pid.h b/include/linux/pid.h
index 3c8ef5a199ca..1484db6ca8d1 100644
--- a/include/linux/pid.h
+++ b/include/linux/pid.h
@@ -3,6 +3,7 @@
 #define _LINUX_PID_H
 
 #include <linux/rculist.h>
+#include <linux/wait.h>
 
 enum pid_type
 {
@@ -60,6 +61,8 @@ struct pid
 	unsigned int level;
 	/* lists of tasks that use this pid */
 	struct hlist_head tasks[PIDTYPE_MAX];
+	/* wait queue for pidfd notifications */
+	wait_queue_head_t wait_pidfd;
 	struct rcu_head rcu;
 	struct upid numbers[1];
 };
diff --git a/kernel/fork.c b/kernel/fork.c
index 5525837ed80e..721f8c9d2921 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1685,8 +1685,37 @@ static void pidfd_show_fdinfo(struct seq_file *m, struct file *f)
 }
 #endif
 
+/*
+ * Poll support for process exit notification.
+ */
+static unsigned int pidfd_poll(struct file *file, struct poll_table_struct *pts)
+{
+	struct task_struct *task;
+	struct pid *pid = file->private_data;
+	int poll_flags = 0;
+
+	poll_wait(file, &pid->wait_pidfd, pts);
+
+	rcu_read_lock();
+	task = pid_task(pid, PIDTYPE_PID);
+	WARN_ON_ONCE(task && !thread_group_leader(task));
+
+	/*
+	 * Inform pollers only when the whole thread group exits, if thread
+	 * group leader exits before all other threads in the group, then
+	 * poll(2) should block, similar to the wait(2) family.
+	 */
+	if (!task || (task->exit_state && thread_group_empty(task)))
+		poll_flags = POLLIN | POLLRDNORM;
+	rcu_read_unlock();
+
+	return poll_flags;
+}
+
+
 const struct file_operations pidfd_fops = {
 	.release = pidfd_release,
+	.poll = pidfd_poll,
 #ifdef CONFIG_PROC_FS
 	.show_fdinfo = pidfd_show_fdinfo,
 #endif
diff --git a/kernel/pid.c b/kernel/pid.c
index 20881598bdfa..5c90c239242f 100644
--- a/kernel/pid.c
+++ b/kernel/pid.c
@@ -214,6 +214,8 @@ struct pid *alloc_pid(struct pid_namespace *ns)
 	for (type = 0; type < PIDTYPE_MAX; ++type)
 		INIT_HLIST_HEAD(&pid->tasks[type]);
 
+	init_waitqueue_head(&pid->wait_pidfd);
+
 	upid = pid->numbers + ns->level;
 	spin_lock_irq(&pidmap_lock);
 	if (!(ns->pid_allocated & PIDNS_ADDING))
diff --git a/kernel/signal.c b/kernel/signal.c
index 1581140f2d99..a17fff073c3d 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -1800,6 +1800,14 @@ int send_sigqueue(struct sigqueue *q, struct pid *pid, enum pid_type type)
 	return ret;
 }
 
+static void do_notify_pidfd(struct task_struct *task)
+{
+	struct pid *pid;
+
+	pid = task_pid(task);
+	wake_up_all(&pid->wait_pidfd);
+}
+
 /*
  * Let a parent know about the death of a child.
  * For a stopped/continued status change, use do_notify_parent_cldstop instead.
@@ -1823,6 +1831,9 @@ bool do_notify_parent(struct task_struct *tsk, int sig)
 	BUG_ON(!tsk->ptrace &&
 	       (tsk->group_leader != tsk || !thread_group_empty(tsk)));
 
+	/* Wake up all pidfd waiters */
+	do_notify_pidfd(tsk);
+
 	if (sig != SIGCHLD) {
 		/*
 		 * This is only possible if parent == real_parent.
-- 
2.21.0.593.g511ec345e18-goog

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v2 1/2] Add polling support to pidfd
@ 2019-04-30 16:21 ` joel
  0 siblings, 0 replies; 33+ messages in thread
From: Joel Fernandes (Google) @ 2019-04-30 16:21 UTC (permalink / raw)


Android low memory killer (LMK) needs to know when a process dies once
it is sent the kill signal. It does so by checking for the existence of
/proc/pid which is both racy and slow. For example, if a PID is reused
between when LMK sends a kill signal and checks for existence of the
PID, since the wrong PID is now possibly checked for existence.

This patch adds polling support to pidfd. Using the polling support, LMK
will be able to get notified when a process exists in race-free and fast
way, and allows the LMK to do other things (such as by polling on other
fds) while awaiting the process being killed to die.

For notification to polling processes, we follow the same existing
mechanism in the kernel used when the parent of the task group is to be
notified of a child's death (do_notify_parent).  This is precisely when
the tasks waiting on a poll of pidfd are also awakened in this patch.

We have decided to include the waitqueue in struct pid for the following
reasons:
1. The wait queue has to survive for the lifetime of the poll. Including
it in task_struct would not be option in this case because the task can
be reaped and destroyed before the poll returns.

2. By including the struct pid for the waitqueue means that during
de_thread(), the new thread group leader automatically gets the new
waitqueue/pid even though its task_struct is different.

Appropriate test cases are added in the second patch to provide coverage
of all the cases the patch is handling.

Andy had a similar patch [1] in the past which was a good reference
however this patch tries to handle different situations properly related
to thread group existence, and how/where it notifies. And also solves
other bugs (waitqueue lifetime).  Daniel had a similar patch [2]
recently which this patch supercedes.

[1] https://lore.kernel.org/patchwork/patch/345098/
[2] https://lore.kernel.org/lkml/20181029175322.189042-1-dancol at google.com/

Cc: Andy Lutomirski <luto at amacapital.net>
Cc: Steven Rostedt <rostedt at goodmis.org>
Cc: Daniel Colascione <dancol at google.com>
Cc: Christian Brauner <christian at brauner.io>
Cc: Jann Horn <jannh at google.com>
Cc: Tim Murray <timmurray at google.com>
Cc: Jonathan Kowalski <bl0pbl33p at gmail.com>
Cc: Linus Torvalds <torvalds at linux-foundation.org>
Cc: Al Viro <viro at zeniv.linux.org.uk>
Cc: Kees Cook <keescook at chromium.org>
Cc: David Howells <dhowells at redhat.com>
Cc: Oleg Nesterov <oleg at redhat.com>
Cc: kernel-team at android.com
(Oleg improved the code by showing how to avoid tasklist_lock)
Suggested-by: Oleg Nesterov <oleg at redhat.com>
Co-developed-by: Daniel Colascione <dancol at google.com>
Signed-off-by: Daniel Colascione <dancol at google.com>
Signed-off-by: Joel Fernandes (Google) <joel at joelfernandes.org>

---

v1 -> v2:
* Restructure poll code to avoid tasklist_lock (Oleg)
* use task_pid instead of get_pid_task in notify_pidfd (Oleg)
* Added comments to code, commit message nits (Christian)
* Test case nits/improvements (Christian)

RFC -> v1:
* Based on CLONE_PIDFD patches: https://lwn.net/Articles/786244/
* Updated selftests.
* Renamed poll wake function to do_notify_pidfd.
* Removed depending on EXIT flags
* Removed POLLERR flag since semantics are controversial and
  we don't have usecases for it right now (later we can add if there's
  a need for it).

 include/linux/pid.h |  3 +++
 kernel/fork.c       | 29 +++++++++++++++++++++++++++++
 kernel/pid.c        |  2 ++
 kernel/signal.c     | 11 +++++++++++
 4 files changed, 45 insertions(+)

diff --git a/include/linux/pid.h b/include/linux/pid.h
index 3c8ef5a199ca..1484db6ca8d1 100644
--- a/include/linux/pid.h
+++ b/include/linux/pid.h
@@ -3,6 +3,7 @@
 #define _LINUX_PID_H
 
 #include <linux/rculist.h>
+#include <linux/wait.h>
 
 enum pid_type
 {
@@ -60,6 +61,8 @@ struct pid
 	unsigned int level;
 	/* lists of tasks that use this pid */
 	struct hlist_head tasks[PIDTYPE_MAX];
+	/* wait queue for pidfd notifications */
+	wait_queue_head_t wait_pidfd;
 	struct rcu_head rcu;
 	struct upid numbers[1];
 };
diff --git a/kernel/fork.c b/kernel/fork.c
index 5525837ed80e..721f8c9d2921 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1685,8 +1685,37 @@ static void pidfd_show_fdinfo(struct seq_file *m, struct file *f)
 }
 #endif
 
+/*
+ * Poll support for process exit notification.
+ */
+static unsigned int pidfd_poll(struct file *file, struct poll_table_struct *pts)
+{
+	struct task_struct *task;
+	struct pid *pid = file->private_data;
+	int poll_flags = 0;
+
+	poll_wait(file, &pid->wait_pidfd, pts);
+
+	rcu_read_lock();
+	task = pid_task(pid, PIDTYPE_PID);
+	WARN_ON_ONCE(task && !thread_group_leader(task));
+
+	/*
+	 * Inform pollers only when the whole thread group exits, if thread
+	 * group leader exits before all other threads in the group, then
+	 * poll(2) should block, similar to the wait(2) family.
+	 */
+	if (!task || (task->exit_state && thread_group_empty(task)))
+		poll_flags = POLLIN | POLLRDNORM;
+	rcu_read_unlock();
+
+	return poll_flags;
+}
+
+
 const struct file_operations pidfd_fops = {
 	.release = pidfd_release,
+	.poll = pidfd_poll,
 #ifdef CONFIG_PROC_FS
 	.show_fdinfo = pidfd_show_fdinfo,
 #endif
diff --git a/kernel/pid.c b/kernel/pid.c
index 20881598bdfa..5c90c239242f 100644
--- a/kernel/pid.c
+++ b/kernel/pid.c
@@ -214,6 +214,8 @@ struct pid *alloc_pid(struct pid_namespace *ns)
 	for (type = 0; type < PIDTYPE_MAX; ++type)
 		INIT_HLIST_HEAD(&pid->tasks[type]);
 
+	init_waitqueue_head(&pid->wait_pidfd);
+
 	upid = pid->numbers + ns->level;
 	spin_lock_irq(&pidmap_lock);
 	if (!(ns->pid_allocated & PIDNS_ADDING))
diff --git a/kernel/signal.c b/kernel/signal.c
index 1581140f2d99..a17fff073c3d 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -1800,6 +1800,14 @@ int send_sigqueue(struct sigqueue *q, struct pid *pid, enum pid_type type)
 	return ret;
 }
 
+static void do_notify_pidfd(struct task_struct *task)
+{
+	struct pid *pid;
+
+	pid = task_pid(task);
+	wake_up_all(&pid->wait_pidfd);
+}
+
 /*
  * Let a parent know about the death of a child.
  * For a stopped/continued status change, use do_notify_parent_cldstop instead.
@@ -1823,6 +1831,9 @@ bool do_notify_parent(struct task_struct *tsk, int sig)
 	BUG_ON(!tsk->ptrace &&
 	       (tsk->group_leader != tsk || !thread_group_empty(tsk)));
 
+	/* Wake up all pidfd waiters */
+	do_notify_pidfd(tsk);
+
 	if (sig != SIGCHLD) {
 		/*
 		 * This is only possible if parent == real_parent.
-- 
2.21.0.593.g511ec345e18-goog

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v2 2/2] Add selftests for pidfd polling
  2019-04-30 16:21 ` joel
  (?)
@ 2019-04-30 16:21   ` joel
  -1 siblings, 0 replies; 33+ messages in thread
From: Joel Fernandes (Google) @ 2019-04-30 16:21 UTC (permalink / raw)
  To: linux-kernel
  Cc: Joel Fernandes (Google),
	Al Viro, Andrew Morton, Andy Lutomirski, Arnd Bergmann,
	Christian Brauner, Daniel Colascione, David Howells,
	Eric W. Biederman, Greg Kroah-Hartman, Ingo Molnar, Jann Horn,
	Jonathan Kowalski, Kees Cook, kernel-team, KJ Tsanaktsidis,
	Linus Torvalds, linux-kselftest, Michal Hocko, Nadav Amit,
	Oleg Nesterov, Peter Zijlstra (Intel),
	Serge Hallyn, Shuah Khan, Steven Rostedt, Thomas Gleixner,
	Tim Murray, Tycho Andersen

Other than verifying pidfd based polling, the tests make sure that
wait semantics are preserved with the pidfd poll. Notably the 2 cases:
1. If a thread group leader exits while threads still there, then no
   pidfd poll notifcation should happen.
2. If a non-thread group leader does an execve, then the thread group
   leader is signaled to exit and is replaced with the execing thread
   as the new leader, however the parent is not notified in this case.

Signed-off-by: Joel Fernandes (Google) <joel@joelfernandes.org>
---
 tools/testing/selftests/pidfd/Makefile     |   2 +-
 tools/testing/selftests/pidfd/pidfd_test.c | 210 +++++++++++++++++++++
 2 files changed, 211 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/pidfd/Makefile b/tools/testing/selftests/pidfd/Makefile
index deaf8073bc06..4b31c14f273c 100644
--- a/tools/testing/selftests/pidfd/Makefile
+++ b/tools/testing/selftests/pidfd/Makefile
@@ -1,4 +1,4 @@
-CFLAGS += -g -I../../../../usr/include/
+CFLAGS += -g -I../../../../usr/include/ -lpthread
 
 TEST_GEN_PROGS := pidfd_test
 
diff --git a/tools/testing/selftests/pidfd/pidfd_test.c b/tools/testing/selftests/pidfd/pidfd_test.c
index d59378a93782..8b404ccbc4ff 100644
--- a/tools/testing/selftests/pidfd/pidfd_test.c
+++ b/tools/testing/selftests/pidfd/pidfd_test.c
@@ -4,18 +4,47 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <linux/types.h>
+#include <pthread.h>
 #include <sched.h>
 #include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <syscall.h>
+#include <sys/epoll.h>
+#include <sys/mman.h>
 #include <sys/mount.h>
 #include <sys/wait.h>
+#include <time.h>
 #include <unistd.h>
 
 #include "../kselftest.h"
 
+#define str(s) _str(s)
+#define _str(s) #s
+#define CHILD_THREAD_MIN_WAIT 3 /* seconds */
+
+#define MAX_EVENTS 5
+#ifndef __NR_pidfd_send_signal
+#define __NR_pidfd_send_signal 424
+#endif
+
+#ifndef CLONE_PIDFD
+#define CLONE_PIDFD 0x00001000
+#endif
+
+static pid_t pidfd_clone(int flags, int *pidfd, int (*fn)(void *))
+{
+	size_t stack_size = 1024;
+	char *stack[1024] = { 0 };
+
+#ifdef __ia64__
+	return __clone2(fn, stack, stack_size, flags | SIGCHLD, NULL, pidfd);
+#else
+	return clone(fn, stack + stack_size, flags | SIGCHLD, NULL, pidfd);
+#endif
+}
+
 static inline int sys_pidfd_send_signal(int pidfd, int sig, siginfo_t *info,
 					unsigned int flags)
 {
@@ -368,10 +397,191 @@ static int test_pidfd_send_signal_syscall_support(void)
 	return 0;
 }
 
+static void *test_pidfd_poll_exec_thread(void *priv)
+{
+	ksft_print_msg("Child Thread: starting. pid %d tid %d ; and sleeping\n",
+			getpid(), syscall(SYS_gettid));
+	ksft_print_msg("Child Thread: doing exec of sleep\n");
+
+	execl("/bin/sleep", "sleep", str(CHILD_THREAD_MIN_WAIT), (char *)NULL);
+
+	ksft_print_msg("Child Thread: DONE. pid %d tid %d\n",
+			getpid(), syscall(SYS_gettid));
+	return NULL;
+}
+
+static void poll_pidfd(const char *test_name, int pidfd)
+{
+	int c;
+	int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
+	struct epoll_event event, events[MAX_EVENTS];
+
+	if (epoll_fd == -1)
+		ksft_exit_fail_msg("%s test: Failed to create epoll file descriptor "
+				   "(errno %d)\n",
+				   test_name, errno);
+
+	event.events = EPOLLIN;
+	event.data.fd = pidfd;
+
+	if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, pidfd, &event)) {
+		ksft_exit_fail_msg("%s test: Failed to add epoll file descriptor "
+				   "(errno %d)\n",
+				   test_name, errno);
+	}
+
+	c = epoll_wait(epoll_fd, events, MAX_EVENTS, 5000);
+	if (c != 1 || !(events[0].events & EPOLLIN))
+		ksft_exit_fail_msg("%s test: Unexpected epoll_wait result (c=%d, events=%x) ",
+				   "(errno %d)\n",
+				   test_name, c, events[0].events, errno);
+
+	close(epoll_fd);
+	return;
+
+}
+
+static int child_poll_exec_test(void *args)
+{
+	pthread_t t1;
+
+	ksft_print_msg("Child (pidfd): starting. pid %d tid %d\n", getpid(),
+			syscall(SYS_gettid));
+	pthread_create(&t1, NULL, test_pidfd_poll_exec_thread, NULL);
+	/*
+	 * Exec in the non-leader thread will destroy the leader immediately.
+	 * If the wait in the parent returns too soon, the test fails.
+	 */
+	while (1)
+		sleep(1);
+}
+
+static int test_pidfd_poll_exec(int use_waitpid)
+{
+	int pid, pidfd = 0;
+	int status, ret;
+	pthread_t t1;
+	time_t prog_start = time(NULL);
+	const char *test_name = "pidfd_poll check for premature notification on child thread exec";
+
+	ksft_print_msg("Parent: pid: %d\n", getpid());
+	pid = pidfd_clone(CLONE_PIDFD, &pidfd, child_poll_exec_test);
+	if (pid < 0)
+		ksft_exit_fail_msg("%s test: pidfd_clone failed (ret %d, errno %d)\n",
+				   test_name, pid, errno);
+
+	ksft_print_msg("Parent: Waiting for Child (%d) to complete.\n", pid);
+
+	if (use_waitpid) {
+		ret = waitpid(pid, &status, 0);
+		if (ret == -1)
+			ksft_print_msg("Parent: error\n");
+
+		if (ret == pid)
+			ksft_print_msg("Parent: Child process waited for.\n");
+	} else {
+		poll_pidfd(test_name, pidfd);
+	}
+
+	time_t prog_time = time(NULL) - prog_start;
+
+	ksft_print_msg("Time waited for child: %lu\n", prog_time);
+
+	close(pidfd);
+
+	if (prog_time < CHILD_THREAD_MIN_WAIT || prog_time > CHILD_THREAD_MIN_WAIT + 2)
+		ksft_exit_fail_msg("%s test: Failed\n", test_name);
+	else
+		ksft_test_result_pass("%s test: Passed\n", test_name);
+}
+
+static void *test_pidfd_poll_leader_exit_thread(void *priv)
+{
+	ksft_print_msg("Child Thread: starting. pid %d tid %d ; and sleeping\n",
+			getpid(), syscall(SYS_gettid));
+	sleep(CHILD_THREAD_MIN_WAIT);
+	ksft_print_msg("Child Thread: DONE. pid %d tid %d\n", getpid(), syscall(SYS_gettid));
+	return NULL;
+}
+
+static time_t *child_exit_secs;
+static int child_poll_leader_exit_test(void *args)
+{
+	pthread_t t1, t2;
+
+	ksft_print_msg("Child: starting. pid %d tid %d\n", getpid(), syscall(SYS_gettid));
+	pthread_create(&t1, NULL, test_pidfd_poll_leader_exit_thread, NULL);
+	pthread_create(&t2, NULL, test_pidfd_poll_leader_exit_thread, NULL);
+
+	/*
+	 * glibc exit calls exit_group syscall, so explicity call exit only
+	 * so that only the group leader exits, leaving the threads alone.
+	 */
+	*child_exit_secs = time(NULL);
+	syscall(SYS_exit, 0);
+}
+
+static int test_pidfd_poll_leader_exit(int use_waitpid)
+{
+	int pid, pidfd = 0;
+	int status, ret;
+	time_t prog_start = time(NULL);
+	const char *test_name = "pidfd_poll check for premature notification on non-empty"
+				"group leader exit";
+
+	child_exit_secs = mmap(NULL, sizeof *child_exit_secs, PROT_READ | PROT_WRITE,
+			MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+
+	if (child_exit_secs == MAP_FAILED)
+		ksft_exit_fail_msg("%s test: mmap failed (errno %d)\n",
+				   test_name, errno);
+
+	ksft_print_msg("Parent: pid: %d\n", getpid());
+	pid = pidfd_clone(CLONE_PIDFD, &pidfd, child_poll_leader_exit_test);
+	if (pid < 0)
+		ksft_exit_fail_msg("%s test: pidfd_clone failed (ret %d, errno %d)\n",
+				   test_name, pid, errno);
+
+	ksft_print_msg("Parent: Waiting for Child (%d) to complete.\n", pid);
+
+	if (use_waitpid) {
+		ret = waitpid(pid, &status, 0);
+		if (ret == -1)
+			ksft_print_msg("Parent: error\n");
+	} else {
+		/*
+		 * This sleep tests for the case where if the child exits, and is in
+		 * EXIT_ZOMBIE, but the thread group leader is non-empty, then the poll
+		 * doesn't prematurely return even though there are active threads
+		 */
+		sleep(1);
+		poll_pidfd(test_name, pidfd);
+	}
+
+	if (ret == pid)
+		ksft_print_msg("Parent: Child process waited for.\n");
+
+	time_t since_child_exit = time(NULL) - *child_exit_secs;
+
+	ksft_print_msg("Time since child exit: %lu\n", since_child_exit);
+
+	close(pidfd);
+
+	if (since_child_exit < CHILD_THREAD_MIN_WAIT ||
+			since_child_exit > CHILD_THREAD_MIN_WAIT + 2)
+		ksft_exit_fail_msg("%s test: Failed\n", test_name);
+	else
+		ksft_test_result_pass("%s test: Passed\n", test_name);
+}
+
 int main(int argc, char **argv)
 {
 	ksft_print_header();
 
+	test_pidfd_poll_exec(0);
+	test_pidfd_poll_exec(1);
+	test_pidfd_poll_leader_exit(0);
+	test_pidfd_poll_leader_exit(1);
 	test_pidfd_send_signal_syscall_support();
 	test_pidfd_send_signal_simple_success();
 	test_pidfd_send_signal_exited_fail();
-- 
2.21.0.593.g511ec345e18-goog


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v2 2/2] Add selftests for pidfd polling
@ 2019-04-30 16:21   ` joel
  0 siblings, 0 replies; 33+ messages in thread
From: joel @ 2019-04-30 16:21 UTC (permalink / raw)


Other than verifying pidfd based polling, the tests make sure that
wait semantics are preserved with the pidfd poll. Notably the 2 cases:
1. If a thread group leader exits while threads still there, then no
   pidfd poll notifcation should happen.
2. If a non-thread group leader does an execve, then the thread group
   leader is signaled to exit and is replaced with the execing thread
   as the new leader, however the parent is not notified in this case.

Signed-off-by: Joel Fernandes (Google) <joel at joelfernandes.org>
---
 tools/testing/selftests/pidfd/Makefile     |   2 +-
 tools/testing/selftests/pidfd/pidfd_test.c | 210 +++++++++++++++++++++
 2 files changed, 211 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/pidfd/Makefile b/tools/testing/selftests/pidfd/Makefile
index deaf8073bc06..4b31c14f273c 100644
--- a/tools/testing/selftests/pidfd/Makefile
+++ b/tools/testing/selftests/pidfd/Makefile
@@ -1,4 +1,4 @@
-CFLAGS += -g -I../../../../usr/include/
+CFLAGS += -g -I../../../../usr/include/ -lpthread
 
 TEST_GEN_PROGS := pidfd_test
 
diff --git a/tools/testing/selftests/pidfd/pidfd_test.c b/tools/testing/selftests/pidfd/pidfd_test.c
index d59378a93782..8b404ccbc4ff 100644
--- a/tools/testing/selftests/pidfd/pidfd_test.c
+++ b/tools/testing/selftests/pidfd/pidfd_test.c
@@ -4,18 +4,47 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <linux/types.h>
+#include <pthread.h>
 #include <sched.h>
 #include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <syscall.h>
+#include <sys/epoll.h>
+#include <sys/mman.h>
 #include <sys/mount.h>
 #include <sys/wait.h>
+#include <time.h>
 #include <unistd.h>
 
 #include "../kselftest.h"
 
+#define str(s) _str(s)
+#define _str(s) #s
+#define CHILD_THREAD_MIN_WAIT 3 /* seconds */
+
+#define MAX_EVENTS 5
+#ifndef __NR_pidfd_send_signal
+#define __NR_pidfd_send_signal 424
+#endif
+
+#ifndef CLONE_PIDFD
+#define CLONE_PIDFD 0x00001000
+#endif
+
+static pid_t pidfd_clone(int flags, int *pidfd, int (*fn)(void *))
+{
+	size_t stack_size = 1024;
+	char *stack[1024] = { 0 };
+
+#ifdef __ia64__
+	return __clone2(fn, stack, stack_size, flags | SIGCHLD, NULL, pidfd);
+#else
+	return clone(fn, stack + stack_size, flags | SIGCHLD, NULL, pidfd);
+#endif
+}
+
 static inline int sys_pidfd_send_signal(int pidfd, int sig, siginfo_t *info,
 					unsigned int flags)
 {
@@ -368,10 +397,191 @@ static int test_pidfd_send_signal_syscall_support(void)
 	return 0;
 }
 
+static void *test_pidfd_poll_exec_thread(void *priv)
+{
+	ksft_print_msg("Child Thread: starting. pid %d tid %d ; and sleeping\n",
+			getpid(), syscall(SYS_gettid));
+	ksft_print_msg("Child Thread: doing exec of sleep\n");
+
+	execl("/bin/sleep", "sleep", str(CHILD_THREAD_MIN_WAIT), (char *)NULL);
+
+	ksft_print_msg("Child Thread: DONE. pid %d tid %d\n",
+			getpid(), syscall(SYS_gettid));
+	return NULL;
+}
+
+static void poll_pidfd(const char *test_name, int pidfd)
+{
+	int c;
+	int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
+	struct epoll_event event, events[MAX_EVENTS];
+
+	if (epoll_fd == -1)
+		ksft_exit_fail_msg("%s test: Failed to create epoll file descriptor "
+				   "(errno %d)\n",
+				   test_name, errno);
+
+	event.events = EPOLLIN;
+	event.data.fd = pidfd;
+
+	if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, pidfd, &event)) {
+		ksft_exit_fail_msg("%s test: Failed to add epoll file descriptor "
+				   "(errno %d)\n",
+				   test_name, errno);
+	}
+
+	c = epoll_wait(epoll_fd, events, MAX_EVENTS, 5000);
+	if (c != 1 || !(events[0].events & EPOLLIN))
+		ksft_exit_fail_msg("%s test: Unexpected epoll_wait result (c=%d, events=%x) ",
+				   "(errno %d)\n",
+				   test_name, c, events[0].events, errno);
+
+	close(epoll_fd);
+	return;
+
+}
+
+static int child_poll_exec_test(void *args)
+{
+	pthread_t t1;
+
+	ksft_print_msg("Child (pidfd): starting. pid %d tid %d\n", getpid(),
+			syscall(SYS_gettid));
+	pthread_create(&t1, NULL, test_pidfd_poll_exec_thread, NULL);
+	/*
+	 * Exec in the non-leader thread will destroy the leader immediately.
+	 * If the wait in the parent returns too soon, the test fails.
+	 */
+	while (1)
+		sleep(1);
+}
+
+static int test_pidfd_poll_exec(int use_waitpid)
+{
+	int pid, pidfd = 0;
+	int status, ret;
+	pthread_t t1;
+	time_t prog_start = time(NULL);
+	const char *test_name = "pidfd_poll check for premature notification on child thread exec";
+
+	ksft_print_msg("Parent: pid: %d\n", getpid());
+	pid = pidfd_clone(CLONE_PIDFD, &pidfd, child_poll_exec_test);
+	if (pid < 0)
+		ksft_exit_fail_msg("%s test: pidfd_clone failed (ret %d, errno %d)\n",
+				   test_name, pid, errno);
+
+	ksft_print_msg("Parent: Waiting for Child (%d) to complete.\n", pid);
+
+	if (use_waitpid) {
+		ret = waitpid(pid, &status, 0);
+		if (ret == -1)
+			ksft_print_msg("Parent: error\n");
+
+		if (ret == pid)
+			ksft_print_msg("Parent: Child process waited for.\n");
+	} else {
+		poll_pidfd(test_name, pidfd);
+	}
+
+	time_t prog_time = time(NULL) - prog_start;
+
+	ksft_print_msg("Time waited for child: %lu\n", prog_time);
+
+	close(pidfd);
+
+	if (prog_time < CHILD_THREAD_MIN_WAIT || prog_time > CHILD_THREAD_MIN_WAIT + 2)
+		ksft_exit_fail_msg("%s test: Failed\n", test_name);
+	else
+		ksft_test_result_pass("%s test: Passed\n", test_name);
+}
+
+static void *test_pidfd_poll_leader_exit_thread(void *priv)
+{
+	ksft_print_msg("Child Thread: starting. pid %d tid %d ; and sleeping\n",
+			getpid(), syscall(SYS_gettid));
+	sleep(CHILD_THREAD_MIN_WAIT);
+	ksft_print_msg("Child Thread: DONE. pid %d tid %d\n", getpid(), syscall(SYS_gettid));
+	return NULL;
+}
+
+static time_t *child_exit_secs;
+static int child_poll_leader_exit_test(void *args)
+{
+	pthread_t t1, t2;
+
+	ksft_print_msg("Child: starting. pid %d tid %d\n", getpid(), syscall(SYS_gettid));
+	pthread_create(&t1, NULL, test_pidfd_poll_leader_exit_thread, NULL);
+	pthread_create(&t2, NULL, test_pidfd_poll_leader_exit_thread, NULL);
+
+	/*
+	 * glibc exit calls exit_group syscall, so explicity call exit only
+	 * so that only the group leader exits, leaving the threads alone.
+	 */
+	*child_exit_secs = time(NULL);
+	syscall(SYS_exit, 0);
+}
+
+static int test_pidfd_poll_leader_exit(int use_waitpid)
+{
+	int pid, pidfd = 0;
+	int status, ret;
+	time_t prog_start = time(NULL);
+	const char *test_name = "pidfd_poll check for premature notification on non-empty"
+				"group leader exit";
+
+	child_exit_secs = mmap(NULL, sizeof *child_exit_secs, PROT_READ | PROT_WRITE,
+			MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+
+	if (child_exit_secs == MAP_FAILED)
+		ksft_exit_fail_msg("%s test: mmap failed (errno %d)\n",
+				   test_name, errno);
+
+	ksft_print_msg("Parent: pid: %d\n", getpid());
+	pid = pidfd_clone(CLONE_PIDFD, &pidfd, child_poll_leader_exit_test);
+	if (pid < 0)
+		ksft_exit_fail_msg("%s test: pidfd_clone failed (ret %d, errno %d)\n",
+				   test_name, pid, errno);
+
+	ksft_print_msg("Parent: Waiting for Child (%d) to complete.\n", pid);
+
+	if (use_waitpid) {
+		ret = waitpid(pid, &status, 0);
+		if (ret == -1)
+			ksft_print_msg("Parent: error\n");
+	} else {
+		/*
+		 * This sleep tests for the case where if the child exits, and is in
+		 * EXIT_ZOMBIE, but the thread group leader is non-empty, then the poll
+		 * doesn't prematurely return even though there are active threads
+		 */
+		sleep(1);
+		poll_pidfd(test_name, pidfd);
+	}
+
+	if (ret == pid)
+		ksft_print_msg("Parent: Child process waited for.\n");
+
+	time_t since_child_exit = time(NULL) - *child_exit_secs;
+
+	ksft_print_msg("Time since child exit: %lu\n", since_child_exit);
+
+	close(pidfd);
+
+	if (since_child_exit < CHILD_THREAD_MIN_WAIT ||
+			since_child_exit > CHILD_THREAD_MIN_WAIT + 2)
+		ksft_exit_fail_msg("%s test: Failed\n", test_name);
+	else
+		ksft_test_result_pass("%s test: Passed\n", test_name);
+}
+
 int main(int argc, char **argv)
 {
 	ksft_print_header();
 
+	test_pidfd_poll_exec(0);
+	test_pidfd_poll_exec(1);
+	test_pidfd_poll_leader_exit(0);
+	test_pidfd_poll_leader_exit(1);
 	test_pidfd_send_signal_syscall_support();
 	test_pidfd_send_signal_simple_success();
 	test_pidfd_send_signal_exited_fail();
-- 
2.21.0.593.g511ec345e18-goog

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v2 2/2] Add selftests for pidfd polling
@ 2019-04-30 16:21   ` joel
  0 siblings, 0 replies; 33+ messages in thread
From: Joel Fernandes (Google) @ 2019-04-30 16:21 UTC (permalink / raw)


Other than verifying pidfd based polling, the tests make sure that
wait semantics are preserved with the pidfd poll. Notably the 2 cases:
1. If a thread group leader exits while threads still there, then no
   pidfd poll notifcation should happen.
2. If a non-thread group leader does an execve, then the thread group
   leader is signaled to exit and is replaced with the execing thread
   as the new leader, however the parent is not notified in this case.

Signed-off-by: Joel Fernandes (Google) <joel at joelfernandes.org>
---
 tools/testing/selftests/pidfd/Makefile     |   2 +-
 tools/testing/selftests/pidfd/pidfd_test.c | 210 +++++++++++++++++++++
 2 files changed, 211 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/pidfd/Makefile b/tools/testing/selftests/pidfd/Makefile
index deaf8073bc06..4b31c14f273c 100644
--- a/tools/testing/selftests/pidfd/Makefile
+++ b/tools/testing/selftests/pidfd/Makefile
@@ -1,4 +1,4 @@
-CFLAGS += -g -I../../../../usr/include/
+CFLAGS += -g -I../../../../usr/include/ -lpthread
 
 TEST_GEN_PROGS := pidfd_test
 
diff --git a/tools/testing/selftests/pidfd/pidfd_test.c b/tools/testing/selftests/pidfd/pidfd_test.c
index d59378a93782..8b404ccbc4ff 100644
--- a/tools/testing/selftests/pidfd/pidfd_test.c
+++ b/tools/testing/selftests/pidfd/pidfd_test.c
@@ -4,18 +4,47 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <linux/types.h>
+#include <pthread.h>
 #include <sched.h>
 #include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <syscall.h>
+#include <sys/epoll.h>
+#include <sys/mman.h>
 #include <sys/mount.h>
 #include <sys/wait.h>
+#include <time.h>
 #include <unistd.h>
 
 #include "../kselftest.h"
 
+#define str(s) _str(s)
+#define _str(s) #s
+#define CHILD_THREAD_MIN_WAIT 3 /* seconds */
+
+#define MAX_EVENTS 5
+#ifndef __NR_pidfd_send_signal
+#define __NR_pidfd_send_signal 424
+#endif
+
+#ifndef CLONE_PIDFD
+#define CLONE_PIDFD 0x00001000
+#endif
+
+static pid_t pidfd_clone(int flags, int *pidfd, int (*fn)(void *))
+{
+	size_t stack_size = 1024;
+	char *stack[1024] = { 0 };
+
+#ifdef __ia64__
+	return __clone2(fn, stack, stack_size, flags | SIGCHLD, NULL, pidfd);
+#else
+	return clone(fn, stack + stack_size, flags | SIGCHLD, NULL, pidfd);
+#endif
+}
+
 static inline int sys_pidfd_send_signal(int pidfd, int sig, siginfo_t *info,
 					unsigned int flags)
 {
@@ -368,10 +397,191 @@ static int test_pidfd_send_signal_syscall_support(void)
 	return 0;
 }
 
+static void *test_pidfd_poll_exec_thread(void *priv)
+{
+	ksft_print_msg("Child Thread: starting. pid %d tid %d ; and sleeping\n",
+			getpid(), syscall(SYS_gettid));
+	ksft_print_msg("Child Thread: doing exec of sleep\n");
+
+	execl("/bin/sleep", "sleep", str(CHILD_THREAD_MIN_WAIT), (char *)NULL);
+
+	ksft_print_msg("Child Thread: DONE. pid %d tid %d\n",
+			getpid(), syscall(SYS_gettid));
+	return NULL;
+}
+
+static void poll_pidfd(const char *test_name, int pidfd)
+{
+	int c;
+	int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
+	struct epoll_event event, events[MAX_EVENTS];
+
+	if (epoll_fd == -1)
+		ksft_exit_fail_msg("%s test: Failed to create epoll file descriptor "
+				   "(errno %d)\n",
+				   test_name, errno);
+
+	event.events = EPOLLIN;
+	event.data.fd = pidfd;
+
+	if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, pidfd, &event)) {
+		ksft_exit_fail_msg("%s test: Failed to add epoll file descriptor "
+				   "(errno %d)\n",
+				   test_name, errno);
+	}
+
+	c = epoll_wait(epoll_fd, events, MAX_EVENTS, 5000);
+	if (c != 1 || !(events[0].events & EPOLLIN))
+		ksft_exit_fail_msg("%s test: Unexpected epoll_wait result (c=%d, events=%x) ",
+				   "(errno %d)\n",
+				   test_name, c, events[0].events, errno);
+
+	close(epoll_fd);
+	return;
+
+}
+
+static int child_poll_exec_test(void *args)
+{
+	pthread_t t1;
+
+	ksft_print_msg("Child (pidfd): starting. pid %d tid %d\n", getpid(),
+			syscall(SYS_gettid));
+	pthread_create(&t1, NULL, test_pidfd_poll_exec_thread, NULL);
+	/*
+	 * Exec in the non-leader thread will destroy the leader immediately.
+	 * If the wait in the parent returns too soon, the test fails.
+	 */
+	while (1)
+		sleep(1);
+}
+
+static int test_pidfd_poll_exec(int use_waitpid)
+{
+	int pid, pidfd = 0;
+	int status, ret;
+	pthread_t t1;
+	time_t prog_start = time(NULL);
+	const char *test_name = "pidfd_poll check for premature notification on child thread exec";
+
+	ksft_print_msg("Parent: pid: %d\n", getpid());
+	pid = pidfd_clone(CLONE_PIDFD, &pidfd, child_poll_exec_test);
+	if (pid < 0)
+		ksft_exit_fail_msg("%s test: pidfd_clone failed (ret %d, errno %d)\n",
+				   test_name, pid, errno);
+
+	ksft_print_msg("Parent: Waiting for Child (%d) to complete.\n", pid);
+
+	if (use_waitpid) {
+		ret = waitpid(pid, &status, 0);
+		if (ret == -1)
+			ksft_print_msg("Parent: error\n");
+
+		if (ret == pid)
+			ksft_print_msg("Parent: Child process waited for.\n");
+	} else {
+		poll_pidfd(test_name, pidfd);
+	}
+
+	time_t prog_time = time(NULL) - prog_start;
+
+	ksft_print_msg("Time waited for child: %lu\n", prog_time);
+
+	close(pidfd);
+
+	if (prog_time < CHILD_THREAD_MIN_WAIT || prog_time > CHILD_THREAD_MIN_WAIT + 2)
+		ksft_exit_fail_msg("%s test: Failed\n", test_name);
+	else
+		ksft_test_result_pass("%s test: Passed\n", test_name);
+}
+
+static void *test_pidfd_poll_leader_exit_thread(void *priv)
+{
+	ksft_print_msg("Child Thread: starting. pid %d tid %d ; and sleeping\n",
+			getpid(), syscall(SYS_gettid));
+	sleep(CHILD_THREAD_MIN_WAIT);
+	ksft_print_msg("Child Thread: DONE. pid %d tid %d\n", getpid(), syscall(SYS_gettid));
+	return NULL;
+}
+
+static time_t *child_exit_secs;
+static int child_poll_leader_exit_test(void *args)
+{
+	pthread_t t1, t2;
+
+	ksft_print_msg("Child: starting. pid %d tid %d\n", getpid(), syscall(SYS_gettid));
+	pthread_create(&t1, NULL, test_pidfd_poll_leader_exit_thread, NULL);
+	pthread_create(&t2, NULL, test_pidfd_poll_leader_exit_thread, NULL);
+
+	/*
+	 * glibc exit calls exit_group syscall, so explicity call exit only
+	 * so that only the group leader exits, leaving the threads alone.
+	 */
+	*child_exit_secs = time(NULL);
+	syscall(SYS_exit, 0);
+}
+
+static int test_pidfd_poll_leader_exit(int use_waitpid)
+{
+	int pid, pidfd = 0;
+	int status, ret;
+	time_t prog_start = time(NULL);
+	const char *test_name = "pidfd_poll check for premature notification on non-empty"
+				"group leader exit";
+
+	child_exit_secs = mmap(NULL, sizeof *child_exit_secs, PROT_READ | PROT_WRITE,
+			MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+
+	if (child_exit_secs == MAP_FAILED)
+		ksft_exit_fail_msg("%s test: mmap failed (errno %d)\n",
+				   test_name, errno);
+
+	ksft_print_msg("Parent: pid: %d\n", getpid());
+	pid = pidfd_clone(CLONE_PIDFD, &pidfd, child_poll_leader_exit_test);
+	if (pid < 0)
+		ksft_exit_fail_msg("%s test: pidfd_clone failed (ret %d, errno %d)\n",
+				   test_name, pid, errno);
+
+	ksft_print_msg("Parent: Waiting for Child (%d) to complete.\n", pid);
+
+	if (use_waitpid) {
+		ret = waitpid(pid, &status, 0);
+		if (ret == -1)
+			ksft_print_msg("Parent: error\n");
+	} else {
+		/*
+		 * This sleep tests for the case where if the child exits, and is in
+		 * EXIT_ZOMBIE, but the thread group leader is non-empty, then the poll
+		 * doesn't prematurely return even though there are active threads
+		 */
+		sleep(1);
+		poll_pidfd(test_name, pidfd);
+	}
+
+	if (ret == pid)
+		ksft_print_msg("Parent: Child process waited for.\n");
+
+	time_t since_child_exit = time(NULL) - *child_exit_secs;
+
+	ksft_print_msg("Time since child exit: %lu\n", since_child_exit);
+
+	close(pidfd);
+
+	if (since_child_exit < CHILD_THREAD_MIN_WAIT ||
+			since_child_exit > CHILD_THREAD_MIN_WAIT + 2)
+		ksft_exit_fail_msg("%s test: Failed\n", test_name);
+	else
+		ksft_test_result_pass("%s test: Passed\n", test_name);
+}
+
 int main(int argc, char **argv)
 {
 	ksft_print_header();
 
+	test_pidfd_poll_exec(0);
+	test_pidfd_poll_exec(1);
+	test_pidfd_poll_leader_exit(0);
+	test_pidfd_poll_leader_exit(1);
 	test_pidfd_send_signal_syscall_support();
 	test_pidfd_send_signal_simple_success();
 	test_pidfd_send_signal_exited_fail();
-- 
2.21.0.593.g511ec345e18-goog

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* Re: [PATCH v2 1/2] Add polling support to pidfd
  2019-04-30 16:21 ` joel
  (?)
@ 2019-04-30 19:07   ` christian
  -1 siblings, 0 replies; 33+ messages in thread
From: Christian Brauner @ 2019-04-30 19:07 UTC (permalink / raw)
  To: Joel Fernandes (Google)
  Cc: linux-kernel, Andy Lutomirski, Steven Rostedt, Daniel Colascione,
	Jann Horn, Tim Murray, Jonathan Kowalski, Linus Torvalds,
	Al Viro, Kees Cook, David Howells, Oleg Nesterov, kernel-team,
	Andrew Morton, Arnd Bergmann, Eric W. Biederman,
	Greg Kroah-Hartman, Ingo Molnar, KJ Tsanaktsidis,
	linux-kselftest, Michal Hocko, Nadav Amit, Peter Zijlstra (Intel),
	Serge Hallyn, Shuah Khan, Thomas Gleixner, Tycho Andersen

On Tue, Apr 30, 2019 at 12:21:53PM -0400, Joel Fernandes (Google) wrote:
> Android low memory killer (LMK) needs to know when a process dies once
> it is sent the kill signal. It does so by checking for the existence of
> /proc/pid which is both racy and slow. For example, if a PID is reused
> between when LMK sends a kill signal and checks for existence of the
> PID, since the wrong PID is now possibly checked for existence.
> 
> This patch adds polling support to pidfd. Using the polling support, LMK
> will be able to get notified when a process exists in race-free and fast
> way, and allows the LMK to do other things (such as by polling on other
> fds) while awaiting the process being killed to die.
> 
> For notification to polling processes, we follow the same existing
> mechanism in the kernel used when the parent of the task group is to be
> notified of a child's death (do_notify_parent).  This is precisely when
> the tasks waiting on a poll of pidfd are also awakened in this patch.
> 
> We have decided to include the waitqueue in struct pid for the following
> reasons:
> 1. The wait queue has to survive for the lifetime of the poll. Including
> it in task_struct would not be option in this case because the task can
> be reaped and destroyed before the poll returns.
> 
> 2. By including the struct pid for the waitqueue means that during
> de_thread(), the new thread group leader automatically gets the new
> waitqueue/pid even though its task_struct is different.
> 
> Appropriate test cases are added in the second patch to provide coverage
> of all the cases the patch is handling.
> 
> Andy had a similar patch [1] in the past which was a good reference
> however this patch tries to handle different situations properly related
> to thread group existence, and how/where it notifies. And also solves
> other bugs (waitqueue lifetime).  Daniel had a similar patch [2]
> recently which this patch supercedes.
> 
> [1] https://lore.kernel.org/patchwork/patch/345098/
> [2] https://lore.kernel.org/lkml/20181029175322.189042-1-dancol@google.com/
> 
> Cc: Andy Lutomirski <luto@amacapital.net>
> Cc: Steven Rostedt <rostedt@goodmis.org>
> Cc: Daniel Colascione <dancol@google.com>
> Cc: Christian Brauner <christian@brauner.io>
> Cc: Jann Horn <jannh@google.com>
> Cc: Tim Murray <timmurray@google.com>
> Cc: Jonathan Kowalski <bl0pbl33p@gmail.com>
> Cc: Linus Torvalds <torvalds@linux-foundation.org>
> Cc: Al Viro <viro@zeniv.linux.org.uk>
> Cc: Kees Cook <keescook@chromium.org>
> Cc: David Howells <dhowells@redhat.com>
> Cc: Oleg Nesterov <oleg@redhat.com>
> Cc: kernel-team@android.com
> (Oleg improved the code by showing how to avoid tasklist_lock)
> Suggested-by: Oleg Nesterov <oleg@redhat.com>
> Co-developed-by: Daniel Colascione <dancol@google.com>
> Signed-off-by: Daniel Colascione <dancol@google.com>
> Signed-off-by: Joel Fernandes (Google) <joel@joelfernandes.org>

This looks good to me. Once Oleg has given his Ack/Review I'm going to
move this into pidfd for-next and as mentioned before schedule it for
5.3 after CLONE_PIDFD has been merged.

Reviewed-by: Christian Brauner <christian@brauner.io>

> 
> ---
> 
> v1 -> v2:
> * Restructure poll code to avoid tasklist_lock (Oleg)
> * use task_pid instead of get_pid_task in notify_pidfd (Oleg)
> * Added comments to code, commit message nits (Christian)
> * Test case nits/improvements (Christian)
> 
> RFC -> v1:
> * Based on CLONE_PIDFD patches: https://lwn.net/Articles/786244/
> * Updated selftests.
> * Renamed poll wake function to do_notify_pidfd.
> * Removed depending on EXIT flags
> * Removed POLLERR flag since semantics are controversial and
>   we don't have usecases for it right now (later we can add if there's
>   a need for it).
> 
>  include/linux/pid.h |  3 +++
>  kernel/fork.c       | 29 +++++++++++++++++++++++++++++
>  kernel/pid.c        |  2 ++
>  kernel/signal.c     | 11 +++++++++++
>  4 files changed, 45 insertions(+)
> 
> diff --git a/include/linux/pid.h b/include/linux/pid.h
> index 3c8ef5a199ca..1484db6ca8d1 100644
> --- a/include/linux/pid.h
> +++ b/include/linux/pid.h
> @@ -3,6 +3,7 @@
>  #define _LINUX_PID_H
>  
>  #include <linux/rculist.h>
> +#include <linux/wait.h>
>  
>  enum pid_type
>  {
> @@ -60,6 +61,8 @@ struct pid
>  	unsigned int level;
>  	/* lists of tasks that use this pid */
>  	struct hlist_head tasks[PIDTYPE_MAX];
> +	/* wait queue for pidfd notifications */
> +	wait_queue_head_t wait_pidfd;
>  	struct rcu_head rcu;
>  	struct upid numbers[1];
>  };
> diff --git a/kernel/fork.c b/kernel/fork.c
> index 5525837ed80e..721f8c9d2921 100644
> --- a/kernel/fork.c
> +++ b/kernel/fork.c
> @@ -1685,8 +1685,37 @@ static void pidfd_show_fdinfo(struct seq_file *m, struct file *f)
>  }
>  #endif
>  
> +/*
> + * Poll support for process exit notification.
> + */
> +static unsigned int pidfd_poll(struct file *file, struct poll_table_struct *pts)
> +{
> +	struct task_struct *task;
> +	struct pid *pid = file->private_data;
> +	int poll_flags = 0;
> +
> +	poll_wait(file, &pid->wait_pidfd, pts);
> +
> +	rcu_read_lock();
> +	task = pid_task(pid, PIDTYPE_PID);
> +	WARN_ON_ONCE(task && !thread_group_leader(task));
> +
> +	/*
> +	 * Inform pollers only when the whole thread group exits, if thread
> +	 * group leader exits before all other threads in the group, then
> +	 * poll(2) should block, similar to the wait(2) family.
> +	 */
> +	if (!task || (task->exit_state && thread_group_empty(task)))
> +		poll_flags = POLLIN | POLLRDNORM;
> +	rcu_read_unlock();
> +
> +	return poll_flags;
> +}
> +
> +
>  const struct file_operations pidfd_fops = {
>  	.release = pidfd_release,
> +	.poll = pidfd_poll,
>  #ifdef CONFIG_PROC_FS
>  	.show_fdinfo = pidfd_show_fdinfo,
>  #endif
> diff --git a/kernel/pid.c b/kernel/pid.c
> index 20881598bdfa..5c90c239242f 100644
> --- a/kernel/pid.c
> +++ b/kernel/pid.c
> @@ -214,6 +214,8 @@ struct pid *alloc_pid(struct pid_namespace *ns)
>  	for (type = 0; type < PIDTYPE_MAX; ++type)
>  		INIT_HLIST_HEAD(&pid->tasks[type]);
>  
> +	init_waitqueue_head(&pid->wait_pidfd);
> +
>  	upid = pid->numbers + ns->level;
>  	spin_lock_irq(&pidmap_lock);
>  	if (!(ns->pid_allocated & PIDNS_ADDING))
> diff --git a/kernel/signal.c b/kernel/signal.c
> index 1581140f2d99..a17fff073c3d 100644
> --- a/kernel/signal.c
> +++ b/kernel/signal.c
> @@ -1800,6 +1800,14 @@ int send_sigqueue(struct sigqueue *q, struct pid *pid, enum pid_type type)
>  	return ret;
>  }
>  
> +static void do_notify_pidfd(struct task_struct *task)
> +{
> +	struct pid *pid;
> +
> +	pid = task_pid(task);
> +	wake_up_all(&pid->wait_pidfd);
> +}
> +
>  /*
>   * Let a parent know about the death of a child.
>   * For a stopped/continued status change, use do_notify_parent_cldstop instead.
> @@ -1823,6 +1831,9 @@ bool do_notify_parent(struct task_struct *tsk, int sig)
>  	BUG_ON(!tsk->ptrace &&
>  	       (tsk->group_leader != tsk || !thread_group_empty(tsk)));
>  
> +	/* Wake up all pidfd waiters */
> +	do_notify_pidfd(tsk);
> +
>  	if (sig != SIGCHLD) {
>  		/*
>  		 * This is only possible if parent == real_parent.
> -- 
> 2.21.0.593.g511ec345e18-goog

^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v2 1/2] Add polling support to pidfd
@ 2019-04-30 19:07   ` christian
  0 siblings, 0 replies; 33+ messages in thread
From: christian @ 2019-04-30 19:07 UTC (permalink / raw)


On Tue, Apr 30, 2019 at 12:21:53PM -0400, Joel Fernandes (Google) wrote:
> Android low memory killer (LMK) needs to know when a process dies once
> it is sent the kill signal. It does so by checking for the existence of
> /proc/pid which is both racy and slow. For example, if a PID is reused
> between when LMK sends a kill signal and checks for existence of the
> PID, since the wrong PID is now possibly checked for existence.
> 
> This patch adds polling support to pidfd. Using the polling support, LMK
> will be able to get notified when a process exists in race-free and fast
> way, and allows the LMK to do other things (such as by polling on other
> fds) while awaiting the process being killed to die.
> 
> For notification to polling processes, we follow the same existing
> mechanism in the kernel used when the parent of the task group is to be
> notified of a child's death (do_notify_parent).  This is precisely when
> the tasks waiting on a poll of pidfd are also awakened in this patch.
> 
> We have decided to include the waitqueue in struct pid for the following
> reasons:
> 1. The wait queue has to survive for the lifetime of the poll. Including
> it in task_struct would not be option in this case because the task can
> be reaped and destroyed before the poll returns.
> 
> 2. By including the struct pid for the waitqueue means that during
> de_thread(), the new thread group leader automatically gets the new
> waitqueue/pid even though its task_struct is different.
> 
> Appropriate test cases are added in the second patch to provide coverage
> of all the cases the patch is handling.
> 
> Andy had a similar patch [1] in the past which was a good reference
> however this patch tries to handle different situations properly related
> to thread group existence, and how/where it notifies. And also solves
> other bugs (waitqueue lifetime).  Daniel had a similar patch [2]
> recently which this patch supercedes.
> 
> [1] https://lore.kernel.org/patchwork/patch/345098/
> [2] https://lore.kernel.org/lkml/20181029175322.189042-1-dancol at google.com/
> 
> Cc: Andy Lutomirski <luto at amacapital.net>
> Cc: Steven Rostedt <rostedt at goodmis.org>
> Cc: Daniel Colascione <dancol at google.com>
> Cc: Christian Brauner <christian at brauner.io>
> Cc: Jann Horn <jannh at google.com>
> Cc: Tim Murray <timmurray at google.com>
> Cc: Jonathan Kowalski <bl0pbl33p at gmail.com>
> Cc: Linus Torvalds <torvalds at linux-foundation.org>
> Cc: Al Viro <viro at zeniv.linux.org.uk>
> Cc: Kees Cook <keescook at chromium.org>
> Cc: David Howells <dhowells at redhat.com>
> Cc: Oleg Nesterov <oleg at redhat.com>
> Cc: kernel-team at android.com
> (Oleg improved the code by showing how to avoid tasklist_lock)
> Suggested-by: Oleg Nesterov <oleg at redhat.com>
> Co-developed-by: Daniel Colascione <dancol at google.com>
> Signed-off-by: Daniel Colascione <dancol at google.com>
> Signed-off-by: Joel Fernandes (Google) <joel at joelfernandes.org>

This looks good to me. Once Oleg has given his Ack/Review I'm going to
move this into pidfd for-next and as mentioned before schedule it for
5.3 after CLONE_PIDFD has been merged.

Reviewed-by: Christian Brauner <christian at brauner.io>

> 
> ---
> 
> v1 -> v2:
> * Restructure poll code to avoid tasklist_lock (Oleg)
> * use task_pid instead of get_pid_task in notify_pidfd (Oleg)
> * Added comments to code, commit message nits (Christian)
> * Test case nits/improvements (Christian)
> 
> RFC -> v1:
> * Based on CLONE_PIDFD patches: https://lwn.net/Articles/786244/
> * Updated selftests.
> * Renamed poll wake function to do_notify_pidfd.
> * Removed depending on EXIT flags
> * Removed POLLERR flag since semantics are controversial and
>   we don't have usecases for it right now (later we can add if there's
>   a need for it).
> 
>  include/linux/pid.h |  3 +++
>  kernel/fork.c       | 29 +++++++++++++++++++++++++++++
>  kernel/pid.c        |  2 ++
>  kernel/signal.c     | 11 +++++++++++
>  4 files changed, 45 insertions(+)
> 
> diff --git a/include/linux/pid.h b/include/linux/pid.h
> index 3c8ef5a199ca..1484db6ca8d1 100644
> --- a/include/linux/pid.h
> +++ b/include/linux/pid.h
> @@ -3,6 +3,7 @@
>  #define _LINUX_PID_H
>  
>  #include <linux/rculist.h>
> +#include <linux/wait.h>
>  
>  enum pid_type
>  {
> @@ -60,6 +61,8 @@ struct pid
>  	unsigned int level;
>  	/* lists of tasks that use this pid */
>  	struct hlist_head tasks[PIDTYPE_MAX];
> +	/* wait queue for pidfd notifications */
> +	wait_queue_head_t wait_pidfd;
>  	struct rcu_head rcu;
>  	struct upid numbers[1];
>  };
> diff --git a/kernel/fork.c b/kernel/fork.c
> index 5525837ed80e..721f8c9d2921 100644
> --- a/kernel/fork.c
> +++ b/kernel/fork.c
> @@ -1685,8 +1685,37 @@ static void pidfd_show_fdinfo(struct seq_file *m, struct file *f)
>  }
>  #endif
>  
> +/*
> + * Poll support for process exit notification.
> + */
> +static unsigned int pidfd_poll(struct file *file, struct poll_table_struct *pts)
> +{
> +	struct task_struct *task;
> +	struct pid *pid = file->private_data;
> +	int poll_flags = 0;
> +
> +	poll_wait(file, &pid->wait_pidfd, pts);
> +
> +	rcu_read_lock();
> +	task = pid_task(pid, PIDTYPE_PID);
> +	WARN_ON_ONCE(task && !thread_group_leader(task));
> +
> +	/*
> +	 * Inform pollers only when the whole thread group exits, if thread
> +	 * group leader exits before all other threads in the group, then
> +	 * poll(2) should block, similar to the wait(2) family.
> +	 */
> +	if (!task || (task->exit_state && thread_group_empty(task)))
> +		poll_flags = POLLIN | POLLRDNORM;
> +	rcu_read_unlock();
> +
> +	return poll_flags;
> +}
> +
> +
>  const struct file_operations pidfd_fops = {
>  	.release = pidfd_release,
> +	.poll = pidfd_poll,
>  #ifdef CONFIG_PROC_FS
>  	.show_fdinfo = pidfd_show_fdinfo,
>  #endif
> diff --git a/kernel/pid.c b/kernel/pid.c
> index 20881598bdfa..5c90c239242f 100644
> --- a/kernel/pid.c
> +++ b/kernel/pid.c
> @@ -214,6 +214,8 @@ struct pid *alloc_pid(struct pid_namespace *ns)
>  	for (type = 0; type < PIDTYPE_MAX; ++type)
>  		INIT_HLIST_HEAD(&pid->tasks[type]);
>  
> +	init_waitqueue_head(&pid->wait_pidfd);
> +
>  	upid = pid->numbers + ns->level;
>  	spin_lock_irq(&pidmap_lock);
>  	if (!(ns->pid_allocated & PIDNS_ADDING))
> diff --git a/kernel/signal.c b/kernel/signal.c
> index 1581140f2d99..a17fff073c3d 100644
> --- a/kernel/signal.c
> +++ b/kernel/signal.c
> @@ -1800,6 +1800,14 @@ int send_sigqueue(struct sigqueue *q, struct pid *pid, enum pid_type type)
>  	return ret;
>  }
>  
> +static void do_notify_pidfd(struct task_struct *task)
> +{
> +	struct pid *pid;
> +
> +	pid = task_pid(task);
> +	wake_up_all(&pid->wait_pidfd);
> +}
> +
>  /*
>   * Let a parent know about the death of a child.
>   * For a stopped/continued status change, use do_notify_parent_cldstop instead.
> @@ -1823,6 +1831,9 @@ bool do_notify_parent(struct task_struct *tsk, int sig)
>  	BUG_ON(!tsk->ptrace &&
>  	       (tsk->group_leader != tsk || !thread_group_empty(tsk)));
>  
> +	/* Wake up all pidfd waiters */
> +	do_notify_pidfd(tsk);
> +
>  	if (sig != SIGCHLD) {
>  		/*
>  		 * This is only possible if parent == real_parent.
> -- 
> 2.21.0.593.g511ec345e18-goog

^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v2 1/2] Add polling support to pidfd
@ 2019-04-30 19:07   ` christian
  0 siblings, 0 replies; 33+ messages in thread
From: Christian Brauner @ 2019-04-30 19:07 UTC (permalink / raw)


On Tue, Apr 30, 2019@12:21:53PM -0400, Joel Fernandes (Google) wrote:
> Android low memory killer (LMK) needs to know when a process dies once
> it is sent the kill signal. It does so by checking for the existence of
> /proc/pid which is both racy and slow. For example, if a PID is reused
> between when LMK sends a kill signal and checks for existence of the
> PID, since the wrong PID is now possibly checked for existence.
> 
> This patch adds polling support to pidfd. Using the polling support, LMK
> will be able to get notified when a process exists in race-free and fast
> way, and allows the LMK to do other things (such as by polling on other
> fds) while awaiting the process being killed to die.
> 
> For notification to polling processes, we follow the same existing
> mechanism in the kernel used when the parent of the task group is to be
> notified of a child's death (do_notify_parent).  This is precisely when
> the tasks waiting on a poll of pidfd are also awakened in this patch.
> 
> We have decided to include the waitqueue in struct pid for the following
> reasons:
> 1. The wait queue has to survive for the lifetime of the poll. Including
> it in task_struct would not be option in this case because the task can
> be reaped and destroyed before the poll returns.
> 
> 2. By including the struct pid for the waitqueue means that during
> de_thread(), the new thread group leader automatically gets the new
> waitqueue/pid even though its task_struct is different.
> 
> Appropriate test cases are added in the second patch to provide coverage
> of all the cases the patch is handling.
> 
> Andy had a similar patch [1] in the past which was a good reference
> however this patch tries to handle different situations properly related
> to thread group existence, and how/where it notifies. And also solves
> other bugs (waitqueue lifetime).  Daniel had a similar patch [2]
> recently which this patch supercedes.
> 
> [1] https://lore.kernel.org/patchwork/patch/345098/
> [2] https://lore.kernel.org/lkml/20181029175322.189042-1-dancol at google.com/
> 
> Cc: Andy Lutomirski <luto at amacapital.net>
> Cc: Steven Rostedt <rostedt at goodmis.org>
> Cc: Daniel Colascione <dancol at google.com>
> Cc: Christian Brauner <christian at brauner.io>
> Cc: Jann Horn <jannh at google.com>
> Cc: Tim Murray <timmurray at google.com>
> Cc: Jonathan Kowalski <bl0pbl33p at gmail.com>
> Cc: Linus Torvalds <torvalds at linux-foundation.org>
> Cc: Al Viro <viro at zeniv.linux.org.uk>
> Cc: Kees Cook <keescook at chromium.org>
> Cc: David Howells <dhowells at redhat.com>
> Cc: Oleg Nesterov <oleg at redhat.com>
> Cc: kernel-team at android.com
> (Oleg improved the code by showing how to avoid tasklist_lock)
> Suggested-by: Oleg Nesterov <oleg at redhat.com>
> Co-developed-by: Daniel Colascione <dancol at google.com>
> Signed-off-by: Daniel Colascione <dancol at google.com>
> Signed-off-by: Joel Fernandes (Google) <joel at joelfernandes.org>

This looks good to me. Once Oleg has given his Ack/Review I'm going to
move this into pidfd for-next and as mentioned before schedule it for
5.3 after CLONE_PIDFD has been merged.

Reviewed-by: Christian Brauner <christian at brauner.io>

> 
> ---
> 
> v1 -> v2:
> * Restructure poll code to avoid tasklist_lock (Oleg)
> * use task_pid instead of get_pid_task in notify_pidfd (Oleg)
> * Added comments to code, commit message nits (Christian)
> * Test case nits/improvements (Christian)
> 
> RFC -> v1:
> * Based on CLONE_PIDFD patches: https://lwn.net/Articles/786244/
> * Updated selftests.
> * Renamed poll wake function to do_notify_pidfd.
> * Removed depending on EXIT flags
> * Removed POLLERR flag since semantics are controversial and
>   we don't have usecases for it right now (later we can add if there's
>   a need for it).
> 
>  include/linux/pid.h |  3 +++
>  kernel/fork.c       | 29 +++++++++++++++++++++++++++++
>  kernel/pid.c        |  2 ++
>  kernel/signal.c     | 11 +++++++++++
>  4 files changed, 45 insertions(+)
> 
> diff --git a/include/linux/pid.h b/include/linux/pid.h
> index 3c8ef5a199ca..1484db6ca8d1 100644
> --- a/include/linux/pid.h
> +++ b/include/linux/pid.h
> @@ -3,6 +3,7 @@
>  #define _LINUX_PID_H
>  
>  #include <linux/rculist.h>
> +#include <linux/wait.h>
>  
>  enum pid_type
>  {
> @@ -60,6 +61,8 @@ struct pid
>  	unsigned int level;
>  	/* lists of tasks that use this pid */
>  	struct hlist_head tasks[PIDTYPE_MAX];
> +	/* wait queue for pidfd notifications */
> +	wait_queue_head_t wait_pidfd;
>  	struct rcu_head rcu;
>  	struct upid numbers[1];
>  };
> diff --git a/kernel/fork.c b/kernel/fork.c
> index 5525837ed80e..721f8c9d2921 100644
> --- a/kernel/fork.c
> +++ b/kernel/fork.c
> @@ -1685,8 +1685,37 @@ static void pidfd_show_fdinfo(struct seq_file *m, struct file *f)
>  }
>  #endif
>  
> +/*
> + * Poll support for process exit notification.
> + */
> +static unsigned int pidfd_poll(struct file *file, struct poll_table_struct *pts)
> +{
> +	struct task_struct *task;
> +	struct pid *pid = file->private_data;
> +	int poll_flags = 0;
> +
> +	poll_wait(file, &pid->wait_pidfd, pts);
> +
> +	rcu_read_lock();
> +	task = pid_task(pid, PIDTYPE_PID);
> +	WARN_ON_ONCE(task && !thread_group_leader(task));
> +
> +	/*
> +	 * Inform pollers only when the whole thread group exits, if thread
> +	 * group leader exits before all other threads in the group, then
> +	 * poll(2) should block, similar to the wait(2) family.
> +	 */
> +	if (!task || (task->exit_state && thread_group_empty(task)))
> +		poll_flags = POLLIN | POLLRDNORM;
> +	rcu_read_unlock();
> +
> +	return poll_flags;
> +}
> +
> +
>  const struct file_operations pidfd_fops = {
>  	.release = pidfd_release,
> +	.poll = pidfd_poll,
>  #ifdef CONFIG_PROC_FS
>  	.show_fdinfo = pidfd_show_fdinfo,
>  #endif
> diff --git a/kernel/pid.c b/kernel/pid.c
> index 20881598bdfa..5c90c239242f 100644
> --- a/kernel/pid.c
> +++ b/kernel/pid.c
> @@ -214,6 +214,8 @@ struct pid *alloc_pid(struct pid_namespace *ns)
>  	for (type = 0; type < PIDTYPE_MAX; ++type)
>  		INIT_HLIST_HEAD(&pid->tasks[type]);
>  
> +	init_waitqueue_head(&pid->wait_pidfd);
> +
>  	upid = pid->numbers + ns->level;
>  	spin_lock_irq(&pidmap_lock);
>  	if (!(ns->pid_allocated & PIDNS_ADDING))
> diff --git a/kernel/signal.c b/kernel/signal.c
> index 1581140f2d99..a17fff073c3d 100644
> --- a/kernel/signal.c
> +++ b/kernel/signal.c
> @@ -1800,6 +1800,14 @@ int send_sigqueue(struct sigqueue *q, struct pid *pid, enum pid_type type)
>  	return ret;
>  }
>  
> +static void do_notify_pidfd(struct task_struct *task)
> +{
> +	struct pid *pid;
> +
> +	pid = task_pid(task);
> +	wake_up_all(&pid->wait_pidfd);
> +}
> +
>  /*
>   * Let a parent know about the death of a child.
>   * For a stopped/continued status change, use do_notify_parent_cldstop instead.
> @@ -1823,6 +1831,9 @@ bool do_notify_parent(struct task_struct *tsk, int sig)
>  	BUG_ON(!tsk->ptrace &&
>  	       (tsk->group_leader != tsk || !thread_group_empty(tsk)));
>  
> +	/* Wake up all pidfd waiters */
> +	do_notify_pidfd(tsk);
> +
>  	if (sig != SIGCHLD) {
>  		/*
>  		 * This is only possible if parent == real_parent.
> -- 
> 2.21.0.593.g511ec345e18-goog

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v2 2/2] Add selftests for pidfd polling
  2019-04-30 16:21   ` joel
  (?)
@ 2019-04-30 19:20     ` christian
  -1 siblings, 0 replies; 33+ messages in thread
From: Christian Brauner @ 2019-04-30 19:20 UTC (permalink / raw)
  To: Joel Fernandes (Google)
  Cc: linux-kernel, Al Viro, Andrew Morton, Andy Lutomirski,
	Arnd Bergmann, Daniel Colascione, David Howells,
	Eric W. Biederman, Greg Kroah-Hartman, Ingo Molnar, Jann Horn,
	Jonathan Kowalski, Kees Cook, kernel-team, KJ Tsanaktsidis,
	Linus Torvalds, linux-kselftest, Michal Hocko, Nadav Amit,
	Oleg Nesterov, Peter Zijlstra (Intel),
	Serge Hallyn, Shuah Khan, Steven Rostedt, Thomas Gleixner,
	Tim Murray, Tycho Andersen

On Tue, Apr 30, 2019 at 12:21:54PM -0400, Joel Fernandes (Google) wrote:
> Other than verifying pidfd based polling, the tests make sure that
> wait semantics are preserved with the pidfd poll. Notably the 2 cases:
> 1. If a thread group leader exits while threads still there, then no
>    pidfd poll notifcation should happen.
> 2. If a non-thread group leader does an execve, then the thread group
>    leader is signaled to exit and is replaced with the execing thread
>    as the new leader, however the parent is not notified in this case.
> 
> Signed-off-by: Joel Fernandes (Google) <joel@joelfernandes.org>
> ---
>  tools/testing/selftests/pidfd/Makefile     |   2 +-
>  tools/testing/selftests/pidfd/pidfd_test.c | 210 +++++++++++++++++++++
>  2 files changed, 211 insertions(+), 1 deletion(-)
> 
> diff --git a/tools/testing/selftests/pidfd/Makefile b/tools/testing/selftests/pidfd/Makefile
> index deaf8073bc06..4b31c14f273c 100644
> --- a/tools/testing/selftests/pidfd/Makefile
> +++ b/tools/testing/selftests/pidfd/Makefile
> @@ -1,4 +1,4 @@
> -CFLAGS += -g -I../../../../usr/include/
> +CFLAGS += -g -I../../../../usr/include/ -lpthread
>  
>  TEST_GEN_PROGS := pidfd_test
>  
> diff --git a/tools/testing/selftests/pidfd/pidfd_test.c b/tools/testing/selftests/pidfd/pidfd_test.c
> index d59378a93782..8b404ccbc4ff 100644
> --- a/tools/testing/selftests/pidfd/pidfd_test.c
> +++ b/tools/testing/selftests/pidfd/pidfd_test.c
> @@ -4,18 +4,47 @@
>  #include <errno.h>
>  #include <fcntl.h>
>  #include <linux/types.h>
> +#include <pthread.h>
>  #include <sched.h>
>  #include <signal.h>
>  #include <stdio.h>
>  #include <stdlib.h>
>  #include <string.h>
>  #include <syscall.h>
> +#include <sys/epoll.h>
> +#include <sys/mman.h>
>  #include <sys/mount.h>
>  #include <sys/wait.h>
> +#include <time.h>
>  #include <unistd.h>
>  
>  #include "../kselftest.h"
>  
> +#define str(s) _str(s)
> +#define _str(s) #s
> +#define CHILD_THREAD_MIN_WAIT 3 /* seconds */
> +
> +#define MAX_EVENTS 5
> +#ifndef __NR_pidfd_send_signal
> +#define __NR_pidfd_send_signal 424
> +#endif
> +
> +#ifndef CLONE_PIDFD
> +#define CLONE_PIDFD 0x00001000
> +#endif
> +
> +static pid_t pidfd_clone(int flags, int *pidfd, int (*fn)(void *))
> +{
> +	size_t stack_size = 1024;
> +	char *stack[1024] = { 0 };
> +
> +#ifdef __ia64__
> +	return __clone2(fn, stack, stack_size, flags | SIGCHLD, NULL, pidfd);
> +#else
> +	return clone(fn, stack + stack_size, flags | SIGCHLD, NULL, pidfd);
> +#endif
> +}
> +
>  static inline int sys_pidfd_send_signal(int pidfd, int sig, siginfo_t *info,
>  					unsigned int flags)
>  {
> @@ -368,10 +397,191 @@ static int test_pidfd_send_signal_syscall_support(void)
>  	return 0;
>  }
>  
> +static void *test_pidfd_poll_exec_thread(void *priv)
> +{
> +	ksft_print_msg("Child Thread: starting. pid %d tid %d ; and sleeping\n",
> +			getpid(), syscall(SYS_gettid));
> +	ksft_print_msg("Child Thread: doing exec of sleep\n");
> +
> +	execl("/bin/sleep", "sleep", str(CHILD_THREAD_MIN_WAIT), (char *)NULL);
> +
> +	ksft_print_msg("Child Thread: DONE. pid %d tid %d\n",
> +			getpid(), syscall(SYS_gettid));
> +	return NULL;
> +}
> +
> +static void poll_pidfd(const char *test_name, int pidfd)
> +{
> +	int c;
> +	int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
> +	struct epoll_event event, events[MAX_EVENTS];
> +
> +	if (epoll_fd == -1)
> +		ksft_exit_fail_msg("%s test: Failed to create epoll file descriptor "
> +				   "(errno %d)\n",
> +				   test_name, errno);
> +
> +	event.events = EPOLLIN;
> +	event.data.fd = pidfd;
> +
> +	if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, pidfd, &event)) {
> +		ksft_exit_fail_msg("%s test: Failed to add epoll file descriptor "
> +				   "(errno %d)\n",
> +				   test_name, errno);
> +	}
> +
> +	c = epoll_wait(epoll_fd, events, MAX_EVENTS, 5000);
> +	if (c != 1 || !(events[0].events & EPOLLIN))
> +		ksft_exit_fail_msg("%s test: Unexpected epoll_wait result (c=%d, events=%x) ",
> +				   "(errno %d)\n",
> +				   test_name, c, events[0].events, errno);
> +
> +	close(epoll_fd);
> +	return;

nit: Function with void usually do not do an explicit return at the end. :)

> +
> +}
> +
> +static int child_poll_exec_test(void *args)
> +{
> +	pthread_t t1;
> +
> +	ksft_print_msg("Child (pidfd): starting. pid %d tid %d\n", getpid(),
> +			syscall(SYS_gettid));
> +	pthread_create(&t1, NULL, test_pidfd_poll_exec_thread, NULL);
> +	/*
> +	 * Exec in the non-leader thread will destroy the leader immediately.
> +	 * If the wait in the parent returns too soon, the test fails.
> +	 */
> +	while (1)
> +		sleep(1);
> +}
> +
> +static int test_pidfd_poll_exec(int use_waitpid)

Please make int use_waitpid a proper bool and make the function void as
it's return value is never checked in main.

(I know the other ones in the test file here do the same thing and I
should switch them to void soon at some point.)

> +{
> +	int pid, pidfd = 0;
> +	int status, ret;
> +	pthread_t t1;
> +	time_t prog_start = time(NULL);
> +	const char *test_name = "pidfd_poll check for premature notification on child thread exec";
> +
> +	ksft_print_msg("Parent: pid: %d\n", getpid());
> +	pid = pidfd_clone(CLONE_PIDFD, &pidfd, child_poll_exec_test);
> +	if (pid < 0)
> +		ksft_exit_fail_msg("%s test: pidfd_clone failed (ret %d, errno %d)\n",
> +				   test_name, pid, errno);
> +
> +	ksft_print_msg("Parent: Waiting for Child (%d) to complete.\n", pid);
> +
> +	if (use_waitpid) {
> +		ret = waitpid(pid, &status, 0);
> +		if (ret == -1)
> +			ksft_print_msg("Parent: error\n");
> +
> +		if (ret == pid)
> +			ksft_print_msg("Parent: Child process waited for.\n");
> +	} else {
> +		poll_pidfd(test_name, pidfd);
> +	}
> +
> +	time_t prog_time = time(NULL) - prog_start;
> +
> +	ksft_print_msg("Time waited for child: %lu\n", prog_time);
> +
> +	close(pidfd);
> +
> +	if (prog_time < CHILD_THREAD_MIN_WAIT || prog_time > CHILD_THREAD_MIN_WAIT + 2)

I'm sorry, can you please either briefly explain or comment where
this +2 comes from? Why is that the cut-off?

> +		ksft_exit_fail_msg("%s test: Failed\n", test_name);
> +	else
> +		ksft_test_result_pass("%s test: Passed\n", test_name);
> +}
> +
> +static void *test_pidfd_poll_leader_exit_thread(void *priv)
> +{
> +	ksft_print_msg("Child Thread: starting. pid %d tid %d ; and sleeping\n",
> +			getpid(), syscall(SYS_gettid));
> +	sleep(CHILD_THREAD_MIN_WAIT);
> +	ksft_print_msg("Child Thread: DONE. pid %d tid %d\n", getpid(), syscall(SYS_gettid));
> +	return NULL;
> +}
> +
> +static time_t *child_exit_secs;
> +static int child_poll_leader_exit_test(void *args)
> +{
> +	pthread_t t1, t2;
> +
> +	ksft_print_msg("Child: starting. pid %d tid %d\n", getpid(), syscall(SYS_gettid));
> +	pthread_create(&t1, NULL, test_pidfd_poll_leader_exit_thread, NULL);
> +	pthread_create(&t2, NULL, test_pidfd_poll_leader_exit_thread, NULL);
> +
> +	/*
> +	 * glibc exit calls exit_group syscall, so explicity call exit only
> +	 * so that only the group leader exits, leaving the threads alone.
> +	 */
> +	*child_exit_secs = time(NULL);

Why is child_exit_secs a pointer?


> +	syscall(SYS_exit, 0);
> +}
> +
> +static int test_pidfd_poll_leader_exit(int use_waitpid)

Should be void as it's return value isn't checked at all.

(I know the other ones in the test file here do the same thing and I
should switch them to void soon at some point.)

> +{
> +	int pid, pidfd = 0;
> +	int status, ret;
> +	time_t prog_start = time(NULL);
> +	const char *test_name = "pidfd_poll check for premature notification on non-empty"
> +				"group leader exit";
> +
> +	child_exit_secs = mmap(NULL, sizeof *child_exit_secs, PROT_READ | PROT_WRITE,
> +			MAP_SHARED | MAP_ANONYMOUS, -1, 0);
> +
> +	if (child_exit_secs == MAP_FAILED)
> +		ksft_exit_fail_msg("%s test: mmap failed (errno %d)\n",
> +				   test_name, errno);
> +
> +	ksft_print_msg("Parent: pid: %d\n", getpid());
> +	pid = pidfd_clone(CLONE_PIDFD, &pidfd, child_poll_leader_exit_test);
> +	if (pid < 0)
> +		ksft_exit_fail_msg("%s test: pidfd_clone failed (ret %d, errno %d)\n",
> +				   test_name, pid, errno);
> +
> +	ksft_print_msg("Parent: Waiting for Child (%d) to complete.\n", pid);
> +
> +	if (use_waitpid) {
> +		ret = waitpid(pid, &status, 0);
> +		if (ret == -1)
> +			ksft_print_msg("Parent: error\n");
> +	} else {
> +		/*
> +		 * This sleep tests for the case where if the child exits, and is in
> +		 * EXIT_ZOMBIE, but the thread group leader is non-empty, then the poll
> +		 * doesn't prematurely return even though there are active threads
> +		 */
> +		sleep(1);
> +		poll_pidfd(test_name, pidfd);
> +	}
> +
> +	if (ret == pid)
> +		ksft_print_msg("Parent: Child process waited for.\n");
> +
> +	time_t since_child_exit = time(NULL) - *child_exit_secs;
> +
> +	ksft_print_msg("Time since child exit: %lu\n", since_child_exit);
> +
> +	close(pidfd);
> +
> +	if (since_child_exit < CHILD_THREAD_MIN_WAIT ||
> +			since_child_exit > CHILD_THREAD_MIN_WAIT + 2)

Same question as above.

> +		ksft_exit_fail_msg("%s test: Failed\n", test_name);
> +	else
> +		ksft_test_result_pass("%s test: Passed\n", test_name);
> +}
> +
>  int main(int argc, char **argv)
>  {
>  	ksft_print_header();
>  
> +	test_pidfd_poll_exec(0);

test_pidfd_poll_exec(false);

> +	test_pidfd_poll_exec(1);

test_pidfd_poll_exec(true);

> +	test_pidfd_poll_leader_exit(0);

test_pidfd_poll_leader_exit(false);

> +	test_pidfd_poll_leader_exit(1);

test_pidfd_poll_leader_exit(true);

>  	test_pidfd_send_signal_syscall_support();
>  	test_pidfd_send_signal_simple_success();
>  	test_pidfd_send_signal_exited_fail();
> -- 
> 2.21.0.593.g511ec345e18-goog
> 

^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v2 2/2] Add selftests for pidfd polling
@ 2019-04-30 19:20     ` christian
  0 siblings, 0 replies; 33+ messages in thread
From: christian @ 2019-04-30 19:20 UTC (permalink / raw)


On Tue, Apr 30, 2019 at 12:21:54PM -0400, Joel Fernandes (Google) wrote:
> Other than verifying pidfd based polling, the tests make sure that
> wait semantics are preserved with the pidfd poll. Notably the 2 cases:
> 1. If a thread group leader exits while threads still there, then no
>    pidfd poll notifcation should happen.
> 2. If a non-thread group leader does an execve, then the thread group
>    leader is signaled to exit and is replaced with the execing thread
>    as the new leader, however the parent is not notified in this case.
> 
> Signed-off-by: Joel Fernandes (Google) <joel at joelfernandes.org>
> ---
>  tools/testing/selftests/pidfd/Makefile     |   2 +-
>  tools/testing/selftests/pidfd/pidfd_test.c | 210 +++++++++++++++++++++
>  2 files changed, 211 insertions(+), 1 deletion(-)
> 
> diff --git a/tools/testing/selftests/pidfd/Makefile b/tools/testing/selftests/pidfd/Makefile
> index deaf8073bc06..4b31c14f273c 100644
> --- a/tools/testing/selftests/pidfd/Makefile
> +++ b/tools/testing/selftests/pidfd/Makefile
> @@ -1,4 +1,4 @@
> -CFLAGS += -g -I../../../../usr/include/
> +CFLAGS += -g -I../../../../usr/include/ -lpthread
>  
>  TEST_GEN_PROGS := pidfd_test
>  
> diff --git a/tools/testing/selftests/pidfd/pidfd_test.c b/tools/testing/selftests/pidfd/pidfd_test.c
> index d59378a93782..8b404ccbc4ff 100644
> --- a/tools/testing/selftests/pidfd/pidfd_test.c
> +++ b/tools/testing/selftests/pidfd/pidfd_test.c
> @@ -4,18 +4,47 @@
>  #include <errno.h>
>  #include <fcntl.h>
>  #include <linux/types.h>
> +#include <pthread.h>
>  #include <sched.h>
>  #include <signal.h>
>  #include <stdio.h>
>  #include <stdlib.h>
>  #include <string.h>
>  #include <syscall.h>
> +#include <sys/epoll.h>
> +#include <sys/mman.h>
>  #include <sys/mount.h>
>  #include <sys/wait.h>
> +#include <time.h>
>  #include <unistd.h>
>  
>  #include "../kselftest.h"
>  
> +#define str(s) _str(s)
> +#define _str(s) #s
> +#define CHILD_THREAD_MIN_WAIT 3 /* seconds */
> +
> +#define MAX_EVENTS 5
> +#ifndef __NR_pidfd_send_signal
> +#define __NR_pidfd_send_signal 424
> +#endif
> +
> +#ifndef CLONE_PIDFD
> +#define CLONE_PIDFD 0x00001000
> +#endif
> +
> +static pid_t pidfd_clone(int flags, int *pidfd, int (*fn)(void *))
> +{
> +	size_t stack_size = 1024;
> +	char *stack[1024] = { 0 };
> +
> +#ifdef __ia64__
> +	return __clone2(fn, stack, stack_size, flags | SIGCHLD, NULL, pidfd);
> +#else
> +	return clone(fn, stack + stack_size, flags | SIGCHLD, NULL, pidfd);
> +#endif
> +}
> +
>  static inline int sys_pidfd_send_signal(int pidfd, int sig, siginfo_t *info,
>  					unsigned int flags)
>  {
> @@ -368,10 +397,191 @@ static int test_pidfd_send_signal_syscall_support(void)
>  	return 0;
>  }
>  
> +static void *test_pidfd_poll_exec_thread(void *priv)
> +{
> +	ksft_print_msg("Child Thread: starting. pid %d tid %d ; and sleeping\n",
> +			getpid(), syscall(SYS_gettid));
> +	ksft_print_msg("Child Thread: doing exec of sleep\n");
> +
> +	execl("/bin/sleep", "sleep", str(CHILD_THREAD_MIN_WAIT), (char *)NULL);
> +
> +	ksft_print_msg("Child Thread: DONE. pid %d tid %d\n",
> +			getpid(), syscall(SYS_gettid));
> +	return NULL;
> +}
> +
> +static void poll_pidfd(const char *test_name, int pidfd)
> +{
> +	int c;
> +	int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
> +	struct epoll_event event, events[MAX_EVENTS];
> +
> +	if (epoll_fd == -1)
> +		ksft_exit_fail_msg("%s test: Failed to create epoll file descriptor "
> +				   "(errno %d)\n",
> +				   test_name, errno);
> +
> +	event.events = EPOLLIN;
> +	event.data.fd = pidfd;
> +
> +	if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, pidfd, &event)) {
> +		ksft_exit_fail_msg("%s test: Failed to add epoll file descriptor "
> +				   "(errno %d)\n",
> +				   test_name, errno);
> +	}
> +
> +	c = epoll_wait(epoll_fd, events, MAX_EVENTS, 5000);
> +	if (c != 1 || !(events[0].events & EPOLLIN))
> +		ksft_exit_fail_msg("%s test: Unexpected epoll_wait result (c=%d, events=%x) ",
> +				   "(errno %d)\n",
> +				   test_name, c, events[0].events, errno);
> +
> +	close(epoll_fd);
> +	return;

nit: Function with void usually do not do an explicit return at the end. :)

> +
> +}
> +
> +static int child_poll_exec_test(void *args)
> +{
> +	pthread_t t1;
> +
> +	ksft_print_msg("Child (pidfd): starting. pid %d tid %d\n", getpid(),
> +			syscall(SYS_gettid));
> +	pthread_create(&t1, NULL, test_pidfd_poll_exec_thread, NULL);
> +	/*
> +	 * Exec in the non-leader thread will destroy the leader immediately.
> +	 * If the wait in the parent returns too soon, the test fails.
> +	 */
> +	while (1)
> +		sleep(1);
> +}
> +
> +static int test_pidfd_poll_exec(int use_waitpid)

Please make int use_waitpid a proper bool and make the function void as
it's return value is never checked in main.

(I know the other ones in the test file here do the same thing and I
should switch them to void soon at some point.)

> +{
> +	int pid, pidfd = 0;
> +	int status, ret;
> +	pthread_t t1;
> +	time_t prog_start = time(NULL);
> +	const char *test_name = "pidfd_poll check for premature notification on child thread exec";
> +
> +	ksft_print_msg("Parent: pid: %d\n", getpid());
> +	pid = pidfd_clone(CLONE_PIDFD, &pidfd, child_poll_exec_test);
> +	if (pid < 0)
> +		ksft_exit_fail_msg("%s test: pidfd_clone failed (ret %d, errno %d)\n",
> +				   test_name, pid, errno);
> +
> +	ksft_print_msg("Parent: Waiting for Child (%d) to complete.\n", pid);
> +
> +	if (use_waitpid) {
> +		ret = waitpid(pid, &status, 0);
> +		if (ret == -1)
> +			ksft_print_msg("Parent: error\n");
> +
> +		if (ret == pid)
> +			ksft_print_msg("Parent: Child process waited for.\n");
> +	} else {
> +		poll_pidfd(test_name, pidfd);
> +	}
> +
> +	time_t prog_time = time(NULL) - prog_start;
> +
> +	ksft_print_msg("Time waited for child: %lu\n", prog_time);
> +
> +	close(pidfd);
> +
> +	if (prog_time < CHILD_THREAD_MIN_WAIT || prog_time > CHILD_THREAD_MIN_WAIT + 2)

I'm sorry, can you please either briefly explain or comment where
this +2 comes from? Why is that the cut-off?

> +		ksft_exit_fail_msg("%s test: Failed\n", test_name);
> +	else
> +		ksft_test_result_pass("%s test: Passed\n", test_name);
> +}
> +
> +static void *test_pidfd_poll_leader_exit_thread(void *priv)
> +{
> +	ksft_print_msg("Child Thread: starting. pid %d tid %d ; and sleeping\n",
> +			getpid(), syscall(SYS_gettid));
> +	sleep(CHILD_THREAD_MIN_WAIT);
> +	ksft_print_msg("Child Thread: DONE. pid %d tid %d\n", getpid(), syscall(SYS_gettid));
> +	return NULL;
> +}
> +
> +static time_t *child_exit_secs;
> +static int child_poll_leader_exit_test(void *args)
> +{
> +	pthread_t t1, t2;
> +
> +	ksft_print_msg("Child: starting. pid %d tid %d\n", getpid(), syscall(SYS_gettid));
> +	pthread_create(&t1, NULL, test_pidfd_poll_leader_exit_thread, NULL);
> +	pthread_create(&t2, NULL, test_pidfd_poll_leader_exit_thread, NULL);
> +
> +	/*
> +	 * glibc exit calls exit_group syscall, so explicity call exit only
> +	 * so that only the group leader exits, leaving the threads alone.
> +	 */
> +	*child_exit_secs = time(NULL);

Why is child_exit_secs a pointer?


> +	syscall(SYS_exit, 0);
> +}
> +
> +static int test_pidfd_poll_leader_exit(int use_waitpid)

Should be void as it's return value isn't checked at all.

(I know the other ones in the test file here do the same thing and I
should switch them to void soon at some point.)

> +{
> +	int pid, pidfd = 0;
> +	int status, ret;
> +	time_t prog_start = time(NULL);
> +	const char *test_name = "pidfd_poll check for premature notification on non-empty"
> +				"group leader exit";
> +
> +	child_exit_secs = mmap(NULL, sizeof *child_exit_secs, PROT_READ | PROT_WRITE,
> +			MAP_SHARED | MAP_ANONYMOUS, -1, 0);
> +
> +	if (child_exit_secs == MAP_FAILED)
> +		ksft_exit_fail_msg("%s test: mmap failed (errno %d)\n",
> +				   test_name, errno);
> +
> +	ksft_print_msg("Parent: pid: %d\n", getpid());
> +	pid = pidfd_clone(CLONE_PIDFD, &pidfd, child_poll_leader_exit_test);
> +	if (pid < 0)
> +		ksft_exit_fail_msg("%s test: pidfd_clone failed (ret %d, errno %d)\n",
> +				   test_name, pid, errno);
> +
> +	ksft_print_msg("Parent: Waiting for Child (%d) to complete.\n", pid);
> +
> +	if (use_waitpid) {
> +		ret = waitpid(pid, &status, 0);
> +		if (ret == -1)
> +			ksft_print_msg("Parent: error\n");
> +	} else {
> +		/*
> +		 * This sleep tests for the case where if the child exits, and is in
> +		 * EXIT_ZOMBIE, but the thread group leader is non-empty, then the poll
> +		 * doesn't prematurely return even though there are active threads
> +		 */
> +		sleep(1);
> +		poll_pidfd(test_name, pidfd);
> +	}
> +
> +	if (ret == pid)
> +		ksft_print_msg("Parent: Child process waited for.\n");
> +
> +	time_t since_child_exit = time(NULL) - *child_exit_secs;
> +
> +	ksft_print_msg("Time since child exit: %lu\n", since_child_exit);
> +
> +	close(pidfd);
> +
> +	if (since_child_exit < CHILD_THREAD_MIN_WAIT ||
> +			since_child_exit > CHILD_THREAD_MIN_WAIT + 2)

Same question as above.

> +		ksft_exit_fail_msg("%s test: Failed\n", test_name);
> +	else
> +		ksft_test_result_pass("%s test: Passed\n", test_name);
> +}
> +
>  int main(int argc, char **argv)
>  {
>  	ksft_print_header();
>  
> +	test_pidfd_poll_exec(0);

test_pidfd_poll_exec(false);

> +	test_pidfd_poll_exec(1);

test_pidfd_poll_exec(true);

> +	test_pidfd_poll_leader_exit(0);

test_pidfd_poll_leader_exit(false);

> +	test_pidfd_poll_leader_exit(1);

test_pidfd_poll_leader_exit(true);

>  	test_pidfd_send_signal_syscall_support();
>  	test_pidfd_send_signal_simple_success();
>  	test_pidfd_send_signal_exited_fail();
> -- 
> 2.21.0.593.g511ec345e18-goog
> 

^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v2 2/2] Add selftests for pidfd polling
@ 2019-04-30 19:20     ` christian
  0 siblings, 0 replies; 33+ messages in thread
From: Christian Brauner @ 2019-04-30 19:20 UTC (permalink / raw)


On Tue, Apr 30, 2019@12:21:54PM -0400, Joel Fernandes (Google) wrote:
> Other than verifying pidfd based polling, the tests make sure that
> wait semantics are preserved with the pidfd poll. Notably the 2 cases:
> 1. If a thread group leader exits while threads still there, then no
>    pidfd poll notifcation should happen.
> 2. If a non-thread group leader does an execve, then the thread group
>    leader is signaled to exit and is replaced with the execing thread
>    as the new leader, however the parent is not notified in this case.
> 
> Signed-off-by: Joel Fernandes (Google) <joel at joelfernandes.org>
> ---
>  tools/testing/selftests/pidfd/Makefile     |   2 +-
>  tools/testing/selftests/pidfd/pidfd_test.c | 210 +++++++++++++++++++++
>  2 files changed, 211 insertions(+), 1 deletion(-)
> 
> diff --git a/tools/testing/selftests/pidfd/Makefile b/tools/testing/selftests/pidfd/Makefile
> index deaf8073bc06..4b31c14f273c 100644
> --- a/tools/testing/selftests/pidfd/Makefile
> +++ b/tools/testing/selftests/pidfd/Makefile
> @@ -1,4 +1,4 @@
> -CFLAGS += -g -I../../../../usr/include/
> +CFLAGS += -g -I../../../../usr/include/ -lpthread
>  
>  TEST_GEN_PROGS := pidfd_test
>  
> diff --git a/tools/testing/selftests/pidfd/pidfd_test.c b/tools/testing/selftests/pidfd/pidfd_test.c
> index d59378a93782..8b404ccbc4ff 100644
> --- a/tools/testing/selftests/pidfd/pidfd_test.c
> +++ b/tools/testing/selftests/pidfd/pidfd_test.c
> @@ -4,18 +4,47 @@
>  #include <errno.h>
>  #include <fcntl.h>
>  #include <linux/types.h>
> +#include <pthread.h>
>  #include <sched.h>
>  #include <signal.h>
>  #include <stdio.h>
>  #include <stdlib.h>
>  #include <string.h>
>  #include <syscall.h>
> +#include <sys/epoll.h>
> +#include <sys/mman.h>
>  #include <sys/mount.h>
>  #include <sys/wait.h>
> +#include <time.h>
>  #include <unistd.h>
>  
>  #include "../kselftest.h"
>  
> +#define str(s) _str(s)
> +#define _str(s) #s
> +#define CHILD_THREAD_MIN_WAIT 3 /* seconds */
> +
> +#define MAX_EVENTS 5
> +#ifndef __NR_pidfd_send_signal
> +#define __NR_pidfd_send_signal 424
> +#endif
> +
> +#ifndef CLONE_PIDFD
> +#define CLONE_PIDFD 0x00001000
> +#endif
> +
> +static pid_t pidfd_clone(int flags, int *pidfd, int (*fn)(void *))
> +{
> +	size_t stack_size = 1024;
> +	char *stack[1024] = { 0 };
> +
> +#ifdef __ia64__
> +	return __clone2(fn, stack, stack_size, flags | SIGCHLD, NULL, pidfd);
> +#else
> +	return clone(fn, stack + stack_size, flags | SIGCHLD, NULL, pidfd);
> +#endif
> +}
> +
>  static inline int sys_pidfd_send_signal(int pidfd, int sig, siginfo_t *info,
>  					unsigned int flags)
>  {
> @@ -368,10 +397,191 @@ static int test_pidfd_send_signal_syscall_support(void)
>  	return 0;
>  }
>  
> +static void *test_pidfd_poll_exec_thread(void *priv)
> +{
> +	ksft_print_msg("Child Thread: starting. pid %d tid %d ; and sleeping\n",
> +			getpid(), syscall(SYS_gettid));
> +	ksft_print_msg("Child Thread: doing exec of sleep\n");
> +
> +	execl("/bin/sleep", "sleep", str(CHILD_THREAD_MIN_WAIT), (char *)NULL);
> +
> +	ksft_print_msg("Child Thread: DONE. pid %d tid %d\n",
> +			getpid(), syscall(SYS_gettid));
> +	return NULL;
> +}
> +
> +static void poll_pidfd(const char *test_name, int pidfd)
> +{
> +	int c;
> +	int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
> +	struct epoll_event event, events[MAX_EVENTS];
> +
> +	if (epoll_fd == -1)
> +		ksft_exit_fail_msg("%s test: Failed to create epoll file descriptor "
> +				   "(errno %d)\n",
> +				   test_name, errno);
> +
> +	event.events = EPOLLIN;
> +	event.data.fd = pidfd;
> +
> +	if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, pidfd, &event)) {
> +		ksft_exit_fail_msg("%s test: Failed to add epoll file descriptor "
> +				   "(errno %d)\n",
> +				   test_name, errno);
> +	}
> +
> +	c = epoll_wait(epoll_fd, events, MAX_EVENTS, 5000);
> +	if (c != 1 || !(events[0].events & EPOLLIN))
> +		ksft_exit_fail_msg("%s test: Unexpected epoll_wait result (c=%d, events=%x) ",
> +				   "(errno %d)\n",
> +				   test_name, c, events[0].events, errno);
> +
> +	close(epoll_fd);
> +	return;

nit: Function with void usually do not do an explicit return at the end. :)

> +
> +}
> +
> +static int child_poll_exec_test(void *args)
> +{
> +	pthread_t t1;
> +
> +	ksft_print_msg("Child (pidfd): starting. pid %d tid %d\n", getpid(),
> +			syscall(SYS_gettid));
> +	pthread_create(&t1, NULL, test_pidfd_poll_exec_thread, NULL);
> +	/*
> +	 * Exec in the non-leader thread will destroy the leader immediately.
> +	 * If the wait in the parent returns too soon, the test fails.
> +	 */
> +	while (1)
> +		sleep(1);
> +}
> +
> +static int test_pidfd_poll_exec(int use_waitpid)

Please make int use_waitpid a proper bool and make the function void as
it's return value is never checked in main.

(I know the other ones in the test file here do the same thing and I
should switch them to void soon at some point.)

> +{
> +	int pid, pidfd = 0;
> +	int status, ret;
> +	pthread_t t1;
> +	time_t prog_start = time(NULL);
> +	const char *test_name = "pidfd_poll check for premature notification on child thread exec";
> +
> +	ksft_print_msg("Parent: pid: %d\n", getpid());
> +	pid = pidfd_clone(CLONE_PIDFD, &pidfd, child_poll_exec_test);
> +	if (pid < 0)
> +		ksft_exit_fail_msg("%s test: pidfd_clone failed (ret %d, errno %d)\n",
> +				   test_name, pid, errno);
> +
> +	ksft_print_msg("Parent: Waiting for Child (%d) to complete.\n", pid);
> +
> +	if (use_waitpid) {
> +		ret = waitpid(pid, &status, 0);
> +		if (ret == -1)
> +			ksft_print_msg("Parent: error\n");
> +
> +		if (ret == pid)
> +			ksft_print_msg("Parent: Child process waited for.\n");
> +	} else {
> +		poll_pidfd(test_name, pidfd);
> +	}
> +
> +	time_t prog_time = time(NULL) - prog_start;
> +
> +	ksft_print_msg("Time waited for child: %lu\n", prog_time);
> +
> +	close(pidfd);
> +
> +	if (prog_time < CHILD_THREAD_MIN_WAIT || prog_time > CHILD_THREAD_MIN_WAIT + 2)

I'm sorry, can you please either briefly explain or comment where
this +2 comes from? Why is that the cut-off?

> +		ksft_exit_fail_msg("%s test: Failed\n", test_name);
> +	else
> +		ksft_test_result_pass("%s test: Passed\n", test_name);
> +}
> +
> +static void *test_pidfd_poll_leader_exit_thread(void *priv)
> +{
> +	ksft_print_msg("Child Thread: starting. pid %d tid %d ; and sleeping\n",
> +			getpid(), syscall(SYS_gettid));
> +	sleep(CHILD_THREAD_MIN_WAIT);
> +	ksft_print_msg("Child Thread: DONE. pid %d tid %d\n", getpid(), syscall(SYS_gettid));
> +	return NULL;
> +}
> +
> +static time_t *child_exit_secs;
> +static int child_poll_leader_exit_test(void *args)
> +{
> +	pthread_t t1, t2;
> +
> +	ksft_print_msg("Child: starting. pid %d tid %d\n", getpid(), syscall(SYS_gettid));
> +	pthread_create(&t1, NULL, test_pidfd_poll_leader_exit_thread, NULL);
> +	pthread_create(&t2, NULL, test_pidfd_poll_leader_exit_thread, NULL);
> +
> +	/*
> +	 * glibc exit calls exit_group syscall, so explicity call exit only
> +	 * so that only the group leader exits, leaving the threads alone.
> +	 */
> +	*child_exit_secs = time(NULL);

Why is child_exit_secs a pointer?


> +	syscall(SYS_exit, 0);
> +}
> +
> +static int test_pidfd_poll_leader_exit(int use_waitpid)

Should be void as it's return value isn't checked at all.

(I know the other ones in the test file here do the same thing and I
should switch them to void soon at some point.)

> +{
> +	int pid, pidfd = 0;
> +	int status, ret;
> +	time_t prog_start = time(NULL);
> +	const char *test_name = "pidfd_poll check for premature notification on non-empty"
> +				"group leader exit";
> +
> +	child_exit_secs = mmap(NULL, sizeof *child_exit_secs, PROT_READ | PROT_WRITE,
> +			MAP_SHARED | MAP_ANONYMOUS, -1, 0);
> +
> +	if (child_exit_secs == MAP_FAILED)
> +		ksft_exit_fail_msg("%s test: mmap failed (errno %d)\n",
> +				   test_name, errno);
> +
> +	ksft_print_msg("Parent: pid: %d\n", getpid());
> +	pid = pidfd_clone(CLONE_PIDFD, &pidfd, child_poll_leader_exit_test);
> +	if (pid < 0)
> +		ksft_exit_fail_msg("%s test: pidfd_clone failed (ret %d, errno %d)\n",
> +				   test_name, pid, errno);
> +
> +	ksft_print_msg("Parent: Waiting for Child (%d) to complete.\n", pid);
> +
> +	if (use_waitpid) {
> +		ret = waitpid(pid, &status, 0);
> +		if (ret == -1)
> +			ksft_print_msg("Parent: error\n");
> +	} else {
> +		/*
> +		 * This sleep tests for the case where if the child exits, and is in
> +		 * EXIT_ZOMBIE, but the thread group leader is non-empty, then the poll
> +		 * doesn't prematurely return even though there are active threads
> +		 */
> +		sleep(1);
> +		poll_pidfd(test_name, pidfd);
> +	}
> +
> +	if (ret == pid)
> +		ksft_print_msg("Parent: Child process waited for.\n");
> +
> +	time_t since_child_exit = time(NULL) - *child_exit_secs;
> +
> +	ksft_print_msg("Time since child exit: %lu\n", since_child_exit);
> +
> +	close(pidfd);
> +
> +	if (since_child_exit < CHILD_THREAD_MIN_WAIT ||
> +			since_child_exit > CHILD_THREAD_MIN_WAIT + 2)

Same question as above.

> +		ksft_exit_fail_msg("%s test: Failed\n", test_name);
> +	else
> +		ksft_test_result_pass("%s test: Passed\n", test_name);
> +}
> +
>  int main(int argc, char **argv)
>  {
>  	ksft_print_header();
>  
> +	test_pidfd_poll_exec(0);

test_pidfd_poll_exec(false);

> +	test_pidfd_poll_exec(1);

test_pidfd_poll_exec(true);

> +	test_pidfd_poll_leader_exit(0);

test_pidfd_poll_leader_exit(false);

> +	test_pidfd_poll_leader_exit(1);

test_pidfd_poll_leader_exit(true);

>  	test_pidfd_send_signal_syscall_support();
>  	test_pidfd_send_signal_simple_success();
>  	test_pidfd_send_signal_exited_fail();
> -- 
> 2.21.0.593.g511ec345e18-goog
> 

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v2 1/2] Add polling support to pidfd
  2019-04-30 16:21 ` joel
  (?)
@ 2019-05-01 15:13   ` oleg
  -1 siblings, 0 replies; 33+ messages in thread
From: Oleg Nesterov @ 2019-05-01 15:13 UTC (permalink / raw)
  To: Joel Fernandes (Google)
  Cc: linux-kernel, Andy Lutomirski, Steven Rostedt, Daniel Colascione,
	Christian Brauner, Jann Horn, Tim Murray, Jonathan Kowalski,
	Linus Torvalds, Al Viro, Kees Cook, David Howells, kernel-team,
	Andrew Morton, Arnd Bergmann, Eric W. Biederman,
	Greg Kroah-Hartman, Ingo Molnar, KJ Tsanaktsidis,
	linux-kselftest, Michal Hocko, Nadav Amit, Peter Zijlstra (Intel),
	Serge Hallyn, Shuah Khan, Thomas Gleixner, Tycho Andersen

On 04/30, Joel Fernandes (Google) wrote:
>
> +static unsigned int pidfd_poll(struct file *file, struct poll_table_struct *pts)
> +{
> +	struct task_struct *task;
> +	struct pid *pid = file->private_data;
> +	int poll_flags = 0;
> +
> +	poll_wait(file, &pid->wait_pidfd, pts);
> +
> +	rcu_read_lock();
> +	task = pid_task(pid, PIDTYPE_PID);
> +	WARN_ON_ONCE(task && !thread_group_leader(task));
                             ^^^^^^^^^^^^^^^^^^^^^^^^^^

Ah, this is not right, we can race with de_thread() which changes the leader,
in particular it does leader->exit_signal = -1 to indicate that this thread is
no longer a group leader, but pid_task() can return the old leader.

We are going to check thread_group_empty() below, it won't be true in this case,
so this race should not make any harm.

Just remove this WARN_ON(). We can't use has_group_leader_pid(), it can return
false if pid_task() returns the new leader.

Otherwise I see no problems.

Oleg.


^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v2 1/2] Add polling support to pidfd
@ 2019-05-01 15:13   ` oleg
  0 siblings, 0 replies; 33+ messages in thread
From: oleg @ 2019-05-01 15:13 UTC (permalink / raw)


On 04/30, Joel Fernandes (Google) wrote:
>
> +static unsigned int pidfd_poll(struct file *file, struct poll_table_struct *pts)
> +{
> +	struct task_struct *task;
> +	struct pid *pid = file->private_data;
> +	int poll_flags = 0;
> +
> +	poll_wait(file, &pid->wait_pidfd, pts);
> +
> +	rcu_read_lock();
> +	task = pid_task(pid, PIDTYPE_PID);
> +	WARN_ON_ONCE(task && !thread_group_leader(task));
                             ^^^^^^^^^^^^^^^^^^^^^^^^^^

Ah, this is not right, we can race with de_thread() which changes the leader,
in particular it does leader->exit_signal = -1 to indicate that this thread is
no longer a group leader, but pid_task() can return the old leader.

We are going to check thread_group_empty() below, it won't be true in this case,
so this race should not make any harm.

Just remove this WARN_ON(). We can't use has_group_leader_pid(), it can return
false if pid_task() returns the new leader.

Otherwise I see no problems.

Oleg.

^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v2 1/2] Add polling support to pidfd
@ 2019-05-01 15:13   ` oleg
  0 siblings, 0 replies; 33+ messages in thread
From: Oleg Nesterov @ 2019-05-01 15:13 UTC (permalink / raw)


On 04/30, Joel Fernandes (Google) wrote:
>
> +static unsigned int pidfd_poll(struct file *file, struct poll_table_struct *pts)
> +{
> +	struct task_struct *task;
> +	struct pid *pid = file->private_data;
> +	int poll_flags = 0;
> +
> +	poll_wait(file, &pid->wait_pidfd, pts);
> +
> +	rcu_read_lock();
> +	task = pid_task(pid, PIDTYPE_PID);
> +	WARN_ON_ONCE(task && !thread_group_leader(task));
                             ^^^^^^^^^^^^^^^^^^^^^^^^^^

Ah, this is not right, we can race with de_thread() which changes the leader,
in particular it does leader->exit_signal = -1 to indicate that this thread is
no longer a group leader, but pid_task() can return the old leader.

We are going to check thread_group_empty() below, it won't be true in this case,
so this race should not make any harm.

Just remove this WARN_ON(). We can't use has_group_leader_pid(), it can return
false if pid_task() returns the new leader.

Otherwise I see no problems.

Oleg.

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v2 1/2] Add polling support to pidfd
  2019-05-01 15:13   ` oleg
  (?)
@ 2019-05-02 15:13     ` christian
  -1 siblings, 0 replies; 33+ messages in thread
From: Christian Brauner @ 2019-05-02 15:13 UTC (permalink / raw)
  To: Oleg Nesterov
  Cc: Joel Fernandes (Google),
	linux-kernel, Andy Lutomirski, Steven Rostedt, Daniel Colascione,
	Jann Horn, Tim Murray, Jonathan Kowalski, Linus Torvalds,
	Al Viro, Kees Cook, David Howells, kernel-team, Andrew Morton,
	Arnd Bergmann, Eric W. Biederman, Greg Kroah-Hartman,
	Ingo Molnar, KJ Tsanaktsidis, linux-kselftest, Michal Hocko,
	Nadav Amit, Peter Zijlstra (Intel),
	Serge Hallyn, Shuah Khan, Thomas Gleixner, Tycho Andersen

On Wed, May 01, 2019 at 05:13:12PM +0200, Oleg Nesterov wrote:
> On 04/30, Joel Fernandes (Google) wrote:
> >
> > +static unsigned int pidfd_poll(struct file *file, struct poll_table_struct *pts)
> > +{
> > +	struct task_struct *task;
> > +	struct pid *pid = file->private_data;
> > +	int poll_flags = 0;
> > +
> > +	poll_wait(file, &pid->wait_pidfd, pts);
> > +
> > +	rcu_read_lock();
> > +	task = pid_task(pid, PIDTYPE_PID);
> > +	WARN_ON_ONCE(task && !thread_group_leader(task));
>                              ^^^^^^^^^^^^^^^^^^^^^^^^^^
> 
> Ah, this is not right, we can race with de_thread() which changes the leader,
> in particular it does leader->exit_signal = -1 to indicate that this thread is
> no longer a group leader, but pid_task() can return the old leader.
> 
> We are going to check thread_group_empty() below, it won't be true in this case,
> so this race should not make any harm.
> 
> Just remove this WARN_ON(). We can't use has_group_leader_pid(), it can return
> false if pid_task() returns the new leader.
> 
> Otherwise I see no problems.

I'll remove the WARN_ON() check when applying this. Can I get your
Acked/Review, Oleg?

Christian

^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v2 1/2] Add polling support to pidfd
@ 2019-05-02 15:13     ` christian
  0 siblings, 0 replies; 33+ messages in thread
From: christian @ 2019-05-02 15:13 UTC (permalink / raw)


On Wed, May 01, 2019 at 05:13:12PM +0200, Oleg Nesterov wrote:
> On 04/30, Joel Fernandes (Google) wrote:
> >
> > +static unsigned int pidfd_poll(struct file *file, struct poll_table_struct *pts)
> > +{
> > +	struct task_struct *task;
> > +	struct pid *pid = file->private_data;
> > +	int poll_flags = 0;
> > +
> > +	poll_wait(file, &pid->wait_pidfd, pts);
> > +
> > +	rcu_read_lock();
> > +	task = pid_task(pid, PIDTYPE_PID);
> > +	WARN_ON_ONCE(task && !thread_group_leader(task));
>                              ^^^^^^^^^^^^^^^^^^^^^^^^^^
> 
> Ah, this is not right, we can race with de_thread() which changes the leader,
> in particular it does leader->exit_signal = -1 to indicate that this thread is
> no longer a group leader, but pid_task() can return the old leader.
> 
> We are going to check thread_group_empty() below, it won't be true in this case,
> so this race should not make any harm.
> 
> Just remove this WARN_ON(). We can't use has_group_leader_pid(), it can return
> false if pid_task() returns the new leader.
> 
> Otherwise I see no problems.

I'll remove the WARN_ON() check when applying this. Can I get your
Acked/Review, Oleg?

Christian

^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v2 1/2] Add polling support to pidfd
@ 2019-05-02 15:13     ` christian
  0 siblings, 0 replies; 33+ messages in thread
From: Christian Brauner @ 2019-05-02 15:13 UTC (permalink / raw)


On Wed, May 01, 2019@05:13:12PM +0200, Oleg Nesterov wrote:
> On 04/30, Joel Fernandes (Google) wrote:
> >
> > +static unsigned int pidfd_poll(struct file *file, struct poll_table_struct *pts)
> > +{
> > +	struct task_struct *task;
> > +	struct pid *pid = file->private_data;
> > +	int poll_flags = 0;
> > +
> > +	poll_wait(file, &pid->wait_pidfd, pts);
> > +
> > +	rcu_read_lock();
> > +	task = pid_task(pid, PIDTYPE_PID);
> > +	WARN_ON_ONCE(task && !thread_group_leader(task));
>                              ^^^^^^^^^^^^^^^^^^^^^^^^^^
> 
> Ah, this is not right, we can race with de_thread() which changes the leader,
> in particular it does leader->exit_signal = -1 to indicate that this thread is
> no longer a group leader, but pid_task() can return the old leader.
> 
> We are going to check thread_group_empty() below, it won't be true in this case,
> so this race should not make any harm.
> 
> Just remove this WARN_ON(). We can't use has_group_leader_pid(), it can return
> false if pid_task() returns the new leader.
> 
> Otherwise I see no problems.

I'll remove the WARN_ON() check when applying this. Can I get your
Acked/Review, Oleg?

Christian

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v2 1/2] Add polling support to pidfd
  2019-05-02 15:13     ` christian
  (?)
@ 2019-05-02 16:02       ` oleg
  -1 siblings, 0 replies; 33+ messages in thread
From: Oleg Nesterov @ 2019-05-02 16:02 UTC (permalink / raw)
  To: Christian Brauner
  Cc: Joel Fernandes (Google),
	linux-kernel, Andy Lutomirski, Steven Rostedt, Daniel Colascione,
	Jann Horn, Tim Murray, Jonathan Kowalski, Linus Torvalds,
	Al Viro, Kees Cook, David Howells, kernel-team, Andrew Morton,
	Arnd Bergmann, Eric W. Biederman, Greg Kroah-Hartman,
	Ingo Molnar, KJ Tsanaktsidis, linux-kselftest, Michal Hocko,
	Nadav Amit, Peter Zijlstra (Intel),
	Serge Hallyn, Shuah Khan, Thomas Gleixner, Tycho Andersen

On 05/02, Christian Brauner wrote:
>
> On Wed, May 01, 2019 at 05:13:12PM +0200, Oleg Nesterov wrote:
> >
> > Otherwise I see no problems.
>
> I'll remove the WARN_ON() check when applying this. Can I get your
> Acked/Review, Oleg?

Yes, feel free to add

	Reviewed-by: Oleg Nesterov <oleg@redhat.com>


Hmm. Somehow I didn't read the changelog before, I just noticed
Suggested-by: Oleg Nesterov <oleg@redhat.com>

Please remove ;) Thanks Joel, I appreciate it, but it is not my idea.

Oleg.


^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v2 1/2] Add polling support to pidfd
@ 2019-05-02 16:02       ` oleg
  0 siblings, 0 replies; 33+ messages in thread
From: oleg @ 2019-05-02 16:02 UTC (permalink / raw)


On 05/02, Christian Brauner wrote:
>
> On Wed, May 01, 2019 at 05:13:12PM +0200, Oleg Nesterov wrote:
> >
> > Otherwise I see no problems.
>
> I'll remove the WARN_ON() check when applying this. Can I get your
> Acked/Review, Oleg?

Yes, feel free to add

	Reviewed-by: Oleg Nesterov <oleg at redhat.com>


Hmm. Somehow I didn't read the changelog before, I just noticed
Suggested-by: Oleg Nesterov <oleg at redhat.com>

Please remove ;) Thanks Joel, I appreciate it, but it is not my idea.

Oleg.

^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v2 1/2] Add polling support to pidfd
@ 2019-05-02 16:02       ` oleg
  0 siblings, 0 replies; 33+ messages in thread
From: Oleg Nesterov @ 2019-05-02 16:02 UTC (permalink / raw)


On 05/02, Christian Brauner wrote:
>
> On Wed, May 01, 2019@05:13:12PM +0200, Oleg Nesterov wrote:
> >
> > Otherwise I see no problems.
>
> I'll remove the WARN_ON() check when applying this. Can I get your
> Acked/Review, Oleg?

Yes, feel free to add

	Reviewed-by: Oleg Nesterov <oleg at redhat.com>


Hmm. Somehow I didn't read the changelog before, I just noticed
Suggested-by: Oleg Nesterov <oleg at redhat.com>

Please remove ;) Thanks Joel, I appreciate it, but it is not my idea.

Oleg.

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v2 1/2] Add polling support to pidfd
  2019-05-02 16:02       ` oleg
  (?)
@ 2019-05-02 19:14         ` joel
  -1 siblings, 0 replies; 33+ messages in thread
From: Joel Fernandes @ 2019-05-02 19:14 UTC (permalink / raw)
  To: Oleg Nesterov
  Cc: Christian Brauner, linux-kernel, Andy Lutomirski, Steven Rostedt,
	Daniel Colascione, Jann Horn, Tim Murray, Jonathan Kowalski,
	Linus Torvalds, Al Viro, Kees Cook, David Howells, kernel-team,
	Andrew Morton, Arnd Bergmann, Eric W. Biederman,
	Greg Kroah-Hartman, Ingo Molnar, KJ Tsanaktsidis,
	linux-kselftest, Michal Hocko, Nadav Amit, Peter Zijlstra (Intel),
	Serge Hallyn, Shuah Khan, Thomas Gleixner, Tycho Andersen

On Thu, May 02, 2019 at 06:02:48PM +0200, Oleg Nesterov wrote:
> On 05/02, Christian Brauner wrote:
> >
> > On Wed, May 01, 2019 at 05:13:12PM +0200, Oleg Nesterov wrote:
> > >
> > > Otherwise I see no problems.
> >
> > I'll remove the WARN_ON() check when applying this. Can I get your
> > Acked/Review, Oleg?

Oh, ok. Good point about the de_thread race. Agreed with you.

> Yes, feel free to add
> 
> 	Reviewed-by: Oleg Nesterov <oleg@redhat.com>
> 
> Hmm. Somehow I didn't read the changelog before, I just noticed
> Suggested-by: Oleg Nesterov <oleg@redhat.com>
> Please remove ;) Thanks Joel, I appreciate it, but it is not my idea.

Ok no problem. You have been very helpful so thank you for that!

Also thanks Christian for removing the warning and adding Oleg's Reviewed-by.

 - Joel


^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v2 1/2] Add polling support to pidfd
@ 2019-05-02 19:14         ` joel
  0 siblings, 0 replies; 33+ messages in thread
From: joel @ 2019-05-02 19:14 UTC (permalink / raw)


On Thu, May 02, 2019 at 06:02:48PM +0200, Oleg Nesterov wrote:
> On 05/02, Christian Brauner wrote:
> >
> > On Wed, May 01, 2019 at 05:13:12PM +0200, Oleg Nesterov wrote:
> > >
> > > Otherwise I see no problems.
> >
> > I'll remove the WARN_ON() check when applying this. Can I get your
> > Acked/Review, Oleg?

Oh, ok. Good point about the de_thread race. Agreed with you.

> Yes, feel free to add
> 
> 	Reviewed-by: Oleg Nesterov <oleg at redhat.com>
> 
> Hmm. Somehow I didn't read the changelog before, I just noticed
> Suggested-by: Oleg Nesterov <oleg at redhat.com>
> Please remove ;) Thanks Joel, I appreciate it, but it is not my idea.

Ok no problem. You have been very helpful so thank you for that!

Also thanks Christian for removing the warning and adding Oleg's Reviewed-by.

 - Joel

^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v2 1/2] Add polling support to pidfd
@ 2019-05-02 19:14         ` joel
  0 siblings, 0 replies; 33+ messages in thread
From: Joel Fernandes @ 2019-05-02 19:14 UTC (permalink / raw)


On Thu, May 02, 2019@06:02:48PM +0200, Oleg Nesterov wrote:
> On 05/02, Christian Brauner wrote:
> >
> > On Wed, May 01, 2019@05:13:12PM +0200, Oleg Nesterov wrote:
> > >
> > > Otherwise I see no problems.
> >
> > I'll remove the WARN_ON() check when applying this. Can I get your
> > Acked/Review, Oleg?

Oh, ok. Good point about the de_thread race. Agreed with you.

> Yes, feel free to add
> 
> 	Reviewed-by: Oleg Nesterov <oleg at redhat.com>
> 
> Hmm. Somehow I didn't read the changelog before, I just noticed
> Suggested-by: Oleg Nesterov <oleg at redhat.com>
> Please remove ;) Thanks Joel, I appreciate it, but it is not my idea.

Ok no problem. You have been very helpful so thank you for that!

Also thanks Christian for removing the warning and adding Oleg's Reviewed-by.

 - Joel

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v2 1/2] Add polling support to pidfd
  2019-05-02 19:14         ` joel
  (?)
@ 2019-05-02 19:35           ` christian
  -1 siblings, 0 replies; 33+ messages in thread
From: Christian Brauner @ 2019-05-02 19:35 UTC (permalink / raw)
  To: Joel Fernandes
  Cc: Oleg Nesterov, linux-kernel, Andy Lutomirski, Steven Rostedt,
	Daniel Colascione, Jann Horn, Tim Murray, Jonathan Kowalski,
	Linus Torvalds, Al Viro, Kees Cook, David Howells, kernel-team,
	Andrew Morton, Arnd Bergmann, Eric W. Biederman,
	Greg Kroah-Hartman, Ingo Molnar, KJ Tsanaktsidis,
	linux-kselftest, Michal Hocko, Nadav Amit, Peter Zijlstra (Intel),
	Serge Hallyn, Shuah Khan, Thomas Gleixner, Tycho Andersen

On Thu, May 02, 2019 at 03:14:37PM -0400, Joel Fernandes wrote:
> On Thu, May 02, 2019 at 06:02:48PM +0200, Oleg Nesterov wrote:
> > On 05/02, Christian Brauner wrote:
> > >
> > > On Wed, May 01, 2019 at 05:13:12PM +0200, Oleg Nesterov wrote:
> > > >
> > > > Otherwise I see no problems.
> > >
> > > I'll remove the WARN_ON() check when applying this. Can I get your
> > > Acked/Review, Oleg?
> 
> Oh, ok. Good point about the de_thread race. Agreed with you.
> 
> > Yes, feel free to add
> > 
> > 	Reviewed-by: Oleg Nesterov <oleg@redhat.com>
> > 
> > Hmm. Somehow I didn't read the changelog before, I just noticed
> > Suggested-by: Oleg Nesterov <oleg@redhat.com>
> > Please remove ;) Thanks Joel, I appreciate it, but it is not my idea.
> 
> Ok no problem. You have been very helpful so thank you for that!

Yep, big thank you, Oleg! :)

Christian

^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v2 1/2] Add polling support to pidfd
@ 2019-05-02 19:35           ` christian
  0 siblings, 0 replies; 33+ messages in thread
From: christian @ 2019-05-02 19:35 UTC (permalink / raw)


On Thu, May 02, 2019 at 03:14:37PM -0400, Joel Fernandes wrote:
> On Thu, May 02, 2019 at 06:02:48PM +0200, Oleg Nesterov wrote:
> > On 05/02, Christian Brauner wrote:
> > >
> > > On Wed, May 01, 2019 at 05:13:12PM +0200, Oleg Nesterov wrote:
> > > >
> > > > Otherwise I see no problems.
> > >
> > > I'll remove the WARN_ON() check when applying this. Can I get your
> > > Acked/Review, Oleg?
> 
> Oh, ok. Good point about the de_thread race. Agreed with you.
> 
> > Yes, feel free to add
> > 
> > 	Reviewed-by: Oleg Nesterov <oleg at redhat.com>
> > 
> > Hmm. Somehow I didn't read the changelog before, I just noticed
> > Suggested-by: Oleg Nesterov <oleg at redhat.com>
> > Please remove ;) Thanks Joel, I appreciate it, but it is not my idea.
> 
> Ok no problem. You have been very helpful so thank you for that!

Yep, big thank you, Oleg! :)

Christian

^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v2 1/2] Add polling support to pidfd
@ 2019-05-02 19:35           ` christian
  0 siblings, 0 replies; 33+ messages in thread
From: Christian Brauner @ 2019-05-02 19:35 UTC (permalink / raw)


On Thu, May 02, 2019@03:14:37PM -0400, Joel Fernandes wrote:
> On Thu, May 02, 2019@06:02:48PM +0200, Oleg Nesterov wrote:
> > On 05/02, Christian Brauner wrote:
> > >
> > > On Wed, May 01, 2019@05:13:12PM +0200, Oleg Nesterov wrote:
> > > >
> > > > Otherwise I see no problems.
> > >
> > > I'll remove the WARN_ON() check when applying this. Can I get your
> > > Acked/Review, Oleg?
> 
> Oh, ok. Good point about the de_thread race. Agreed with you.
> 
> > Yes, feel free to add
> > 
> > 	Reviewed-by: Oleg Nesterov <oleg at redhat.com>
> > 
> > Hmm. Somehow I didn't read the changelog before, I just noticed
> > Suggested-by: Oleg Nesterov <oleg at redhat.com>
> > Please remove ;) Thanks Joel, I appreciate it, but it is not my idea.
> 
> Ok no problem. You have been very helpful so thank you for that!

Yep, big thank you, Oleg! :)

Christian

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v2 1/2] Add polling support to pidfd
  2019-05-02 16:02       ` oleg
  (?)
@ 2019-05-14 15:16         ` christian
  -1 siblings, 0 replies; 33+ messages in thread
From: Christian Brauner @ 2019-05-14 15:16 UTC (permalink / raw)
  To: Oleg Nesterov, Joel Fernandes (Google)
  Cc: linux-kernel, Andy Lutomirski, Steven Rostedt, Daniel Colascione,
	Jann Horn, Tim Murray, Jonathan Kowalski, Linus Torvalds,
	Al Viro, Kees Cook, David Howells, kernel-team, Andrew Morton,
	Arnd Bergmann, Eric W. Biederman, Greg Kroah-Hartman,
	Ingo Molnar, KJ Tsanaktsidis, linux-kselftest, Michal Hocko,
	Nadav Amit, Peter Zijlstra (Intel),
	Serge Hallyn, Shuah Khan, Thomas Gleixner, Tycho Andersen

On Thu, May 02, 2019 at 06:02:48PM +0200, Oleg Nesterov wrote:
> On 05/02, Christian Brauner wrote:
> >
> > On Wed, May 01, 2019 at 05:13:12PM +0200, Oleg Nesterov wrote:
> > >
> > > Otherwise I see no problems.
> >
> > I'll remove the WARN_ON() check when applying this. Can I get your
> > Acked/Review, Oleg?
> 
> Yes, feel free to add
> 
> 	Reviewed-by: Oleg Nesterov <oleg@redhat.com>

Applied to 

https://git.kernel.org/pub/scm/linux/kernel/git/brauner/linux.git/log/?h=for-next

and targeted for the 5.3 merge window.

Thank you all!
Christian

^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v2 1/2] Add polling support to pidfd
@ 2019-05-14 15:16         ` christian
  0 siblings, 0 replies; 33+ messages in thread
From: christian @ 2019-05-14 15:16 UTC (permalink / raw)


On Thu, May 02, 2019 at 06:02:48PM +0200, Oleg Nesterov wrote:
> On 05/02, Christian Brauner wrote:
> >
> > On Wed, May 01, 2019 at 05:13:12PM +0200, Oleg Nesterov wrote:
> > >
> > > Otherwise I see no problems.
> >
> > I'll remove the WARN_ON() check when applying this. Can I get your
> > Acked/Review, Oleg?
> 
> Yes, feel free to add
> 
> 	Reviewed-by: Oleg Nesterov <oleg at redhat.com>

Applied to 

https://git.kernel.org/pub/scm/linux/kernel/git/brauner/linux.git/log/?h=for-next

and targeted for the 5.3 merge window.

Thank you all!
Christian

^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v2 1/2] Add polling support to pidfd
@ 2019-05-14 15:16         ` christian
  0 siblings, 0 replies; 33+ messages in thread
From: Christian Brauner @ 2019-05-14 15:16 UTC (permalink / raw)


On Thu, May 02, 2019@06:02:48PM +0200, Oleg Nesterov wrote:
> On 05/02, Christian Brauner wrote:
> >
> > On Wed, May 01, 2019@05:13:12PM +0200, Oleg Nesterov wrote:
> > >
> > > Otherwise I see no problems.
> >
> > I'll remove the WARN_ON() check when applying this. Can I get your
> > Acked/Review, Oleg?
> 
> Yes, feel free to add
> 
> 	Reviewed-by: Oleg Nesterov <oleg at redhat.com>

Applied to 

https://git.kernel.org/pub/scm/linux/kernel/git/brauner/linux.git/log/?h=for-next

and targeted for the 5.3 merge window.

Thank you all!
Christian

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH v2 2/2] Add selftests for pidfd polling
  2019-04-30 16:21   ` joel
  (?)
@ 2019-05-14 15:17     ` christian
  -1 siblings, 0 replies; 33+ messages in thread
From: Christian Brauner @ 2019-05-14 15:17 UTC (permalink / raw)
  To: Joel Fernandes (Google)
  Cc: linux-kernel, Al Viro, Andrew Morton, Andy Lutomirski,
	Arnd Bergmann, Daniel Colascione, David Howells,
	Eric W. Biederman, Greg Kroah-Hartman, Ingo Molnar, Jann Horn,
	Jonathan Kowalski, Kees Cook, kernel-team, KJ Tsanaktsidis,
	Linus Torvalds, linux-kselftest, Michal Hocko, Nadav Amit,
	Oleg Nesterov, Peter Zijlstra (Intel),
	Serge Hallyn, Shuah Khan, Steven Rostedt, Thomas Gleixner,
	Tim Murray, Tycho Andersen

On Tue, Apr 30, 2019 at 12:21:54PM -0400, Joel Fernandes (Google) wrote:
> Other than verifying pidfd based polling, the tests make sure that
> wait semantics are preserved with the pidfd poll. Notably the 2 cases:
> 1. If a thread group leader exits while threads still there, then no
>    pidfd poll notifcation should happen.
> 2. If a non-thread group leader does an execve, then the thread group
>    leader is signaled to exit and is replaced with the execing thread
>    as the new leader, however the parent is not notified in this case.
> 
> Signed-off-by: Joel Fernandes (Google) <joel@joelfernandes.org>

Applied to 

https://git.kernel.org/pub/scm/linux/kernel/git/brauner/linux.git/log/?h=for-next

and targeted for the 5.3 merge window.

Thank you all!
Christian

^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v2 2/2] Add selftests for pidfd polling
@ 2019-05-14 15:17     ` christian
  0 siblings, 0 replies; 33+ messages in thread
From: christian @ 2019-05-14 15:17 UTC (permalink / raw)


On Tue, Apr 30, 2019 at 12:21:54PM -0400, Joel Fernandes (Google) wrote:
> Other than verifying pidfd based polling, the tests make sure that
> wait semantics are preserved with the pidfd poll. Notably the 2 cases:
> 1. If a thread group leader exits while threads still there, then no
>    pidfd poll notifcation should happen.
> 2. If a non-thread group leader does an execve, then the thread group
>    leader is signaled to exit and is replaced with the execing thread
>    as the new leader, however the parent is not notified in this case.
> 
> Signed-off-by: Joel Fernandes (Google) <joel at joelfernandes.org>

Applied to 

https://git.kernel.org/pub/scm/linux/kernel/git/brauner/linux.git/log/?h=for-next

and targeted for the 5.3 merge window.

Thank you all!
Christian

^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v2 2/2] Add selftests for pidfd polling
@ 2019-05-14 15:17     ` christian
  0 siblings, 0 replies; 33+ messages in thread
From: Christian Brauner @ 2019-05-14 15:17 UTC (permalink / raw)


On Tue, Apr 30, 2019@12:21:54PM -0400, Joel Fernandes (Google) wrote:
> Other than verifying pidfd based polling, the tests make sure that
> wait semantics are preserved with the pidfd poll. Notably the 2 cases:
> 1. If a thread group leader exits while threads still there, then no
>    pidfd poll notifcation should happen.
> 2. If a non-thread group leader does an execve, then the thread group
>    leader is signaled to exit and is replaced with the execing thread
>    as the new leader, however the parent is not notified in this case.
> 
> Signed-off-by: Joel Fernandes (Google) <joel at joelfernandes.org>

Applied to 

https://git.kernel.org/pub/scm/linux/kernel/git/brauner/linux.git/log/?h=for-next

and targeted for the 5.3 merge window.

Thank you all!
Christian

^ permalink raw reply	[flat|nested] 33+ messages in thread

end of thread, other threads:[~2019-05-14 15:17 UTC | newest]

Thread overview: 33+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-04-30 16:21 [PATCH v2 1/2] Add polling support to pidfd Joel Fernandes (Google)
2019-04-30 16:21 ` Joel Fernandes (Google)
2019-04-30 16:21 ` joel
2019-04-30 16:21 ` [PATCH v2 2/2] Add selftests for pidfd polling Joel Fernandes (Google)
2019-04-30 16:21   ` Joel Fernandes (Google)
2019-04-30 16:21   ` joel
2019-04-30 19:20   ` Christian Brauner
2019-04-30 19:20     ` Christian Brauner
2019-04-30 19:20     ` christian
2019-05-14 15:17   ` Christian Brauner
2019-05-14 15:17     ` Christian Brauner
2019-05-14 15:17     ` christian
2019-04-30 19:07 ` [PATCH v2 1/2] Add polling support to pidfd Christian Brauner
2019-04-30 19:07   ` Christian Brauner
2019-04-30 19:07   ` christian
2019-05-01 15:13 ` Oleg Nesterov
2019-05-01 15:13   ` Oleg Nesterov
2019-05-01 15:13   ` oleg
2019-05-02 15:13   ` Christian Brauner
2019-05-02 15:13     ` Christian Brauner
2019-05-02 15:13     ` christian
2019-05-02 16:02     ` Oleg Nesterov
2019-05-02 16:02       ` Oleg Nesterov
2019-05-02 16:02       ` oleg
2019-05-02 19:14       ` Joel Fernandes
2019-05-02 19:14         ` Joel Fernandes
2019-05-02 19:14         ` joel
2019-05-02 19:35         ` Christian Brauner
2019-05-02 19:35           ` Christian Brauner
2019-05-02 19:35           ` christian
2019-05-14 15:16       ` Christian Brauner
2019-05-14 15:16         ` Christian Brauner
2019-05-14 15:16         ` christian

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.