一段有关内核、用户空间共享内存的代码

自己写了一个虚拟的字符设备/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)


用户空间:

#include<stdio.h>

#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<sys/mman.h>
#include<string.h>


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


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


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


    }


    close(new_fd) ;
    return 0;

}


内核空间:

#include<linux/kernel.h>
#include<linux/init.h>
#include<linux/module.h>
//#include<linux/sched.h>
#include<linux/fs.h>
#include<linux/types.h>
#include<linux/kdev_t.h>
#include<linux/cdev.h>
#include<asm/uaccess.h>
#include<linux/slab.h>
#include<linux/mm.h>


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


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


static int gMajor = 0 ;
static int gMinor = 0 ;
module_param(gMajor,int,0);


#define DEVICE "test"


struct cdev * my_cdev = NULL ;


#define KMALLOC_SIZE 1024*80


 int test_open(struct inode *inode,struct file *filp)
{
    struct cdev * pdev = NULL ;
    int major = 0 ;
    filp->private_data = kmalloc(KMALLOC_SIZE,GFP_KERNEL) ;
    if(filp->private_data==NULL){
        printk("test_open error !!!\n");
        return -1 ;
    }
    if(inode->i_cdev)pdev= inode->i_cdev ;
    major = MAJOR(pdev->dev) ;
    dprintk("major = %d \n",major) ;
    return 0;


}


 int test_release(struct inode *inode ,struct file *filp)
{
    if(filp->private_data)kfree(filp->private_data);
    dprintk("\n");
    return 0;
}


 ssize_t test_read(struct file *filp,char __user *buffer,size_t count,loff_t *offp)
{
    int ret = -1 ;
    dprintk("the file position *offp = %lld,file pos =%lld\n",(long long)(*offp),(long long)filp->f_pos);
    if(count +*offp>KMALLOC_SIZE){
       count = KMALLOC_SIZE - *offp ;
    }
    ret =  copy_to_user(buffer,filp->private_data+(*offp),(unsigned long)count);
    if(ret != 0){
        eprintk("test_read error ret = %d!!!\n",ret);
        return -1 ;
    }


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


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


    if(*offp+count>KMALLOC_SIZE){
        printk("the device space is limit\n");
        count = KMALLOC_SIZE-*offp ;
    }
    ret = copy_from_user((char *)filp->private_data+(*offp),buffer,count);
    if(ret != 0){
        eprintk("write error ret = %d!!!\n",ret);
        return ret ;
    }
    *offp +=count ;
    dprintk("the file position *offp = %lld,file pos =%lld\n",(long long)(*offp),(long long)filp->f_pos);
    return count ;
}


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


 switch(where)
 {
    case 0 :
     filp->f_pos = 0 ;
     filp->f_pos += off ;
    break ;
    case 1 :
     filp->f_pos += off ;
     break ;
    case 2 :
     filp->f_pos = 0 ;
     filp->f_pos += KMALLOC_SIZE  ;
    default :
        break ;
  }
   return filp->f_pos ;
}


 int test_mmap(struct file *filp,struct vm_area_struct *vm)
{
    unsigned long phy_addr = __pa(filp->private_data);
    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);
    dprintk("vm->vm_start = 0x%x vm->vm_end = 0x%x size = %d vm->vm_pgoff = %d \n",vm->vm_start,vm->vm_end,\
             vm->vm_end - vm->vm_start,vm->vm_pgoff);


    if(remap_pfn_range(vm,vm->vm_start,pfn,vm->vm_end-vm->vm_start,vm->vm_page_prot))
        return -EAGAIN;
    vm->vm_flags |= VM_RESERVED ;
    vm->vm_page_prot = pgprot_noncached(vm->vm_page_prot);
    return 0;
}


struct file_operations  my_ops = {
    .owner   = THIS_MODULE ,
    .open    = test_open ,
    .release = test_release ,
    .mmap    = test_mmap ,
    .read    = test_read ,
    .write   = test_write ,
    .llseek  = test_seek ,
} ;


 static int __init test_init(void)
{
    dev_t dev ;
    int ret = -1 ;
    dprintk("module init\n");
    if(gMajor!=0){
        dev = MKDEV(gMajor,gMinor) ;
        ret = register_chrdev_region(dev,1,DEVICE) ;
    }else{
       ret  = alloc_chrdev_region(&dev,0,1,DEVICE) ;
       gMajor = MAJOR(dev);
    }
    if(ret != 0){
        dprintk("register chrdev dev error \n");
        return ret ;
    }
    dprintk("major = %d \n",gMajor);


    my_cdev = cdev_alloc() ;
    my_cdev->ops = &my_ops ;
    my_cdev->owner = THIS_MODULE ;
    cdev_add(my_cdev,dev,1) ;
    return 0;
}


static void __exit test_exit(void)
{
   dprintk("module exit \n");
   cdev_del(my_cdev) ;
   unregister_chrdev_region(MKDEV(gMajor,gMinor),1);
}


module_init(test_init) ;
module_exit(test_exit) ;
MODULE_LICENSE("GPL");
MODULE_AUTHOR("BIN");

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值