Linux Kmalloc Allocator Guide-Free Linux Device Drivers Tutorial

PREV_LEC | NEXT_LEC

Linux Kmalloc Allocator Guide

Free Linux Kernel Development Course — Kernel Memory Management Series, Lecture 10

Level: Intermediate
Kernel: 6.x
Reading Time: 14 min
free linux kernel development course
free linux device drivers course
free embedded systems course
free embedded linux course
linux kmalloc allocator

The linux kmalloc allocator is the function every kernel module writer reaches for first when a driver needs a small, physically contiguous chunk of memory. If you have ever written void *ptr = kmalloc(...) in a character device driver and wondered what happens underneath, or which of kzalloc, kcalloc, and krealloc to pick, this lecture answers that with current kernel 6.x behavior — not decade-old defaults. This lecture is part of our free linux kernel development course and continues the Kernel Memory Management chapter after the buddy system and slab allocator lectures.

What You Will Learn

  • What the kmalloc family of functions actually does and how it sits on top of SLUB
  • The difference between kmalloc, kzalloc, kcalloc, and krealloc
  • Correct use of GFP flags (GFP_KERNEL, GFP_ATOMIC, GFP_DMA) in the linux kmalloc allocator API
  • Why kzfree() is gone and how kfree_sensitive() replaced it
  • Realistic kmalloc size limits on a modern kernel, and when to switch to kvmalloc()
  • A complete, original kernel module demonstrating every function in the family

Prerequisites

  • Completion of the previous lecture on the linux slab allocator
  • Basic kernel module build setup (Makefile, insmod/rmmod)
  • Comfort reading dmesg output

What Is the Kmalloc Family in the Linux Kernel?

kmalloc() is the kernel-space equivalent of user-space malloc(). It is declared in <linux/slab.h> and, on the current kernel, is served entirely by the SLUB allocator (SLAB was removed in kernel 6.8, and SLOB was removed even earlier). Every pointer that kmalloc() returns is guaranteed to be physically contiguous, which is why device drivers use it for DMA buffers, small structures, and anything hardware needs to see as one unbroken block.

Where kmalloc Sits in the Allocator Stack
Driver code: kmalloc() / kzalloc() / kcalloc() / krealloc()
SLUB allocator (per-size kmalloc caches)
Buddy page allocator
Physical RAM (contiguous pages)

kmalloc() Prototype and GFP Flags

#include <linux/slab.h>

void *kmalloc(size_t size, gfp_t flags);
void kfree(const void *ptr);

size is the number of bytes requested. flags tells the allocator how and where to get that memory. The most common flags in the linux kmalloc allocator API are:

Flag Meaning Typical Context
GFP_KERNEL Standard flag; allocation may sleep while memory is reclaimed Process context (open, ioctl, probe)
GFP_ATOMIC Never sleeps; dips into an emergency memory pool Interrupt handlers, spinlock-held code
GFP_DMA Memory usable by legacy 24-bit DMA hardware Old ISA-class DMA devices
GFP_NOWAIT Like GFP_ATOMIC but without touching the emergency reserve Best-effort allocations that can fail cleanly
__GFP_ZERO Zero the memory after allocation Combined internally by kzalloc()

On success, kmalloc() returns a virtual address that is part of the kernel’s direct (logical) mapping. On failure it returns NULL — always check it, because a driver that dereferences an unchecked kmalloc() result is one memory-pressure event away from a kernel panic.

kzalloc, kcalloc, and krealloc — the Modern Variants

Plain kmalloc() memory is not zeroed — it can contain leftover data from whoever used that memory block before you. The rest of the family exists to make safer, more convenient allocations:

Function Behavior Use When
kzalloc(size, flags) kmalloc + zero-fill in one call Default choice unless you will overwrite every byte anyway
kcalloc(n, size, flags) Zeroed array allocation with built-in overflow checking on n * size Allocating arrays — safer than kmalloc(n * size, …)
krealloc(ptr, new_size, flags) Resizes an existing allocation, copying old contents automatically Growing/shrinking a buffer without a manual alloc+copy+free
kmalloc_array(n, size, flags) Non-zeroed array allocation with overflow checking Array allocation when you don’t need zero-fill

