【原创】(十六)Linux内存管理之CMA
背景
-
read the fucking source code!
--by 鲁迅 -
a picture is worth a thousand words.
--by 高尔基
说明:
- kernel版本:4.14
- arm64处理器,contex-a53,双核
- 使用工具:source insight 3.5, visio
1. 概述
contiguous memory allocator, cma
,连续内存分配器,用于分配连续的大块内存。cma分配器
,会reserve一片物理内存区域:
- 设备驱动不用时,内存管理系统将该区域用于分配和管理可移动类型页面;
- 设备驱动使用时,用于连续内存分配,此时已经分配的页面需要进行迁移;
此外,cma分配器
还可以与dma子系统
集成在一起,使用dma的设备驱动程序无需使用单独的cma api
。
2. 数据结构
内核定义了struct cma
结构,用于管理一个cma区域
,此外还定义了全局的cma数组
,如下:
struct cma { unsigned long base_pfn; unsigned long count; unsigned long *bitmap; unsigned int order_per_bit; /* order of pages represented by one bit */ struct mutex lock; #ifdef config_cma_debugfs struct hlist_head mem_head; spinlock_t mem_head_lock; #endif const char *name; }; extern struct cma cma_areas[max_cma_areas]; extern unsigned cma_area_count;
-
base_pfn
:cma区域物理地址的起始页帧号; -
count
:cma区域总体的页数; -
*bitmap
:位图,用于描述页的分配情况; -
order_per_bit
:位图中每个bit
描述的物理页面的order
值,其中页面数为2^order
值;
来一张图就会清晰明了:
3. 流程分析
3.1 cma区域创建
3.1.1 方式一 根据dts来配置
之前的文章也都分析过,物理内存的描述放置在dts
中,最终会在系统启动过程中,对dtb
文件进行解析,从而完成内存信息注册。
cma
的内存在dts
中的描述示例如下图:
在dtb
解析过程中,会调用到rmem_cma_setup
函数:
reservedmem_of_declare(cma, "shared-dma-pool", rmem_cma_setup);
3.1.2 方式二 根据参数或宏配置
可以通过内核参数或配置宏,来进行cma区域的创建,最终会调用到cma_declare_contiguous
函数,如下图:
3.2 cma添加到buddy system
在创建完cma区域
后,该内存区域成了保留区域,如果单纯给驱动使用,显然会造成内存的浪费,因此内存管理模块会将cma区域
添加到buddy system
中,用于可移动页面的分配和管理。cma区域
是通过cma_init_reserved_areas
接口来添加到buddy system
中的。
core_initcall(cma_init_reserved_areas);
core_initcall
宏将cma_init_reserved_areas
函数放置到特定的段中,在系统启动的时候会调用到该函数。
3.3 cma分配/释放
- cma分配,入口函数为
cma_alloc
:
- cma释放,入口函数为
cma_release
:
函数比较简单,直接贴上代码
/** * cma_release() - release allocated pages * @cma: contiguous memory region for which the allocation is performed. * @pages: allocated pages. * @count: number of allocated pages. * * this function releases memory allocated by alloc_cma(). * it returns false when provided pages do not belong to contiguous area and * true otherwise. */ bool cma_release(struct cma *cma, const struct page *pages, unsigned int count) { unsigned long pfn; if (!cma || !pages) return false; pr_debug("%s(page %p)\n", __func__, (void *)pages); pfn = page_to_pfn(pages); if (pfn < cma->base_pfn || pfn >= cma->base_pfn + cma->count) return false; vm_bug_on(pfn + count > cma->base_pfn + cma->count); free_contig_range(pfn, count); cma_clear_bitmap(cma, pfn, count); trace_cma_release(pfn, pages, count); return true; }
3.4 dma使用
代码参考driver/base/dma-contiguous.c
,主要包括的接口有:
/** * dma_alloc_from_contiguous() - allocate pages from contiguous area * @dev: pointer to device for which the allocation is performed. * @count: requested number of pages. * @align: requested alignment of pages (in page_size order). * @gfp_mask: gfp flags to use for this allocation. * * this function allocates memory buffer for specified device. it uses * device specific contiguous memory area if available or the default * global one. requires architecture specific dev_get_cma_area() helper * function. */ struct page *dma_alloc_from_contiguous(struct device *dev, size_t count, unsigned int align, gfp_t gfp_mask); /** * dma_release_from_contiguous() - release allocated pages * @dev: pointer to device for which the pages were allocated. * @pages: allocated pages. * @count: number of allocated pages. * * this function releases memory allocated by dma_alloc_from_contiguous(). * it returns false when provided pages do not belong to contiguous area and * true otherwise. */ bool dma_release_from_contiguous(struct device *dev, struct page *pages, int count);
在上述的接口中,实际调用的就是cma_alloc/cma_release
接口来实现的。
整体来看,cma分配器还是比较简单易懂,也不再深入分析。
4.后记
内存管理的分析先告一段落,后续可能还会针对某些模块进一步的研究与完善。
内存管理子系统,极其复杂,盘根错节,很容易就懵圈了,尽管费了不少心力,也只能说略知皮毛。
学习就像是爬山,面对一座高山,可能会有心理障碍,但是当你跨越之后,再看到同样高的山,心理上你将不再畏惧。
接下来将研究进程管理子系统
,将任督二脉打通。
未来会持续分析内核中的各类框架,并发机制等,敬请关注,一起探讨。
推荐阅读
-
【原创】(十三)Linux内存管理之vma/malloc/mmap
-
【原创】(十)Linux内存管理 - zoned page frame allocator - 5
-
【原创】(十四)Linux内存管理之page fault处理
-
【原创】(八)Linux内存管理 - zoned page frame allocator - 3
-
【原创】(十二)Linux内存管理之vmap与vmalloc
-
【原创】(九)Linux内存管理 - zoned page frame allocator - 4
-
【原创】(四)Linux内存模型之Sparse Memory Model
-
【原创】(十六)Linux内存管理之CMA
-
【原创】(五)Linux内存管理zone_sizes_init
-
Linux系统内存管理系列之五