Netdev List
 help / color / mirror / Atom feed
From: Jim Cromie via B4 Relay <devnull+jim.cromie.gmail.com@kernel.org>
To: "Andrew Morton" <akpm@linux-foundation.org>,
	"Pablo Neira Ayuso" <pablo@netfilter.org>,
	"Florian Westphal" <fw@strlen.de>, "Phil Sutter" <phil@nwl.cc>,
	"Alexei Starovoitov" <ast@kernel.org>,
	"Daniel Borkmann" <daniel@iogearbox.net>,
	"Andrii Nakryiko" <andrii@kernel.org>,
	"Eduard Zingerman" <eddyz87@gmail.com>,
	"Danilo Krummrich" <dakr@kernel.org>,
	"Matthew Brost" <matthew.brost@intel.com>,
	"Boris Brezillon" <boris.brezillon@collabora.com>,
	"Peter Zijlstra" <peterz@infradead.org>,
	"Ingo Molnar" <mingo@redhat.com>, "Will Deacon" <will@kernel.org>,
	"Waiman Long" <longman@redhat.com>,
	"David S. Miller" <davem@davemloft.net>,
	"Eric Dumazet" <edumazet@google.com>,
	"Jakub Kicinski" <kuba@kernel.org>,
	"Paolo Abeni" <pabeni@redhat.com>,
	"Simon Horman" <horms@kernel.org>,
	"Kumar Kartikeya Dwivedi" <memxor@gmail.com>,
	"Martin KaFai Lau" <martin.lau@linux.dev>,
	"Song Liu" <song@kernel.org>,
	"Yonghong Song" <yonghong.song@linux.dev>,
	"Jiri Olsa" <jolsa@kernel.org>,
	"Emil Tsalapatis" <emil@etsalapatis.com>,
	"John Fastabend" <john.fastabend@gmail.com>,
	"Thomas Hellström" <thomas.hellstrom@linux.intel.com>,
	"Alice Ryhl" <aliceryhl@google.com>,
	"Maarten Lankhorst" <maarten.lankhorst@linux.intel.com>,
	"Maxime Ripard" <mripard@kernel.org>,
	"Thomas Zimmermann" <tzimmermann@suse.de>,
	"David Airlie" <airlied@gmail.com>,
	"Simona Vetter" <simona@ffwll.ch>,
	"Boqun Feng" <boqun@kernel.org>, "Boqun Feng" <boqun@kernel.org>
Cc: netfilter-devel@vger.kernel.org, bpf@vger.kernel.org,
	 dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org,
	 linux-mm@kvack.org, coreteam@netfilter.org,
	netdev@vger.kernel.org,  Jim Cromie <jim.cromie@gmail.com>
Subject: [PATCH 1/9] lib/folio_pool: Introduce Direct-Map Large Folio Pool & Scratchpad bump allocators
Date: Mon, 17 Aug 2026 11:22:15 -0600	[thread overview]
Message-ID: <20260817-folio-pool-v1-v1-1-0c1d230aa3af@gmail.com> (raw)
In-Reply-To: <20260817-folio-pool-v1-v1-0-0c1d230aa3af@gmail.com>

From: Jim Cromie <jim.cromie@gmail.com>

Introduce region-based linear bump allocators backed by Direct-Map Large
Folios (order-N compound pages via folio_alloc()), bringing O(1) bulk
teardown and SLUB bypass to batch-oriented kernel subsystems.

The implementation provides one core engine and one thin wrapper:

  - struct folio_scratchpad: Core variable-sized bump allocator. Accepts
    arbitrary size and alignment per allocation (alloc_bytes / alloc_obj).
    Used for Netlink batches, Netfilter transactions, and BPF syscalls.

  - struct folio_pool: Thin wrapper around folio_scratchpad that binds a
    fixed element size and alignment at init time (alloc / alloc_type).
    Used for homogeneous objects like Lockdep dependency edges and BPF
    verifier frames.

