Hi, i have a problem with vmalloc() and vm_ops.page_mkwrite().
ReadOnly access works, but on a write access the VM will endless invoke the vm_ops.page_mkwrite() handler. I tracked down the problem to the struct page.mapping pointer, which is NULL. The problem original occurs with the fb_defio driver (driver/video/fb_defio.c). This driver use the vm_ops.page_mkwrite() handler for tracking the modified pages, which will be in an extra thread handled, to perform the IO and clean and write protect all pages with page_clean(). I am not sure if the is a feature of the new rmap code or a bug. Is there an way to get a similar functionality? Currently, i have no idea how to get the ptep from a page alloced with vmalloc(). Greetings, Stefani Here is a small sample driver: #include <linux/module.h> #include <linux/errno.h> #include <linux/string.h> #include <linux/mm.h> #include <linux/vmalloc.h> #include <linux/fs.h> #define DEVICE_NAME "mydrv" #define DEVICE_MAJOR 240 static u8 *mydrv_memory; static const u_long mydrv_memory_size=1024*1024; // 1 Megabyte #ifdef MODULE static u_long vmas=0; #endif static void mydrv_vma_open(struct vm_area_struct *vma) { #ifdef MODULE if (vmas++==0) try_module_get(THIS_MODULE); #endif } static void mydrv_vma_close(struct vm_area_struct *vma) { #ifdef MODULE if (--vmas==0) module_put(THIS_MODULE); #endif } struct page *mydrv_vma_nopage(struct vm_area_struct *vma,unsigned long address,int *type) { unsigned long offset; struct page *page; offset = (address - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT); printk("--> mydrv_vma_nopage:%lu(%08lx)\n",offset,offset); if (offset >= mydrv_memory_size) return NOPAGE_SIGBUS; page = vmalloc_to_page(mydrv_memory + offset); if (!page) return NOPAGE_OOM; get_page(page); if (type) *type = VM_FAULT_MINOR; return page; } int mydrv_mkwrite(struct vm_area_struct *vma,struct page *page) { printk("--> mydrv_mkwrite:%p\n",page->mapping); return 0; } struct vm_operations_struct mydrv_vm_ops = { .open = mydrv_vma_open, .close = mydrv_vma_close, .nopage = mydrv_vma_nopage, .page_mkwrite = mydrv_mkwrite, }; static int mydrv_mmap(struct file *file, struct vm_area_struct *vma) { vma->vm_ops = &mydrv_vm_ops; vma->vm_flags |= ( VM_IO | VM_RESERVED | VM_DONTEXPAND ); vma->vm_private_data = 0; mydrv_vma_open(vma); return 0; } int mydrv_open(struct inode *inode, struct file *file) { int minor; minor=MINOR(file->f_dentry->d_inode->i_rdev); printk("--> mydrv_open called for minor: %d\n", minor); if (minor>0) { printk("--> mydrv_open minor %d failed\n",minor); return -ENODEV; } printk("--> mydrv_open o.K.\n"); return 0; } int mydrv_close(struct inode *inode, struct file *file) { int minor; minor=MINOR(file->f_dentry->d_inode->i_rdev); printk("--> mydrv_close for minor: %d\n", minor); return 0; } struct file_operations mydrv_fops = { .owner=THIS_MODULE, .mmap=mydrv_mmap, .open=mydrv_open, .release=mydrv_close, }; int init_module(void) { printk("--> init_module called\n"); if (!(mydrv_memory = vmalloc(mydrv_memory_size))) return -ENOMEM; if (register_chrdev(DEVICE_MAJOR, DEVICE_NAME, &mydrv_fops) < 0) { printk("--> Error registering driver.\n"); return -ENODEV; } memset(mydrv_memory, 0, mydrv_memory_size); printk("--> init_module done\n"); return 0; } void cleanup_module(void) { printk("--> cleanup_module called\n"); unregister_chrdev(DEVICE_MAJOR,DEVICE_NAME); vfree(mydrv_memory); printk("--> cleanup_module done\n"); } MODULE_LICENSE("GPL"); MODULE_AUTHOR("Stefan Seibold <[EMAIL PROTECTED]>"); MODULE_DESCRIPTION("Test Driver"); - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/