How Does a Custom Slab Cache Work in Linux? – Free Linux Device Drivers Course in Hyderabad

Custom Slab Cache in Linux Kernel: Complete Beginner-to-Advanced Guide
Free Linux Kernel Development Course by EmbeddedPathashala
📘 1800+ Words
🧩 Beginner Friendly
🖥️ Updated for Linux 6.x / 7.x
🆓 100% Free

If you are following our free Linux kernel development course, this lecture explains
a custom slab cache in the Linux kernel — what it is, why kernel and driver code creates
its own memory caches instead of always using kmalloc(), and how the whole allocation
lifecycle works, from creation to destruction. This tutorial is written fresh for modern kernels
(Linux 6.8 and later, including the current 7.x series), where the SLUB allocator is now the
only slab allocator in the tree — the older SLAB and SLOB allocators were removed from
mainline Linux in kernel 6.8, so everything you learn here maps directly to what you’ll find in
today’s kernel source.

🎯 What You Will Learn
Why custom slab caches exist
kmem_cache_create() explained
Object allocation and freeing
Cache destruction & cleanup
SLUB internals (2026 kernel)
Security & debugging flags
Real driver use cases
Common mistakes to avoid

✅ Prerequisites

Before this lecture, you should be comfortable with:

Basic C programming
Writing a simple loadable kernel module
kmalloc() / kfree() basics
GFP flags (GFP_KERNEL vs GFP_ATOMIC)

If any of these feel unfamiliar, go back to the earlier lectures in this
free embedded systems course before continuing.

1. What Is a Custom Slab Cache, and Why Not Just Use kmalloc()?

Every time the kernel needs a small chunk of memory for a data structure, it could call
kmalloc(). But kmalloc() rounds your request up to the nearest
“power-of-two-ish” generic size bucket. If your structure is, say, 300 bytes, kmalloc will
hand you a 384-byte or 512-byte chunk from a generic pool shared by thousands of unrelated
allocations across the whole kernel. That wastes memory and gives you no control over
initialization, alignment, or debugging.

A custom slab cache solves this by asking the slab allocator (SLUB, in
current kernels) to manage a dedicated pool sized exactly for your structure. Every
object that comes out of that pool is the right size, can be pre-initialized with a
constructor, and can be tracked separately in /proc/slabinfo — which is
extremely useful when hunting memory leaks in your own driver.

Generic kmalloc pool vs. Dedicated Custom Cache

kmalloc() generic pools

Shared by everyone in the kernel · fixed size buckets · no custom constructor

Custom slab cache

Dedicated to one struct · exact size · optional constructor · easy to track

2. The Custom Slab Cache Lifecycle (Big Picture)

Working with a custom slab cache always follows the same four-stage lifecycle. Understanding
this flow before looking at any single API makes everything else click into place.

Custom Slab Cache Workflow
1. Create Cache
→
2. Allocate Object
→
3. Use / Free Object
→
4. Destroy Cache

Stages 2 and 3 typically repeat many times during the life of a driver — you allocate and
free objects over and over — while stages 1 and 4 happen exactly once, usually in your
module’s init and exit functions.

3. Creating a Cache with kmem_cache_create()

The entry point is a single call that registers a new named cache with the slab subsystem.
In modern kernel headers (<linux/slab.h>), the function looks like this:

struct kmem_cache *kmem_cache_create(const char *name,
                                      unsigned int size,
                                      unsigned int align,
                                      slab_flags_t flags,
                                      void (*ctor)(void *));
Parameter Meaning
name Unique cache name, visible under /proc/slabinfo
size Size in bytes of one object (usually sizeof(struct your_type))
align Required byte alignment; pass 0 to let SLUB decide
flags Behavior/debug flags — covered in Section 6
ctor Optional constructor run whenever a fresh object is carved out

Important: this call must be made from normal process context (never from
an interrupt handler), and its return value must always be checked — a NULL
return means the cache could not be created, usually due to memory pressure at boot.