Subsystem Autonomy & Runtime Static-Key Control:
Both allocators support fine-grained, per-subsystem policy control via
DEFINE_FOLIO_POOL_STATIC_KEY_PARAM() alongside a global master switch
(folio_pool.enabled):

  - Independent Maintainer Policy: Subsystem maintainers choose their
    own default enablement policy (DECLARE_STATIC_KEY_TRUE or FALSE)
    and expose dedicated module/boot parameters (e.g. lockdep.folio_pool,
    nf_tables.trans_scratchpad, drm_gpuvm.scratchpad) to control adoption
    and rollout independently without cross-subsystem coupling.

  - Granular In-Situ Triage & A/B Benchmarking: Allows toggling between
    folio bump allocation and baseline SLUB at runtime on the same
    booted kernel, isolating regressions and capturing precise ftrace
    and PMU instruction deltas without rebooting.

  - Zero Instruction Overhead: Evaluated via static_branch_likely()
    to compile to direct fallthrough execution with static NOP patching.

Mark folio_scratchpad_alloc and folio_scratchpad_free noinline to enable
precise ftrace and hardware performance counter instrumentation.

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
 include/linux/folio_pool.h | 279 +++++++++++++++++++++++++++++++++++++++++++++
 lib/Makefile               |   2 +-
 lib/folio_pool.c           | 230 +++++++++++++++++++++++++++++++++++++
 3 files changed, 510 insertions(+), 1 deletion(-)

