Hello, I am trying to implement a simple character device that implements the mmap() method (struct file_operations). I can't get it work, the source code is appended. This is the scenario: The kernel module, that implements the device, allocates a page from the high memory zone upon insmod. The page is freed upon rmmod. The mmap() method implementation uses the nopage() approach (as described in LDD3 Ch15). I understand it in a way, that the mmap() method just sets up the nopage() method to be called when the process first accesses the mmapped memory. The nopage() method is supposed to provide the actual page to satisfy the request. In my scenario, I want to use the page allocated at insmod time. That's what the code (hopefully) does. The problem is that the user space process segfaults, when it tries to access the mmapped memory. It also seems to me that the nopage() method is not called. I am obviously doing something wrong but I have a hard time figuring it out. This is the source code of the character device implementation: // Linux Kernel 2.6.12.2 #include <linux/kernel.h> #include <linux/module.h> #include <linux/fs.h> #include <asm/page.h> #include <linux/gfp.h> #include <linux/string.h> #include <linux/cdev.h> #include <linux/mm.h> #define FIRST_MINOR 0 #define MINOR_COUNT 1 #define DEVICE_NAME "mmap" static dev_t device_number; static struct cdev device; static unsigned long page; static int open_fop(struct inode *, struct file *); static int release_fop(struct inode *, struct file *); static int mmap_fop(struct file *, struct vm_area_struct *); static struct file_operations fops= { owner:THIS_MODULE, open:open_fop, release:release_fop, mmap:mmap_fop, }; static void open_vm_op(struct vm_area_struct *area); static void close_vm_op(struct vm_area_struct *area); struct page* nopage_vm_op(struct vm_area_struct *area, unsigned long address, int *type); static struct vm_operations_struct vm_ops= { open:open_vm_op, close:close_vm_op, nopage:nopage_vm_op, }; static int __init init(void) { int ret; if(!(page=__get_free_page(GFP_HIGHUSER))){ ret=-ENOMEM; goto out; } memset((char*)page, 0, PAGE_SIZE); if((ret=alloc_chrdev_region(&device_number, FIRST_MINOR, MINOR_COUNT, DEVICE_NAME))<0) goto err1; cdev_init(&device, &fops); if((ret=cdev_add(&device, device_number, MINOR_COUNT))<0) goto err2; out: return ret; err2: unregister_chrdev_region(device_number, MINOR_COUNT); err1: free_page(page); goto out; } static void __exit exit(void) { cdev_del(&device); unregister_chrdev_region(device_number, MINOR_COUNT); free_page(page); } module_init(init); module_exit(exit); MODULE_LICENSE("GPL"); static int open_fop(struct inode *inode, struct file *file) { printk(KERN_NOTICE "open()\n"); try_module_get(THIS_MODULE); return 0; } static int release_fop(struct inode *inode, struct file *file) { printk(KERN_NOTICE "release()\n"); module_put(THIS_MODULE); return 0; } static int mmap_fop(struct file *file, struct vm_area_struct *vma) { int size=vma->vm_end-vma->vm_start; printk(KERN_NOTICE "mmap()\n"); if(size>PAGE_SIZE){ printk(KERN_ERR "bad size (%d)\n", size); return -EINVAL; } if(vma->vm_pgoff!=0){ printk(KERN_ERR "bad offset (%lu)\n", vma->vm_pgoff); return -EINVAL; } vma->vm_flags=VM_RESERVED; vma->vm_ops=&vm_ops; return 0; } static void open_vm_op(struct vm_area_struct *area) { printk(KERN_NOTICE "open_vm()\n"); } static void close_vm_op(struct vm_area_struct *area) { printk(KERN_NOTICE "close_vm()\n"); } // Does not seem to be called when the user space process // tries to access the mmap-ed memory. struct page* nopage_vm_op(struct vm_area_struct *area, unsigned long address, int *type) { struct page *ret; printk("nopage_vm(%lu)\n", address); ret=pfn_to_page(__pa(page)>>PAGE_SHIFT); get_page(ret); if(type) *type=VM_FAULT_MINOR; return ret; } This is the source code of the program that maps the memory: #include <assert.h> #include <errno.h> #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <sys/mman.h> #define START 0 #define LENGTH 4096 // man 2 getpagesize #define PROTECTION ( PROT_READ | PROT_WRITE ) #define FLAGS MAP_SHARED #define OFFSET 0 #define COUNT 128 int main(int argc, char *argv[]) { // mknod mmap c 253 0 char *device="mmap"; volatile int *shp; int sh; void *mem; int fd; int it; if(argc==2) device=argv[1]; fd=open(device, O_RDWR); assert(fd!=-1); mem=mmap(START, LENGTH, PROTECTION, FLAGS, fd, OFFSET); if(mem==(void*)-1){ perror("mmap"); assert(0); } printf("pid(%d)\n", getpid()); // sleep(10); it=COUNT; shp=(int*)mem; while(it--){ // Segmentation fault here. sh=*shp; printf("read(%d), write(%d)\n", sh, ++sh); *shp=sh; sleep(1); } munmap(mem, LENGTH); return 0; } The output of the program: pid(12270) Segmentation fault The output of the dmesg: open() mmap() close_vm() release() BlackHole -- To unsubscribe from this list: send an email with "unsubscribe kernelnewbies" to ecartis@xxxxxxxxxxxx Please read the FAQ at http://kernelnewbies.org/FAQ