Fundamentals 15 min read

CMA (Contiguous Memory Allocator) Technical Principle Analysis and Source Code Interpretation

Linux’s Contiguous Memory Allocator (CMA) reserves and manages large physical memory blocks for devices by integrating with the Buddy system, using structures like struct cma, bitmap allocation, and APIs such as cma_init_reserved_mem and cma_alloc, while handling page migration, LRU and per‑CPU PCP caches to ensure efficient allocation and release.

OPPO Kernel Craftsman
OPPO Kernel Craftsman
OPPO Kernel Craftsman
CMA (Contiguous Memory Allocator) Technical Principle Analysis and Source Code Interpretation

This article introduces the CMA (Contiguous Memory Allocator) technical principle in Linux, analyzing CMA's initialization and allocation processes through source code, while explaining related concepts including page migration, LRU (Least Recently Used) cache, and PCP (Per-CPU Page) cache.

CMA Overview: The Linux Buddy system manages memory at Page granularity (4KB per page), with maximum allocation of 4MB for contiguous physical pages. However, embedded devices like GPU, Camera, and HDMI require large contiguous memory regions. CMA was designed to solve this problem by reserving memory during system initialization that can be used by device drivers when needed, while being available to the Buddy system for general use when devices are idle.

Key Data Structures and APIs: The struct cma describes a CMA region with fields including base_pfn (starting page frame number), count (number of pages), bitmap (allocation status), and order_per_bit. Main APIs include cma_init_reserved_mem for creating CMA from reserved memory, cma_init_reserved_areas for returning CMA to Buddy system, cma_alloc for allocation, and cma_release for freeing.

Initialization Process: CMA regions are created via DTS reserved memory or command-line parameters. The initialization flow is: setup_arch → arm64_memblock_init → early_init_fdt_scan_reserved_mem → __reserved_mem_init_node → rmem_cma_setup. The function cma_activate_area sets migrate type to MIGRATE_CMA and releases all pages to the Buddy system.

Allocation Process: cma_alloc calculates bitmap information, finds free space, sets bitmap to 1, and calls alloc_contig_range for actual allocation. The alloc_contig_range function isolates the memory range, drains PCP cache, and migrates existing pages using __alloc_contig_migrate_range.

Page Migration: Pages in CMA must be movable. Two types of pages can be migrated: 1) LRU pages (anonymous and file pages from user process address space), 2) Non-LRU movable pages (requiring driver implementation of page->mapping->a_ops methods). The migration process involves: allocating new page, unmapping old page mappings, copying page content and struct page properties, establishing new mappings, and releasing the old page.

LRU Cache and PCP Cache: LRU cache (struct pagevec) is a per-CPU cache that batches page additions to LRU lists to reduce lock contention. PCP cache (struct per_cpu_pages) allows each CPU to locally store pages allocated from Buddy, reducing lock acquisition overhead.

Memory ManagementLinux Kernellru-cacheEmbedded SystemsPage MigrationBuddy SystemCMAContiguous Memory
OPPO Kernel Craftsman
Written by

OPPO Kernel Craftsman

Sharing Linux kernel-related cutting-edge technology, technical articles, technical news, and curated tutorials

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.