diff --git a/include/linux/folio_pool.h b/include/linux/folio_pool.h
new file mode 100644
index 000000000000..5bbca8818877
--- /dev/null
+++ b/include/linux/folio_pool.h
@@ -0,0 +1,279 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+#ifndef _LINUX_FOLIO_POOL_H
+#define _LINUX_FOLIO_POOL_H
+
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/page-flags.h>
+#include <linux/mm.h>
+#include <linux/gfp.h>
+#include <linux/jump_label.h>
+#include <linux/moduleparam.h>
+#include <linux/cleanup.h>
+
+DECLARE_STATIC_KEY_TRUE(folio_pool_enabled_key);
+
+#define DEFINE_FOLIO_POOL_STATIC_KEY_PARAM(key_name, param_name, desc)		\
+	DEFINE_STATIC_KEY_TRUE(key_name);					\
+	static int key_name##_set(const char *val, const struct kernel_param *kp) \
+	{									\
+		bool enable;							\
+		int ret = kstrtobool(val, &enable);				\
+		if (ret)							\
+			return ret;						\
+		if (enable)							\
+			static_branch_enable(&key_name);			\
+		else								\
+			static_branch_disable(&key_name);			\
+		return 0;							\
+	}									\
+	static int key_name##_get(char *buffer, const struct kernel_param *kp)	\
+	{									\
+		return sprintf(buffer, "%c\n",					\
+			       static_branch_likely(&key_name) ? 'Y' : 'N');	\
+	}									\
+	static const struct kernel_param_ops key_name##_ops = {			\
+		.set = key_name##_set,						\
+		.get = key_name##_get,						\
+	};									\
+	module_param_cb(param_name, &key_name##_ops, NULL, 0644);		\
+	MODULE_PARM_DESC(param_name, desc)
+
+#define DEFINE_FOLIO_POOL_STATIC_KEY_PARAM_FALSE(key_name, param_name, desc)	\
+	DEFINE_STATIC_KEY_FALSE(key_name);					\
+	static int key_name##_set(const char *val, const struct kernel_param *kp) \
+	{									\
+		bool enable;							\
+		int ret = kstrtobool(val, &enable);				\
+		if (ret)							\
+			return ret;						\
+		if (enable)							\
+			static_branch_enable(&key_name);			\
+		else								\
+			static_branch_disable(&key_name);			\
+		return 0;							\
+	}									\
+	static int key_name##_get(char *buffer, const struct kernel_param *kp)	\
+	{									\
+		return sprintf(buffer, "%c\n",					\
+			       static_branch_unlikely(&key_name) ? 'Y' : 'N');	\
+	}									\
+	static const struct kernel_param_ops key_name##_ops = {			\
+		.set = key_name##_set,						\
+		.get = key_name##_get,						\
+	};									\
+	module_param_cb(param_name, &key_name##_ops, NULL, 0644);		\
+	MODULE_PARM_DESC(param_name, desc)
+
+#define FOLIO_POOL_64K_ORDER (PAGE_SHIFT < 16 ? 16 - PAGE_SHIFT : 0)
+
+struct folio_pool_chunk {
+	struct list_head link;
+	struct folio *folio;
+};
+
+/*
+ * 1. Variable-Sized Scratchpad (Core Bump Allocator Engine)
+ */
+struct folio_scratchpad {
+	struct list_head chunks;
+	void *free_ptr;
+	size_t remaining;
+	unsigned int chunk_order;
+	struct static_key *key;
+	spinlock_t lock;
+};
+
+#define FOLIO_SCRATCHPAD_INIT(name, _order) {				\
+	.chunks = LIST_HEAD_INIT((name).chunks),			\
+	.chunk_order = (_order),					\
+	.key = NULL,							\
+	.lock = __SPIN_LOCK_UNLOCKED((name).lock),			\
+}
+
+#define FOLIO_SCRATCHPAD_INIT_KEY(name, _order, _key) {			\
+	.chunks = LIST_HEAD_INIT((name).chunks),			\
+	.chunk_order = (_order),					\
+	.key = (struct static_key *)(_key),				\
+	.lock = __SPIN_LOCK_UNLOCKED((name).lock),			\
+}
+
+void folio_scratchpad_init(struct folio_scratchpad *sp, unsigned int order);
+void folio_scratchpad_init_key(struct folio_scratchpad *sp, unsigned int order,
+			       struct static_key *key);
+void *folio_scratchpad_alloc(struct folio_scratchpad *sp, size_t size,
+			     size_t align, gfp_t gfp);
+void folio_scratchpad_reset(struct folio_scratchpad *sp);
+void folio_scratchpad_free(struct folio_scratchpad *sp);
+void folio_scratchpad_stats(struct folio_scratchpad *sp, unsigned int *nr_chunks,
+			    size_t *chunk_size, size_t *tail_used);
+
+DEFINE_FREE(folio_scratchpad, struct folio_scratchpad *, if (_T) folio_scratchpad_free(_T))
+
+/**
+ * is_folio_pool_ptr - Check whether an address resides in a folio pool/scratchpad
+ * @ptr: Object pointer to test
+ *
+ * Direct-map large folios allocated via folio_alloc() are not slab pages,
+ * unlike objects returned by kmalloc/kzalloc.
+ */
+static inline bool is_folio_pool_ptr(const void *ptr)
+{
+	return ptr && !is_vmalloc_addr(ptr) && !folio_test_slab(virt_to_folio(ptr));
+}
+
+/**
+ * folio_pool_free_elem - Safely release a pool object or SLUB fallback element
+ * @ptr: Object pointer to release
+ *
+ * If @ptr belongs to a direct-map large folio, individual deallocation is a safe
+ * no-op (reclaimed in bulk by folio_scratchpad_free/reset). If @ptr was allocated
+ * via SLUB/vmalloc fallback, releases it immediately.
+ */
+static inline void folio_pool_free_elem(const void *ptr)
+{
+	if (!ptr || is_folio_pool_ptr(ptr))
+		return;
+	kvfree(ptr);
+}
+
+static inline void folio_scratchpad_free_elem(const void *ptr)
+{
+	folio_pool_free_elem(ptr);
+}
+
+/**
+ * folio_pool_realloc - Reallocate memory for an object, handling pool vs slab backing
+ * @ptr: Existing object pointer (may be from folio_pool/scratchpad or SLUB)
+ * @old_size: Size of original object
+ * @new_size: Desired new size
+ * @gfp: Allocation flags
+ *
+ * If @ptr is SLUB-backed, delegates directly to krealloc(). If @ptr resides
+ * in a direct-map large folio, allocates a fresh @new_size buffer from SLUB
+ * and copies @old_size bytes; the original scratchpad slot remains abandoned
+ * until the entire scratchpad is released or reset at batch boundary.
+ */
+static inline void *folio_pool_realloc(void *ptr, size_t old_size,
+				       size_t new_size, gfp_t gfp)
+{
+	void *new_ptr;
+
+	if (!ptr)
+		return kmalloc(new_size, gfp);
+
+	if (!is_folio_pool_ptr(ptr))
+		return krealloc(ptr, new_size, gfp);
+
+	new_ptr = kmalloc(new_size, gfp);
+	if (new_ptr)
+		memcpy(new_ptr, ptr, min(old_size, new_size));
+	return new_ptr;
+}
+
+static inline void *folio_scratchpad_realloc(void *ptr, size_t old_size,
+					     size_t new_size, gfp_t gfp)
+{
+	return folio_pool_realloc(ptr, old_size, new_size, gfp);
+}
+
+/**
+ * folio_scratchpad_alloc_obj - Allocate a typed object from an embedded scratchpad
+ * @ptr: Pointer to container struct (e.g. nft_net)
+ * @member: Name of the struct folio_scratchpad field (e.g. trans_scratchpad)
+ * @type: Type of object being allocated
+ * @gfp: Allocation flags
+ */
+#define folio_scratchpad_alloc_obj(ptr, member, type, gfp)			\
+	((type *)folio_scratchpad_alloc(&(ptr)->member,				\
+					sizeof(type),				\
+					__alignof__(type),			\
+					gfp))
+
+/**
+ * folio_scratchpad_alloc_bytes - Allocate variable-sized bytes from an embedded scratchpad
+ * @ptr: Pointer to container struct (e.g. nft_net)
+ * @member: Name of the struct folio_scratchpad field (e.g. trans_scratchpad)
+ * @size: Size of memory to allocate
+ * @align: Alignment requirement
+ * @gfp: Allocation flags
+ */
+#define folio_scratchpad_alloc_bytes(ptr, member, size, align, gfp)		\
+	folio_scratchpad_alloc(&(ptr)->member, size, align, gfp)
+
+/**
+ * folio_scratchpad_alloc_type - Allocate a typed object from a scratchpad pointer
+ * @sp: Pointer to struct folio_scratchpad
+ * @type: Type of object being allocated
+ * @gfp: Allocation flags
+ */
+#define folio_scratchpad_alloc_type(sp, type, gfp)				\
+	((type *)folio_scratchpad_alloc(sp,					\
+					sizeof(type),				\
+					__alignof__(type),			\
+					gfp))
+
+/*
+ * 2. Fixed-Slot Uniform Pool (Specialized Thin Wrapper on Scratchpad)
+ */
+struct folio_pool {
+	struct folio_scratchpad base;
+	size_t elem_size;
+	size_t elem_align;
+};
+
+#define FOLIO_POOL_INIT(name, _elem_size, _order) {			\
+	.base = FOLIO_SCRATCHPAD_INIT((name).base, _order),		\
+	.elem_size = (_elem_size),					\
+	.elem_align = ((_elem_size) > sizeof(void *) ? (_elem_size) : sizeof(void *)), \
+}
+
+#define FOLIO_POOL_INIT_KEY(name, _elem_size, _order, _key) {		\
+	.base = FOLIO_SCRATCHPAD_INIT_KEY((name).base, _order, _key),	\
+	.elem_size = (_elem_size),					\
+	.elem_align = ((_elem_size) > sizeof(void *) ? (_elem_size) : sizeof(void *)), \
+}
+
+void folio_pool_init(struct folio_pool *fp, size_t elem_size, unsigned int order);
+void folio_pool_init_key(struct folio_pool *fp, size_t elem_size, unsigned int order,
+			 struct static_key *key);
+void folio_pool_init_align(struct folio_pool *fp, size_t elem_size,
+			   size_t elem_align, unsigned int order);
+
+static inline void *folio_pool_alloc(struct folio_pool *fp, gfp_t gfp)
+{
+	return folio_scratchpad_alloc(&fp->base, fp->elem_size, fp->elem_align, gfp);
+}
+
+static inline void folio_pool_free(struct folio_pool *fp)
+{
+	folio_scratchpad_free(&fp->base);
+}
+
+static inline void folio_pool_stats(struct folio_pool *fp, unsigned int *nr_chunks,
+				    size_t *chunk_size, size_t *tail_used)
+{
+	folio_scratchpad_stats(&fp->base, nr_chunks, chunk_size, tail_used);
+}
+
+/**
+ * folio_pool_alloc_obj - Allocate a typed object from a container's embedded folio_pool
+ * @ptr: Pointer to container struct (e.g. env)
+ * @member: Name of the struct folio_pool field (e.g. state_pool)
+ * @type: Type of object being allocated (e.g. struct bpf_verifier_stack_elem)
+ * @gfp: Allocation flags
+ */
+#define folio_pool_alloc_obj(ptr, member, type, gfp)				\
+	((type *)folio_pool_alloc(&(ptr)->member, gfp))
+
+/**
+ * folio_pool_alloc_type - Allocate a typed object from a struct folio_pool pointer
+ * @fp: Pointer to struct folio_pool
+ * @type: Type of object being allocated
+ * @gfp: Allocation flags
+ */
+#define folio_pool_alloc_type(fp, type, gfp)					\
+	((type *)folio_pool_alloc(fp, gfp))
+
+#endif /* _LINUX_FOLIO_POOL_H */
diff --git a/lib/Makefile b/lib/Makefile
index 7f75cc6edf94..b5f2f41f96fb 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -58,7 +58,7 @@ obj-y += bcd.o sort.o parser.o debug_locks.o random32.o \
 	 bsearch.o find_bit.o llist.o lwq.o memweight.o kfifo.o \
 	 percpu-refcount.o rhashtable.o base64.o \
 	 once.o refcount.o rcuref.o usercopy.o errseq.o bucket_locks.o \
