前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >vmalloc与mmap

vmalloc与mmap

作者头像
刘盼
发布2019-05-17 15:48:46
1.9K0
发布2019-05-17 15:48:46
举报
文章被收录于专栏:人人都是极客人人都是极客

mmap()系统调用是在用户进程与内核之间共享内存区域的常用方法。我们最近有个程序,需要应用进程能够读取内核驱动获取的数据,经过简单的调研,决定采用mmap方式。实现起来不难,在驱动中注册一个字符设备,实现该设备的mmap()方法即可。但这其中有一点小曲折。

在实现设备的mmap()方法时,需要将物理内存映射到应用程序通过mmap()系统调用传下来的vma中。vma代表的是进程的一段虚拟地址空间。在第一版里,考虑的不全面,利用alloc_pages()将整个内存段申请为一段连续的物理地址空间。然后通过remap_pfn_range()函数将这段连续的物理内存映射到vma中。经过长时间的测试,没有发现问题。直到今天,在部署一个老集群时,遇到了问题。这个集群中有很多老机器,内存只有十多个G,而且长时间运行后产生了大量的内存碎片。从而导致,我们无法获得足够的连续物理内存。没办法,只好重新调整驱动中分配内存的方式,改用vmalloc获取地址空间。

 在kernel里,通常有3种申请内存的方式:vmalloc, kmalloc, alloc_pages。kmalloc与alloc_pages类似,均是申请连续的地址空间。而vmalloc则可以申请一段不连续的物理地址空间,并将其映射到连续的线性地址上。每次vmalloc之后,内核会创建一个vm_struct,用以映射分配到的不连续的内存区域。vm_struct类似vma,但是又不是一回事。vma是将物理内存映射到进程的虚拟地址空间。而vm_struct是将物理内存映射到内核的线性地址空间。  

既然vmalloc拿到的不是连续的物理内存,那么将这些内存映射到vma时,就不能直接利用remap_pfn_range()了。

此时可以采用两种方法,一种是实现vm_operations_struct的fault()方法,用以在缺页时再映射需要的页。此方法操作起来较为麻烦。

另一种方法是直接使用remap_vmalloc_range()函数。该函数的原型为:

int remap_vmalloc_range(struct vm_area_struct *vma, void *addr, unsigned long pgoff)

其中参数vma是mmap使用调用传下来的,addr即为vmalloc()所分配内存的起始地址。而pgoff则为mmap()系统调用里的偏移参数,可以通过vma->vm_pgoff获得。该函数成功执行后,返回值为0。如果返回值为负数,则说明出错了。通常是由于所传的参数不正确。

  需要注意的是,需要映射到用户空间的内存段,不能直接利用vmalloc()分配,而应该使用vmalloc_user()函数。该函数除了分配内存之外,还会将相应的vm_struct结构标记为VM_USERMAP。否则,remap_vmalloc_range将返回错误。

  在这个项目中碰到的教训是,永远不要假设系统中一定会有超过一个页的连续物理内存。

  不过较新的内核具有compact机制,可以整理内存碎片。但是,目前至少有一大部分机器不支持,或未开启此机制。

【来源:https://blog.csdn.net/arethe_qin/article/details/18673583 】

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-04-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 人人都是极客 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档