Skip to content

Day 92 - kmalloc() Internals

Objective

Implement a simplified Linux-style kmalloc() frontend and understand how allocation requests are routed through predefined kmalloc caches, the SLUB allocator, and the Buddy Allocator.

Learning Goals

After completing this lab, you should understand:

  • Why Linux provides kmalloc() instead of exposing kmem_cache directly.
  • How allocation sizes are mapped to predefined kmalloc caches.
  • How kmalloc() interacts with the SLUB allocator.
  • How SLUB obtains backing pages from the Buddy Allocator.
  • The purpose of kzalloc() and kcalloc().
  • The difference between GFP_KERNEL and GFP_ATOMIC.

Lab Architecture

Application / Driver
        │
        ▼
kmalloc()
kzalloc()
kcalloc()
kfree()
        │
        ▼
kmalloc Cache Lookup
        │
        ▼
kmem_cache_alloc()
kmem_cache_free()
        │
        ▼
SLUB Allocator
        │
        ▼
Buddy Allocator
        │
        ▼
Physical Pages

Lab 1 - kmalloc Cache Lookup

Objective

Verify that allocation requests are routed to the nearest predefined kmalloc cache.

Implementation

Implemented:

  • kmalloc cache manager
  • Fixed-size kmalloc cache table
  • Cache lookup by allocation size

Example cache table:

Request Size Selected Cache
5 kmalloc-8
16 kmalloc-16
17 kmalloc-32
100 kmalloc-128

Expected Result

Example output:

[KMALLOC] size=5 -> kmalloc-8
[KMALLOC] size=16 -> kmalloc-16
[KMALLOC] size=17 -> kmalloc-32
[KMALLOC] size=100 -> kmalloc-128

The allocator should select the smallest cache capable of satisfying the requested allocation size.


Lab 2 - Slab Reuse Within the Same Cache

Objective

Verify that multiple allocation requests belonging to the same size class reuse the same kmalloc cache and slab.

Implementation

Allocate several objects:

kmalloc(20)
kmalloc(24)
kmalloc(31)

All requests should be routed to:

kmalloc-32

Expected Result

The dump should show:

[CACHE] kmalloc-32:
used = 3
slabs = 1

demonstrating that different allocation sizes can share the same slab when they belong to the same size class.


Lab 3 - Object Reuse After kfree()

Objective

Verify that freed objects are reused by subsequent allocations.

Implementation

Perform the following sequence:

Allocate:
p1
p2
p3

↓

kfree(p2)

↓

Allocate p4

Expected Result

p4 should reuse the memory previously owned by p2.

Example:

p2 == p4

The bitmap should mark the object as free after kfree() and allocate the lowest-index available object during the next allocation.


Lab 4 - kzalloc() and kcalloc()

Objective

Validate zero-initialized allocation.

Implementation

kzalloc()

  1. Allocate memory with kmalloc().
  2. Fill the object with a known pattern.
  3. Free the object.
  4. Allocate again using kzalloc().

kcalloc()

Allocate an array using:

kcalloc(4, 8, GFP_KERNEL);

Also verify integer-overflow protection.

Expected Result

The reused object should contain only zero bytes after kzalloc().

kcalloc() should:

  • Return zero-initialized memory.
  • Detect multiplication overflow.
  • Return NULL on overflow.

Lab 5 - GFP Allocation Policy

Objective

Validate allocation rules under different execution contexts.

Implementation

Verify the following combinations:

Context GFP Flag Expected
Process Context GFP_KERNEL Success
IRQ Context GFP_KERNEL Fail
IRQ Context GFP_ATOMIC Success

Expected Result

Example:

PROCESS_CONTEXT + GFP_KERNEL
PASS

IRQ_CONTEXT + GFP_KERNEL
PASS

IRQ_CONTEXT + GFP_ATOMIC
PASS

This demonstrates that sleeping allocations are not permitted in interrupt context.


Summary

This lab completed the simplified Linux kernel allocation path.

kmalloc()
        │
        ▼
kmalloc cache lookup
        │
        ▼
kmem_cache_alloc()
        │
        ▼
SLUB Allocator
        │
        ▼
Buddy Allocator
        │
        ▼
Physical Pages

The implementation now models the overall Linux memory allocation architecture, with kmalloc() acting as the public allocation interface while SLUB and the Buddy Allocator remain internal implementation layers.