Unverified Commit 50704c39 authored by Christian Brauner's avatar Christian Brauner
Browse files

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: default avatarDarrick J. Wong <djwong@kernel.org>
Signed-off-by: default avatarChristian Brauner <brauner@kernel.org>
parent 5bd97f5c
Loading
Loading
Loading
Loading
+40 −24
Original line number Diff line number Diff line
@@ -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");