-	 generic-radix-tree.o bitmap-str.o
+	 generic-radix-tree.o bitmap-str.o folio_pool.o
 obj-y += string_helpers.o
 obj-y += hexdump.o
 obj-$(CONFIG_TEST_HEXDUMP) += test_hexdump.o
diff --git a/lib/folio_pool.c b/lib/folio_pool.c
new file mode 100644
index 000000000000..07a290db6c50
--- /dev/null
+++ b/lib/folio_pool.c
@@ -0,0 +1,230 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Direct-Map Large Folio Scratchpad & Pool bump allocators.
+ */
+#include <linux/export.h>
+#include <linux/string.h>
+#include <linux/moduleparam.h>
+#include <linux/folio_pool.h>
+
+DEFINE_STATIC_KEY_TRUE(folio_pool_enabled_key);
+EXPORT_SYMBOL_GPL(folio_pool_enabled_key);
+
+static int folio_pool_enabled_set(const char *val, const struct kernel_param *kp)
+{
+	bool enable;
+	int ret = kstrtobool(val, &enable);
+
+	if (ret)
+		return ret;
+
+	if (enable)
+		static_branch_enable(&folio_pool_enabled_key);
+	else
+		static_branch_disable(&folio_pool_enabled_key);
+
+	return 0;
+}
+
+static int folio_pool_enabled_get(char *buffer, const struct kernel_param *kp)
+{
+	return sprintf(buffer, "%c\n", static_branch_likely(&folio_pool_enabled_key) ? 'Y' : 'N');
+}
+
+static const struct kernel_param_ops folio_pool_enabled_ops = {
+	.set = folio_pool_enabled_set,
+	.get = folio_pool_enabled_get,
+};
+
+module_param_cb(enabled, &folio_pool_enabled_ops, NULL, 0644);
+MODULE_PARM_DESC(enabled, "Toggle folio_pool/scratchpad bump allocator (0 = fallback to SLUB)");
+
+/*
+ * 1. Variable-Sized Scratchpad (Core Engine)
+ */
+void folio_scratchpad_init_key(struct folio_scratchpad *sp, unsigned int order,
+			       struct static_key *key)
+{
+	INIT_LIST_HEAD(&sp->chunks);
+	sp->free_ptr = NULL;
+	sp->remaining = 0;
+	sp->chunk_order = order;
+	sp->key = key;
+	spin_lock_init(&sp->lock);
+}
+EXPORT_SYMBOL_GPL(folio_scratchpad_init_key);
+
+void folio_scratchpad_init(struct folio_scratchpad *sp, unsigned int order)
+{
+	folio_scratchpad_init_key(sp, order, NULL);
+}
+EXPORT_SYMBOL_GPL(folio_scratchpad_init);
+
+static inline bool folio_scratchpad_is_enabled(const struct folio_scratchpad *sp)
+{
+	if (sp->key)
+		return static_key_enabled(sp->key);
+	return static_branch_likely(&folio_pool_enabled_key);
+}
+
+noinline void *folio_scratchpad_alloc(struct folio_scratchpad *sp, size_t size,
+				     size_t align, gfp_t gfp)
+{
+	struct folio_pool_chunk *chunk;
+	struct folio *folio;
+	void *elem, *base;
+	size_t chunk_size, aligned_size, pad, header_offset;
+	unsigned long flags;
+
+	if (!folio_scratchpad_is_enabled(sp))
+		return kvzalloc(size, gfp);
+
+	if (unlikely(!size))
+		return NULL;
+
+	align = max_t(size_t, sizeof(void *), align ? align : sizeof(void *));
+
+	spin_lock_irqsave(&sp->lock, flags);
+	pad = (uintptr_t)sp->free_ptr & (align - 1);
+	if (pad)
+		pad = align - pad;
+	aligned_size = size + pad;
+
+	if (sp->remaining < aligned_size) {
+		spin_unlock_irqrestore(&sp->lock, flags);
+
+		folio = folio_alloc(gfp, sp->chunk_order);
+		if (!folio && sp->chunk_order > 0)
+			folio = folio_alloc(gfp, 0);
+		if (!folio)
+			return NULL;
+
+		base = folio_address(folio);
+		chunk = (struct folio_pool_chunk *)base;
+		chunk->folio = folio;
+		chunk_size = folio_size(folio);
+		header_offset = ALIGN(sizeof(*chunk), max_t(size_t, sizeof(void *), align));
+
+		spin_lock_irqsave(&sp->lock, flags);
+		list_add(&chunk->link, &sp->chunks);
+		sp->free_ptr = base + header_offset;
+		sp->remaining = chunk_size - header_offset;
+
+		pad = (uintptr_t)sp->free_ptr & (align - 1);
+		if (pad)
+			pad = align - pad;
+		aligned_size = size + pad;
+	}
+
+	if (sp->remaining < aligned_size) {
+		spin_unlock_irqrestore(&sp->lock, flags);
+		return NULL;
+	}
+
+	elem = sp->free_ptr + pad;
+	sp->free_ptr += aligned_size;
+	sp->remaining -= aligned_size;
+	spin_unlock_irqrestore(&sp->lock, flags);
+
+	memset(elem, 0, size);
+	return elem;
+}
+EXPORT_SYMBOL_GPL(folio_scratchpad_alloc);
+
+noinline void folio_scratchpad_reset(struct folio_scratchpad *sp)
+{
+	struct folio_pool_chunk *head, *chunk, *tmp;
+	size_t header_offset;
+	unsigned long flags;
+
+	spin_lock_irqsave(&sp->lock, flags);
+	if (list_empty(&sp->chunks)) {
+		sp->free_ptr = NULL;
+		sp->remaining = 0;
+		spin_unlock_irqrestore(&sp->lock, flags);
+		return;
+	}
+
+	/* Retain primary head chunk; free overflow chunks */
+	head = list_first_entry(&sp->chunks, struct folio_pool_chunk, link);
+	list_for_each_entry_safe(chunk, tmp, &sp->chunks, link) {
+		if (chunk == head)
+			continue;
+		list_del(&chunk->link);
+		folio_put(chunk->folio);
+	}
+
+	header_offset = ALIGN(sizeof(*head), sizeof(void *));
+	sp->free_ptr = folio_address(head->folio) + header_offset;
+	sp->remaining = folio_size(head->folio) - header_offset;
+	spin_unlock_irqrestore(&sp->lock, flags);
+}
+EXPORT_SYMBOL_GPL(folio_scratchpad_reset);
+
+noinline void folio_scratchpad_free(struct folio_scratchpad *sp)
+{
+	struct folio_pool_chunk *chunk, *tmp;
+	struct folio *folio;
+	unsigned long flags;
+
+	spin_lock_irqsave(&sp->lock, flags);
+	sp->free_ptr = NULL;
+	sp->remaining = 0;
+	list_for_each_entry_safe(chunk, tmp, &sp->chunks, link) {
+		folio = chunk->folio;
+		list_del(&chunk->link);
+		folio_put(folio);
+	}
+	spin_unlock_irqrestore(&sp->lock, flags);
+}
+EXPORT_SYMBOL_GPL(folio_scratchpad_free);
+
+/*
+ * 2. Fixed-Slot Uniform Pool (Specialized Thin Wrapper on Scratchpad)
+ */
+void folio_pool_init_align(struct folio_pool *fp, size_t elem_size,
+			   size_t elem_align, unsigned int order)
+{
+	folio_scratchpad_init(&fp->base, order);
+	fp->elem_size = elem_size;
+	fp->elem_align = max_t(size_t, sizeof(void *), elem_align ? elem_align : sizeof(void *));
+}
+EXPORT_SYMBOL_GPL(folio_pool_init_align);
+
+void folio_pool_init_key(struct folio_pool *fp, size_t elem_size, unsigned int order,
+			 struct static_key *key)
+{
+	size_t align = sizeof(void *);
+
+	if (elem_size && is_power_of_2(elem_size))
+		align = max_t(size_t, sizeof(void *), elem_size);
+	folio_scratchpad_init_key(&fp->base, order, key);
+	fp->elem_size = elem_size;
+	fp->elem_align = align;
+}
+EXPORT_SYMBOL_GPL(folio_pool_init_key);
+
+void folio_pool_init(struct folio_pool *fp, size_t elem_size, unsigned int order)
+{
+	folio_pool_init_key(fp, elem_size, order, NULL);
+}
+EXPORT_SYMBOL_GPL(folio_pool_init);
+
+void folio_scratchpad_stats(struct folio_scratchpad *sp, unsigned int *nr_chunks,
+			    size_t *chunk_size, size_t *tail_used)
+{
+	unsigned long flags;
+	size_t csz;
+
+	csz = (PAGE_SIZE << sp->chunk_order);
+	if (chunk_size)
+		*chunk_size = csz;
+
+	spin_lock_irqsave(&sp->lock, flags);
+	if (nr_chunks)
+		*nr_chunks = list_count_nodes(&sp->chunks);
+	if (tail_used)
+		*tail_used = csz > sp->remaining ? csz - sp->remaining : 0;
+	spin_unlock_irqrestore(&sp->lock, flags);
+}
+EXPORT_SYMBOL_GPL(folio_scratchpad_stats);

