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 <djwong@kernel.org>
Signed-off-by: Christian Brauner <brauner@kernel.org>
This commit is contained in:
Christian Brauner
2026-02-16 14:32:01 +01:00
parent 5bd97f5c5f
commit 50704c391f

View File

@@ -22,6 +22,7 @@
#include <net/net_namespace.h>
#include <linux/coredump.h>
#include <linux/rhashtable.h>
#include <linux/llist.h>
#include <linux/xattr.h>
#include <linux/cookie.h>
@@ -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");