Chinaunix首页 | 论坛 | 博客
  • 博客访问: 4242077
  • 博文数量: 1148
  • 博客积分: 25453
  • 博客等级: 上将
  • 技术积分: 11949
  • 用 户 组: 普通用户
  • 注册时间: 2010-05-06 21:14
文章分类

全部博文(1148)

文章存档

2012年(15)

2011年(1078)

2010年(58)

分类:

2011-12-12 20:53:24

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/string.h>
#include <linux/vmalloc.h>
#include <asm/uaccess.h>

MODULE_LICENSE("GPL");
#define MAX_COOKIE_LENGTH PAGE_SIZE

static struct proc_dir_entry *proc_entry;    //注意结构体
static char *cookie_pot; // Space for fortune strings
static int cookie_index; // Index to write next fortune
static int next_fortune; // Index to read next fortune

int fortune_read( char *page, char **start, off_t off,
                   int count, int *eof, void *data )
{
  int len;
  if (off > 0) {
    *eof = 1;
    return 0;
  }

  if (next_fortune >= cookie_index) next_fortune = 0;
  len = sprintf(page, "%s\n", &cookie_pot[next_fortune]);//写入数据的缓冲区(page)已经在内核空间,直接spirntf
  next_fortune += len;
  return len;
}

ssize_t fortune_write( struct file *filp, const char __user *buff,
                        unsigned long len, void *data )
{
  int space_available = (MAX_COOKIE_LENGTH-cookie_index)+1;
  if (len > space_available) {
    printk(KERN_INFO "fortune: cookie pot is full!\n");
    return -ENOSPC;
  }
//把用户空间数据拷贝内核  

if (copy_from_user( &cookie_pot[cookie_index], buff, len )) {
    return -EFAULT;
  }
  cookie_index += len;
  cookie_pot[cookie_index-1] = 0;
  return len;
}


int init_fortune_module( void )
{
  int ret = 0;
  cookie_pot = (char *)vmalloc( MAX_COOKIE_LENGTH );  // 分配空间,内核态缓存用户数据
  if (!cookie_pot) {
    ret = -ENOMEM;
  } else {
    memset( cookie_pot, 0, MAX_COOKIE_LENGTH );
    proc_entry = create_proc_entry( "fortune", 0644, NULL ); //在/proc创建fortune文件,并指定权限
    if (proc_entry == NULL) {
      ret = -ENOMEM;
      vfree(cookie_pot);
      printk(KERN_INFO "fortune: Couldn't create proc entry\n");
    } else {
      cookie_index = 0;
      next_fortune = 0;
      proc_entry->read_proc = fortune_read;   //对文件fortune读操作所调用的函数
      proc_entry->write_proc = fortune_write; //对文件fortune写操作所调用的函数
      proc_entry->owner = THIS_MODULE;
      printk(KERN_INFO "fortune: Module loaded.\n");
    }
  }
  return ret;
}
void cleanup_fortune_module( void )
{
  remove_proc_entry("fortune", NULL);  //删除文件
  vfree(cookie_pot);  //释放
  printk(KERN_INFO "fortune: Module unloaded.\n");
}
module_init( init_fortune_module );
module_exit( cleanup_fortune_module );



1、struct proc_dir_entry 结构体是用来管理/proc文件系统目录项,其成员有:

struct proc_dir_entry {

unsigned int low_ino;

unsigned short namelen;

const char *name;

mode_t mode;

nlink_t nlink;

uid_t uid;

gid_t gid;

loff_t size;

const struct inode_operations *proc_iops;

/*

* NULL ->proc_fops means "PDE is going away RSN" or

* "PDE is just created". In either case, e.g. ->read_proc won't be

* called because it's too late or too early, respectively.

*

* If you're allocating ->proc_fops dynamically, save a pointer

* somewhere.

*/

const struct file_operations *proc_fops;

struct proc_dir_entry *next, *parent, *subdir;

void *data;

read_proc_t *read_proc;   // file read function

write_proc_t *write_proc; //file write function

atomic_t count; /* use count */

int pde_users; /* number of callers into module in progress */

spinlock_t pde_unload_lock; /* proc_fops checks and pde_users bumps */

struct completion *pde_unload_completion;

struct list_head pde_openers; /* who did ->open, but not ->release */

};

