免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
123下一页
最近访问板块 发新帖
查看: 7600 | 回复: 21
打印 上一主题 下一主题

[内核模块] 奔溃吐槽 kmalloc(size,flag)的flag很重要 不小心会造成奔溃 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2012-12-10 20:26 |只看该作者 |倒序浏览
这几天在tcp_ipv4.c文件的一个函数改动一些东西
我在里面用kmalloc(4096,GFP_KERNEL)分配了一空间存放数据
谁知,编译完之后 重启电脑直接给我奔溃.....
欲哭无泪...找了两天终于找到了 祸首罪魁居然是kmalloc(4096,GFP_KERNEL)
我仔细的研究了kmalloc函数 将其该为kmalloc(4096,GFP_ATOMIC )相安无事 写个帖子谨记
资料如下:http://blog.csdn.net/flyingdon/article/details/5107346
Kmalloc内存分配和malloc相似,除非被阻塞否则他执行的速度非常快,而且不对获得空间清零。

Flags参数

#include<linux/slab.h>

Void *kmalloc(size_t size, int flags);

第一个参数是要分配的块的大小,第二个参数是分配标志(flags),他提供了多种kmalloc的行为。

最常用的GFP_KERNEL,他表示内存分配(最终总是调用get_free_pages来实现实际的分配,这就是,这就是GFP前缀的由来)是代表运行在内核空间的进程执行的。使用GFP_KERNEL容许kmalloc在分配空闲内存时候如果内存不足容许把当前进程睡眠以等待。因此这时分配函数必须是可重入的。如果在进程上下文之外如:中断处理程序、tasklet以及内核定时器中这种情况下current进程不该睡眠,驱动程序该使用GFP_ATOMIC.

GFP_ATOMIC

用来从中断处理和进程上下文之外的其他代码中分配内存. 从不睡眠.

GFP_KERNEL

内核内存的正常分配. 可能睡眠.

GFP_USER

用来为用户空间页来分配内存; 它可能睡眠.

GFP_HIGHUSER

如同 GFP_USER, 但是从高端内存分配, 如果有. 高端内存在下一个子节描述.

GFP_NOIO

GFP_NOFS

这个标志功能如同 GFP_KERNEL, 但是它们增加限制到内核能做的来满足请求. 一个 GFP_NOFS 分配不允许进行任何文件系统调用, 而 GFP_NOIO 根本不允许任何 I/O 初始化. 它们主要地用在文件系统和虚拟内存代码, 那里允许一个分配睡眠, 但是递归的文件系统调用会是一个坏注意.

上面列出的这些分配标志可以是下列标志的相或来作为参数, 这些标志改变这些分配如何进行:

__GFP_DMA

这个标志要求分配在能够 DMA 的内存区. 确切的含义是平台依赖的并且在下面章节来解释.

__GFP_HIGHMEM

这个标志指示分配的内存可以位于高端内存.

__GFP_COLD

正常地, 内存分配器尽力返回"缓冲热"的页 -- 可能在处理器缓冲中找到的页. 相反, 这个标志请求一个"冷"页, 它在一段时间没被使用. 它对分配页作 DMA 读是有用的, 此时在处理器缓冲中出现是无用的. 一个完整的对如何分配 DMA 缓存的讨论看"直接内存存取"一节在第 1 章.

__GFP_NOWARN

这个很少用到的标志阻止内核来发出警告(使用 printk ), 当一个分配无法满足.

__GFP_HIGH

这个标志标识了一个高优先级请求, 它被允许来消耗甚至被内核保留给紧急状况的最后的内存页.

__GFP_REPEAT

__GFP_NOFAIL

__GFP_NORETRY

这些标志修改分配器如何动作, 当它有困难满足一个分配. __GFP_REPEAT 意思是" 更尽力些尝试" 通过重复尝试 -- 但是分配可能仍然失败. __GFP_NOFAIL 标志告诉分配器不要失败; 它尽最大努力来满足要求. 使用 __GFP_NOFAIL 是强烈不推荐的; 可能从不会有有效的理由在一个设备驱动中使用它. 最后, __GFP_NORETRY 告知分配器立即放弃如果得不到请求的内存.



2.内存区段

__GFP_DMA和__GFP_HIGHMEM的使用与平台相关,Linux把内存分成3个区段:可用于DMA的内存、常规内存、以及高端内存。X86平台上ISA设备DMA区段是内存的前16MB,而PCI设备无此限制。

内存区后面的机制在 mm/page_alloc.c 中实现, 而内存区的初始化在平台特定的文件中, 常常在 arch 目录树的 mm/init.c。

Linux 处理内存分配通过创建一套固定大小的内存对象池. 分配请求被这样来处理, 进入一个持有足够大的对象的池子并且将整个内存块递交给请求者. 驱动开发者应当记住的一件事情是, 内核只能分配某些预定义的, 固定大小的字节数组.

如果你请求一个任意数量内存, 你可能得到稍微多于你请求的, 至多是 2 倍数量. 同样, 程序员应当记住 kmalloc 能够处理的最小分配是 32 或者 64 字节, 依赖系统的体系所使用的页大小. kmalloc 能够分配的内存块的大小有一个上限. 这个限制随着体系和内核配置选项而变化. 如果你的代码是要完全可移植, 它不能指望可以分配任何大于 128 KB. 如果你需要多于几个 KB, 但是, 有个比 kmalloc 更好的方法来获得内存