Modernization note: the old kzfree() function that this chapter’s original book referenced no longer exists. Kernel commit 453431a54934 renamed it to kfree_sensitive(), which uses memzero_explicit() so the compiler cannot optimize the zeroing away. Use kfree_sensitive() whenever the buffer held a key, password, or any other secret; use plain kfree() for everything else.

Realistic kmalloc() Size Limits on Modern Kernels

Older references (including the print book this lecture is based on) quote a flat “4 MB per allocation” limit. That number came from a specific 32-bit configuration and is not reliable today. The real limit is KMALLOC_MAX_SIZE, and it is derived from MAX_ORDER and the architecture’s page size at build time — it commonly works out to somewhere between 4 MB and 32 MB on a 64-bit kernel, but you should never hardcode a number in driver code. Two practical rules instead:

  • Keep kmalloc() requests small — ideally well under a page (4 KB) to stay in the fast, cache-friendly SLUB size classes.
  • For anything in the megabyte range, don’t guess whether kmalloc will succeed — use kvmalloc() instead (covered next).

When to Use kvmalloc() Instead

kvmalloc() is the modern kernel’s answer to “I don’t know if this allocation is small enough for kmalloc.” It first tries kmalloc(); if that fails because the request is too large or physical memory is fragmented, it transparently falls back to vmalloc(). Free the result with kvfree() regardless of which path was actually used internally — you don’t need to remember which allocator served the request.

#include <linux/mm.h>

void *buf = kvmalloc(size, GFP_KERNEL);
if (!buf)
    return -ENOMEM;
/* ... use buf ... */
kvfree(buf);

Original Driver Example: ep_kmalloc_family_demo

The following module is original EmbeddedPathashala example code — not copied from any book — and exercises every function covered in this lecture in one place.

#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/string.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("EmbeddedPathashala");
MODULE_DESCRIPTION("Demo of the kmalloc allocator family");

struct ep_sensor_reading {
    int  id;
    int  value;
    char label[16];
};

#define EP_ARRAY_COUNT 8

static struct ep_sensor_reading *ep_reading;
static int  *ep_array;
static void *ep_big_buf;

static int __init ep_kmalloc_family_init(void)
{
    /* 1. Plain kmalloc - contents are NOT zeroed */
    ep_reading = kmalloc(sizeof(*ep_reading), GFP_KERNEL);
    if (!ep_reading) {
        pr_err("ep_kmalloc_demo: kmalloc failed\n");
        return -ENOMEM;
    }
    ep_reading->id = 1;
    ep_reading->value = 42;
    strscpy(ep_reading->label, "temp", sizeof(ep_reading->label));
    pr_info("ep_kmalloc_demo: kmalloc -> id=%d value=%d label=%s\n",
            ep_reading->id, ep_reading->value, ep_reading->label);

    /* 2. kzalloc - zero-filled allocation, the safe default */
    ep_array = kzalloc(EP_ARRAY_COUNT * sizeof(int), GFP_KERNEL);
    if (!ep_array) {
        pr_err("ep_kmalloc_demo: kzalloc failed\n");
        goto err_free_reading;
    }
    pr_info("ep_kmalloc_demo: kzalloc -> ep_array[0]=%d (should be 0)\n",
            ep_array[0]);
    kfree(ep_array);

    /* 3. kcalloc - array allocation with overflow-checked n * size */
    ep_array = kcalloc(EP_ARRAY_COUNT, sizeof(int), GFP_KERNEL);
    if (!ep_array) {
        pr_err("ep_kmalloc_demo: kcalloc failed\n");
        goto err_free_reading;
    }
    ep_array[0] = 100;
    pr_info("ep_kmalloc_demo: kcalloc -> allocated %d ints, ep_array[0]=%d\n",
            EP_ARRAY_COUNT, ep_array[0]);

    /* 4. krealloc - grow the array, old data is preserved */
    ep_array = krealloc(ep_array, (EP_ARRAY_COUNT * 2) * sizeof(int), GFP_KERNEL);
    if (!ep_array) {
        pr_err("ep_kmalloc_demo: krealloc failed\n");
        goto err_free_reading;
    }
    ep_array[EP_ARRAY_COUNT] = 999;
    pr_info("ep_kmalloc_demo: krealloc -> resized to %d ints, ep_array[%d]=%d\n",
            EP_ARRAY_COUNT * 2, EP_ARRAY_COUNT, ep_array[EP_ARRAY_COUNT]);

    /* 5. kvmalloc - large buffer; kernel picks kmalloc or vmalloc for us */
    ep_big_buf = kvmalloc(2 * 1024 * 1024, GFP_KERNEL); /* 2 MB */
    if (!ep_big_buf) {
        pr_err("ep_kmalloc_demo: kvmalloc failed\n");
        kfree(ep_array);
        goto err_free_reading;
    }
    pr_info("ep_kmalloc_demo: kvmalloc -> 2MB buffer allocated at %p\n",
            ep_big_buf);

    return 0;

err_free_reading:
    kfree(ep_reading);
    return -ENOMEM;
}

