vmalloc() and vmap()¶
Purpose¶
vmalloc() allocates virtually contiguous kernel memory.
Unlike kmalloc(), which requires physically contiguous pages, vmalloc() allocates individual pages from the Buddy Allocator and maps them into a contiguous virtual address range.
This allows the kernel to allocate large memory regions even when physical memory is fragmented.
Besides vmalloc(), Linux also provides vmap(), which creates a virtually contiguous mapping from an existing array of physical pages instead of allocating new pages.
Both APIs build virtually contiguous kernel virtual memory while differing in how the backing pages are managed.
Memory Layout¶
Virtual Address Space
+-----------+
| Page 0 | ─────────────► PFN 12
+-----------+
| Page 1 | ─────────────► PFN 87
+-----------+
| Page 2 | ─────────────► PFN 35
+-----------+
| Page 3 | ─────────────► PFN 201
+-----------+
Virtual Memory
Contiguous
Physical Memory
Non-contiguous
Relationship with Buddy Allocator¶
Each page mapped by vmalloc() is allocated independently from the Buddy Allocator.
vmalloc()
│
├── alloc_pages(order = 0)
├── alloc_pages(order = 0)
├── alloc_pages(order = 0)
└── alloc_pages(order = 0)
│
▼
Create Virtual Mapping
│
▼
Return Virtual Address
Since every page is allocated independently, the backing physical pages do not need to be contiguous.
vmap()¶
Unlike vmalloc(), vmap() does not allocate physical pages.
Instead, it creates a virtually contiguous mapping for pages that already exist. The caller supplies an array of struct page *, and vmap() builds a contiguous virtual address range that maps those pages.
Caller
alloc_pages()
alloc_pages()
alloc_pages()
│
▼
vmap()
│
▼
Create Virtual Mapping
│
▼
Return Virtual Address
The caller still owns the backing pages. Removing the mapping with vunmap() does not free those pages.
Address Translation¶
The kernel can translate a virtual address back to its backing page by using vmalloc_to_page().
Virtual Address
│
▼
Locate vmalloc area
│
▼
Calculate page index
│
▼
struct page
│
▼
Physical Frame Number (PFN)
Advantages¶
- Supports large kernel allocations.
- Does not require contiguous physical memory.
- Works even when physical memory is fragmented.
- Simplifies allocation of large software buffers.
Limitations¶
- Slightly slower than
kmalloc(). - Requires page table mappings.
- Physical pages are scattered, making it unsuitable for hardware that requires contiguous DMA buffers.
Typical Use Cases¶
- Large kernel buffers
- Large lookup tables
- Software-managed memory pools
- Kernel data structures that do not require physically contiguous memory
Ownership Comparison¶
The main difference between vmalloc() and vmap() is ownership of the backing pages.
| API | Allocates Pages | Owns Pages | Removes Mapping | Frees Pages |
|---|---|---|---|---|
vmalloc() |
Yes | Yes | vfree() |
vfree() |
vmap() |
No | No | vunmap() |
Caller |
vmalloc()
│
alloc_pages()
│
▼
Virtual Mapping
│
vfree()
│
▼
Mapping removed
Pages freed
======================
Caller
alloc_pages()
│
▼
vmap()
│
▼
Virtual Mapping
│
vunmap()
│
▼
Mapping removed
Caller
free_pages()
Comparison¶
| Item | kmalloc() |
vmalloc() |
vmap() |
|---|---|---|---|
| Virtual Address | Contiguous | Contiguous | Contiguous |
| Physical Memory | Contiguous | Not required | Determined by caller |
| Backing Allocation | SLUB | Buddy + Page Mapping | Existing Pages |
| Allocation Unit | Object | Individual Pages | Existing Pages |
| Suitable for DMA | Yes | Generally No | Depends on backing pages |
| Allocation Speed | Faster | Slower | Faster than vmalloc() (no page allocation) |