Linux驱动程序:不使用nopage将mmap()内核缓冲区映射到用户空间 [英] Linux Driver: mmap() kernel buffer to userspace without using nopage
问题描述
我正在为一个数据采集设备实现一个Linux设备驱动程序,它不断地将数据流入我在内核中分配的循环缓冲区(使用__get_free_pages()
)。循环缓冲区(由PCIe硬件写入)驻留在RAM中,我希望用户空间能够mmap()该RAM区域,以便用户空间可以读取其内容。
根据LDD3:
remap_pfn_range的一个有趣的限制是,它只允许访问保留的页和物理内存顶部以上的物理地址。 ..。 因此,REMAP_PFN_RANGE不允许您重新映射常规地址,其中包括通过调用GET_FREE_PAGE获得的地址。 ..。 将实际RAM映射到用户空间的方法是使用
vm_ops->nopage
一次处理一个页面错误。
在我的例子中,我确切地知道在调用mmap()
的时刻需要将哪些地址映射到整个缓冲区的给定VMA位置,那么为什么我必须在访问页面时使用nopage()
方法,每次一个页面出错?
我还预计用户空间程序将按顺序访问我的缓冲区,这会在每次跨越页面边界时调用nopage()
函数时导致性能损失。这在实践中是否会对性能造成相当大的影响?(我的缓冲区很大,比如16 MB。)
(值得注意的是,我在以前的一个设备驱动程序中使用过从__get_free_pages()
返回的内存中的remap_pfn_range()
,从未出现过任何问题,但我可能只是在该系统上走运。)
推荐答案
进一步研究后,根据LWN:
,看起来LDD3的声明已经过时- http://lwn.net/Articles/162860/--"驱动程序页面重新映射的演变"
TL;DR:过去,驱动程序可能会在kmalloc()
/__get_free_pages()
分配的页面上手动设置PG_reserved
,然后使用remap_pfn_range()
,,但现在驱动程序应该使用vm_insert_page()
来执行相同的操作。
vm_insert_page()
显然仅适用于0阶(单页)分配,因此如果要分配N个页面,则必须调用vm_insert_page()
N次。
在Firewire驱动程序中可以看到这种用法的示例:drivers/firewire/core-iso.c
fw_iso_buffer_alloc()
中的alloc_page()
来分配单个页面,然后通过重复调用fw_iso_buffer_map_vma()
中的vm_insert_page()
将这些页面映射到用户空间VMA中。(fw_iso_Buffer_map_vma()由drivers/firewire/core-cdev.c
中的mmap处理程序调用。)
这篇关于Linux驱动程序:不使用nopage将mmap()内核缓冲区映射到用户空间的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!