上文介绍了解析文件路径名的一个通体的过程,这里再把其中的一些细节拿出来进行分析。首先对于文件名的特点,可以分为三类:普通文件名,'.'和'..',对于'.'的处理很简单,因为它表示当前目录,因此直接通过continue进入下一轮查找即可,对于'..',也就是退回到父目录,本身也不是一件难事,但是这里要考虑到几个特殊情况,先看看内核处理'..'的方法:
相关阅读:Linux虚拟文件系统--文件路径名的解析(2)--回退父目录
static __always_inline void follow_dotdot(struct nameidata *nd)
{
set_root(nd);
while(1) {
struct vfsmount *parent;
struct dentry *old = nd->path.dentry;
/*如果当前所处的目录即为根目录则break*/
if (nd->path.dentry == nd->root.dentry &&
nd->path.mnt == nd->root.mnt) {
break;
}
spin_lock(&dcache_lock);
//如果当前所处的目录不为当前路径所属文件系统的根目录,也就是说可以直接向上退一级
if (nd->path.dentry != nd->path.mnt->mnt_root) {
nd->path.dentry = dget(nd->path.dentry->d_parent);//当前的目录退到上一级
spin_unlock(&dcache_lock);
dput(old);
break;
}
/*下面的情况对应于当前所处的目录为文件系统的根目录*/
spin_unlock(&dcache_lock);
spin_lock(&vfsmount_lock);
parent = nd->path.mnt->mnt_parent;//取父文件系统
if (parent == nd->path.mnt) {//父文件系统即为本身,则表明没有父文件系统,直接break
spin_unlock(&vfsmount_lock);
break;
}
mntget(parent);//增加父文件系统的引用计数
nd->path.dentry = dget(nd->path.mnt->mnt_mountpoint);//取当前文件系统的挂载点,这样就退回到了父文件系统
spin_unlock(&vfsmount_lock);
dput(old);
mntput(nd->path.mnt);
nd->path.mnt = parent;//设置当前路径的mnt为父文件系统
}
/*一般情况下,前面的操作可以保证返回到上级目录,但是有一种情况就是
当前目录的上级目录有可能还挂载了其他的文件系统,这样会隐藏之前的文件系统,
follow_mount()用来处理这种情况*/
follow_mount(&nd->path);
}
while循环里面的路径可以分为三种:
1.当前目录为nd中已经预设好的根目录,也就是说无法再向上退一层了,这种情况直接break
2.当前目录不为所属文件系统的根目录,这种情况是最常见的,可以向上退一层
3.当前目录为所属文件系统的挂载点,这种情况下,后退一层的话则会进入到父文件系统中,所以先要做一个文件系统的交换,再通过while(1)循环回到前面两种情况