static void __exit ep_kmalloc_family_exit(void)
{
    kvfree(ep_big_buf);
    kfree(ep_array);

    /* kfree_sensitive() zeroes memory before freeing.
     * Use it for anything that could have held sensitive data. */
    kfree_sensitive(ep_reading);

    pr_info("ep_kmalloc_demo: all buffers freed\n");
}

module_init(ep_kmalloc_family_init);
module_exit(ep_kmalloc_family_exit);

Build and Run

# Makefile
obj-m += ep_kmalloc_demo.o

all:
	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
$ make
$ sudo insmod ep_kmalloc_demo.ko
$ dmesg | tail -n 6
$ sudo rmmod ep_kmalloc_demo

Expected dmesg Output

[ 1234.001122] ep_kmalloc_demo: kmalloc -> id=1 value=42 label=temp
[ 1234.001130] ep_kmalloc_demo: kzalloc -> ep_array[0]=0 (should be 0)
[ 1234.001135] ep_kmalloc_demo: kcalloc -> allocated 8 ints, ep_array[0]=100
[ 1234.001140] ep_kmalloc_demo: krealloc -> resized to 16 ints, ep_array[8]=999
[ 1234.001148] ep_kmalloc_demo: kvmalloc -> 2MB buffer allocated at 00000000a1b2c3d4
[ 1234.005210] ep_kmalloc_demo: all buffers freed

kmalloc vs vmalloc — Quick Comparison

Aspect kmalloc() vmalloc()
Physical memory Contiguous Not contiguous
Virtual memory Contiguous Contiguous
Typical size Bytes to a few KB Large buffers, MB range
Speed Fast (SLUB cache) Slower (page table setup)
DMA-safe Yes No, not directly

The next lecture in this free linux device drivers course covers vmalloc() in full depth, including how its page-table mapping works and when it is genuinely the better choice.

Real-World Use Cases

  • Allocating a small per-device private data structure in a driver’s probe() function
  • Building a DMA-capable buffer for a network or storage driver
  • Growing a dynamically sized command buffer in a character device driver using krealloc()
  • Allocating temporary key material that must be wiped with kfree_sensitive() before release

Common Mistakes

Mistake Why It’s a Problem Fix
Not checking the return value of kmalloc() NULL dereference under memory pressure Always check and return -ENOMEM
Using kmalloc() for large buffers Fails more often as physical memory fragments Use kvmalloc() or the page allocator
Calling kmalloc(n * size, GFP_KERNEL) Integer overflow in the multiplication Use kmalloc_array() or kcalloc()
Freeing sensitive buffers with plain kfree() Secret data can remain in freed memory Use kfree_sensitive()
Using GFP_ATOMIC everywhere “to be safe” Drains the emergency memory pool unnecessarily Use GFP_KERNEL in process context

