Chinaunix首页 | 论坛 | 博客
  • 博客访问: 411170
  • 博文数量: 118
  • 博客积分: 294
  • 博客等级: 二等列兵
  • 技术积分: 667
  • 用 户 组: 普通用户
  • 注册时间: 2010-09-16 20:31
文章分类

全部博文(118)

文章存档

2014年(3)

2012年(25)

2011年(90)

分类:

2011-06-17 18:55:12

原文地址:proc文件系统分析(三) 作者:datao0907

处理基本文件的索引节点操作

对于pid文件夹里面的文件(/proc/pid)索引节点统一,内核静态地定义proc_base_inode_operations作为索引节点操作,定义如下:

  1. //索引节点操作
  2. static const struct inode_operations proc_tgid_base_inode_operations = {
  3.     .lookup = proc_tgid_base_lookup,
  4.     .getattr = pid_getattr,//直接将参数dentry的属性赋值给指定的文件
  5.     .setattr = proc_setattr,//修改dentry的属性
  6. }
  7. //文件操作
  8. static const struct file_operations proc_tgid_base_operations = {
  9.     .read = generic_read_dir,
  10.     .readdir = proc_tgid_base_readdir,
  11. }

每个pid中的项定义如下:

  1. struct pid_entry {
  2.     char *name;
  3.     ine len;
  4.     mode_t mode;
  5.     const struct inode_operaions *iop;
  6.     const struct file_operation *fop;
  7.     union proc_op op;
  8. }

lookup定义如下:

  1. static struct *proc_tgid_base_lookup(struct inode *dir,struct dentry*dentry,struct nameidata *nd)
  2. {
  3.     //tgid_base_stuff:规定pid文件夹中的所有子文件夹项,及相应的处理函数,不同的文件夹不同的文
  4.     //件处理函数,但都类似
  5.     return proc_pident_lookup(dir,dentry,tgid_base_stuff,ARRAY_SIZE(tgid_base_stuff));
  6. }

而具体的调用函数proc_pident_lookup定义如下:

  1. //在ents文件夹中查找dentry的目录项
  2. static struct dentry *proc_pident_lookup(struct inode* dir,struct dentry *dentry,const struct pid_entry                             *ents,unsigned int nents)
  3. {
  4.     struct inode *inode;
  5.     struct dentry *error;
  6.     struct task_struct *task = get_proc_task(dir);
  7.     const struct pid_entry *p,*last;
  8.     
  9.     error = ERR_PTR(-ENOENT);
  10.     inode = NULL;
  11.     
  12.     if(!task)
  13.         goto out_no_task;
  14.     
  15.     last = &ents[nents-1];
  16.     //进行遍历查找
  17.     for(p=ents;p<=last;p++){
  18.      if(p->len != dentry->d_name.len) continue;
  19.      if(!memcpy(dentry->d_name.name,p->name,p->len)) break;
  20.     }
  21.     if(p->last) goto out_no_break;
  22.     //创建索引节点,并进行缓存
  23.     error = proc_pident_instantiate(dir,dentry,task,p);
  24. out:
  25.     put_task_struct(task);
  26. out_no_task:
  27.     return error;
  28. }

readdir函数原型如下:

  1. //从filp文件中读取一项填入dirent
  2. static int proc_tgid_base_readdir(struct file* filp,void *dirent,filldir_t filldir)
  3. {
  4.     return proc_pident_readdir(filp,dirent,filldir,tgid_base_stuff,ARRAY_SIZE(tgid_base_stuff));
  5. }

具体执行函数如下:

  1. //在ents中读取文件,filldir_t定义为:typedef int (*filldir_t)(void*,const char*,int,loff_t,ino_t,unsigned);
  2. static int proc_pident_readdir(struct file* filep,
  3.         void *dirent,filldir_t filldir,const struct pid_entry *ents,unsigned int nents)
  4. {
  5.     int i;
  6.     //与文件相对应的dentry
  7.     struct dentry *dentry = filp->f_path.entry;
  8.     //找出对应的索引节点
  9.     struct inode *inode = dentry ->d_inode;
  10.     //找出pid
  11.     struct task_struct *task = get_proc_task(inode);
  12.     const struct pid_entry *p,*last;
  13.     ino_t ino;
  14.     int ret;
  15.     
  16.     ret = -ENOENT;
  17.     if(!task)
  18.          goto out_no_task;
  19.     
  20.     ret = 0;
  21.     //当前文件偏移量
  22.     i = filp->f_pos;
  23.     switch(i){
  24.     //最开始就是.,表示本目录
  25.     case 0:
  26.         ino = inode->i_ino;
  27.         if(filldir(dirent,.,1,i,ino,DT_DIR)<0) goto out;
  28.         
  29.         i++;
  30.         filp->f_pos++;
  31.     //接着指向父目录
  32.     case 1:
  33.         ino = parent_ino(dentry);
  34.         //写入具体的空间
  35.         if(filldir(dirent,..,2,i,ino,DT_DIR)<0) goto out;
  36.         
  37.         i++;
  38.         filp->f_pos++;
  39.          default:
  40.         i -=2;
  41.         if( i>= nents) {
  42.             ret = 1;
  43.             goto out;
  44.     }    //找出偏移量,则对应具体文件夹
  45.          p = ents+i;
  46.         last = &ents[nents-1];
  47.         while(p<=last){
  48.         //找到之后,写入缓存中,再调用filldir写入dirent
  49.         if(proc_pident_fill_cache(filp,dirent,filldir,task,p)<0)
  50.                 goto out;
  51.         //写完之后位置添加,看来一次性读完pid文件夹下的文件
  52.          filp->f_pos++;
  53.          p++;
  54.         }
  55.     }
  56.         ret = 1;
  57. out:    put_task_struct(task);

  58. out_no_task:
  59.         return ret;
  60. }

/proc文件操作接口

/proc是一个文件系统,它不仅可以显示系统的状态,也可以方便其它驱动注册自己的文件夹,这些函数接口如下:

常见的操作函数有:

创建文件: struct proc_dir_entry *create_proc_entry(const char *name,mode_t mode, struct proc_dir_entry *parent)

函数原型如下:

  1. struct proc_dir_entry *create_proc_entry(const char* name,mode_t mode,
  2. struct proc_dir_entry *parent)
  3. {
  4. …....
  5. //利用slab分配器分配struct proc_dir_entry结构体,进行部分初始化
  6. ent = proc_creat(&parent,name,mode,nlink);
  7. if(ent) {
  8. //针对不同类型的文件,实行不同的函数操作,并实现父子目录的连接
  9. if(proc_register(parent,ent)<0) {
  10. kfree(ent);
  11. en = NULL;
  12. }
  13. }
  14. }

除了上面的函数可以进行创建文件之外,下面的函数也可以进行创建,只不过进行了简单的封装:

  1. //创建文件之外,注册了读取函数read_proc和数据项,而inode中的read函数最终也是指向read_proc
  2. struct proc_dir_entry *create_proc_read_entry(const char*name,
  3. mode_t mode,struct proc_dir_entry *base,
  4. read_proc_t *read_proc,void *data)
  5. //创建文件之后,注册get_info指针
  6. struct proc_dir_entry * create_proc_info_entry(const char* name,
  7. mode_t mode,struct proc_dir_entry* base,get_info_t *get_info)

创建文件夹

  1. struct proc_dir_entry* proc_mkdir(const char*name,struct proc_dir_entry* parent);
  2. struct proc_dir_entry* proc_mkdir_mode(const char*name,
  3. mode_t mode,struct proc_dir_entry* parent);



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