背景

  • Read the fucking source code! --By 鲁迅
  • A picture is worth a thousand words. --By 高尔基

说明:

  1. Kernel版本:4.14
  2. ARM64处理器,Contex-A53,双核
  3. 使用工具:Source Insight 3.5, Visio

1. 概述

Contiguous Memory Allocator, CMA,连续内存分配器,用于分配连续的大块内存。

CMA分配器,会Reserve一片物理内存区域:

  1. 设备驱动不用时,内存管理系统将该区域用于分配和管理可移动类型页面;
  2. 设备驱动使用时,用于连续内存分配,此时已经分配的页面需要进行迁移;

此外,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内存管理之CMA的更多相关文章

  1. Linux学习之CentOS(二十六)--Linux磁盘管理:LVM逻辑卷的创建及使用

    在上一篇随笔里面 Linux学习之CentOS(二十五)--Linux磁盘管理:LVM逻辑卷基本概念及LVM的工作原理,详细的讲解了Linux的动态磁盘管理LVM逻辑卷的基本概念以及LVM的工作原理, ...

  2. Linux学习之十六-Linux用户管理

    Linux用户管理 Linux系统跟Windows系统一样,可以创建不同的用户,不同的用户组.在不同用户下使用系统具有相应的权限 创建一个普通用户时,会修改几个文件,拷贝一些初始文件到用户家目录中 修 ...

  3. 【原创】(十)Linux内存管理 - zoned page frame allocator - 5

    背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...

  4. 伙伴系统之避免碎片--Linux内存管理(十六)

    1 前景提要 1.1 碎片化问题 分页与分段 页是信息的物理单位, 分页是为了实现非连续分配, 以便解决内存碎片问题, 或者说分页是由于系统管理的需要. 段是信息的逻辑单位,它含有一组意义相对完整的信 ...

  5. 【原创】(六)Linux内存管理 - zoned page frame allocator - 1

    背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...

  6. [转帖]Linux分页机制之概述--Linux内存管理(六)

    Linux分页机制之概述--Linux内存管理(六) 2016年09月01日 19:46:08 JeanCheng 阅读数:5491 标签: linuxkernel内存管理分页架构更多 个人分类: ┈ ...

  7. linux基础-第十六单元 yum管理RPM包

    第十六单元 yum管理RPM包 yum的功能 本地yum配置 光盘挂载和镜像挂载 本地yum配置 网络yum配置 网络yum配置 Yum命令的使用 使用yum安装软件 使用yum删除软件 安装组件 删 ...

  8. 伙伴系统之伙伴系统概述--Linux内存管理(十五)

    在内核初始化完成之后, 内存管理的责任就由伙伴系统来承担. 伙伴系统基于一种相对简单然而令人吃惊的强大算法. Linux内核使用二进制伙伴算法来管理和分配物理内存页面, 该算法由Knowlton设计, ...

  9. 启动期间的内存管理之bootmem_init初始化内存管理–Linux内存管理(十二)

    1. 启动过程中的内存初始化 首先我们来看看start_kernel是如何初始化系统的, start_kerne定义在init/main.c?v=4.7, line 479 其代码很复杂, 我们只截取 ...

随机推荐

  1. UVa11400 - Lighting System Design——[动态规划]

    题干略. 题意分析: 很容易理解一类灯泡要么全部换要么全不换,其实费用节省的主要原因是由于替换灯泡类型而排除了低压电压源,于是我们就可以推断出灯泡类型替换的原则: 对于两类灯泡a1和a2,a1可以被a ...

  2. H3C NAT Server

  3. [转]分布式监控工具Ganglia 介绍 与 集群部署.

    如果你目的很明确就是冲着标题来的,不爱看我唠叨,请直接进入第二个分割线之后的内容. 其实之前就是有做Swift监控平台的打算的,但是因为没什么硬性需求么,也不要紧的,就一直搁置了.最近实验室来了个大二 ...

  4. 2018.11.2浪在ACM集训队第三次测试赛

    2018.11.2 浪在ACM 集训队第三次测试赛 整理人:孔晓霞 A 珠心算测试 参考博客:[1]李继朋  B 比例简化 参考博客: [1]李继朋 C 螺旋矩阵 参考博客:[1]朱远迪 D 子矩阵 ...

  5. Linux 内核总线方法

    有几个给 bus_type 结构定义的方法; 它们允许总线代码作为一个设备核心和单独驱动之 间的中介. 在 2.6.10 内核中定义的方法是: int (*match)(struct device * ...

  6. Java逻辑思维训练题

    两柱香问题题目:有两柱不均匀的香,每柱香燃烧完需要1个小时,问:怎样用两柱香切出一个15分钟的时间段?这个题的重点就是怎么切. 答案:将甲香的一头点着,将乙香的两头点着,当乙香燃烧完时,说明已经过了半 ...

  7. jekyll 在博客添加流程图

    本文告诉大家如何在博客使用流程图. 如果你使用的是我博客的模板,那么就可以直接使用我说的文件,如果是自己的主题,就需要在自己文件对应的地方加上代码. 在我的博客里,需要添加下面的js到博客,可以打开 ...

  8. 【Docker】Jenkins的安装与更新

    一.Jenkins安装 1.获取docker镜像 2.查看jenkins版本 3.启动jenkins容器 docker run -d --name jenkins_01 -p 8081:8080 -v ...

  9. 如何删除Word自动编号后文字和编号之间的空白距离

    一.出现的现象:使用word进行自动编号之后,编号和其后的文字出现如下图所示的空白 二.如何解决问题 选中列表内容右键->调整列表缩进->选择“编号之后(W)"为不特别标注-&g ...

  10. System类StringBuilder小结