Linux mmap:在用户空间映射使用 kmalloc 分配的内核缓冲区

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6967933/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-05 05:32:41  来源:igfitidea点击:

mmap: mapping in user space a kernel buffer allocated with kmalloc

linuxlinux-kernellinux-device-drivermmap

提问by MirkoBanchi

Which is the correct way to map in an user space process a buffer allocated with kmalloc? Maybe i didn't understand memory mapping yet...I write a kernel module that allocs this buffer (for example 120 bytes) and i would read and write it in a user-space process. Obviously i created a char device and implemented a mmapmethod in the file_operationsstruct. My method is:

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

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;
}

where mem_areapoints at a memory area allocated with kmallocat module init. The area is filled with the same value (for example 0x10). All works but i think there is something wrong in this code:

wheremem_area指向用kmallocat 模块 init分配的内存区域。该区域填充有相同的值(例如 0x10)。一切正常,但我认为这段代码有问题:

  1. kmalloccould return a pointer that isn't page aligned and, in that case, i don't think is correct the value of the third parameter of remap_pfn_rangein fact in user space i read the wrong value. Instead all works if i use __get_free_page(because the the function always returns a pointer that is page aligned) or when kmallocreturns a page aligned pointer. Memory mapping works with memory regions that are multple of PAGE_SIZEso, should i allocate an entire page instead of using kmalloc?

  2. When my_mmapis called, the kernel has allocated some pages yet? I ask this because i found some implementations of custom mmapmethod that call remap_pfn_rangewith vma->vm_pgoffas third parameter...how could be useful this? Is this the page frame of the first new allocated page? If i pass as third parameter a page frame like i do in my_mmap, i should free pages starting from page in vma->vm_pgoff?

  3. However i found an implementation of mmapmethod that maps a buffer allocated with kmalloc. To correctly map the buffer an operation (that i don't undestand for now) is performed before remap_pfn_range. Suppose that memis the pointer returned by kmalloc, mem_areais initialized in this manner:

    mem_area=(int *)(((unsigned long)mem + PAGE_SIZE - 1) & PAGE_MASK);
    
  1. kmalloc可能会返回一个不是页面对齐的指针,在这种情况下,我认为remap_pfn_range实际上在用户空间中我读取了错误的值的第三个参数的值是不正确的。相反,如果我使用__get_free_page(因为该函数总是kmalloc返回一个页面对齐的指针)或者当返回一个页面对齐的指针时,所有的工作。内存映射适用于多个这样的内存区域,PAGE_SIZE我应该分配整个页面而不是使用kmalloc吗?

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

  3. 但是我找到了一个mmap方法的实现,它映射了一个分配有kmalloc. 为了正确映射缓冲区,在remap_pfn_range. 假设mem是通过返回的指针kmallocmem_area以这种方式被初始化:

    mem_area=(int *)(((unsigned long)mem + PAGE_SIZE - 1) & PAGE_MASK);
    

So mem_areacontains the same value of memonly if memis page aligned otherwise is should contain the pointer at the beginning of the next page. However, with this operation if i pass as third param of remap_pfn_rangethe value __pa(mem_area) >> PAGE_SHIFTmapping works well. Why?

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

Thank you all!

谢谢你们!

回答by caf

  1. Yes, you should be allocating a whole number of pages.

  2. No, the kernel hasn't allocated any pages. vm->vm_pgoffis the requested offset within the device being mapped - it's the last parameter to the userspace mmap()call, translated from bytes to pages. You're probably looking at the memor kmemmmap implementations, in which case the offset represents the physical or linear page that userspace wants to map.

  3. That is just allocating a page-aligned buffer within the kmalloc()allocated buffer. You're better off using __get_free_pages()as you've already surmised, cutting out the middle-man.

  1. 是的,您应该分配整数页。

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

  3. 这只是在kmalloc()分配的缓冲区中分配一个页面对齐的缓冲区。你最好使用__get_free_pages()你已经猜到的,去掉中间人。

You should be testing that the size being mapped does not exceed your buffer.

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