浅浅讲解下Linux内存管理之CMA

news2024/11/27 14:51:57

说明:

  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值;

来一张图就会清晰明了:

  资料直通车:Linux内核源码技术学习路线+视频教程内核源码

学习直通车:Linux内核源码内存调优文件系统进程管理设备驱动/网络协议栈

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分配器还是比较简单易懂,也不再深入分析。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/85820.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

c语言内存和文件处理有关知识

内存 分配内存的函数calloc&#xff0c;malloc 定义于头文件 <stdlib.h>功能malloc分配内存(函数)calloc分配并清零内存(函数)realloc扩充之前分配的内存块(函数)free归还还之前分配的内存(函数)aligned_alloc(C11)分配对齐的内存(函数) 函数原型 void *malloc(unsigne…

Java基础之Collection的ArrayList

Java基础之Collection的ArrayList一、add()与addAll()二、remove()三、trimToSize()1、案例一、add()与addAll() 跟C 的vector不同&#xff0c;ArrayList没有push_back()方法&#xff0c;对应的方法是add(E e)&#xff0c;ArrayList也没有insert()方法&#xff0c;对应的方法是…

Oracle---初学篇

Oracle初学篇 Oracle的启动&#xff0c;监听&#xff0c;用户 文章目录Oracle初学篇Oracle的启动Oracle的监听监听服务的主要文件1.listener.ora2.tnsnames.ora3.sqlnet.oraOracle用户Oracle安装成功后默认的三个用户创建用户Oracle的启动 之前写了关于如何在CentOS7上搭建Ora…

2021年全国研究生数学建模竞赛华为杯D题抗乳腺癌候选药物的优化建模求解全过程文档及程序

2021年全国研究生数学建模竞赛华为杯 D题 抗乳腺癌候选药物的优化建模 原题再现&#xff1a; 一、背景介绍   乳腺癌是目前世界上最常见&#xff0c;致死率较高的癌症之一。乳腺癌的发展与雌激素受体密切相关&#xff0c;有研究发现&#xff0c;雌激素受体α亚型&#xff0…

LeetCode 0547. 省份数量:图的连通分量

【LetMeFly】547.省份数量 力扣题目链接&#xff1a;https://leetcode.cn/problems/number-of-provinces/ 有 n 个城市&#xff0c;其中一些彼此相连&#xff0c;另一些没有相连。如果城市 a 与城市 b 直接相连&#xff0c;且城市 b 与城市 c 直接相连&#xff0c;那么城市 a …

Windows文件夹开启大小写敏感

Windows 的文件系统的文件名&#xff0c;是大小写不敏感的&#xff0c;也就是你的文件名是 a.txt 或者 A.txt&#xff0c;在 Windows 中都是一视同仁&#xff0c;认为是同一个文件。 自从 Windows 10 引入 Linux 子系统&#xff08;WSL&#xff09;后&#xff0c;有越来越多开…

JAVA毕业设计——基于ssm的汽车租赁管理系统 (源代码+数据库)

代码地址 https://github.com/ynwynw/carRental-public 毕业设计所有选题地址 https://github.com/ynwynw/allProject 基于Springboot的汽车租赁管理系统 (源代码数据库)601 一、系统介绍 汽车租赁系统总共分为两个大的模块&#xff0c;分别是系统模块和业务模块。其中系统模…

基于混沌原子搜索优化的电力系统(HPS)负载频率自动控制(ALFC)(Matlab代码实现)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客 &#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜…

Spring Security 中的四种权限控制方式

Spring Security 中对于权限控制默认已经提供了很多了&#xff0c;但是&#xff0c;一个优秀的框架必须具备良好的扩展性&#xff0c;恰好&#xff0c;Spring Security 的扩展性就非常棒&#xff0c;我们既可以使用 Spring Security 提供的方式做授权&#xff0c;也可以自定义授…

如何实现外网访问API接口

Application Programming Interface 缩写为API&#xff0c;中文翻译为“应用程序接口”&#xff0c;是一些预先定义的函数&#xff0c;或指软件系统不同组成部分衔接的约定。目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力&#xff0c;而又无需访问源码&…

