[PATCH 4/8] pidfd: take a lock-free exec_update_seq fast path in __pidfd_fget()
From: Christian Brauner
Date: Mon May 25 2026 - 03:27:57 EST
Convert __pidfd_fget() (pidfd_getfd(2)) to
exec_update_read_begin_or_lock(): check ptrace_may_access() and
fget_task() lock-free, falling back to exec_update_lock on a racing
exec()/TSYNC. The check + fget moves to pidfd_fget_access(), and a
speculative file reference is dropped before retry. The exiting-task
fixup (PF_EXITING -> ESRCH/EBADF) is unchanged.
Signed-off-by: Christian Brauner (Amutable) <brauner@xxxxxxxxxx>
---
kernel/pid.c | 27 +++++++++++++++++++--------
1 file changed, 19 insertions(+), 8 deletions(-)
diff --git a/kernel/pid.c b/kernel/pid.c
index fd5c2d4aa349..7ac85f417485 100644
--- a/kernel/pid.c
+++ b/kernel/pid.c
@@ -876,21 +876,32 @@ static __init int pid_namespace_sysctl_init(void)
}
subsys_initcall(pid_namespace_sysctl_init);
+static struct file *pidfd_fget_access(struct task_struct *task, int fd)
+{
+ if (!ptrace_may_access(task, PTRACE_MODE_ATTACH_REALCREDS))
+ return ERR_PTR(-EPERM);
+ return fget_task(task, fd);
+}
+
static struct file *__pidfd_fget(struct task_struct *task, int fd)
{
+ struct signal_struct *sig = task->signal;
struct file *file;
+ unsigned int seq = 0;
int ret;
- ret = down_read_killable(&task->signal->exec_update_lock);
+retry:
+ ret = exec_update_read_begin_or_killable(sig, &seq);
if (ret)
return ERR_PTR(ret);
-
- if (ptrace_may_access(task, PTRACE_MODE_ATTACH_REALCREDS))
- file = fget_task(task, fd);
- else
- file = ERR_PTR(-EPERM);
-
- up_read(&task->signal->exec_update_lock);
+ file = pidfd_fget_access(task, fd);
+ if (exec_update_read_needs_retry(sig, seq)) {
+ if (!IS_ERR_OR_NULL(file))
+ fput(file);
+ seq = 1;
+ goto retry;
+ }
+ exec_update_read_done(sig, seq);
if (!file) {
/*
--
2.47.3
--j3ezp33mpunnwnqz
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0005-futex-take-a-lock-free-exec_update_seq-fast-path-in-.patch"