Day 92 - kmalloc() Internals¶
Overview¶
Today we completed a simplified Linux-style implementation of the kmalloc() allocation path.
Instead of allocating memory directly, kmalloc() now acts as the public kernel memory allocation interface. It selects an appropriate kmalloc cache according to the requested allocation size and delegates the actual object allocation to the SLUB allocator, which obtains memory pages from the Buddy Allocator.
This completes the simplified Linux memory allocation stack developed throughout the previous labs.
What I Learned¶
1. Why kmalloc() Exists¶
Linux does not require every subsystem to create its own kmem_cache.
Instead, the kernel pre-creates a set of general-purpose kmalloc caches, allowing callers to allocate small objects through a unified API.
For example:
This hides the underlying SLUB allocator and provides a simple allocation interface for kernel subsystems and device drivers.
2. kmalloc Cache Lookup¶
A fixed table of kmalloc caches was created during initialization.
kmalloc-8
kmalloc-16
kmalloc-32
kmalloc-64
kmalloc-128
kmalloc-256
kmalloc-512
kmalloc-1024
kmalloc-2048
kmalloc-4096
Each allocation request searches for the smallest cache capable of satisfying the requested size.
3. Relationship Between kmalloc(), SLUB, and Buddy¶
kmalloc() itself does not allocate physical memory.
Instead, it forwards allocation requests to the appropriate kmem_cache.
The SLUB allocator manages fixed-size objects, while the Buddy Allocator supplies page-backed slab memory when additional slabs are required.
4. Zero-initialized Allocation¶
kzalloc() allocates memory through kmalloc() before clearing the allocated bytes with memset().
kcalloc() extends this behavior by allocating an array of objects while performing integer-overflow checking before computing the total allocation size.
5. GFP Allocation Policy¶
A simplified execution-context model was retained from the previous implementation.
Two allocation flags were supported:
GFP_KERNELGFP_ATOMIC
The simulated rules matched Linux's common behavior:
| Context | GFP_KERNEL | GFP_ATOMIC |
|---|---|---|
| Process Context | ✅ | ✅ |
| IRQ Context | ❌ | ✅ |
This demonstrates why sleeping allocations are not permitted inside interrupt handlers.
Implementation¶
Implemented a Linux-style kernel memory allocation frontend.
Completed:
- kmalloc cache manager
- kmalloc cache lookup
kmalloc()kzalloc()kcalloc()kfree()- GFP allocation policy validation
- Execution context simulation
- Integration with the SLUB allocator
- Integration with the Buddy Allocator
Labs¶
Lab 1¶
Validated kmalloc cache lookup.
Verified that allocation requests were routed to the nearest predefined kmalloc cache.
Examples:
kmalloc(5)→kmalloc-8kmalloc(16)→kmalloc-16kmalloc(17)→kmalloc-32kmalloc(100)→kmalloc-128
Lab 2¶
Verified slab reuse within the same kmalloc cache.
Multiple allocation requests with different sizes mapped to the same size class and reused the same slab.
Lab 3¶
Verified object reuse after kfree().
Confirmed that freeing an object updated the bitmap correctly and that subsequent allocations reused the lowest-index free object.
Lab 4¶
Validated kzalloc() and kcalloc().
Verified:
- Zero-initialized allocation
- Reuse of previously freed objects
- Integer-overflow detection in
kcalloc()
Lab 5¶
Validated GFP allocation rules.
Confirmed that:
GFP_KERNELsucceeds in process context.GFP_KERNELis rejected in IRQ context.GFP_ATOMICsucceeds in IRQ context.
Result¶
A complete simplified Linux kernel memory allocation path is now available.
The memory subsystem now closely resembles the architecture used by the Linux kernel, where kmalloc() serves as the public allocation interface while SLUB and the Buddy Allocator remain internal implementation layers.
Next¶
Next, we will continue exploring Linux kernel memory management by studying additional allocation mechanisms and their relationship with the existing kmalloc() infrastructure.