-- 
2.55.0



  reply	other threads:[~2026-08-17 17:22 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-17 17:22 [PATCH 0/9] lib/folio_pool: Direct-Map Large Folio Pool & Scratchpad bump allocators Jim Cromie via B4 Relay
2026-08-17 17:22 ` Jim Cromie via B4 Relay [this message]
2026-08-17 17:22 ` [PATCH 2/9] netfilter/nf_tables: Add folio_scratchpad collector to struct nftables_pernet Jim Cromie via B4 Relay
2026-08-17 17:22 ` [PATCH 3/9] bpf/verifier: Route verifier stack state node allocations to folio_pool Jim Cromie via B4 Relay
2026-08-17 17:22 ` [PATCH 4/9] drm/gpuvm: Route gpuva_op allocations to folio_scratchpad Jim Cromie via B4 Relay
2026-08-17 17:22 ` [PATCH 5/9] bpf/syscall: Route generic_map_update_batch key/value " Jim Cromie via B4 Relay
2026-08-17 17:22 ` [PATCH 6/9] locking/lockdep: Fallback to folio_pool in alloc_list_entry when static pool is full Jim Cromie via B4 Relay
2026-08-17 21:01   ` Peter Zijlstra
2026-08-17 17:22 ` [PATCH 7/9] locking/lockdep: Traverse adjacency lists directly in zap_class() Jim Cromie via B4 Relay
2026-08-17 17:22 ` [PATCH 8/9] locking/lockdep: Shrink static list_entries array to early bootstrap buffer Jim Cromie via B4 Relay
2026-08-17 17:22 ` [PATCH 9/9] locking/lockdep: Migrate and compact boot-time dependency graph from __initdata Jim Cromie via B4 Relay
2026-08-17 18:17 ` [PATCH 0/9] lib/folio_pool: Direct-Map Large Folio Pool & Scratchpad bump allocators David Hildenbrand (Arm)
2026-08-17 18:34 ` Matthew Wilcox

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260817-folio-pool-v1-v1-1-0c1d230aa3af@gmail.com \
    --to=devnull+jim.cromie.gmail.com@kernel.org \
    --cc=airlied@gmail.com \
    --cc=akpm@linux-foundation.org \
    --cc=aliceryhl@google.com \
    --cc=andrii@kernel.org \
    --cc=ast@kernel.org \
    --cc=boqun@kernel.org \
    --cc=boris.brezillon@collabora.com \
    --cc=bpf@vger.kernel.org \
    --cc=coreteam@netfilter.org \
    --cc=dakr@kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=davem@davemloft.net \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=eddyz87@gmail.com \
    --cc=edumazet@google.com \
    --cc=emil@etsalapatis.com \
    --cc=fw@strlen.de \
    --cc=horms@kernel.org \
    --cc=jim.cromie@gmail.com \
    --cc=john.fastabend@gmail.com \
    --cc=jolsa@kernel.org \
    --cc=kuba@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=longman@redhat.com \
    --cc=maarten.lankhorst@linux.intel.com \
    --cc=martin.lau@linux.dev \
    --cc=matthew.brost@intel.com \
    --cc=memxor@gmail.com \
    --cc=mingo@redhat.com \
    --cc=mripard@kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=netfilter-devel@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=pablo@netfilter.org \
    --cc=peterz@infradead.org \
    --cc=phil@nwl.cc \
    --cc=simona@ffwll.ch \
    --cc=song@kernel.org \
    --cc=thomas.hellstrom@linux.intel.com \
    --cc=tzimmermann@suse.de \
    --cc=will@kernel.org \
    --cc=yonghong.song@linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox