From: Christian Brauner Date: Mon, 16 Feb 2026 13:32:01 +0000 (+0100) Subject: pidfs: adapt to rhashtable-based simple_xattrs X-Git-Tag: v7.1-rc1~246^2^2~9 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=50704c391fbf11cf52faa27d46c3bb59da33a191;p=thirdparty%2Fkernel%2Flinux.git pidfs: adapt to rhashtable-based simple_xattrs Adapt pidfs to use the rhashtable-based xattr path by switching from a dedicated slab cache to simple_xattrs_alloc(). Previously pidfs used a custom kmem_cache (pidfs_xattr_cachep) that allocated a struct containing an embedded simple_xattrs plus simple_xattrs_init(). Replace this with simple_xattrs_alloc() which combines kzalloc + rhashtable_init, and drop the dedicated slab cache entirely. Use simple_xattr_free_rcu() for replaced xattr entries to allow concurrent RCU readers to finish. Link: https://patch.msgid.link/20260216-work-xattr-socket-v1-5-c2efa4f74cb7@kernel.org Acked-by: Darrick J. Wong Signed-off-by: Christian Brauner --- diff --git a/fs/pidfs.c b/fs/pidfs.c index 318253344b5c5..bae8e5d32a1cd 100644 --- a/fs/pidfs.c +++ b/fs/pidfs.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -31,7 +32,6 @@ #define PIDFS_PID_DEAD ERR_PTR(-ESRCH) static struct kmem_cache *pidfs_attr_cachep __ro_after_init; -static struct kmem_cache *pidfs_xattr_cachep __ro_after_init; static struct path pidfs_root_path = {}; @@ -46,9 +46,8 @@ enum pidfs_attr_mask_bits { PIDFS_ATTR_BIT_COREDUMP = 1, }; -struct pidfs_attr { +struct pidfs_anon_attr { unsigned long attr_mask; - struct simple_xattrs *xattrs; struct /* exit info */ { __u64 cgroupid; __s32 exit_code; @@ -93,6 +92,13 @@ static const struct rhashtable_params pidfs_ino_ht_params = { * inode number and the inode generation number to compare or * use file handles. */ +struct pidfs_attr { + struct simple_xattrs *xattrs; + union { + struct pidfs_anon_attr; + struct llist_node pidfs_llist; + }; +}; #if BITS_PER_LONG == 32 @@ -178,10 +184,30 @@ void pidfs_remove_pid(struct pid *pid) pidfs_ino_ht_params); } +static LLIST_HEAD(pidfs_free_list); + +static void pidfs_free_attr_work(struct work_struct *work) +{ + struct pidfs_attr *attr, *next; + struct llist_node *head; + + head = llist_del_all(&pidfs_free_list); + llist_for_each_entry_safe(attr, next, head, pidfs_llist) { + struct simple_xattrs *xattrs = attr->xattrs; + + if (xattrs) { + simple_xattrs_free(xattrs, NULL); + kfree(xattrs); + } + kfree(attr); + } +} + +static DECLARE_WORK(pidfs_free_work, pidfs_free_attr_work); + void pidfs_free_pid(struct pid *pid) { - struct pidfs_attr *attr __free(kfree) = no_free_ptr(pid->attr); - struct simple_xattrs *xattrs __free(kfree) = NULL; + struct pidfs_attr *attr = pid->attr; /* * Any dentry must've been wiped from the pid by now. @@ -200,9 +226,10 @@ void pidfs_free_pid(struct pid *pid) if (IS_ERR(attr)) return; - xattrs = no_free_ptr(attr->xattrs); - if (xattrs) - simple_xattrs_free(xattrs, NULL); + if (likely(!attr->xattrs)) + kfree(attr); + else if (llist_add(&attr->pidfs_llist, &pidfs_free_list)) + schedule_work(&pidfs_free_work); } #ifdef CONFIG_PROC_FS @@ -1011,7 +1038,7 @@ static int pidfs_xattr_get(const struct xattr_handler *handler, xattrs = READ_ONCE(attr->xattrs); if (!xattrs) - return 0; + return -ENODATA; name = xattr_full_name(handler, suffix); return simple_xattr_get(xattrs, name, value, size); @@ -1031,22 +1058,16 @@ static int pidfs_xattr_set(const struct xattr_handler *handler, /* Ensure we're the only one to set @attr->xattrs. */ WARN_ON_ONCE(!inode_is_locked(inode)); - xattrs = READ_ONCE(attr->xattrs); - if (!xattrs) { - xattrs = kmem_cache_zalloc(pidfs_xattr_cachep, GFP_KERNEL); - if (!xattrs) - return -ENOMEM; - - simple_xattrs_init(xattrs); - smp_store_release(&pid->attr->xattrs, xattrs); - } + xattrs = simple_xattrs_lazy_alloc(&attr->xattrs, value, flags); + if (IS_ERR_OR_NULL(xattrs)) + return PTR_ERR(xattrs); name = xattr_full_name(handler, suffix); old_xattr = simple_xattr_set(xattrs, name, value, size, flags); if (IS_ERR(old_xattr)) return PTR_ERR(old_xattr); - simple_xattr_free(old_xattr); + simple_xattr_free_rcu(old_xattr); return 0; } @@ -1124,11 +1145,6 @@ void __init pidfs_init(void) (SLAB_HWCACHE_ALIGN | SLAB_RECLAIM_ACCOUNT | SLAB_ACCOUNT | SLAB_PANIC), NULL); - pidfs_xattr_cachep = kmem_cache_create("pidfs_xattr_cache", - sizeof(struct simple_xattrs), 0, - (SLAB_HWCACHE_ALIGN | SLAB_RECLAIM_ACCOUNT | - SLAB_ACCOUNT | SLAB_PANIC), NULL); - pidfs_mnt = kern_mount(&pidfs_type); if (IS_ERR(pidfs_mnt)) panic("Failed to mount pidfs pseudo filesystem");