I'm trying to implement a fault handler to map memory allocated
with __get_free_pages() to userspace. In module init, I'm allocating
64k by calling __get_free_pages(GFP_KERNEL, get_order(size)), where
size = 64 << 10.
I've also added an ioctl so that userspace can obtain the size and
virtual address of allocated block, to for example mmap() a smaller
portion of the allocated memory, like so:
void *p = mmap(0, size / 2, PROT_READ | PROT_WRITE, MAP_SHARED,
fd, addr + size / 2);
Mmap is implemented as follows:
int my_mmap(struct file *filp, struct vm_area_struct *vma)
{
vma->vm_ops
= &my_vm_ops;
return
0;
}
and the fault handler like this:
int my_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
vmf->page
= virt_to_page(vmf->pgoff << PAGE_SHIFT);
get_page(vmf->page);
return
0;
}
This seems to work, mmap returns virtual address and memory can be
read & written without problems.
However, when I unload the module, there's an error due to bad
page state when calling free_pages() to free the memory:
BUG: Bad page state in process rmmod pfn:01648 page:c102c900 flags:40040000 count:0 mapcount:0 mapping:(null) index:0 (Not tainted) Pid: 2412, comm: rmmod Not tainted 2.6.29.3-140.fc11.i586 #1 Call Trace: [<c047c727>] bad_page+0xdf/0xf4 [<c047cdef>] free_pages_check+0xac/0xc9 [<c047ce3e>] __free_pages_ok+0x32/0x13b [<c047d352>] __free_pages+0x23/0x25 [<c047d376>] free_pages+0x22/0x24 [<d081a124>] my_exit+0x78/0x7a [my_mod] [<c044fc90>] sys_delete_module+0x17b/0x1cd [<c046587f>] ? audit_syscall_entry+0x163/0x185 [<c0403f72>] syscall_call+0x7/0xb So what's special about doing allocation by __get_free_pages()? If
I use vmalloc() & vfree() and call vmalloc_to_page() in fault
handler instead of virt_to_page(), it works just fine.
|