]> www.infradead.org Git - nvme.git/commitdiff
pidfs: use private inode slab cache
authorChristian Brauner <brauner@kernel.org>
Wed, 5 Mar 2025 10:08:14 +0000 (11:08 +0100)
committerChristian Brauner <brauner@kernel.org>
Wed, 5 Mar 2025 12:26:09 +0000 (13:26 +0100)
Introduce a private inode slab cache for pidfs. In follow-up patches
pidfs will gain the ability to provide exit information to userspace
after the task has been reaped. This means storing exit information even
after the task has already been released and struct pid's task linkage
is gone. Store that information alongside the inode.

Link: https://lore.kernel.org/r/20250305-work-pidfs-kill_on_last_close-v3-4-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>
fs/pidfs.c

index ecc0dd886714c8fe48335ce77c87d27dd0a46537..282511a36fd96e887f180dcd6caefa086e0816a0 100644 (file)
 #include "internal.h"
 #include "mount.h"
 
+static struct kmem_cache *pidfs_cachep __ro_after_init;
+
+/*
+ * Stashes information that userspace needs to access even after the
+ * process has been reaped.
+ */
+struct pidfs_exit_info {
+       __u64 cgroupid;
+       __s32 exit_code;
+};
+
+struct pidfs_inode {
+       struct pidfs_exit_info exit_info;
+       struct inode vfs_inode;
+};
+
+static inline struct pidfs_inode *pidfs_i(struct inode *inode)
+{
+       return container_of(inode, struct pidfs_inode, vfs_inode);
+}
+
 static struct rb_root pidfs_ino_tree = RB_ROOT;
 
 #if BITS_PER_LONG == 32
@@ -492,9 +513,29 @@ static void pidfs_evict_inode(struct inode *inode)
        put_pid(pid);
 }
 
+static struct inode *pidfs_alloc_inode(struct super_block *sb)
+{
+       struct pidfs_inode *pi;
+
+       pi = alloc_inode_sb(sb, pidfs_cachep, GFP_KERNEL);
+       if (!pi)
+               return NULL;
+
+       memset(&pi->exit_info, 0, sizeof(pi->exit_info));
+
+       return &pi->vfs_inode;
+}
+
+static void pidfs_free_inode(struct inode *inode)
+{
+       kmem_cache_free(pidfs_cachep, pidfs_i(inode));
+}
+
 static const struct super_operations pidfs_sops = {
+       .alloc_inode    = pidfs_alloc_inode,
        .drop_inode     = generic_delete_inode,
        .evict_inode    = pidfs_evict_inode,
+       .free_inode     = pidfs_free_inode,
        .statfs         = simple_statfs,
 };
 
@@ -704,8 +745,19 @@ struct file *pidfs_alloc_file(struct pid *pid, unsigned int flags)
        return pidfd_file;
 }
 
+static void pidfs_inode_init_once(void *data)
+{
+       struct pidfs_inode *pi = data;
+
+       inode_init_once(&pi->vfs_inode);
+}
+
 void __init pidfs_init(void)
 {
+       pidfs_cachep = kmem_cache_create("pidfs_cache", sizeof(struct pidfs_inode), 0,
+                                        (SLAB_HWCACHE_ALIGN | SLAB_RECLAIM_ACCOUNT |
+                                         SLAB_ACCOUNT | SLAB_PANIC),
+                                        pidfs_inode_init_once);
        pidfs_mnt = kern_mount(&pidfs_type);
        if (IS_ERR(pidfs_mnt))
                panic("Failed to mount pidfs pseudo filesystem");