为了创建可读可写的proc文件并指定该proc文件的读写操作函数,必须设置这些创建proc文件的函数返回指针指向的struct proc_dir_entry结构的write_proc字段,并指定该proc文件的访问权限有写权限,如上例.这样用户就可通过cat 和 echo命令来查看文件的内容和向文件写数据.

2、create_proc_entry函数原型:

struct proc_dir_entry *create_proc_entry( const char *name, mode_t mode,struct proc_dir_entry *parent );

作用:该函数用于在/proc文件系统中创建一个虚拟文件(proc条目)。

参数:

      name: 给出要创建的文件名称;
      mode:给出建立的该proc文件的访问权限;
      parent:指定建立的proc文件所在的目录;

      如果要在/proc根目录下建立proc文件,parent应当为NULL
       若返回NULL,说明create出错


remove_proc_entry函数原型:
void remove_proc_entry( const char *name, struct proc_dir_entry *parent ); 
作用:
用于删除创建的proc文件。
参数:
 name:给出要删除的proc文件的名称;
 parent:指定创建的proc文件所在的目录。

parent参数可以是NULL(指/proc根目录),也可以取其他值,这取决于我们创建时将这个文件放到了什么地方。可以使用的其他一些值 proc_dir_entry:proc_root_fs、proc_net、proc_bus、proc_root_driver等。这些取值在linux/proc_fs.h中引入,如下:

     extern struct proc_dir_entry proc_root; (/proc目录)

     extern struct proc_dir_entry *proc_root_fs; (/proc/fs目录)

     extern struct proc_dir_entry *proc_net;   (/proc/net)

     extern struct proc_dir_entry *proc_bus;   (/proc/bus)

     extern struct proc_dir_entry *proc_root_driver; (/proc/driver)

     extern struct proc_dir_entry *proc_root_kcore; (/proc/kcore)

注意:上面的定义中,proc_root和其他变量的类型不同,其他的都是指针,在使用时要注意。利用这些位置值,我们可在/proc文件系统的根目录(/proc)及其内部的目录下(如/proc/net、/proc/bus等)建立文件。除此之外,我们还可以用自己创建的目录(proc_mkdir)

3、/proc文件写函数:

   我们可以使用write_proc函数向/proc中写入一项。此函数原型:

     int mod_write( struct file *filp, const char __user *buff, unsigned long len, void *data );

    参数: filp 参数实际上是一个打开文件结构;

               buff 参数是存放在缓冲区的要写入的字符串数据;

               len 参数定义了在 buff 中有多少数据要被写入;

               data 参数是一个指向私有数据的指针(proc_dir_entry中)。

    注意:缓冲区buff地址实际上是一个用户空间的缓冲区,因此我们不能直接读取它,一般使用 copy_from_user 函数来维护用户空间的数据

/proc文件读函数:

    我们可以使用read_proc函数从一个/proc项中读取数据(从内核空间到用户空间)。此函数原型:


      int mod_read( char *page, char **start, off_t off, int count, int *eof, void *data );

      参数:page 参数是这些数据写入到的位置;

              count 定义了可以写入的最大字符数;

               在返回多页数据(通常一页是 4KB)时,我们需要使用 start 和 off 参数;

               当所有数据全部写入之后,就需要设置 eof(文件结束参数);

               与 write 类似,data 表示的也是私有数据。

      注意:此处提供的page缓冲区在内核空间中,因此我们可以直接读出,而不用调用copy_to_user。



阅读(1414) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~