for(;;;){
unsigned long hash;
struct qstr this;
//这个结构体struct qstr保存着一些当前查询的信息
unsigned int c;
nd->flags |= LOOKUP_CONTINUE;
//检查访问权限,这儿检查是路径中各层目录的访问权限
err = exec_permission_lite(inode, nd);
if (err == -EAGAIN)
err = vfs_permission(nd, MAY_EXEC);
if (err)
break;
this.name = name;
c = *(const unsigned char *)name;
//初始化hash表
hash = init_name_hash();
//算出下一级目录的杂凑值,当前目录是根目录,
//比如现在我们查的是/linux/drivers/char/sep4020_char/sep4020_gpio.c
//现在算的是linux的杂凑值
do {
name++;
hash = partial_name_hash(c, hash);
c = *(const unsigned char *)name;
} while (c && (c != '/'));
this.len = name - (const char *) this.name;
this.hash = end_name_hash(hash);
/* remove trailing slashes? */
//如果已经是最后一级目录,也就是我们要找的最终文件
if (!c)
goto last_component;
//如果要查找的是一个目录,如/linux/drivers
while (*++name == '/');
if (!*name)
goto last_with_slashes;
/*
* "." and ".." are special - ".." especially so because it has
* to be able to know about the current root directory and
* parent relationships.
*/
//如果下一级目录是/./或者../呢
if (this.name[0] == '.') switch (this.len) {
//对于这儿的switch case语句有点不明白,也许是GCC本身的优化
default:
break;
case 2:
if (this.name[1] != '.')
break;
//如果是../,就需要返回到上一级目录,由follow_dotdot完成,找到父目录
follow_dotdot(nd);
inode = nd->dentry->d_inode;
/* fallthrough */
case 1:
continue;
}
/*
* See if the low-level filesystem might want
* to use its own hash..
*/
//如果文件系统提供了杂凑值的算法,就重新再算一遍
if (nd->dentry->d_op && nd->dentry->d_op->d_hash) {
err = nd->dentry->d_op->d_hash(nd->dentry, &this);
if (err < 0)
break;
}
/* This does the actual lookups.. */
//真正的开始查找了,do_lookup(),首先现在内存中的杂凑表中查找,如果没有找到
//那么就要到磁盘或者相应的块设备中去查找,并在内存建立相应的数据结构
err = do_lookup(nd, &this, &next);
//next是struct path类型的结构体,定义于/linux/fs/namei.c,用于保存从磁盘或者其他块设备上查找的信息
if (err)
break;
err = -ENOENT;
inode = next.dentry->d_inode;
if (!inode)
goto out_dput;
err = -ENOTDIR;
if (!inode->i_op)
goto out_dput;
//如果文件系统支持连接文件,并且follow_link存在,调用do_follow_link继续擦找,
//因为各个文件系统的差异,最终还是调用的inode节点的操作结构体的lookup函数
if (inode->i_op->follow_link) {
err = do_follow_link(&next, nd);
if (err)
goto return_err;
err = -ENOENT;
inode = nd->dentry->d_inode;
if (!inode)
break;
err = -ENOTDIR;
if (!inode->i_op)
break;
} else
path_to_nameidata(&next, nd);
err = -ENOTDIR;
if (!inode->i_op->lookup)
break;
continue;
/* here ends the main loop */
//对中间节点和对路径名的终点的处理是不一样的,存在一点差异
//下面是对路径名终点的处理
last_with_slashes:
lookup_flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
last_component:
/* Clear LOOKUP_CONTINUE iff it was previously unset */
//如果已经是最终文件了,就不需要再找下去了
nd->flags &= lookup_flags | ~LOOKUP_CONTINUE;
if (lookup_flags & LOOKUP_PARENT)
goto lookup_parent;
//如果最终是/..形式,就需要返回其父目录
if (this.name[0] == '.') switch (this.len) {
default:
break;
case 2:
if (this.name[1] != '.')
break;
follow_dotdot(nd);
inode = nd->dentry->d_inode;
/* fallthrough */
case 1:
goto return_reval;
}
if (nd->dentry->d_op && nd->dentry->d_op->d_hash) {
err = nd->dentry->d_op->d_hash(nd->dentry, &this);
if (err < 0)
break;
}
err = do_lookup(nd, &this, &next);
if (err)
break;
inode = next.dentry->d_inode;
if ((lookup_flags & LOOKUP_FOLLOW)
//中间节点如果是连接节点的话,无条件的跟踪下去
//但是对于路径名的终点,只有设置了标志位LOOKUP_FOLLOW才会跟踪下去
&& inode && inode->i_op && inode->i_op->follow_link) {
err = do_follow_link(&next, nd);
if (err)
goto return_err;
inode = nd->dentry->d_inode;
} else
path_to_nameidata(&next, nd);
err = -ENOENT;
if (!inode)
break;
//同样,对于路径名终点是目录的情况,只有在标志位中设置了LOOKUP_DIRECTORY,
//并且操作结构体中lookup存在的情况下才会查找
if (lookup_flags & LOOKUP_DIRECTORY) {
err = -ENOTDIR;
if (!inode->i_op || !inode->i_op->lookup)
break;
}
goto return_base;
lookup_parent:
nd->last = this;
nd->last_type = LAST_NORM;
if (this.name[0] != '.')
goto return_base;
if (this.len == 1)
nd->last_type = LAST_DOT;
else if (this.len == 2 && this.name[1] == '.')
nd->last_type = LAST_DOTDOT;
else
goto return_base;
return_reval:
/*
* We bypassed the ordinary revalidation routines.
* We may need to check the cached dentry for staleness.
*/
if (nd->dentry && nd->dentry->d_sb &&
(nd->dentry->d_sb->s_type->fs_flags & FS_REVAL_DOT)) {
err = -ESTALE;
/* Note: we do not d_invalidate() */
if (!nd->dentry->d_op->d_revalidate(nd->dentry, nd))
break;
}
return_base:
return 0;
out_dput:
dput_path(&next, nd);
break;
}
|