在设备驱动程序或者内核模块中动态开辟内存,不是用malloc,而是kmalloc ,vmalloc,或者用get_free_pages直接申请页。释放内存用的是kfree,vfree,或free_pages. kmalloc函数返回的是虚拟地址(线性地址). kmalloc特殊之处在于它分配的内存是物理上连续的,这对于要进行DMA的设备十分重要. 而用vmalloc分配的内存只是线性地址连续,物理地址不一定连续,不能直接用于DMA.

  注意kmalloc最大只能开辟128k-16,16个字节是被页描述符结构占用了。kmalloc用法参见khg.

  内存映射的I/O口,寄存器或者是硬件设备的RAM(如显存)一般占用F0000000以上的地址空间。在驱动程序中不能直接访问,要通过kernel函数vremap获得重新映射以后的地址。

  另外,很多硬件需要一块比较大的连续内存用作DMA传送。这块内存需要一直驻留在内存,不能被交换到文件中去。但是kmalloc最多只能开辟大小为32XPAGE_SIZE的内存,一般的PAGE_SIZE=4kB,也就是128kB的大小的内存。

评分

参与人数 1可用积分 +2 收起 理由
Godbach + 2 感谢分享

查看全部评分

论坛徽章:
36
IT运维版块每日发帖之星
日期:2016-04-10 06:20:00IT运维版块每日发帖之星
日期:2016-04-16 06:20:0015-16赛季CBA联赛之广东
日期:2016-04-16 19:59:32IT运维版块每日发帖之星
日期:2016-04-18 06:20:00IT运维版块每日发帖之星
日期:2016-04-19 06:20:00每日论坛发贴之星
日期:2016-04-19 06:20:00IT运维版块每日发帖之星
日期:2016-04-25 06:20:00IT运维版块每日发帖之星
日期:2016-05-06 06:20:00IT运维版块每日发帖之星
日期:2016-05-08 06:20:00IT运维版块每日发帖之星
日期:2016-05-13 06:20:00IT运维版块每日发帖之星
日期:2016-05-28 06:20:00每日论坛发贴之星
日期:2016-05-28 06:20:00
2 [报告]
发表于 2012-12-10 22:50 |只看该作者
回复 1# SCDXMOE

感谢 LZ 分享。


   

论坛徽章:
0
3 [报告]
发表于 2012-12-10 23:33 |只看该作者
又复习一次。。。学习了。。

论坛徽章:
0
4 [报告]
发表于 2012-12-11 09:34 |只看该作者
kmalloc是从slab分配的内存,不是什么调用get_free_page,另外kmalloc能分配多大的内存,看kmalloc size那个头文件设置了哪些大小常量(一般是32B, 64B, 128B, 512B, 1KB,... 一直到4MB),这些常量的内存block,都会预先在slab系统里分配好,kmalloc只是在里面获取一个最小的满足需求的slab block。很多时候只是从slab链表里获得,只有slab链表里没有空闲的了,才会去get_free_page真正申请一页或者几页内存。

你这函数用在什么地方?为什么要用到GFP_ATOMIC这样的禁止中断的方式来做?会降低系统响应性能的。如果不是专用系统而是在PC上,这样的做法可能完全不可取。

论坛徽章:
0
5 [报告]
发表于 2012-12-11 09:41 |只看该作者
leslielg您好:我用在tcp_ipv4.c 的 tcp_v4_rcv()函数中 想分配空间来存放skb的数据 对skb的数据做相应的处理之后再放回去!您有什么指点,忘不吝指教 期待您的回复 谢谢 回复 4# leslielg


   

论坛徽章:
0
6 [报告]
发表于 2012-12-11 10:04 |只看该作者
回复 5# SCDXMOE


    你那个之前大概看过,是个空指针的错误,应该不会是kmalloc的问题。感觉更多可能是你代码的问题,你把你完整的代码贴出来给大家看下吧。  

论坛徽章:
0
7 [报告]
发表于 2012-12-11 10:21 |只看该作者
您好hmsghnh:不知道您说的“ 你那个之前大概看过” 你是指的哪个??代码 你说的这个http://bbs.chinaunix.net/thread-4056635-1-1.html帖子 我有贴出的 代码 回复 6# hmsghnh


   

论坛徽章:
2
2015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:53:17
8 [报告]
发表于 2012-12-11 13:04 |只看该作者
kmalloc的第二个参数和代码运行context之间的关系, 是判断一个人写没写过kernel代码的第一依据。

论坛徽章:
6
金牛座
日期:2013-10-08 10:19:10技术图书徽章
日期:2013-10-14 16:24:09CU十二周年纪念徽章
日期:2013-10-24 15:41:34狮子座
日期:2013-11-24 19:26:19未羊
日期:2014-01-23 15:50:002015年亚洲杯之阿联酋
日期:2015-05-09 14:36:15
9 [报告]
发表于 2012-12-11 13:09 |只看该作者
回复 4# leslielg
你这函数用在什么地方?为什么要用到GFP_ATOMIC这样的禁止中断的方式来做?会降低系统响应性能的。如果不是专用系统而是在PC上,这样的做法可能完全不可取。

网络处理是在软中断中进行的,必须使用GFP_ATOMIC来申请内存。
   

论坛徽章:
6
金牛座
日期:2013-10-08 10:19:10技术图书徽章
日期:2013-10-14 16:24:09CU十二周年纪念徽章
日期:2013-10-24 15:41:34狮子座
日期:2013-11-24 19:26:19未羊
日期:2014-01-23 15:50:002015年亚洲杯之阿联酋
日期:2015-05-09 14:36:15
10 [报告]
发表于 2012-12-11 13:12 |只看该作者
回复 5# SCDXMOE
如果是频繁的申请(比如每当有数据包到来都会申请),那么最好不要用kmalloc函数。
个人建议的方法:
协议栈初始化的时候,创建一个slab高速缓存,使用的时候从这个专有的slab中分配,而不是通过kmalloc从通用slab高速缓存中分配。

   
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP