vm_insert_page()和remap_pfn_range()有何不同?

5
我想通过使用ioremap_wc() 将设备内存(NIC)映射到内核空间内存区域。然后,我想将内存区域从内核空间重新映射到用户空间,并且我可以使用以下两个函数: vm_insert_page()remap_pfn_range() 通常情况下,POSIX的mmap(3) 使用第二个函数:remap_pfn_range() 那么,vm_insert_page()remap_pfn_range() 有什么区别?在什么情况下需要使用vm_insert_page() 而不是 remap_pfn_range()
3个回答

4
正如它们的名称所示,vm_insert_page() 映射一个单页,而 remap_pfn_range() 则映射一块连续的内核内存。请查看原型和注释:vm_insert_pageremap_pfn_range
例如,您可以使用 vm_insert_page 来映射 vmalloc 区域。
do {
    page = vmalloc_to_page(vaddr);
    vm_insert_page(vma, uaddr, page);
    vaddr += PAGE_SIZE;
} while(/* there is something to map */);

使用remap_pfn_range是不可能的,因为它只映射一连续块的内核内存。

另一个区别是,使用remap_pfn_range不仅可以映射RAM缓冲区,还可以映射其他范围。而使用vm_inser_page只能映射RAM缓冲区。

来自Linus的解释


谢谢!这是否意味着我不能使用vm_inser_page将设备内存(NIC)区域从内核空间重新映射到用户空间,因为“使用vm_inser_page只能映射RAM缓冲区”? - Alex
1
确切地说,您只能使用“vm_insert_page”将“page”映射到虚拟内存。 - Federico
我正在尝试在驱动程序的mmap()函数中使用remap_pfn_range()重新映射使用kzalloc_node()分配的内存,并在close函数中使用kfree()释放内存。然而,我的系统在一段时间后崩溃,崩溃跟踪指向kmem_cache_alloc。我想知道可能出了什么问题,以及如何进一步调试。请帮忙。 - sham1810

4

vm_insert_page()函数允许驱动程序将其分配的单个页面插入到用户vma中。页面必须在内核中进行独立分配。它要求页面是为此目的获取的零级分配 order-zero allocation。它不会发出警告,并且不需要设置PG_reserved。

传统上,这是通过 remap_pfn_range() 来完成的,它接受任意页面保护参数。 vm_insert_page() 不允许使用该方法。您的 vma 保护必须正确设置,这意味着如果您想要一个共享可写映射,则最好请求一个共享可写映射!

remap_pfn_range()用于将一组页面映射或重新映射到内存中。

参考链接


谢谢!这句话的意思是,如果你想要一个共享的可写映射,最好请求一个共享的可写映射!那么这是否意味着在我的情况下我必须使用remap_pfn_range()函数,将设备内存(NIC)区域从内核空间重新映射到用户空间? - Alex

2
总结:
当您不需要使用 struct page 时,可以使用 remap_pfn_range 来操作物理页框。如果给定的内存是保留内存,它还将构建页表。 对于需要使用struct page 的内存的物理页帧,请使用 vm_insert_page。 (请注意,还有一个名为vm_insert_pages的函数,它可以将多个页面插入到 VMA 中。)
对于该区域的直接 I/O,请使用 vm_insert_page/vm_insert_pages,因为它们支持 get_user_page 来获取 struct page,这对于后续的 ext4/scatterlist 代码是必要的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接