4. Allocating and Freeing Objects

Once the cache exists, grabbing an object from it is a single call:

void *kmem_cache_alloc(struct kmem_cache *cache, gfp_t flags);

Just like kmalloc(), pass GFP_KERNEL when you’re allowed to sleep
(normal process context) and GFP_ATOMIC when you are inside an interrupt handler,
a spinlock-protected section, or any other atomic context where sleeping is forbidden.

When you’re finished with the object, return it to the cache instead of freeing it back to
the general page allocator:

void kmem_cache_free(struct kmem_cache *cache, void *object);

This is far cheaper than a full free-and-reallocate cycle through kfree()/
kmalloc(), because SLUB simply parks the object back on a per-CPU free list for
instant reuse.

Where Objects Live
Object 1 (in use)
Object 2 (free, on freelist)
Object 3 (in use)
Object 4 (free, on freelist)

All objects live inside the same slab “page” managed by your custom cache

5. Destroying the Cache
void kmem_cache_destroy(struct kmem_cache *cache);

Call this exactly once, in your module’s exit path, and only after every object you
allocated from that cache has already been returned with kmem_cache_free().
Destroying a cache that still has outstanding objects will trigger a kernel warning and is a
classic source of memory-corruption bugs during module unload.

6. Debugging & Security Flags (Updated for Modern Kernels)

The flags parameter controls both debugging behavior and hardening. A few you
should know:

Flag Purpose
SLAB_HWCACHE_ALIGN Aligns objects to the CPU cache line for better performance
SLAB_POISON Fills freed memory with a known pattern to catch use-after-free bugs
SLAB_RED_ZONE Adds guard bytes around each object to catch buffer overruns
SLAB_PANIC Panics the kernel immediately if the cache cannot be created
SLAB_ACCOUNT Tracks allocations per-cgroup for memory accounting

2026 kernel note: On production kernels, freelist pointers inside SLUB are
hardened using a per-cache random obfuscation value, and features such as random freelist
ordering and hardened usercopy checks are enabled by default on distro kernels to make
heap-exploitation techniques against slab caches significantly harder. You don’t need to
configure this yourself — it comes from CONFIG_SLAB_FREELIST_HARDENED and related
options — but it’s worth knowing it’s there when you read crash dumps.

7. A Minimal Working Example

Here is a small, original demo showing the full lifecycle for a fictional
struct pkt_buf used to represent an incoming packet buffer in a driver:

#include <linux/module.h>
#include <linux/slab.h>

struct pkt_buf {
    u8  data[64];
    u32 len;
};

static struct kmem_cache *pkt_cache;

static void pkt_ctor(void *obj)
{
    struct pkt_buf *p = obj;
    p->len = 0;
}

static int __init pktdemo_init(void)
{
    struct pkt_buf *pb;

    pkt_cache = kmem_cache_create("pkt_buf_cache",
                                  sizeof(struct pkt_buf),
                                  0,
                                  SLAB_HWCACHE_ALIGN,
                                  pkt_ctor);
    if (!pkt_cache)
        return -ENOMEM;

    pb = kmem_cache_alloc(pkt_cache, GFP_KERNEL);
    if (!pb) {
        kmem_cache_destroy(pkt_cache);
        return -ENOMEM;
    }

    pb->len = 42;
    pr_info("pktdemo: allocated buffer, len=%u\n", pb->len);

    kmem_cache_free(pkt_cache, pb);
    return 0;
}

static void __exit pktdemo_exit(void)
{
    kmem_cache_destroy(pkt_cache);
}

module_init(pktdemo_init);
module_exit(pktdemo_exit);
MODULE_LICENSE("GPL");

Build it with a standard out-of-tree Makefile, insert it with
insmod, and check dmesg for the printed log line. Then confirm the
cache appeared with:

$ cat /proc/slabinfo | grep pkt_buf_cache

8. Real-World Use Cases

Custom slab caches aren’t a niche feature — they power some of the busiest data structures
in the kernel:

