Testing the kmalloc Maximum Allocation Size with a Custom Kernel Module
Free Linux Device Drivers Course • Free Linux Kernel Development Course • Free Embedded Systems Course — EmbeddedPathashala
Intermediate
13 min
Kernel Module + dmesg
Memory Management
proc buddyinfo
free Linux device drivers course
free Linux kernel development course
free embedded systems course
kernel module debugging
What You Will Learn
- How to write a small, original loadable kernel module to test kmalloc limit behaviour empirically
- How to read the kernel log correctly when an allocation deliberately fails
- How to interpret
/proc/buddyinfoto understand real-time memory fragmentation - Why the exact same test can give different results on a freshly booted system vs. a long-running one
Prerequisites
- Completion of the previous lecture on kmalloc theory (slab and buddy allocator basics)
- A Linux VM or SBC (Raspberry Pi class board) where you can safely build and load test modules
- Basic familiarity with
make,insmod,rmmod, anddmesg
Why Test Empirically Instead of Trusting a Number
In the previous lecture we established that the kmalloc maximum allocation size depends on page size, kernel
configuration, and architecture. Rather than quoting a single number from a book or blog post, the reliable
way to test the kmalloc limit is to write a tiny kernel module that increases its request
size step by step and simply observes where it starts failing on your own target hardware and kernel build.
Building an Original Test Module
The module below is deliberately minimal. It walks through a set of allocation sizes on load, logs the
result of each attempt, frees whatever succeeded, and reports the point of failure. Build it fresh for your
own experiments rather than reusing anyone else’s binary or sample.
// ep_kmalloc_probe.c
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/slab.h>
#define EP_STEP_BYTES (256 * 1024) /* 256 KB steps */
#define EP_MAX_STEPS 64 /* upper bound on iterations */
static int __init ep_kmalloc_probe_init(void)
{
size_t req_size = 0;
void *ptr = NULL;
int i;
pr_info("ep_kmalloc_probe: starting allocation sweep\n");
for (i = 0; i < EP_MAX_STEPS; i++) {
req_size = (size_t)i * EP_STEP_BYTES;
ptr = kmalloc(req_size, GFP_KERNEL);
if (!ptr) {
pr_info("ep_kmalloc_probe: FAILED at request size = %zu bytes\n",
req_size);
break;
}
pr_info("ep_kmalloc_probe: OK request size = %zu bytes (ptr=%p)\n",
req_size, ptr);
kfree(ptr);
}
pr_info("ep_kmalloc_probe: sweep complete\n");
return 0;
}
static void __exit ep_kmalloc_probe_exit(void)
{
pr_info("ep_kmalloc_probe: unloaded\n");
}
module_init(ep_kmalloc_probe_init);
module_exit(ep_kmalloc_probe_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("EmbeddedPathashala: empirical kmalloc limit probe");
A minimal Makefile to build it against your running kernel headers:
obj-m += ep_kmalloc_probe.o
KDIR := /lib/modules/$(shell uname -r)/build
all:
$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
$(MAKE) -C $(KDIR) M=$(PWD) clean
Build, load, and observe the log:
$ make
$ sudo insmod ep_kmalloc_probe.ko
$ dmesg | tail -n 20
$ sudo rmmod ep_kmalloc_probe
(stack trace) in the log even though the module itself handles the
NULL return correctly. Thatwarning is informational, not a crash — read it as “the allocator hit its limit,” not as a bug in your
module.
Interpreting the Allocation Sweep
Your own numbers will differ from this illustration. What matters is the pattern: allocations succeed
smoothly up to a point, then fail consistently once the request size crosses the effective
kmalloc maximum allocation size for your kernel build.
Cross-Checking with /proc/buddyinfo
The kernel exposes live buddy allocator state through /proc/buddyinfo. Each column represents
a page order, and each number is the count of free contiguous blocks currently available at that order.
$ cat /proc/buddyinfo
Node 0, zone DMA32 120 85 40 22 10 4 2 1 0 0 0
Reading left to right, the first column is order 0 (single free pages), and the last column is the highest
order the system tracks. A zero in the highest-order column means there are currently no free blocks large
enough to satisfy an allocation at that order — which is exactly the kind of fragmentation that causes
a large kmalloc() to fail on a long-running system even though the same request succeeded right
after boot.
| System State | Expected High-Order Free Blocks | Large kmalloc Success Likelihood |
|---|---|---|
| Freshly booted | Plentiful | High |
| Up for days, under load | Scarce or zero | Low, unpredictable |
Common Mistakes
- Testing once and treating the result as gospel. Re-run the sweep after the system has
been up for a while; the numbers will likely shift. - Forgetting to free successful allocations inside the loop. This artificially exhausts
memory and skews later iterations. - Ignoring architecture differences. The same module can report different ceilings on an
x86_64 VM versus an ARM64 SBC.
Best Practices
- Always unload test modules after use; don’t leave probe code in production builds
- Run the sweep both right after boot and under normal workload to see the realistic range
- Combine
dmesgoutput with/proc/buddyinfofor a complete picture - Prefer
kvmalloc()in real drivers once you understand where the practical ceiling lies
Troubleshooting Tips
- If
insmodfails immediately, checkdmesgfor a version-mismatch or missing
symbol error before assuming the allocation logic is at fault - If every allocation in the sweep fails, verify you are passing a sane
GFP_KERNELflag and
that the requested step size calculation isn’t overflowing - If results look inconsistent across runs, check overall system memory pressure with
free -h
before repeating the test
Summary / Key Takeaways
- A small, original kernel module that sweeps allocation sizes is the most reliable way to test the
kmalloc limit on your own hardware and kernel build /proc/buddyinfoexplains why the same request can succeed today and fail next
week — it’s a fragmentation snapshot, not a fixed ceiling- Treat any single measured number as a data point for your specific system, not a universal constant
Conclusion
Pairing a hands-on probe module with /proc/buddyinfo turns the abstract idea of a kmalloc
ceiling into something you can measure, reproduce, and reason about on real hardware. This kind of
first-principles verification habit is exactly what separates driver engineers who can debug obscure
allocation failures from those who get stuck guessing. Carry this same “measure, don’t assume” approach
into the next lectures of this free Linux kernel development course.
Frequently Asked Questions
Q1. How do I test the kmalloc limit on my own board?
Build and load a small kernel module that increases its request size step by step, freeing memory after each
successful call, and watch dmesg for the point where allocation starts failing.
Q2. What does /proc/buddyinfo actually show?
It shows, per memory zone, how many free contiguous blocks exist at each page order, from single pages up to
the highest tracked order.
Q3. Why did my large kmalloc succeed once and fail later?
Physical memory fragmentation increases with system uptime and workload, reducing the number of large
contiguous free blocks available to the buddy allocator.
Q4. Is it safe to run an allocation-sweeping module on a production system?
No. Run this kind of probe only on a test VM, development board, or lab system, and always unload it after
use.
Q5. What should I check first if insmod fails?
Check dmesg for kernel version mismatches or missing symbols before assuming a logic error in the
module itself.
Q6. Does the result differ between a Raspberry Pi and a PC?
Yes, results can differ due to page size, memory zone layout, and kernel configuration differences between
architectures.
Continue the Free Linux Device Drivers Course
This lecture is part of EmbeddedPathashala’s free Linux kernel development and device drivers course.
