假设使用基于页面的方案分配缓冲区。一种实现mmap的方法是使用remap_pfn_range,但LDD3表示这不适用于常规内存。看来我们可以通过使用SetPageReserved标记保留的页面来解决此问题,以便将其锁定在内存中。但是,不是所有内核内存都已经不可交换,即已经保留了吗?为什么需要显式设置保留位?
这与从HIGH_MEM分配的页面有关吗?
使用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参数。
my_mmap
然后vm_ops看起来像:
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是一个稍微有趣的功能名称]
my_fault