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

全部博文(118)

文章存档

2014年(3)

2012年(25)

2011年(90)

分类:

2011-06-17 18:55:01

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


挂载文件系统

所有的内核数据初始化完成后,就进行文件系统的挂载,当添加一个新的文件系统,内核就会使用链表来查找与文件系统对应的file_system_type,它提供如何读取文件系统的超级块。而对于proc,结构如下:

  1. fs/proc/root.c
  2. //这也就是register_filesystem函数的参数
  3. static struct file_system_type proc_fs_type={
  4.     .name         = “proc”,
  5.     .get_sb     = proc_get_sb,
  6.     .kill_sb     = proc_kill_sb,
  7. }

通过register_filesystem进行合法性判断并注册到指定的文件系统之后,就利用kern_mount_data()将文件系统挂载到vfs树中。proc_get_sb()函数就是用于获取文件系统的超级块:

该函数主要调用proc_fill_super进行填充:


  1. int proc_fill_super(struct super_block *s)

  2. {

  3. struct inode *root_inode;

  4. s->s_flags |= MS_NOPRIVATE|MS_NOSUID |MS_NOEXEC;

  5. s->s_blocksize = 1024;//块大小不能设置,一般都是1024

  6. s->s_blocksize_bits = 10;//必须是10,2^10=1024

  7. s->s_magic = PROC_SUPER_MAGIC;//用于认知文件系统,宏的具体数字为0x9fa0

  8. s->s_op = &proc_sops;//具体的超级块操作,主要涉及的是索引块的操作

  9. s->s_time_gran = 1;

  10. //系统挂载时,就创建了/proc文件夹的索引节点,用于根目录的索引节点,这里只是增加一个引用计数

  11. de_get(&proc_root);

  12. //转换为vfs具体能识别的索引节点

  13. root_inode = proc_get_inode(s,PROC_ROOT_INO,&proc_root);

  14. if(!root_inode) goto out_no_root;

  15. //索引节点初始化

  16. root_inode->i_uid = 0;

  17. root_inode->i_gid = 0;

  18. //转化为dentry,赋值给super_block对象

  19. s->s_root = d_alloc_root(root_inode);

  20. if(!s->s_root) goto out_no_root;

  21. return 0;

  22. out_no_root:

  23. .....

  24. }

上面的根索引节点的具体定义如下:


  1. struct proc_dir_entry proc_root = {

  2. .low_ino = PROC_ROOT_INO,//根的索引节点号

  3. .namelen = 5,//根文件名长度,文件名

  4. .name = “/proc”,

  5. .mode = S_IFDIR|S_IRUGO|S_IXUGO,

  6. .nlink = 2,

  7. .count = ATOMIC_INIT(1),

  8. .proc_iops = &proc_root_inode_operations,//根文件的具体索引节点操作

  9. .proc_fops = &proc_root_operations,//根文件支持的文件操作

  10. .parent = &proc_root

  11. }

它不仅包含正常的文件及文件夹,还管理进程指定的pid文件,它就必须有自己的索引处理函数和文件操作函数:


  1. static const struct file_operations proc_root_operations = {

  2. .read = generic_read_dir,//这里明显返回错误,因为不能通过read来读取文件夹

  3. .readdir = proc_root_readdir,

  4. }

  5. static const struct inode_operations proc_root_inode_operations = {

  6. .lookup = proc_root_lookup,//这个是关键也是最复杂,所有的查看都调用此接口

  7. .getattr = proc_root_getattr,

  8. }

用户空间的程序访问proc文件,vfs中的查看进程调用real_lookup,它就会调用inode_operations中的lookup指针函数,实际也就是调用proc_root_lookup函数:

proc文件系统中,主要有两种类型的文件:内核运行状态和进程id相关文件,所以在查找期间,就需要两种不同的查找函数。


  1. static struct dentry *proc_root_lookup(struct inode *dir,struct dentry *dentry,struct namedata *nd)

  2. {

  3. if(!proc_lookup(dir,entry,nd)){ //先查找内核运行状态的文件

  4. return NULL;

  5. }

  6. return proc_pid_lookup(dir,dentry,nd);//再查找进程id相关文件

  7. }