TVS管开关电源防护应用及电源防护元件的品类

瞬态抑制二极管简称TVS管。其作用原理是能够在极短的时间内承受反向电压的冲击&#xff0c;使得两极之间的电压钳位在特定电压水平上&#xff0c;有效避免了对后面电路的冲击&#xff0c;从而保护了被保护电子线路中的精密元件不受其损害。 瞬态抑制二极管TVS的钳位响应速度为为…

pytest + yaml 框架 -7.用例分层机制

前言 当我们测试流程类的接口&#xff0c;需反复去调用同一个接口&#xff0c;就会想到复用API&#xff0c;在代码里面可以写成函数去调用。 那么在yaml 文件中&#xff0c;我们可以把单个API写到一个yaml 文件&#xff0c;测试用例去调用导入API。 pip 安装插件 pip instal…

电子产品设计的流程有哪些

电子产品设计过程是指导工业外观设计的具体环节&#xff0c;主要包括产品市场需求分析、产品设计、产品原型设计、生产测试设计、大规模生产等方法和步骤。 一、电子产品设计流程是什么? 1.产品市场需求分析是电子产品设计成功的第一步&#xff0c;也是非常重要的一步。开发者…

JavaSE(数组)

1. 数组 数组创建及初始化 总结&#xff1a; 三种写法包括了动态初始化和静态初始化&#xff0c;其中省略格式不能再省略&#xff08;拆分&#xff09;&#xff1b;没有初始化时&#xff08;默认值为基类类型对应的默认值&#xff09;其中引用类型的默认值为null 三种写法 1…

RK3288-8.1-添加一个人体感应的开关-pir_pin_status

收到一个人体感应的需求,在设置添加一个开关 第一步,确定人体感应接口的GPIO 可知GPIO7_B5为对应GPIO 第二步,注册对应DTS 然后去驱动内注册对应的节点 很基础的东西,就不多说了,省略一万字......................(得到节点) cat sys/devices/platform/attr/pir_pin_status …

CAD尺寸标注不显示数值

在创建一个新的CAD图纸后&#xff0c;使用CAD尺寸标注会看见只有一条直线而没有数字显示&#xff0c;这是为什么呢&#xff1f;实际上是存在数值的&#xff0c;只是默认的数值很小&#xff0c;如果图形尺寸过大就看不清楚需要放大才能看见&#xff0c;就需要调整CAD尺寸标注的格…

RSS Can:借助 V8 让 Golang 应用具备动态化能力(二)

继续聊聊之前做过的一个小东西的踩坑历程&#xff0c;如果你也想高效获取信息&#xff0c;或许这个系列的内容会对你有用。 写在前面 在上一篇文章《RSS Can&#xff1a;使用 Golang 实现更好的 RSS Hub 服务&#xff08;一&#xff09;》里&#xff0c;我们简单介绍了使用 G…

数字孪生技术在智慧园区领域的实践

随着云计算、物联网、大数据、人工智能、5G 等为代表的技术迅速发展和 深入应用&#xff0c;“智慧园区”建设已成为全球园区发展的新趋势。近年来&#xff0c;党中央 和国务院更加注重智慧园区的建设与发展&#xff0c;相继出台了多项政策推动智慧园区的建设&#xff0c;智慧园…

数据镜像软件

什么是数据镜像 数据镜像是复制已传输到 USB 设备或在 USB 设备中修改的文件内容的过程。创建镜像副本后&#xff0c;可以在受密码保护的网络共享中维护这些副本。此共享文件夹最好保存在远程位置&#xff0c;以节省本地计算机上的空间。这样&#xff0c;只有管理员或受信任的…

2023最新SSM计算机毕业设计选题大全(附源码+LW)之java基于疫情防控下社区管理平台my3tu

对于即将毕业或者即将做课设的同学而言&#xff0c;由于经验的欠缺&#xff0c;面临的第一个难题就是选题&#xff0c;确定好题目之后便是开题报告&#xff0c;如果选题首先看自己学习那些技术&#xff0c;不同技术适合做不同的产品&#xff0c;比如自己会些简单的Java语言&…