Building a Mini Linux Kernel Object Registry Using SLAB, RCU, Hash Tables, Shrinkers, and Procfs

Building a Mini Linux Kernel Object Registry Using SLAB, RCU, Hash Tables, Shrinkers, and Procfs
Modern Linux kernels manage massive numbers of dynamically created objects.
Examples include:
- Inodes
- Dentries
- Device objects
- Routing entries
- Network flows
- Filesystem metadata
These objects must support:
- Fast allocation
- Fast lookup
- Safe deletion
- Memory reclamation
- User-space visibility
- Multicore scalability
In this article we build a miniature kernel object registry that combines several important Linux kernel technologies:
SLAB Allocator
Hash Tables
RCU (Read-Copy-Update)
Shrinkers
Procfs
Per-CPU Statistics
The result behaves like a tiny kernel object database.
What Happens When the Module Loads
Load the module:
sudo insmod kobjx_slab_rcu_registry.ko
Initialization sequence:
Module Load
|
v
Create SLAB Cache
|
v
Register Shrinker
|
v
Create /proc/kobjx_stats
|
v
Create Objects
|
v
Insert Into List
|
v
Insert Into Hash Table
|
v
Perform Lookup
|
v
RCU-Safe Deletion
The module demonstrates the complete lifecycle of a kernel-managed object.
High-Level Architecture
+------------------+
| kmem_cache |
+---------+--------+
|
alloc/free
|
v
+----------------------------------+
| kobjx |
+----------------------------------+
| id |
| name |
| created |
| in_use |
+----------------------------------+
| |
v v
global_list global_hash
| |
+----------+----------+
|
v
Lookup
|
v
RCU
|
v
call_rcu()
|
v
SLAB Free
Core Kernel Technologies Used
This project combines six major kernel concepts.
1. SLAB Cache
Provides efficient allocation of fixed-size kernel objects.
Example:
obj = kmem_cache_alloc(
kobjx_cache,
GFP_KERNEL);
Benefits:
- Reduced fragmentation
- Object reuse
- Better cache locality
- Faster allocations
Real kernel users:
inode cache
dentry cache
task_struct
file objects
2. Linked List
Tracks all active objects.
Insertion:
list_add_tail(
&obj->list,
&kobjx_list);
Visualization:
+---------+ +---------+ +---------+
| Obj A | ---> | Obj B | ---> | Obj C |
+---------+ +---------+ +---------+
Purpose:
- Object enumeration
- Reclaim scanning
- Registry tracking
3. Hash Table
Provides fast object lookup by ID.
Insertion:
hash_add_rcu(
kobjx_hash,
&obj->hash_node,
obj->id);
Lookup:
hash_for_each_possible_rcu(
kobjx_hash,
obj,
hash_node,
id)
{
if (obj->id == id)
return obj;
}
Lookup flow:
Object ID
|
v
Hash Function
|
v
Bucket
|
v
Target Object
Average complexity:
O(1)
instead of
O(n)
for linked-list traversal.
The Kernel Object
Each registry entry contains metadata plus bookkeeping structures.
struct kobjx {
u32 id;
char name[32];
unsigned long created;
atomic_t in_use;
struct list_head list;
struct hlist_node hash_node;
struct rcu_head rcu;
};
Field summary:
| Field | Purpose |
|---|---|
| id | Unique identifier |
| name | Human-readable name |
| created | Creation timestamp |
| in_use | Object state |
| list | Linked-list tracking |
| hash_node | Hash bucket entry |
| rcu | Deferred destruction |
Object Creation Flow
Allocation starts from the SLAB cache.
obj = kmem_cache_alloc(
kobjx_cache,
GFP_KERNEL);
Initialization:
obj->id = id;
obj->created = jiffies;
Registration:
list_add_tail(
&obj->list,
&kobjx_list);
hash_add_rcu(
kobjx_hash,
&obj->hash_node,
id);
Lifecycle:
Allocate From SLAB
|
v
Initialize Object
|
v
Insert Into List
|
v
Insert Into Hash
|
v
Object Becomes Active
This is very similar to inode and dentry creation paths inside the Linux VFS.
RCU-Based Lock-Free Lookup
Readers execute:
rcu_read_lock();
obj = kobjx_lookup(id);
rcu_read_unlock();
Lookup path:
Reader
|
v
RCU Read Lock
|
v
Hash Lookup
|
v
Return Object
Advantages:
- No reader locking
- Minimal contention
- Excellent scalability
Used heavily in:
Routing Tables
Dcache
Networking
Scheduler
Safe Object Deletion
A kernel object cannot be freed immediately because another CPU may still be reading it.
Unsafe:
hash_del(&obj->hash_node);
kfree(obj);
Potential failure:
CPU0 -> Reading Object
CPU1 -> Frees Object
CPU0 -> Dereferences Freed Memory
Kernel Crash
Correct approach:
hash_del_rcu(&obj->hash_node);
list_del(&obj->list);
call_rcu(
&obj->rcu,
kobjx_rcu_free);
Deletion lifecycle:
Remove From Hash
|
v
Remove From List
|
v
call_rcu()
|
v
Grace Period
|
v
Actual Free
GitHub Repository



