Received: by 2002:a05:6a10:f347:0:0:0:0 with SMTP id d7csp125932pxu; Wed, 6 Jan 2021 23:55:26 -0800 (PST) X-Google-Smtp-Source: ABdhPJxrP+sAvpWTk7yCx81ujQi+qOizxb1xsgMa1e4a+vW65y34seNxB7jhAKN68LJV4BFxQwZ+ X-Received: by 2002:a17:906:a283:: with SMTP id i3mr4012191ejz.496.1610006126151; Wed, 06 Jan 2021 23:55:26 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1610006126; cv=none; d=google.com; s=arc-20160816; b=YT8cYv35vDWc9ZrrODkGUCn3CxyQDtafQXQlHuKVj/Td35LtH7F0sVKhOaBCCmlckh esi8+hjVcVRCpevH0yhgll7bLFpkYB1/QyotD3KzPxQfR8TJdN+1r43k7tZxdO1QhFik Gevv/0okBXhfz+JQgP3R4nxVO4juoYGeoTs8Psas20ItJZMw4wN4Qkfuw6zDseoZmHCf pxi94Toz1Z83Lx/XlCMigsbtviZgEb/TJ6VeQDtISFq8qZmH+L0JL9LKqA+NCBECvT7I kybbpmqSKHGD7EhnO3I2DeHJBAK/zmw4+ma7Ouzy4dIg4T89Xh051sPPPpABNkrzsUKa P7lA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from; bh=9XeZRVXDRaiA77hqPtMyD4NGN6mF8l+F+991CHoMGZU=; b=IiBf2ryZm+7kTJYRUzqzJg5wdbmYIPi0JJhtLjFiQaxIBgUbvvu2u2s/LR2lAULAiE hpb7peXQCNixkSOfJDxJAjF7swZ1yt+XAZT8pEeq9ru7h2EF1piDTb5w6ri8wz+UEGcF 5pXv4Z2MxhtJtSXd78NKi/GSz6x/HwsKrTCx040ejDx687sd+RbmGD9wovWk3/6TWa/y vF0qRyib1G2G0/uLaPGcsqIGZdN/yUwwqhw3fUuYNBQCZOdLI+s2WH6rPQv/VNgtQlEd UJT4smsDUstspIg880j3gnKYdbGVC0GqTIz4CgSKYAO1whSb07BU2KzQgCbY+PU4bKvL uq0g== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=alibaba.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id v25si1915268edt.63.2021.01.06.23.55.03; Wed, 06 Jan 2021 23:55:26 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=alibaba.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727090AbhAGHxT (ORCPT + 99 others); Thu, 7 Jan 2021 02:53:19 -0500 Received: from out30-57.freemail.mail.aliyun.com ([115.124.30.57]:56950 "EHLO out30-57.freemail.mail.aliyun.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726505AbhAGHxT (ORCPT ); Thu, 7 Jan 2021 02:53:19 -0500 X-Alimail-AntiSpam: AC=PASS;BC=-1|-1;BR=01201311R141e4;CH=green;DM=||false|;DS=||;FP=0|-1|-1|-1|0|-1|-1|-1;HT=e01e04357;MF=wenyang@linux.alibaba.com;NM=1;PH=DS;RN=20;SR=0;TI=SMTPD_---0UKz-yp._1610005953; Received: from localhost(mailfrom:wenyang@linux.alibaba.com fp:SMTPD_---0UKz-yp._1610005953) by smtp.aliyun-inc.com(127.0.0.1); Thu, 07 Jan 2021 15:52:34 +0800 From: Wen Yang To: Greg Kroah-Hartman , Sasha Levin Cc: Xunlei Pang , linux-kernel@vger.kernel.org, "Joel Fernandes (Google)" , Andy Lutomirski , Steven Rostedt , Daniel Colascione , Jann Horn , Tim Murray , Jonathan Kowalski , Linus Torvalds , Al Viro , Kees Cook , David Howells , Oleg Nesterov , kernel-team@android.com, Christian Brauner , stable@vger.kernel.org, Wen Yang Subject: [PATCH v2 4.9 02/10] pidfd: add polling support Date: Thu, 7 Jan 2021 15:52:14 +0800 Message-Id: <20210107075222.62623-3-wenyang@linux.alibaba.com> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20210107075222.62623-1-wenyang@linux.alibaba.com> References: <20210107075222.62623-1-wenyang@linux.alibaba.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: "Joel Fernandes (Google)" [ Upstream commit b53b0b9d9a613c418057f6cb921c2f40a6f78c24 ] This patch adds polling support to pidfd. 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. 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. Cc: Andy Lutomirski Cc: Steven Rostedt Cc: Daniel Colascione Cc: Jann Horn Cc: Tim Murray Cc: Jonathan Kowalski Cc: Linus Torvalds Cc: Al Viro Cc: Kees Cook Cc: David Howells Cc: Oleg Nesterov Cc: kernel-team@android.com Reviewed-by: Oleg Nesterov Co-developed-by: Daniel Colascione Signed-off-by: Daniel Colascione Signed-off-by: Joel Fernandes (Google) Signed-off-by: Christian Brauner Cc: # 4.9.x (pidfd: fix up cherry-pick conflicts for b53b0b9d9a61) Signed-off-by: Wen Yang --- include/linux/pid.h | 3 +++ kernel/fork.c | 26 ++++++++++++++++++++++++++ kernel/pid.c | 2 ++ kernel/signal.c | 11 +++++++++++ 4 files changed, 42 insertions(+) diff --git a/include/linux/pid.h b/include/linux/pid.h index 7599a78..f5552ba 100644 --- a/include/linux/pid.h +++ b/include/linux/pid.h @@ -2,6 +2,7 @@ #define _LINUX_PID_H #include +#include enum pid_type { @@ -62,6 +63,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 4249f60..e3a4a14 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1481,8 +1481,34 @@ 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); + /* + * Inform pollers only when the whole thread group exits. + * If the 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 fa704f8..e605398 100644 --- a/kernel/pid.c +++ b/kernel/pid.c @@ -333,6 +333,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->nr_hashed & PIDNS_HASH_ADDING)) diff --git a/kernel/signal.c b/kernel/signal.c index bedca16..053de87a 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -1632,6 +1632,14 @@ int send_sigqueue(struct sigqueue *q, struct task_struct *t, int group) 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. @@ -1655,6 +1663,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. -- 1.8.3.1