How Does vmalloc() Work in Linux? – Free Linux Device Drivers Course in Hyderabad

vmalloc() in the Linux Kernel: Complete Beginner’s Tutorial
Understand virtually contiguous memory allocation, how it differs from kmalloc(), and when a real driver should reach for it
Topic
vmalloc API
Level
Intermediate
Applies To
Kernel 6.x

Every free Linux kernel development course eventually reaches a question every beginner asks: “kmalloc() gave me an error for a large allocation, what do I use instead?” The answer, most of the time, is vmalloc(). This tutorial explains exactly what vmalloc() does, how it is different from kmalloc(), and the situations where a real device driver should or should not use it.

What You Will Learn

Physical vs virtual memory contiguity
The vmalloc() and vfree() API
Why vmalloc() is slower than kmalloc()
vmalloc_to_page() and DMA limitations
A practical decision checklist

Prerequisites: a basic understanding of kmalloc() and the page allocator, and familiarity with the concept of virtual addresses. If these are new to you, start with our free Linux device drivers course memory management module first.

Physical Contiguity vs Virtual Contiguity

To understand vmalloc(), you first need to understand the difference between two kinds of “contiguous” memory:

  • Physically contiguous memory occupies one unbroken run of physical RAM addresses. kmalloc() always returns this kind of memory.
  • Virtually contiguous memory looks like one unbroken block to your code (you can index it as one array), but underneath, the kernel has stitched together several unrelated physical pages using the page tables. vmalloc() returns this kind of memory.
How vmalloc() Builds One Virtual Block From Scattered Physical Pages
Virtual address range (contiguous)
Page A
Page B
Page C
Page D

Physically, pages A-D can be anywhere in RAM. The page table maps them into one continuous virtual range so your code can treat them as a single buffer.

This is exactly why vmalloc() can succeed for large allocations even when the physical RAM is heavily fragmented: it does not need to find one giant free physical run, only enough individual free pages, however scattered they are.

The vmalloc() API

The core function signature is simple and does not need a GFP flag argument for basic use, because vmalloc() always allocates in a context where sleeping is allowed:

#include <linux/vmalloc.h>

void *buf;
size_t size = 4 * 1024 * 1024; /* 4 MB, unlikely to succeed via kmalloc */

buf = vmalloc(size);
if (!buf)
    return -ENOMEM;

memset(buf, 0, size);

/* ... use buf ... */

vfree(buf);

If you want the memory pre-zeroed in one step, use vzalloc() instead of calling vmalloc() followed by memset():

buf = vzalloc(size);   /* same as vmalloc() + memset(0) */

Why vmalloc() Is Slower Than kmalloc()

vmalloc() has three costs that kmalloc() does not have:

Cost Explanation
Page table setup The kernel must build new page table entries to map the scattered pages into one virtual range, which kmalloc() never needs to do.
TLB pressure Because the underlying pages are not physically contiguous, the CPU’s translation lookaside buffer cannot cover the whole range with one large-page entry, which slightly hurts access performance.
Allocation overhead Locating and mapping many individual pages simply takes more CPU cycles than the fast paths used by kmalloc() or a slab cache.

A Critical Limitation: DMA and Hardware Access

Warning: Memory returned by vmalloc() must never be handed directly to a hardware device for DMA. Since the memory is not physically contiguous, the device (which only understands physical addresses) would read or write the wrong data. If your driver needs memory that a device will access directly, use kmalloc(), a DMA pool, or dma_alloc_coherent() instead.

If you genuinely need to inspect the physical page behind a specific offset inside a vmalloc() buffer (for example, to build a scatter-gather list manually), the kernel provides a helper for that:

struct page *pg = vmalloc_to_page(buf + offset);
unsigned long phys_addr = page_to_phys(pg);

vmalloc() vs kmalloc(): A Quick Decision Table

Situation Recommended API
Small allocation (a few KB or less) kmalloc()
Large allocation (hundreds of KB to several MB) vmalloc()
Memory that a device will access via DMA kmalloc() or dma_alloc_coherent(), never vmalloc()
Called from an interrupt handler kmalloc() with GFP_ATOMIC; vmalloc() cannot be used here
Same fixed-size object allocated repeatedly A custom slab cache

Real-World Use Cases

vmalloc() is commonly used for module loading itself (the kernel maps the executable code and data sections of a loadable module using vmalloc space), for large buffers inside filesystem and networking subsystems, and for kernel-side allocations that mirror large user-space mappings. If you have ever wondered how the kernel loads a multi-megabyte .ko file into a non-contiguous chunk of RAM without needing one giant free physical block, vmalloc() is the mechanism behind it.

Common Mistakes to Avoid

  • Passing vmalloc() memory directly to a DMA-capable device — this is a serious and hard-to-debug data corruption bug.
  • Calling vmalloc() from interrupt context or with a spinlock held — vmalloc() can sleep and is only safe in process context.
  • Using vmalloc() for small, frequent allocations, where the mapping overhead outweighs any benefit.
  • Forgetting that vfree() must be called from process context as well, for the same reason as vmalloc().

Best Practices

  • Reach for vmalloc() only after confirming kmalloc() cannot satisfy the size you need.
  • Prefer vzalloc() over vmalloc() plus a manual memset() for cleaner, less error-prone code.
  • Document clearly in your driver why a particular buffer uses vmalloc(), since it is the less common choice and future maintainers will want to know.
Key Takeaways
vmalloc() gives virtually, not physically, contiguous memory
It succeeds for large allocations even under physical fragmentation
Never use it for DMA-capable buffers
It is slower than kmalloc() due to page table overhead

Frequently Asked Questions

Q1. Can vmalloc() be used inside an interrupt handler?

No. vmalloc() can sleep while it sets up page table mappings, so it must only be called from process context, never from interrupt context or with a spinlock held.

Q2. Why does my driver’s DMA transfer corrupt data when I use vmalloc()?

Because vmalloc() memory is not physically contiguous, the device controller (which only understands physical addresses) ends up reading or writing pages that are not actually next to each other in RAM. Use kmalloc() or dma_alloc_coherent() for any buffer a device will access directly.

Q3. Is there a maximum size limit for vmalloc() allocations?

Yes, vmalloc() draws from a dedicated, limited region of the kernel’s virtual address space, so extremely large allocations can still fail if that region is exhausted, even though physical RAM is available.

Q4. What is the difference between vmalloc() and vzalloc()?

vzalloc() is functionally identical to calling vmalloc() and then zeroing the entire buffer yourself, just in a single, more convenient call.

Q5. Should a beginner driver default to vmalloc() to be safe?

No. kmalloc() should always be the first choice for anything reasonably small, since it is faster and physically contiguous. Move to vmalloc() only when you specifically need a large buffer and do not need DMA access to it.

Continue Your Free Linux Kernel Development Course

This lesson is part of EmbeddedPathashala’s free Linux kernel development course and free Linux device drivers course covering memory management from first principles.

Leave a Reply

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