Chinaunix

标题: 高手指点mmap实现问题 [打印本页]

作者: bin_linux96    时间: 2011-12-02 08:52
标题: 高手指点mmap实现问题
自己写了一个虚拟的字符设备/dev/test ,字符设备在内核中为一块内存(用kmalloc),
我想实现的功能是:先通过mmap函数把设备文件映射到用户空间,然后通过strncpy函数向设备写入数据,然后再通过read去读我写入的数据。
我的问题是:在用户空间中如设置mmap的参数:offset = 0;可以正常实现功能,也就是可以用read读出来,而当offset = 1024*4(4k倍数)时不能实现我想要的结果(用read读不出用strncpy写入的数据)。其他file_operations函数功能都可正常实现。

几个函数的原型如下
系统调用mmap : void *mmap(void *start, size_t length, int prot, int flags,int fd, off_t offset);

内核中mmap:int (*mmap)(struct file *filpstruct vm_area_struct *vma) ;

                      int remap_pfn_range(struct vm_area_struct *vma,unsigned long virt,unsigned long pfn,unsigned long size,pgprot_t prot)

用户空间测试代码如下:
  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. #include<sys/types.h>
  4. #include<sys/stat.h>
  5. #include<fcntl.h>
  6. #include<sys/mman.h>
  7. #include<string.h>

  8. #define MAP_SIZE 1024*4*10
  9. #define OFF_SET 1024*4
  10. int main(void )
  11. {
  12.     int ret,fd ,new_fd ;
  13.     int totalSize = 0 ;
  14.     char cArray [512] = "22221111111111,2,3,4,5,6,7,8,9,a,b,c,d,e,f" ;
  15.     char output [512] = {0} ;
  16.     void * vir_addr = NULL ;

  17.     fd = open("/dev/test",O_RDWR);
  18.     if( fd<=0 ){
  19.         printf("open file error \n");
  20.         return -1 ;
  21.     }

  22.     vir_addr = mmap(NULL,MAP_SIZE,PROT_READ|PROT_WRITE,MAP_SHARED,fd,OFF_SET);
  23.     if(NULL==vir_addr){
  24.         printf("mmap error !!!\n");
  25.         return -1 ;
  26.     }
  27.     printf("vir_addr = 0x%x \n",vir_addr);
  28.     strncpy(vir_addr,cArray,512);
  29.     lseek(fd,OFF_SET,SEEK_SET) [color=Red];//当OFF_SET 是4k的倍数时,不管要不要此句都不行。[/color]   
  30.    int i = 0 ,c;
  31.     for(i = 0;i<50;i++){
  32.     read(fd,&c,1);
  33.     printf("read result = %c\n",c);

  34.     }

  35.     close(new_fd) ;
  36.     return 0;
  37. }
