Allocator APIs Covered
Free Tutorial
Modern Kernel Focus
Friendly Explanations
If you are following our free Linux kernel programming course, this lesson explains vmalloc(), one of the core kernel memory allocation APIs every device driver author must understand. Unlike kmalloc(), which hands you physically contiguous memory, vmalloc() gives you memory that is contiguous only in the kernel’s virtual address space. Understanding this distinction is essential before you write your first Linux device driver, which is exactly why this tutorial is part of our free Linux device drivers course track on EmbeddedPathashala.
By the end of this lesson you will know exactly when to reach for vmalloc(), vzalloc(), or kvmalloc() in your own kernel modules, and why picking the wrong one can hurt performance on real hardware.
vmalloc vs kmalloc
vzalloc() zero-initialised memory
kvmalloc() hybrid allocator
kcalloc() array allocation
Freeing memory correctly
Common driver mistakes
Performance trade-offs
Before starting this lesson of our free Linux kernel development course, you should already be comfortable with:
Writing a “Hello World” kernel module
module_init / module_exit macros
A Linux VM or machine for testing (kernel 6.x recommended)
This lecture is part of EmbeddedPathashala’s free courses:
Free Linux Device Drivers Course
Free Embedded Systems Course
Linux Kernel Memory Management
What Is vmalloc() in the Linux Kernel?
vmalloc() is a Linux kernel API that reserves a block of virtually contiguous memory for use inside kernel code, such as a device driver or kernel module. The key word here is “virtually” — the pages returned may be scattered anywhere in physical RAM, yet the kernel presents them to your code as one continuous virtual address range. This makes vmalloc() ideal for large allocations where physical contiguity is not required, such as big driver-internal buffers, module data structures, or firmware image staging areas.
vmalloc vs kmalloc: Choosing the Right Kernel Allocator
New driver authors often ask whether to use kmalloc() or vmalloc(). The table below, built for this free Linux device drivers course, summarises the practical differences you will run into on real hardware.
| Property | kmalloc() | vmalloc() |
|---|---|---|
| Physical contiguity | Guaranteed | Not guaranteed |
| Typical use case | DMA buffers, small structures | Large driver buffers, module data |
| Maximum practical size | Limited (few MB, slab-bound) | Much larger, bound by vmalloc address space |
| Allocation speed | Fast | Slower (page table setup overhead) |
| Safe for DMA? | Yes | No, generally unsafe for direct DMA |
vzalloc() and kvmalloc(): Friends of vmalloc()
Modern kernel code rarely calls bare vmalloc() alone. Two closely related helpers appear constantly in real driver source trees:
Behaves exactly like vmalloc(), except the returned memory is guaranteed to be zero-filled. Use this whenever your buffer must start in a known, clean state — for example, a status structure that other code will read before you have written to every field.
A smart hybrid allocator introduced to solve a real-world driver problem: small allocations through vmalloc() are wasteful because of page-table setup cost, but very large allocations through kmalloc() often fail because the physical allocator cannot find a big enough contiguous block. kvmalloc() automatically tries kmalloc() first and falls back to vmalloc() only if the physical allocator cannot satisfy the request. This makes it the recommended default for size-variable buffers in current kernel development.
A Simple vmalloc Demo Module (Updated for Modern Kernels)
Here is an original, minimal kernel module written for this lesson to demonstrate the three allocators together. It targets current 6.x kernel APIs and avoids deprecated calling conventions.
#include <linux/init.h>
#include <linux/module.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
#define EP_BUF_SIZE 8192
static void *ep_vbuf;
static void *ep_vzbuf;
static void *ep_kvbuf;
static int __init ep_vmalloc_demo_init(void)
{
ep_vbuf = vmalloc(EP_BUF_SIZE);
if (!ep_vbuf) {
pr_err("ep_demo: vmalloc failed\n");
return -ENOMEM;
}
pr_info("ep_demo: vmalloc() ok, virt=0x%px\n", ep_vbuf);
ep_vzbuf = vzalloc(EP_BUF_SIZE);
if (!ep_vzbuf) {
pr_err("ep_demo: vzalloc failed\n");
vfree(ep_vbuf);
return -ENOMEM;
}
pr_info("ep_demo: vzalloc() ok, zeroed buffer ready\n");
ep_kvbuf = kvmalloc(EP_BUF_SIZE, GFP_KERNEL);
if (!ep_kvbuf) {
pr_err("ep_demo: kvmalloc failed\n");
vfree(ep_vzbuf);
vfree(ep_vbuf);
return -ENOMEM;
}
pr_info("ep_demo: kvmalloc() ok\n");
return 0;
}
static void __exit ep_vmalloc_demo_exit(void)
{
kvfree(ep_kvbuf);
vfree(ep_vzbuf);
vfree(ep_vbuf);
pr_info("ep_demo: module unloaded, memory freed\n");
}
module_init(ep_vmalloc_demo_init);
module_exit(ep_vmalloc_demo_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("EmbeddedPathashala vmalloc/vzalloc/kvmalloc demo");
Build and load it on your test system, then check the kernel log:
make -C /lib/modules/$(uname -r)/build M=$(pwd) modules
sudo insmod ep_vmalloc_demo.ko
dmesg | tail -n 10
sudo rmmod ep_vmalloc_demo
Common Mistakes When Using vmalloc()
- Using vmalloc() memory for DMA: the physical pages are not contiguous, so hardware DMA engines cannot use this memory directly.
- Forgetting to check the return value: like any allocator, vmalloc() can fail under memory pressure — always check for NULL.
- Calling vmalloc() in atomic context: vmalloc() can sleep, so it must never be called from interrupt handlers or with a spinlock held.
- Mixing free functions: memory from vmalloc()/vzalloc() must be freed with vfree(), while kvmalloc() memory should be freed with kvfree(), which picks the correct method automatically.
- Using vmalloc() for tiny, frequent allocations: the page-table setup overhead makes this slower than kmalloc() for small, high-frequency buffers.
Best Practices for vmalloc in Driver Code
- Prefer
kvmalloc()for size-variable buffers unless you have a specific reason to force one allocator. - Use
vzalloc()whenever the buffer’s initial state matters, instead of manually zeroing it afterwards. - Always pair every successful allocation with a matching free call in your error-handling and exit paths.
- Document in code comments why a large vmalloc-based buffer is needed, since large allocations affect system memory pressure.
Performance and Security Considerations
Performance: because vmalloc() has to build page table entries for every page in the region, it is measurably slower than kmalloc() for the same size, especially under repeated allocate/free cycles. Reserve it for buffers that are allocated once and used for the module’s lifetime, rather than allocated and freed on a hot path.
Security: never expose raw vmalloc’d kernel addresses to user space, since predictable kernel virtual addresses can assist attackers in defeating kernel address space layout randomisation (KASLR). Always use the %pK or restricted pointer formats when logging these addresses.
Real-World Use Cases
Firmware blob loading
Large filesystem metadata caches
Kernel module data segments
Graphics driver command buffers
Summary and Key Takeaways
- vmalloc() returns virtually contiguous, not physically contiguous, memory.
- vzalloc() is vmalloc() with guaranteed zero-initialisation.
- kvmalloc() intelligently chooses between kmalloc() and vmalloc() and is the modern recommended default.
- Never use vmalloc-based memory for DMA transfers.
- Always match allocation calls with the correct free function.
Conclusion
This lesson from our free Linux kernel programming course walked through vmalloc(), vzalloc(), and kvmalloc() with an original demo module built for modern 6.x kernels. Mastering these allocators is a core skill for anyone progressing through our free Linux device drivers course, since almost every real driver eventually needs a buffer that kmalloc() alone cannot comfortably provide. In the next lesson, we go one level deeper and explain exactly how the kernel turns these virtual pages into physical memory on demand.
Frequently Asked Questions
Q1. Is vmalloc() memory physically contiguous?
No. vmalloc() only guarantees virtual contiguity; the underlying physical pages can be scattered anywhere in RAM.
Q2. Can I use vmalloc() inside an interrupt handler?
No. vmalloc() can sleep and must only be called from process context.
Q3. What is the difference between vmalloc() and vzalloc()?
vzalloc() is identical to vmalloc() except it also zero-fills the allocated memory before returning it.
Q4. When should I choose kvmalloc() over vmalloc()?
Whenever the allocation size can vary, since kvmalloc() automatically prefers the faster kmalloc() path when possible.
Q5. How do I free memory allocated with kvmalloc()?
Always use kvfree(), which detects the correct underlying allocator and frees the memory safely.
Q6. Why can’t I use vmalloc() memory for DMA?
DMA hardware generally needs physically contiguous memory, and vmalloc() cannot guarantee that.
Q7. Is this tutorial free as part of a full course?
Yes, this lesson is part of EmbeddedPathashala’s free Linux kernel development course and free Linux device drivers course.
