[RFC PATCH 08/24] pidfs: attach pids to future pidfd files
From: Li Chen <hidden>
Date: 2026-07-16 14:37:23
Also in:
linux-arch, linux-doc, linux-fsdevel, linux-kselftest, linux-mm, linux-security-module, lkml
Subsystem:
filesystems (vfs and infrastructure), the rest · Maintainers:
Alexander Viro, Christian Brauner, Linus Torvalds
Associate a future pidfs inode with a preallocated struct pid and reuse the future dentry as the canonical stashed dentry. Preserve the reserved inode identity when the pid is registered. Keep attachment reversible until a task owns the pid so copy_process() failure can return the future file to its taskless state. File-handle lookup requires both the stash and an attached task before accepting an unpublished pid, preventing failed allocations from being reopened through stale state. Assisted-by: Codex:gpt-5.6-sol Signed-off-by: Li Chen <redacted> --- fs/pidfs.c | 89 +++++++++++++++++++++++++++++++++++++++++-- include/linux/pidfs.h | 2 + 2 files changed, 87 insertions(+), 4 deletions(-)
diff --git a/fs/pidfs.c b/fs/pidfs.c
index 28464fe274c9e..36ee4f210f73f 100644
--- a/fs/pidfs.c
+++ b/fs/pidfs.c@@ -115,6 +115,7 @@ struct pidfs_future_file { void *data; const struct pidfs_future_file_ops *ops; struct pidfs_attr *attr; + struct pid *pid; u64 ino; };
@@ -238,7 +239,8 @@ int pidfs_add_pid(struct pid *pid) { int ret; - pid->ino = pidfs_alloc_ino(); + if (!pid->ino) + pid->ino = pidfs_alloc_ino(); ret = rhashtable_insert_fast(&pidfs_ino_ht, &pid->pidfs_hash, pidfs_ino_ht_params); if (unlikely(ret))
@@ -987,9 +989,18 @@ static struct pid *pidfs_ino_get_pid(u64 ino) if (!pid) return NULL; attr = READ_ONCE(pid->attr); - if (IS_ERR_OR_NULL(attr)) + if (IS_ERR(attr)) + return NULL; + /* + * A task can become visible before its future pidfd is published. Let + * ->open() wait across that window, but never expose a dentry for a + * caller-supplied pid when copy_process() has failed. That failure path + * clears the stash before freeing the pid allocation. + */ + if (!attr && (!READ_ONCE(pid->stashed) || + !pid_has_task(pid, PIDTYPE_PID))) return NULL; - if (test_bit(PIDFS_ATTR_BIT_EXIT, &attr->attr_mask)) + if (attr && test_bit(PIDFS_ATTR_BIT_EXIT, &attr->attr_mask)) return NULL; /* Within our pid namespace hierarchy? */ if (pid_vnr(pid) == 0)
@@ -1025,7 +1036,8 @@ static struct dentry *pidfs_fh_to_dentry(struct super_block *sb, if (ret < 0) return ERR_PTR(ret); - VFS_WARN_ON_ONCE(!pid->attr); + VFS_WARN_ON_ONCE(!pid->attr && + !pidfs_future_file(d_inode(path.dentry))); mntput(path.mnt); return path.dentry;
@@ -1103,6 +1115,10 @@ static int pidfs_init_inode(struct inode *inode, void *data) static bool pidfs_inode_data_matches(const struct inode *inode, const void *data) { + struct pidfs_future_file *future = pidfs_future_file(inode); + + if (future) + return READ_ONCE(future->pid) == data; return pidfs_inode_pid(inode) == data; }
@@ -1266,6 +1282,10 @@ struct file *pidfs_alloc_file(struct pid *pid, unsigned int flags) PIDFD_AUTOKILL) != 5); BUILD_BUG_ON(PIDFD_EMPTY & VALID_OPEN_FLAGS); + ret = pidfs_register_pid(pid); + if (ret) + return ERR_PTR(ret); + ret = path_from_stashed(&pid->stashed, pidfs_mnt, get_pid(pid), &path); if (ret < 0) return ERR_PTR(ret);
@@ -1369,6 +1389,67 @@ u64 pidfs_future_file_ino(const struct file *file) return future ? future->ino : 0; } +/** + * pidfs_future_file_set_pid - associate a preallocated pid with a future file + * @file: future pidfs file + * @pid: preallocated pid whose pidfs inode number matches @file + * + * This stashes the future dentry in @pid before copy_process() publishes the + * task. No pid reference is transferred. On a later creation failure the + * producer must call pidfs_future_file_clear_pid() before freeing @pid. + * + * Return: Zero on success or a negative error code. + */ +int pidfs_future_file_set_pid(struct file *file, struct pid *pid) +{ + struct inode *inode = file_inode(file); + struct pidfs_future_file *future = pidfs_future_file(inode); + struct dentry *dentry = file->f_path.dentry; + struct dentry *stashed; + + if (!future || !future->ops->get_pid || future->pid || + pid->ino != future->ino) + return -EBADF; + + WRITE_ONCE(future->pid, pid); + dentry->d_fsdata = &pid->stashed; + stashed = stash_dentry(&pid->stashed, dentry); + if (stashed != dentry) { + dput(stashed); + pidfs_future_file_clear_pid(file, pid); + return -EBUSY; + } + return 0; +} + +/** + * pidfs_future_file_clear_pid - undo an unpublished future-pid association + * @file: future pidfs file + * @pid: pid previously associated with @file + * + * This may be called only after pidfs_future_file_set_pid() and before + * pidfs_future_file_publish_pid(). It removes the stashed dentry so the + * producer can free @pid after a task-creation failure. + * + * The producer must clear the association before attaching @pid to a task. + * File-handle lookup treats an attached pid as a publication-in-progress + * guarantee, so clearing the association later would violate that contract. + */ +void pidfs_future_file_clear_pid(struct file *file, struct pid *pid) +{ + struct inode *inode = file_inode(file); + struct pidfs_future_file *future = pidfs_future_file(inode); + struct dentry *dentry = file->f_path.dentry; + + if (WARN_ON_ONCE(!future || READ_ONCE(future->pid) != pid)) + return; + + WARN_ON_ONCE(cmpxchg(&pid->stashed, dentry, NULL) != dentry); + dentry->d_fsdata = NULL; + WARN_ON_ONCE(pid->attr); + WRITE_ONCE(future->pid, NULL); +} + void __init pidfs_init(void) { if (rhashtable_init(&pidfs_ino_ht, &pidfs_ino_ht_params))
diff --git a/include/linux/pidfs.h b/include/linux/pidfs.h
index 6b7fbc54ab388..828e96f769ba1 100644
--- a/include/linux/pidfs.h
+++ b/include/linux/pidfs.h@@ -28,6 +28,8 @@ struct file *pidfs_alloc_future_file(const char *name, void *data, void *pidfs_future_file_data(const struct file *file, const struct pidfs_future_file_ops *ops); u64 pidfs_future_file_ino(const struct file *file); +int pidfs_future_file_set_pid(struct file *file, struct pid *pid); +void pidfs_future_file_clear_pid(struct file *file, struct pid *pid); void __init pidfs_init(void); void pidfs_prepare_pid(struct pid *pid); int pidfs_add_pid(struct pid *pid);
--
2.52.0