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.