复制代码
内核空间代码:
  1. #include<linux/kernel.h>
  2. #include<linux/init.h>
  3. #include<linux/module.h>
  4. //#include<linux/sched.h>
  5. #include<linux/fs.h>
  6. #include<linux/types.h>
  7. #include<linux/kdev_t.h>
  8. #include<linux/cdev.h>
  9. #include<asm/uaccess.h>
  10. #include<linux/slab.h>
  11. #include<linux/mm.h>

  12. #if 1
  13. #define dprintk(fmt,args...) \
  14.     printk("Dbg->%s_%d:"fmt,__FUNCTION__,__LINE__,##args)
  15. #else
  16. #define dprintk(fmt,args...)
  17. #endif

  18. #define eprintk(fmt,args...) \
  19.     printk("Err->%s_%d:"fmt,__FUNCTION__,__LINE__,##args)

  20. static int gMajor = 0 ;
  21. static int gMinor = 0 ;
  22. module_param(gMajor,int,0);

  23. #define DEVICE "test"

  24. struct cdev * my_cdev = NULL ;

  25. #define KMALLOC_SIZE 1024*80

  26. int test_open(struct inode *inode,struct file *filp)
  27. {
  28.     struct cdev * pdev = NULL ;
  29.     int major = 0 ;
  30.     filp->private_data = kmalloc(KMALLOC_SIZE,GFP_KERNEL) ;
  31.     if(filp->private_data==NULL){
  32.         printk("test_open error !!!\n");
  33.         return -1 ;
  34.     }
  35.     if(inode->i_cdev)pdev= inode->i_cdev ;
  36.     major = MAJOR(pdev->dev) ;
  37.     dprintk("major = %d \n",major) ;
  38.     return 0;

  39. }

  40. int test_release(struct inode *inode ,struct file *filp)
  41. {
  42.     if(filp->private_data)kfree(filp->private_data);
  43.     dprintk("\n");
  44.     return 0;
  45. }

  46. ssize_t test_read(struct file *filp,char __user *buffer,size_t count,loff_t *offp)
  47. {
  48.     int ret = -1 ;
  49.     dprintk("the file position *offp = %lld,file pos =%lld\n",(long long)(*offp),(long long)filp->f_pos);
  50.     if(count +*offp>KMALLOC_SIZE){
  51.        count = KMALLOC_SIZE - *offp ;
  52.     }
  53.     ret =  copy_to_user(buffer,filp->private_data+(*offp),(unsigned long)count);
  54.     if(ret != 0){
  55.         eprintk("test_read error ret = %d!!!\n",ret);
  56.         return -1 ;
  57.     }

  58.     *offp +=count ;
  59.    dprintk("the file position *offp = %lld,file pos =%lld\n",(long long)(*offp),(long long)filp->f_pos);
  60.    return count ;
  61. }

  62. ssize_t test_write(struct file *filp,const char __user *buffer,size_t count,loff_t *offp)
  63. {
  64.     int ret = -1 ;

  65.     if(*offp+count>KMALLOC_SIZE){
  66.         printk("the device space is limit\n");
  67.         count = KMALLOC_SIZE-*offp ;
  68.     }
  69.     ret = copy_from_user((char *)filp->private_data+(*offp),buffer,count);
  70.     if(ret != 0){
  71.         eprintk("write error ret = %d!!!\n",ret);
  72.         return ret ;
  73.     }
  74.     *offp +=count ;
  75.     dprintk("the file position *offp = %lld,file pos =%lld\n",(long long)(*offp),(long long)filp->f_pos);
  76.     return count ;
  77. }

  78. loff_t test_seek(struct file *filp,loff_t off,int where)
  79. {

  80. switch(where)
  81. {
  82.     case 0 :
  83.      filp->f_pos = 0 ;
  84.      filp->f_pos += off ;
  85.     break ;
  86.     case 1 :
  87.      filp->f_pos += off ;
  88.      break ;
  89.     case 2 :
  90.      filp->f_pos = 0 ;
  91.      filp->f_pos += KMALLOC_SIZE  ;
  92.     default :
  93.         break ;
  94.   }
  95.    return filp->f_pos ;
  96. }

  97. int test_mmap(struct file *filp,struct vm_area_struct *vm)
  98. {
  99.     unsigned long phy_addr = __pa(filp->private_data);
  100.     unsigned long pfn = (phy_addr>>PAGE_SHIFT) + vm->vm_pgoff [color=Red];//主要在于如果vm_pgoff不为0时则实现不了功能。[/color]    dprintk("pfn = %ld,phy_addr = %x pgoff = %d\n",pfn,phy_addr,vm->vm_pgoff);
  101.     dprintk("vm->vm_start = 0x%x vm->vm_end = 0x%x size = %d vm->vm_pgoff = %d \n",vm->vm_start,vm->vm_end,\
  102.              vm->vm_end - vm->vm_start,vm->vm_pgoff);

  103.     if(remap_pfn_range(vm,vm->vm_start,pfn,vm->vm_end-vm->vm_start,vm->vm_page_prot))
  104.         return -EAGAIN;
  105.     vm->vm_flags |= VM_RESERVED ;
  106.     vm->vm_page_prot = pgprot_noncached(vm->vm_page_prot);
  107.     return 0;
  108. }

  109. struct file_operations  my_ops = {
  110.     .owner   = THIS_MODULE ,
  111.     .open    = test_open ,
  112.     .release = test_release ,
  113.     .mmap    = test_mmap ,
  114.     .read    = test_read ,
  115.     .write   = test_write ,
  116.     .llseek  = test_seek ,
  117. } ;

  118. static int __init test_init(void)
  119. {
  120.     dev_t dev ;
  121.     int ret = -1 ;
  122.     dprintk("module init\n");
  123.     if(gMajor!=0){
  124.         dev = MKDEV(gMajor,gMinor) ;
  125.         ret = register_chrdev_region(dev,1,DEVICE) ;
  126.     }else{
  127.        ret  = alloc_chrdev_region(&dev,0,1,DEVICE) ;
  128.        gMajor = MAJOR(dev);
  129.     }
  130.     if(ret != 0){
  131.         dprintk("register chrdev dev error \n");
  132.         return ret ;
  133.     }
  134.     dprintk("major = %d \n",gMajor);

  135.     my_cdev = cdev_alloc() ;
  136.     my_cdev->ops = &my_ops ;
  137.     my_cdev->owner = THIS_MODULE ;
  138.     cdev_add(my_cdev,dev,1) ;
  139.     return 0;
  140. }

  141. static void __exit test_exit(void)
  142. {
  143.    dprintk("module exit \n");
  144.    cdev_del(my_cdev) ;
  145.    unregister_chrdev_region(MKDEV(gMajor,gMinor),1);
  146. }

  147. module_init(test_init) ;
  148. module_exit(test_exit) ;
  149. MODULE_LICENSE("GPL");
  150. MODULE_AUTHOR("BIN");
复制代码





欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2