Linux设备驱动程序 之 kmalloc
原型
kmalloc的原型如下:
void *kmalloc(size_t size, gfp_t flags)
第一个参数是要分配的块的大小,第二个参数是分片标志;
flags标志
最常用的标志是GFP_KERNEL,表示内存分配(最终总是调用get_free_page来实现实际的分配,这就是GFP_前缀的由来)是代表在内核空间的进程执行的;换句话说,这意味着调用它的函数正代表某个进程执行系统调用;使用GFP_KERNEL允许在kmalloc在空闲内存较少的时候把当前进程转入休眠以等待一个页面;因此,使用GFP_KERNEL分配内存的函数必须是可重入的;在当前进程休眠时,内核会采取适当的行动,或者把缓冲区的内容刷到硬盘上,或者从搞一个用户进程换出内存,已获得一个内存页面;
GFP_KERNEL分配标志并不是始终适用,有时kmalloc是在进程上下文之外被调用的,例如中断处理程序,tasklet以及内核定时器中调用;这种情况下current进程就不该休眠,驱动程序应该换用GFP_ATOMIC标志;内核通常会为原子性的分配预留一些空闲页面;使用GFP__ATOMIC标志时,kmalloc甚至可以用掉最后一个空闲页面;不过如果连最后一页都没有了,分配就返回失败;
除了GFP_KERNEL和GFP_ATOMIC外,还有一些其他标志可用于替换或者补充这两个标志,不过这两个标志已经可以满足大多数驱动程序的需要了;
下面罗列这些标记:
GFP_ATOMIC-在中断处理程序或者其他运行与进程上下文之外的代码中分配内存,不能休眠;
GFP_KERNEL-内核内存的通常分配方法,可能引起休眠;
GFP_USER-为用户空间页分配内存,可能会休眠;
GFP_HIGHUSER-类似GFP_USER,不过如果有高端内存的话,就从那里分配;
GFP_NOIO GFP_NOFS-这两个标志类似GFP_KERNEL,但是为内核分配内存的工作方式添加了一些限制,具有GFP_NOFS标志的分配不允许执行任何文件系统调用,而GFP_NOIO禁止任何IO的初始化;这两个标志主要在文件系统和虚拟内存代码中使用,这项代码中的分配内存可休眠,但不应该发生递归的文件系统调用;
上面列出的分配标志可以和下面的标志“或”起来使用;下面这些标志控制如何进行分配:
__GFP_DMA-标志请求分配发生在可进行DMA的内存区段中;
__GFP_HIGHMEM-表明要分配的内存可位于高端内存;
__GFP_COLD-通常,内存分配器会试图返回缓存热页面,即可在处理器缓存中找到的页面;相反,这个标志请求尚未使用的冷页面;对用于DMA读取的页面分配,可以使用这个标志,因为这种情况下,页面存在于处理器缓存中没有多大帮助;
__GFP_NOWARN-该标志很少使用;它可以避免内核在无法满足分配请求的时候产生经过;
__GFP_HIGH-该标志标记了一个高优先级的请求,它允许为紧急状况而消耗有内核保留的最后一个页面;
__GFP_REPEAT、__GFP_NOFAIL、__GFP_NORETRY-上述标志告诉分配器在满足分配请求而遇到困难时应该采取何种行动;__GFP_REPEAT表示努力再尝试一次,它会重新尝试分配,当仍有可能失败;__GFP_NOFAIL标志告诉分配器始终不返回失败,它会努力满足分配请求;不鼓励使用这个标志;__GFP_NORETRY告诉分配器,如果请求的内存不可获得,就立即返回;
内存区段
__GFP_DMA和__GFP_HIGHMEM的使用与平台相关,尽管在所有平台上都可以使用这两个标志;
Linux内核把内存分成三个区段:可用于DMA的内存,常规内存以及高端内存;通常的内存分配都放生在常规内存区,但通过设置上面的标志可以把请求在其他区段中分配;其思路是每种计算平台都必须知道如何把自己特定的内存范围归类到这三个区段中,而不是认为所有的RAM都一样;
可用于DMA的内存是指存在于特别地址范围内的内存,外设可以利用这些内存执行DMA访问;在大多数健全的系统上,所有内存都位于这一区段;在x86平台上,DMA区段是RAM的前16MB;PCI设备无此限制;
高端内存是32位平台为了访问大量的内存而存在的一种机制;如果不首先完成一些特殊的映射,我们就无法从内核中直接访问这些内存,因此通常较难处理;但是,如果驱动程序要使用大量的内存,那么在能够使用高端内存的大系统上可以工作的更好;
当一个页面为了满足kmalloc的要求被分配时,内核会创建一个内存区段的列表以供搜索;如果指定了__GFP_DMA标志,则只有DMA区段会被搜索;如果低端地址上没有可用内存,就会分配失败;如果没有指定特定的标志,则常规区段和DMA区段都会被搜索;而如果设置了__GFP_HIGHMEM标志,则所有三区段都会被搜索以及获取一个空闲页面,然而要注意的是,kmalloc不能分配高端内存;
size参数
内核负责管理系统物理内存,物理内存只能按页面进行分配;其结果是kmalloc和典型的用户空间的malloc在实现上有很大的差别;简单的基于堆的分配技术会遇到麻烦,因为页面编辑的处理成为一个很棘手的问题;因此内核使用了特殊的基于页的分配技术,以及最佳地利用系统RAM;
Linux处理内存分配的方法是,创建一系列的内存池对象,每个池中的内存块大小是固定一致的;处理分配请求时,就直接在包含有足够大的内存块的池中传递一个整块请求者;
驱动程序开发应该牢记的就是内核值分配一些预定义的,固定大小的字节数组;如果申请任意数量的内存,那么得到的很可能会多一些,最多会到申请数量的两倍;另外,kmalloc能处理的最小的内存块是32或者64,到底是哪个则取决于当前体系结构使用的页面大小;
对kmalloc能够分配的内存块的大小,存在一个上限;这个限制随着体系架构的不同以及内存配置选项的不同而变化;如果希望代码有完整的可移植性,则不应该分配大于128K的内存;但是,如果希望获得多余几千字节的内存,则最好是用除kmalloc之外的内存获取方法;
Linux设备驱动程序 之 kmalloc的更多相关文章
- 【转】linux设备驱动程序中的阻塞机制
原文网址:http://www.cnblogs.com/geneil/archive/2011/12/04/2275272.html 阻塞与非阻塞是设备访问的两种方式.在写阻塞与非阻塞的驱动程序时,经 ...
- Linux设备驱动程序学习之分配内存
内核为设备驱动提供了一个统一的内存管理接口,所以模块无需涉及分段和分页等问题. 我已经在第一个scull模块中使用了 kmalloc 和 kfree 来分配和释放内存空间. kmalloc 函数内幕 ...
- linux设备驱动程序该添加哪些头文件以及驱动常用头文件介绍(转)
原文链接:http://blog.chinaunix.net/uid-22609852-id-3506475.html 驱动常用头文件介绍 #include <linux/***.h> 是 ...
- Linux设备驱动程序 第三版 读书笔记(一)
Linux设备驱动程序 第三版 读书笔记(一) Bob Zhang 2017.08.25 编写基本的Hello World模块 #include <linux/init.h> #inclu ...
- 教你写Linux设备驱动程序:一个简短的教程
教你写Linux设备驱动程序:一个简短的教程 http://blog.chinaunix.net/uid-20799298-id-99675.html
- linux设备驱动程序_hello word 模块编译各种问题集锦
在看楼经典书籍<linux设备驱动程序>后,第一个程序就是编写一个hello word 模块. 原以为非常easy,真正弄起来,发现问题不少啊.前两天编过一次,因为没有记录,今天看的时候又 ...
- Linux设备驱动程序学习----1.设备驱动程序简介
设备驱动程序简介 更多内容请参考Linux设备驱动程序学习----目录 1. 简介 Linux系统的优点是,系统内部实现细节对所有人都是公开的.Linux内核由大量复杂的代码组成,设备驱动程序可以 ...
- Linux设备驱动程序学习----2.内核模块与应用程序的对比
内核模块与应用程序的对比 更多内容请参考Linux设备驱动程序学习----目录 1. 内核模块与应用程序的对比 内核模块和应用程序之间的不同之处: 大多数中小规模的应用程序是从头到尾执行单个任务,而模 ...
- Linux设备驱动程序学习----3.模块的编译和装载
模块的编译和装载 更多内容请参考Linux设备驱动程序学习----目录 1. 设置测试系统 第1步,要先从kernel.org的镜像网站上获取一个主线内核,并安装到自己的系统中,因为学习驱动程序的编写 ...
随机推荐
- ThinkPHP5.0.*远程代码执行漏洞预警
安全公告 Thinkphp5.0.*存在远程代码执行漏洞. 漏洞描述 Thinkphp5.0.*存在远程代码执行漏洞.攻击者可以利用漏洞实现任意代码执行等高危操作. 目前官方已经出了补丁: https ...
- 媲美pandas的数据分析工具包Datatable
1 前言 data.table 是 R 中一个非常通用和高性能的包,使用简单.方便而且速度快,在 R 语言社区非常受欢迎,每个月的下载量超过 40 万,有近 650 个 CRAN 和 Biocondu ...
- 现有项目springmvc 小结
1. 接口接收json数据 @RequestBody JSONObject param 2.返回json数据封装 DataPacket.jsonResult
- 谷歌浏览器chrome安装vue-devtools 插件
1.打开https://github.com/vuejs/vue-devtools直接下载该项目,或者cmd方式直接输入:git Clone https://github.com/vuejs/vue- ...
- leetcode-21.合并有序链表 · List
题面 合并两个排序链表. 算法 创建结果链表头*res,*p指向头,当两个链表节点都不为空时,比较节点值,值小的挂在p后面,二者(p和小者)顺次后移.知道某条链表空,跳出while循环.接着,直接将不 ...
- windows使用msi包安装mysql8.0.12
1.前言 利用windows提供的二进制分发包(msi)安装是非常简单的,只要根据提示安装就可以了,和安装普通软件没有什么区别.但是如果想在安装的时候就把规划的配置好,是需要看懂每个步骤到底做什么用, ...
- 学习CSRF漏洞并挖掘CSRF漏洞
什么是跨站请求伪造? 跨站请求伪造(英语:Cross-siterequest forgery),也被称为one-clickattack或者session riding,通常缩写为CSRF或者XSRF, ...
- XSS学习收集
XSS platform supporting HTTPShttps://www.w0ai1uo.org/xss/xss.php?do=loginhttps://x.secbox.cn/index.p ...
- PAT Advanced 1008 Elevator (20 分)
The highest building in our city has only one elevator. A request list is made up with N positive nu ...
- window程序意外关闭自动重启脚本实现
@echo off : tasklist|find /i "xxxx"||start yyyy ping/n 127.1>nul 新建 .bat 文件,将其写入文件 xxxx ...