情景1:
int fd=open("/proc");
open->sys_open->do_filp_open
当open的flags包含CREAT标志时->do_path_lookup(dfd, pathname, LOOKUP_PARENT, &nd);
不包含CREAT标志时->path_lookup_open->{
struct file *filp = get_empty_filp();
nd->intent.open.file = filp;
}->do_path_lookup(dfd, name, lookup_flags|LOOKUP_OPEN, nd);{
if (*name=='/') {
nd->path = fs->root;
}
}-> path_walk(name, nd);->link_path_walk(name, nd);->__link_path_walk(name, nd);->{
last_component:
err = do_lookup(nd, &this, &next); // this代表proc字符串 this.name == "proc",nd->path包含根目录的dentry,和vfsmount信息,next 为待查找到的proc对应的path结构,通过next返回。
//通过下面对do_lookup函数的分析可知,do_lookup函数返回时,next->dentry代表proc文件系统的根目录dentry结构,
next->vfsmount代表proc文件系统的vfsmount
inode = next.dentry->d_inode;
if ((lookup_flags & LOOKUP_FOLLOW)
&& inode && inode->i_op && inode->i_op->follow_link) {
err = do_follow_link(&next, nd);
if (err)
goto return_err;
inode = nd->path.dentry->d_inode;
} else
path_to_nameidata(&next, nd);->{
path_to_nameidata(struct path *path, struct nameidata *nd)
if (nd->path.mnt != path->mnt)
mntput(nd->path.mnt);
nd->path.mnt = path->mnt;
nd->path.dentry = path->dentry;
}
err = -ENOENT;
if (!inode)
break;
if (lookup_flags & LOOKUP_DIRECTORY) {
err = -ENOTDIR;
if (!inode->i_op || !inode->i_op->lookup)
break;
}
goto return_base;
return_base:
return 0; //返回到link_path_walk,一路返回到do_filp_open(),下面再来看下do_filp_open相关部分代码
}
do_filp_open(){
if (!(flag & O_CREAT)) {
error = path_lookup_open(dfd, pathname, lookup_flags(flag),
&nd, flag);
if (error)
return ERR_PTR(error);
goto ok;
}
ok:filp = nameidata_to_filp(&nd, open_flag);
return filp;
}
struct file *nameidata_to_filp(struct nameidata *nd, int flags)
{
struct file *filp;
/* Pick up the filp from the open intent */
filp = nd->intent.open.file; //这个file是我们在path_lookup_open中分配的
/* Has the filesystem initialised the file for us? */
if (filp->f_path.dentry == NULL)
filp = __dentry_open(nd->path.dentry, nd->path.mnt, flags, filp,
NULL);
-> static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
int flags, struct file *f,
int (*open)(struct inode *, struct file *)){
inode = dentry->d_inode;
f->f_path.dentry = dentry;
//在这里将为打开/proc而分配的file结构与查找到的dentry结构挂钩
f->f_path.mnt = mnt;
f->f_op = fops_get(inode->i_fop);
//将inode->i_fop复制到file结构体f_op字段
}
else
path_put(&nd->path);
return filp;
}
static int do_lookup(struct nameidata *nd, struct qstr *name,
struct path *path)
//// name代表proc字符串 name.name == "proc",nd->path包含根目录的dentry,和vfsmount信息,path为待查找到的proc对应的path结构,通过此指针返回。
{
struct vfsmount *mnt = nd->path.mnt;
struct dentry *dentry = __d_lookup(nd->path.dentry, name);
done:
path->mnt = mnt;
path->dentry = dentry;
__follow_mount(path); ->{
struct vfsmount *mounted = lookup_mnt(path->mnt, path->dentry);
path->mnt = mounted;
path->dentry = dget(mounted->mnt_root);
//这里path代表了proc文件系统的根目录
}
return 0; //返回到__link_path_walk继续分析
}
情景2 ls /proc
readdir("/proc") -> sys_getdents64()->vfs_readdir(struct file *file){
//file结构代表 /proc,file->f_path.dentry已指向/proc dentry结构 file->f_op已指向/proc inode节点的file_operations结构
(file->f_op->readdir(file, buf, filler); --> static int proc_root_readdir(struct file * filp, void * dirent, filldir_t filldir)
{
//由于这个函数比较大,放在下面分析
}
}
在proc文件系统安装注册过程中,/proc inode的file_operations定义为:
/*
* This is the root "inode" in the /proc tree..
*/
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,
};
/*
* The root /proc directory is special, as it has the
* <pid> directories. Thus we don't use the generic
* directory handling functions for that..
*/
static const struct file_operations proc_root_operations = {
.read = generic_read_dir,
.readdir = proc_root_readdir,
};
static int proc_root_readdir(struct file * filp,
void * dirent, filldir_t filldir)
{
unsigned int nr = filp->f_pos;
int ret;
lock_kernel();
if (nr < FIRST_PROCESS_ENTRY) {
int error = proc_readdir(filp, dirent, filldir);
if (error <= 0) {
unlock_kernel();
return error;
}
filp->f_pos = FIRST_PROCESS_ENTRY;
}
unlock_kernel();
ret = proc_pid_readdir(filp, dirent, filldir);
return ret;
}