如何将Linux内核缓冲区映射到用户空间?

时间:2012-05-25 19:42:31

标签: linux linux-kernel linux-device-driver

假设缓冲区是使用基于页面的方案分配的。实现mmap的一种方法是使用remap_pfn_range,但LDD3表示这对常规内存不起作用。看来我们可以通过使用SetPageReserved标记保留的页面来解决这个问题,以便它被锁定在内存中。但是并非所有内核内存都已经不可交换,即已经保留了吗?为什么需要明确设置保留位?

这是否与从HIGH_MEM分配的页面有关?

2 个答案:

答案 0 :(得分:19)

在mmap方法中从内核映射一组页面的最简单方法是使用错误处理程序映射页面。基本上你最终得到的结论是:

static int my_mmap(struct file *filp, struct vm_area_struct *vma)
{
    vma->vm_ops = &my_vm_ops;
    return 0;
}

static const struct file_operations my_fops = {
    .owner  = THIS_MODULE,
    .open   = nonseekable_open,
    .mmap   = my_mmap,
    .llseek = no_llseek,
};

(其他文件操作是模块需要的任何操作)。同样在my_mmap中,您需要进行任何范围检查等以验证mmap参数。

然后vm_ops看起来像:

static int my_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
    vmf->page = my_page_at_index(vmf->pgoff);
    get_page(vmf->page);

    return 0;
} 

static const struct vm_operations_struct my_vm_ops = {
    .fault      = my_fault
}

您只需要确定传递给您的故障函数的给定vma / vmf哪个页面映射到用户空间。这取决于模块的确切工作方式。例如,如果你做了

my_buf = vmalloc_user(MY_BUF_SIZE);

然后您使用的页面就像

vmalloc_to_page(my_buf + (vmf->pgoff << PAGE_SHIFT));

但是你可以轻松地创建一个数组并为每个条目分配一个页面,使用kmalloc,无论如何。

[只是注意到my_fault是一个稍微有趣的功能名称]

答案 1 :(得分:0)

虽然页面是通过内核驱动程序保留的,但它是通过用户空间访问的。因此,PTE(页表条目)不知道pfn是属于用户空间还是内核空间(即使它们是通过内核驱动程序分配的)。

这就是为什么它们标有SetPageReserved