Filesystem inode caches
dentry (directory entry) cache
task_struct allocation for every process
Network socket buffer metadata
Block-layer request structures

Any structure that gets allocated and freed at very high frequency is a strong candidate
for its own dedicated cache instead of riding on generic kmalloc pools.

9. Common Mistakes and Troubleshooting
⚠️ Destroying a cache with live objects still allocated
⚠️ Using GFP_KERNEL inside interrupt context
⚠️ Forgetting to check kmem_cache_create() for NULL
⚠️ Mixing kfree() with objects from a custom cache
⚠️ Creating a new cache per allocation instead of once at init

Troubleshooting tip: If rmmod hangs or logs a warning about a
cache still having active objects, add temporary pr_info() calls around every
kmem_cache_alloc()/kmem_cache_free() pair to find the leak before
removing them again.

10. Best Practices
Create the cache once, in module init
Always match alloc with free, one-to-one
Use a constructor for fields that need consistent defaults
Enable SLAB_POISON/SLAB_RED_ZONE while developing
Name caches clearly for easy /proc/slabinfo auditing

11. Performance Considerations

Custom caches shine under high-frequency alloc/free churn because SLUB keeps a
per-CPU freelist, so most allocations never touch a lock at all. Choosing
SLAB_HWCACHE_ALIGN avoids false sharing between CPUs when multiple cores
touch neighboring objects concurrently — a subtle but real performance win on
multi-core embedded SoCs.

12. Security Considerations

Slab caches are a favorite target in kernel exploitation research because heap-spray and
use-after-free bugs often manipulate freelist pointers. Modern kernels mitigate this with
freelist pointer hardening, random freelist ordering per cache, and hardened usercopy
boundary checks — all reasons to keep your target kernel updated rather than relying on
an old LTS branch for anything internet-facing.

13. Summary / Key Takeaways
kmem_cache_create() builds a dedicated pool
kmem_cache_alloc()/free() manage objects
kmem_cache_destroy() cleans up once, at exit
SLUB is the only allocator since kernel 6.8
Flags control debugging and hardening

Frequently Asked Questions

Q1. What is a custom slab cache in the Linux kernel?
It’s a dedicated memory pool created with kmem_cache_create() for one specific
data structure, avoiding the size-rounding waste of generic kmalloc().

Q2. Is the SLAB allocator still used in modern kernels?
No. Both SLAB and SLOB were removed from mainline Linux starting with kernel 6.8; SLUB is now
the only slab allocator.

Q3. Can I call kmem_cache_create() from an interrupt handler?
No, it must always be called from process context.

Q4. What happens if I destroy a cache with objects still allocated?
The kernel logs a warning, and the leaked objects can cause memory corruption on module
reload.

Q5. When should GFP_ATOMIC be used instead of GFP_KERNEL?
Use GFP_ATOMIC whenever the allocation happens in a context that cannot sleep, such as an
interrupt handler or while holding a spinlock.

Q6. Does a custom slab cache improve performance?
Yes, for structures allocated and freed at high frequency, because SLUB reuses per-CPU
freelists instead of going through the general page allocator each time.

Q7. What does the constructor function do?
It runs automatically whenever a fresh object is carved out of newly added slab memory,
letting you set consistent default field values.

Q8. Where can I see my custom cache after creating it?
Check /proc/slabinfo — your cache name will appear as its own row with live
object counts.

Conclusion

A custom slab cache gives kernel and driver code precise, efficient control over memory
that would otherwise be wasted in generic kmalloc buckets. Once you’re comfortable with the
four-stage lifecycle — create, allocate, free, destroy — you’re ready to apply the same
pattern in your own drivers. This lecture is part of our ongoing free Linux kernel
development course
and free Linux device drivers course; keep
following along for the next topic.

Continue Your Free Linux Kernel Journey

More free lectures on kernel internals, BLE, and embedded Linux are on the way.

Browse Free Course
Join the Community

Leave a Reply

Your email address will not be published. Required fields are marked *