Skip to content

Commit 4513522

Browse files
committed
pidfs: record exit code and cgroupid at exit
Record the exit code and cgroupid in release_task() and stash in struct pidfs_exit_info so it can be retrieved even after the task has been reaped. Link: https://lore.kernel.org/r/20250305-work-pidfs-kill_on_last_close-v3-5-c8c3d8361705@kernel.org Reviewed-by: Jeff Layton <jlayton@kernel.org> Reviewed-by: Oleg Nesterov <oleg@redhat.com> Signed-off-by: Christian Brauner <brauner@kernel.org>
1 parent 0b42003 commit 4513522

5 files changed

Lines changed: 47 additions & 2 deletions

File tree

fs/internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,7 @@ struct stashed_operations {
325325
int path_from_stashed(struct dentry **stashed, struct vfsmount *mnt, void *data,
326326
struct path *path);
327327
void stashed_dentry_prune(struct dentry *dentry);
328+
struct dentry *stashed_dentry_get(struct dentry **stashed);
328329
/**
329330
* path_mounted - check whether path is mounted
330331
* @path: path to check

fs/libfs.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2113,7 +2113,7 @@ struct timespec64 simple_inode_init_ts(struct inode *inode)
21132113
}
21142114
EXPORT_SYMBOL(simple_inode_init_ts);
21152115

2116-
static inline struct dentry *get_stashed_dentry(struct dentry **stashed)
2116+
struct dentry *stashed_dentry_get(struct dentry **stashed)
21172117
{
21182118
struct dentry *dentry;
21192119

@@ -2215,7 +2215,7 @@ int path_from_stashed(struct dentry **stashed, struct vfsmount *mnt, void *data,
22152215
const struct stashed_operations *sops = mnt->mnt_sb->s_fs_info;
22162216

22172217
/* See if dentry can be reused. */
2218-
path->dentry = get_stashed_dentry(stashed);
2218+
path->dentry = stashed_dentry_get(stashed);
22192219
if (path->dentry) {
22202220
sops->put_data(data);
22212221
goto out_path;

fs/pidfs.c

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,47 @@ struct pid *pidfd_pid(const struct file *file)
458458
return file_inode(file)->i_private;
459459
}
460460

461+
/*
462+
* We're called from release_task(). We know there's at least one
463+
* reference to struct pid being held that won't be released until the
464+
* task has been reaped which cannot happen until we're out of
465+
* release_task().
466+
*
467+
* If this struct pid is referred to by a pidfd then
468+
* stashed_dentry_get() will return the dentry and inode for that struct
469+
* pid. Since we've taken a reference on it there's now an additional
470+
* reference from the exit path on it. Which is fine. We're going to put
471+
* it again in a second and we know that the pid is kept alive anyway.
472+
*
473+
* Worst case is that we've filled in the info and immediately free the
474+
* dentry and inode afterwards since the pidfd has been closed. Since
475+
* pidfs_exit() currently is placed after exit_task_work() we know that
476+
* it cannot be us aka the exiting task holding a pidfd to ourselves.
477+
*/
478+
void pidfs_exit(struct task_struct *tsk)
479+
{
480+
struct dentry *dentry;
481+
482+
might_sleep();
483+
484+
dentry = stashed_dentry_get(&task_pid(tsk)->stashed);
485+
if (dentry) {
486+
struct inode *inode = d_inode(dentry);
487+
struct pidfs_exit_info *exit_info = &pidfs_i(inode)->exit_info;
488+
#ifdef CONFIG_CGROUPS
489+
struct cgroup *cgrp;
490+
491+
rcu_read_lock();
492+
cgrp = task_dfl_cgroup(tsk);
493+
exit_info->cgroupid = cgroup_id(cgrp);
494+
rcu_read_unlock();
495+
#endif
496+
exit_info->exit_code = tsk->exit_code;
497+
498+
dput(dentry);
499+
}
500+
}
501+
461502
static struct vfsmount *pidfs_mnt __ro_after_init;
462503

463504
/*

include/linux/pidfs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ struct file *pidfs_alloc_file(struct pid *pid, unsigned int flags);
66
void __init pidfs_init(void);
77
void pidfs_add_pid(struct pid *pid);
88
void pidfs_remove_pid(struct pid *pid);
9+
void pidfs_exit(struct task_struct *tsk);
910
extern const struct dentry_operations pidfs_dentry_operations;
1011

1112
#endif /* _LINUX_PID_FS_H */

kernel/exit.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
#include <linux/sysfs.h>
7070
#include <linux/user_events.h>
7171
#include <linux/uaccess.h>
72+
#include <linux/pidfs.h>
7273

7374
#include <uapi/linux/wait.h>
7475

@@ -249,6 +250,7 @@ void release_task(struct task_struct *p)
249250
dec_rlimit_ucounts(task_ucounts(p), UCOUNT_RLIMIT_NPROC, 1);
250251
rcu_read_unlock();
251252

253+
pidfs_exit(p);
252254
cgroup_release(p);
253255

254256
write_lock_irq(&tasklist_lock);

0 commit comments

Comments
 (0)