Best Practices

  • Default to kzalloc() unless you can prove you’ll overwrite every byte immediately
  • Match the allocator to the context: GFP_KERNEL in process context, GFP_ATOMIC only in interrupt/atomic context
  • Prefer kcalloc()/kmalloc_array() for any array-style allocation
  • Reach for kvmalloc() the moment a size is not known to be small at compile time

Performance Considerations

Every kmalloc size class is backed by a dedicated SLUB cache, so allocations that land on a common size (32, 64, 128 bytes, and so on) are extremely fast — often just a per-CPU freelist pop. Requests that don’t fit a standard size class get rounded up, so batching many small structures into one larger allocation can reduce both memory waste and allocation overhead.

Security Considerations

Freshly kmalloc’ed memory can contain stale data from a previous allocation of that same slab slot. Never expose raw kmalloc() memory to user space via copy_to_user() without zeroing or fully initializing it first — use kzalloc() or explicitly clear the tail of any partially filled structure to avoid leaking kernel memory contents to user space.

Summary / Key Takeaways

  • The linux kmalloc allocator family provides small, physically contiguous kernel memory backed by SLUB
  • kzalloc, kcalloc, and krealloc cover zeroed, array, and resize use cases respectively
  • kzfree() is gone — use kfree_sensitive() for secret-holding buffers
  • There is no fixed “4 MB” kmalloc limit on modern kernels — use kvmalloc() for anything large or size-uncertain

Conclusion

The kmalloc family is the workhorse allocator you’ll use in almost every Linux driver you write. Picking the right variant — plain kmalloc, zeroed kzalloc, array-safe kcalloc, or resizeable krealloc — and pairing it with the correct GFP flag is a small decision that has a real effect on driver correctness and security. With that foundation in place, the next lecture in this free linux kernel development course moves on to vmalloc() and when virtually-contiguous memory is the better tool for the job.

Frequently Asked Questions

What is the difference between kmalloc and kzalloc?

kmalloc() allocates memory without initializing it, so it can contain leftover data. kzalloc() does the same allocation and then zeroes it, which is safer whenever you don’t overwrite the entire buffer immediately.

Why is kzfree() missing in newer kernel headers?

kzfree() was renamed to kfree_sensitive() in kernel commit 453431a54934. It behaves the same way — zeroing memory before freeing — but the new name makes its security purpose explicit.

What is the real maximum size for a single kmalloc() call?

It depends on KMALLOC_MAX_SIZE, which is derived from MAX_ORDER and the page size at kernel build time. There is no single universal number across kernels and architectures, so don’t hardcode one — use kvmalloc() if you’re unsure a request will fit.

When should I use kvmalloc() instead of kmalloc()?

Use kvmalloc() whenever the allocation size is large or not known to be small at compile time. It tries kmalloc() first and automatically falls back to vmalloc() if that fails, so you don’t have to write that fallback logic yourself.

Is kcalloc() the same as kmalloc(n * size, …)?

No. kcalloc() checks for integer overflow in the n * size multiplication and zero-fills the result, while a manual kmalloc(n * size, …) call does neither, which can silently under-allocate on overflow.

Does krealloc() copy my old data automatically?

Yes. krealloc() copies the contents of the old allocation into the new one up to the smaller of the two sizes, the same behavior as user-space realloc().

Can I use kmalloc() inside an interrupt handler?

Yes, but only with GFP_ATOMIC (or GFP_NOWAIT). GFP_KERNEL can sleep to reclaim memory, which is not allowed in interrupt context.

 

Continue the Free Linux Kernel Development Course

Next up: the vmalloc() allocator, page-table mapping internals, and when to choose virtually-contiguous memory.

PREV_LEC | NEXT_LEC

Leave a Reply

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