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

发布于 2024-11-28 15:27:09 字数 2070 浏览 1 评论 0原文

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

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

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

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

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

  3. 但是我发现了 mmap 方法的实现,该方法映射使用 kmalloc 分配的缓冲区。为了正确映射缓冲区,在 remap_pfn_range 之前执行一个操作(我现在不明白)。假设memkmalloc返回的指针,mem_area的初始化方式如下:

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

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

谢谢大家!

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 mmap method in the file_operations struct. My method is:

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_area points at a memory area allocated with kmalloc at 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:

  1. kmalloc could 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_range in 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 kmalloc returns a page aligned pointer. Memory mapping works with memory regions that are multple of PAGE_SIZE so, should i allocate an entire page instead of using kmalloc?

  2. When my_mmap is called, the kernel has allocated some pages yet? I ask this because i found some implementations of custom mmap method that call remap_pfn_range with vma->vm_pgoff as 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 mmap method 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 mem is the pointer returned by kmalloc, mem_area is initialized in this manner:

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

So mem_area contains the same value of mem only if mem is 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_range the value __pa(mem_area) >> PAGE_SHIFT mapping works well. Why?

Thank you all!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

霞映澄塘 2024-12-05 15:27:09
  1. 是的,您应该分配整数页。

  2. 不,内核尚未分配任何页面。 vm->vm_pgoff 是所映射设备内请求的偏移量 - 它是用户空间 mmap() 调用的最后一个参数,从字节转换为页。 偏移量表示用户空间想要映射的物理或线性页面。

  3. 这只是在 kmalloc() 分配的缓冲区内分配一个页面对齐的缓冲区。您最好使用 __get_free_pages() 正如您已经猜测的那样,省掉中间人。

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

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

  2. No, the kernel hasn't allocated any pages. vm->vm_pgoff is 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 mem or kmem mmap 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.

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文