挂载文件系统
所有的内核数据初始化完成后,就进行文件系统的挂载,当添加一个新的文件系统,内核就会使用链表来查找与文件系统对应的file_system_type,它提供如何读取文件系统的超级块。而对于proc,结构如下:
- fs/proc/root.c
-
//这也就是register_filesystem函数的参数
-
static struct file_system_type proc_fs_type={
-
.name = “proc”,
-
.get_sb = proc_get_sb,
-
.kill_sb = proc_kill_sb,
-
}
通过register_filesystem进行合法性判断并注册到指定的文件系统之后,就利用kern_mount_data()将文件系统挂载到vfs树中。proc_get_sb()函数就是用于获取文件系统的超级块:
该函数主要调用proc_fill_super进行填充:
- int proc_fill_super(struct super_block *s)
-
-
{
-
-
struct inode *root_inode;
-
-
s->s_flags |= MS_NOPRIVATE|MS_NOSUID |MS_NOEXEC;
-
-
s->s_blocksize = 1024;//块大小不能设置,一般都是1024
-
-
s->s_blocksize_bits = 10;//必须是10,2^10=1024
-
-
s->s_magic = PROC_SUPER_MAGIC;//用于认知文件系统,宏的具体数字为0x9fa0
-
-
s->s_op = &proc_sops;//具体的超级块操作,主要涉及的是索引块的操作
-
-
s->s_time_gran = 1;
-
-
//系统挂载时,就创建了/proc文件夹的索引节点,用于根目录的索引节点,这里只是增加一个引用计数
-
-
de_get(&proc_root);
-
-
//转换为vfs具体能识别的索引节点
-
-
root_inode = proc_get_inode(s,PROC_ROOT_INO,&proc_root);
-
-
if(!root_inode) goto out_no_root;
-
-
//索引节点初始化
-
-
root_inode->i_uid = 0;
-
-
root_inode->i_gid = 0;
-
-
//转化为dentry,赋值给super_block对象
-
-
s->s_root = d_alloc_root(root_inode);
-
-
if(!s->s_root) goto out_no_root;
-
-
return 0;
-
-
out_no_root:
-
-
.....
-
-
}
上面的根索引节点的具体定义如下:
- struct proc_dir_entry proc_root = {
-
-
.low_ino = PROC_ROOT_INO,//根的索引节点号
-
-
.namelen = 5,//根文件名长度,文件名
-
-
.name = “/proc”,
-
-
.mode = S_IFDIR|S_IRUGO|S_IXUGO,
-
-
.nlink = 2,
-
-
.count = ATOMIC_INIT(1),
-
-
.proc_iops = &proc_root_inode_operations,//根文件的具体索引节点操作
-
-
.proc_fops = &proc_root_operations,//根文件支持的文件操作
-
-
.parent = &proc_root
-
-
}
它不仅包含正常的文件及文件夹,还管理进程指定的pid文件,它就必须有自己的索引处理函数和文件操作函数:
- static const struct file_operations proc_root_operations = {
-
-
.read = generic_read_dir,//这里明显返回错误,因为不能通过read来读取文件夹
-
-
.readdir = proc_root_readdir,
-
-
}
-
-
static const struct inode_operations proc_root_inode_operations = {
-
-
.lookup = proc_root_lookup,//这个是关键也是最复杂,所有的查看都调用此接口
-
-
.getattr = proc_root_getattr,
-
-
}
用户空间的程序访问proc文件,vfs中的查看进程调用real_lookup,它就会调用inode_operations中的lookup指针函数,实际也就是调用proc_root_lookup函数:
在proc文件系统中,主要有两种类型的文件:内核运行状态和进程id相关文件,所以在查找期间,就需要两种不同的查找函数。
- static struct dentry *proc_root_lookup(struct inode *dir,struct dentry *dentry,struct namedata *nd)
-
-
{
-
-
if(!proc_lookup(dir,entry,nd)){ //先查找内核运行状态的文件
-
-
return NULL;
-
-
}
-
-
return proc_pid_lookup(dir,dentry,nd);//再查找进程id相关文件
-
-
}
其中proc_lookup函数原型如下:
- //在dir中查找文件夹 dentry是否存在?
-
-
struct dentry* proc_lookup(struct inode* dir,struct dentry *dentry,struct nameidata *nd)
-
-
{
-
-
struct inode* inode = NULL;
-
-
struct proc_dir_entry *de;
-
-
int error = -ENOENT;
-
-
//内核锁,防止多个程序处于内核态
-
-
lock_kernel();
-
-
spin_lock(&proc_subdir_lock);
-
-
//从dentry中提取出具体的proc_dir_entry
-
-
de = PDE(dir);
-
-
if(de) {
-
-
for(de = de->subdir;de;de=de->next)
-
-
{
-
-
if(de->namelen != dentry->d_name.len) continue;
-
-
if(!memcpy(dentry->d_name.name,de->name,de->namelen))
-
-
{
-
-
unsigned int ino;
-
-
if(de->show_proc)
-
-
//用于进行对该项进行缓存
-
-
de = de->shadow_proc(current,de);
-
-
//获取对应的索引节点号
-
-
ino = de->low_ino;
-
-
de_get(de);
-
-
spin_unlock(&proc_subdir_lock);
-
-
error = -EINVAL;
-
-
//获取对应的索引节点
-
-
inode = proc_get_inode(dir->i_sb,ino,de);
-
-
spin_lock(&proc_subdir_lock);
-
-
break;
-
-
}
-
-
}
-
-
}
-
-
spin_unlock(&proc_subdir_lock);
-
-
unlock_kernel();
-
-
//存在与否,如果存在就加入缓存中
-
-
if(inode) {
-
-
dentry->d_op = &proc_dentry_operations;
-
-
d_add(dentry,inode);
-
-
return NULL;
-
-
}
-
-
de_put(de);
-
-
return ERR_PTR(error);
-
-
}
-
-
-
而proc_pid_lookup函数原型如下:
- //在指定的pid文件夹中查找dentry是否存在
-
struct dentry *proc_pid_lookup(struct inode *dir,struct dentry *dentry,struct nameidata *nd)
-
{
-
…..
-
//找出指定的进程是否存在,这里就进行了self文件夹的处理
-
result = proc_base_lookup(dir,entry);
-
if(!IS_ERR(result)||PTR_ERR(result)!=-ENOENT)
-
goto out;
-
//将文件夹名称转换为pid
-
tgid = name_to_int(dentry);
-
if(tgid == ~0U) goto out;
-
//获取文件系统的命名空间
-
ns = dentry->d_sb->s_fs_info;
-
rcu_read_lock();
-
//通过pid查找到指定的task
-
task = find_task_by_pid_ns(tgid,ns);
-
if(task)
-
get_task_struct(task);
-
//生成一个新索引节点,并进行缓存
-
result = proc_pid_instantiate(dir,dentry,task,NULL);
-
put_task_struct(task);
-
out:
-
return result;
-
}
self文件夹
self文件夹处理的是当前请求线程的信息,实际为链接文件,定义如下:
- static const struct pid_entry proc_base_stuff[]={
-
-
NOD(“self”,S_IFLNK|S_IRWXUGO,
-
-
//iop
-
-
&proc_self_inode_operations,NULL,{})
-
-
}
其中注册的操作如下:
- static const struct inode_operations proc_self_inode_operations = {
-
.readlink = proc_self_readlink,
-
.follow_link = proc_self_follow_link,
-
}
-
//就只是读取链接文件:将链接文件的内容返回至用户
-
static int proc_self_readlink(struct dentry *dentry,char __user *buffer,int buflen)
-
{
-
char tmp[PROC_NUMBUF];//#define PROC_NUMBUF 13
-
//直接链接到当前pid的文件夹
-
sprintf(tmp,“%d”,task_tgid_vnr(current));
-
return vfs_readlink(dentry,buffer,bufflen,tmp);
-
}
-
//处理链接所具体指向的文件:
-
static void *proc_self_follow_link(struct dentry *dentry,struct nameidata *nd)
-
{
-
char tmp[PROC_NUMBUF];
-
sprintf(tmp,”%d”,task_tgid_vnr(current));
-
//将查找tmp文件过程中得到的信息的结果写入nd中
-
return ERR_PTR(vfs_follow_link(nd,tmp));
-
}
p { margin-bottom: 0.08in; }
其中nameidata定义如下:
- struct nameidata {
-
struct dentry *dentry;
-
struct vfsmount *mnt;
-
struct qstr last;
-
unsigned int flags;
-
int last_type;
-
unsigned depth;
-
char *save_names[MAX_NESTED_LINKS+1];
-
union {
-
struct open_intent_open;
-
}intent;
-
}
阅读(2543) | 评论(0) | 转发(1) |