mmap:在用户空间中映射用 kmalloc 分配的内核缓冲区
在用户空间进程中映射用 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)。一切正常,但我认为这段代码有问题:
kmalloc
可能返回一个未页面对齐的指针,在这种情况下,我认为以下值不正确remap_pfn_range
的第三个参数实际上在用户空间中我读取了错误的值。相反,如果我使用 __get_free_page (因为该函数总是返回一个页面对齐的指针)或者当kmalloc
返回一个页面对齐的指针时,所有的工作都会起作用。内存映射适用于多个PAGE_SIZE
的内存区域,因此,我应该分配整个页面而不是使用kmalloc
吗?当调用
my_mmap
时,内核已经分配了一些页面吗?我问这个是因为我发现了一些自定义mmap
方法的实现,这些方法调用remap_pfn_range
并使用vma->vm_pgoff
作为第三个参数......怎么可能这个有用吗?这是第一个新分配的页面的页框吗?如果我像在my_mmap
中那样将页面框架作为第三个参数传递,我应该释放从vma->vm_pgoff
中的页面开始的页面吗?但是我发现了
mmap
方法的实现,该方法映射使用kmalloc
分配的缓冲区。为了正确映射缓冲区,在remap_pfn_range
之前执行一个操作(我现在不明白)。假设mem
是kmalloc
返回的指针,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:
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 ofremap_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 whenkmalloc
returns a page aligned pointer. Memory mapping works with memory regions that are multple ofPAGE_SIZE
so, should i allocate an entire page instead of usingkmalloc
?When
my_mmap
is called, the kernel has allocated some pages yet? I ask this because i found some implementations of custommmap
method that callremap_pfn_range
withvma->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 inmy_mmap
, i should free pages starting from page invma->vm_pgoff
?However i found an implementation of
mmap
method that maps a buffer allocated withkmalloc
. To correctly map the buffer an operation (that i don't undestand for now) is performed beforeremap_pfn_range
. Suppose thatmem
is the pointer returned bykmalloc
,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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
是的,您应该分配整数页。
不,内核尚未分配任何页面。
vm->vm_pgoff
是所映射设备内请求的偏移量 - 它是用户空间mmap()
调用的最后一个参数,从字节转换为页。 偏移量表示用户空间想要映射的物理或线性页面。这只是在
kmalloc()
分配的缓冲区内分配一个页面对齐的缓冲区。您最好使用__get_free_pages()
正如您已经猜测的那样,省掉中间人。您应该测试映射的大小是否不超过您的缓冲区。
Yes, you should be allocating a whole number of pages.
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 userspacemmap()
call, translated from bytes to pages. You're probably looking at themem
orkmem
mmap implementations, in which case the offset represents the physical or linear page that userspace wants to map.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.