其中proc_lookup函数原型如下:


  1. //在dir中查找文件夹 dentry是否存在?

  2. struct dentry* proc_lookup(struct inode* dir,struct dentry *dentry,struct nameidata *nd)

  3. {

  4. struct inode* inode = NULL;

  5. struct proc_dir_entry *de;

  6. int error = -ENOENT;

  7. //内核锁,防止多个程序处于内核态

  8. lock_kernel();

  9. spin_lock(&proc_subdir_lock);

  10. //从dentry中提取出具体的proc_dir_entry

  11. de = PDE(dir);

  12. if(de) {

  13. for(de = de->subdir;de;de=de->next)

  14. {

  15. if(de->namelen != dentry->d_name.len) continue;

  16. if(!memcpy(dentry->d_name.name,de->name,de->namelen))

  17. {

  18. unsigned int ino;

  19. if(de->show_proc)

  20. //用于进行对该项进行缓存

  21. de = de->shadow_proc(current,de);

  22. //获取对应的索引节点号

  23. ino = de->low_ino;

  24. de_get(de);

  25. spin_unlock(&proc_subdir_lock);

  26. error = -EINVAL;

  27. //获取对应的索引节点

  28. inode = proc_get_inode(dir->i_sb,ino,de);

  29. spin_lock(&proc_subdir_lock);

  30. break;

  31. }

  32. }

  33. }

  34. spin_unlock(&proc_subdir_lock);

  35. unlock_kernel();

  36. //存在与否,如果存在就加入缓存中

  37. if(inode) {

  38. dentry->d_op = &proc_dentry_operations;

  39. d_add(dentry,inode);

  40. return NULL;

  41. }

  42. de_put(de);

  43. return ERR_PTR(error);

  44. }



而proc_pid_lookup函数原型如下:

  1. //在指定的pid文件夹中查找dentry是否存在
  2. struct dentry *proc_pid_lookup(struct inode *dir,struct dentry *dentry,struct nameidata *nd)
  3. {
  4.     …..
  5.     //找出指定的进程是否存在,这里就进行了self文件夹的处理
  6.     result = proc_base_lookup(dir,entry);
  7.     if(!IS_ERR(result)||PTR_ERR(result)!=-ENOENT)
  8.         goto out;
  9.     //将文件夹名称转换为pid
  10.     tgid = name_to_int(dentry);
  11.     if(tgid == ~0U) goto out;
  12.     //获取文件系统的命名空间
  13.     ns = dentry->d_sb->s_fs_info;
  14.     rcu_read_lock();
  15.     //通过pid查找到指定的task
  16.     task = find_task_by_pid_ns(tgid,ns);
  17.     if(task)
  18.         get_task_struct(task);
  19.     //生成一个新索引节点,并进行缓存
  20.     result = proc_pid_instantiate(dir,dentry,task,NULL);
  21.     put_task_struct(task);
  22. out:
  23.     return result;
  24. }

self文件夹

self文件夹处理的是当前请求线程的信息,实际为链接文件,定义如下:

  1. static const struct pid_entry proc_base_stuff[]={

  2. NOD(“self”,S_IFLNK|S_IRWXUGO,

  3. //iop

  4. &proc_self_inode_operations,NULL,{})

  5. }

其中注册的操作如下:

  1. static const struct inode_operations proc_self_inode_operations = {
  2.     .readlink     = proc_self_readlink,
  3.     .follow_link     = proc_self_follow_link,
  4. }
  5. //就只是读取链接文件:将链接文件的内容返回至用户
  6. static int proc_self_readlink(struct dentry *dentry,char __user *buffer,int buflen)
  7. {
  8.     char tmp[PROC_NUMBUF];//#define PROC_NUMBUF 13
  9.     //直接链接到当前pid的文件夹
  10.     sprintf(tmp,%d”,task_tgid_vnr(current));
  11.     return vfs_readlink(dentry,buffer,bufflen,tmp);
  12. }
  13. //处理链接所具体指向的文件:
  14. static void *proc_self_follow_link(struct dentry *dentry,struct nameidata *nd)
  15. {
  16.     char tmp[PROC_NUMBUF];
  17.     sprintf(tmp,%d”,task_tgid_vnr(current));
  18.     //将查找tmp文件过程中得到的信息的结果写入nd中
  19.     return ERR_PTR(vfs_follow_link(nd,tmp));
  20. }

p { margin-bottom: 0.08in; }

其中nameidata定义如下:

  1. struct nameidata {
  2.     struct dentry *dentry;
  3.     struct vfsmount *mnt;
  4.     struct qstr     last;
  5.     unsigned int flags;
  6.     int     last_type;
  7.     unsigned     depth;
  8.     char *save_names[MAX_NESTED_LINKS+1];    
  9.     union {
  10.     struct open_intent_open;
  11.     }intent;
  12. }

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