mmap:在用户空间中映射一个用kmalloc分配的内核缓冲区

Mir*_*chi 11 linux mmap linux-device-driver linux-kernel

在用户空间进程中映射使用kmalloc分配的缓冲区的正确方法是什么?也许我还没有理解内存映射......我编写了一个内核模块来分配这个缓冲区(例如120字节),我会在用户空间进程中读取和写入它.显然我创建了一个char设备并mmapfile_operationsstruct中实现了一个方法.我的方法是:

static int my_mmap(struct file *filp, struct vm_area_struct *vma)
{
  //printk(KERN_INFO "Allocated virtual memory length = %d", vma->vm_end - vma->vm_start);

  long unsigned int size = vma->vm_end - vma->vm_start;

  if (remap_pfn_range(vma, vma->vm_start,
                      __pa(mem_area) >> PAGE_SHIFT,  //what about vma->vm_pgoff?
                      size,
                      vma->vm_page_prot) < 0)
    return -EAGAIN;

  vma->vm_flags |= VM_LOCKED;
  vma->vm_ops = &vmops;
  vma->vm_flags |= VM_RESERVED;

  my_vm_open(vma);

  return 0;
}
Run Code Online (Sandbox Code Playgroud)

其中,mem_area在与分配的内存区域指向kmalloc在模块初始化.该区域填充相同的值(例如0x10).一切正常,但我认为这段代码有问题:

  1. kmalloc可以返回一个非页面对齐的指针,在这种情况下,我认为不正确的第三个参数的值remap_pfn_range实际上在用户空间中我读错了值.相反,如果我使用__get_free_page(因为该函数总是返回kmalloc页面对齐的指针)或返回页面对齐指针时所有工作.内存映射适用于多个内存区域PAGE_SIZE,如果我分配整个页面而不是使用kmalloc

  2. 什么时候my_mmap调用,内核已经分配了一些页面呢?我问这个,因为我发现定制的一些实现mmap调用方法remap_pfn_rangevma->vm_pgoff作为第三个参数...怎么可能是有用的呢?这是第一个新分配页面的页面框架吗?如果我作为第三个参数传递一个像我一样的页面框架my_mmap,我应该从页面开始释放页面vma->vm_pgoff

  3. 但是我找到了一个mmap映射分配的缓冲区的方法的实现kmalloc.为了正确映射缓冲区,之前执行了一个操作(我现在没有看不到)remap_pfn_range.假设mem是返回的指针kmalloc,mem_area以这种方式初始化:

    mem_area=(int *)(((unsigned long)mem + PAGE_SIZE - 1) & PAGE_MASK);
    
    Run Code Online (Sandbox Code Playgroud)

因此mem_area,mem仅当mem页面对齐时才包含相同的值,否则应包含下一页开头的指针.但是,如果我通过此操作,remap_pfn_range则值__pa(mem_area) >> PAGE_SHIFT映射的第三个参数效果很好.为什么?

谢谢你们!

caf*_*caf 6

  1. 是的,您应该分配一定数量的页面.

  2. 不,内核没有分配任何页面. vm->vm_pgoff是被映射的设备中请求的偏移量 - 它是用户空间mmap()调用的最后一个参数,从字节转换为页面.您可能正在查看memkmemmmap实现,在这种情况下,offset表示用户空间要映射的物理或线性页面.

  3. 这只是在kmalloc()分配的缓冲区中分配页面对齐的缓冲区.你__get_free_pages()已经猜测过你最好不要使用,切断了中间人.

您应该测试所映射的大小是否超过您的缓冲区.