最近追完了open系统调用,感觉东西很杂。文件系统在整体上比较好理解,但是并不好看懂,杂糅在一起的有很多函数,很多宏,以及很多结构体。在这里,我们首先对结构体做一个简单的介绍。
以下所有的源码都选自linux kernel 4.18.16,可以参考Bootlin。
nameidata
nameidata结构体在路径寻找中有着重要的作用,通常它叫做nd,通过它可以很容易的找到当前的路径path,以及当前文件系统的root,也就是当前文件系统的“根”,话句话说,就是当前文件系统的挂载点目录。
(其实说成是挂载点也不太好,因为一个文件系统一般是挂载到另外一个文件系统目录下的,挂载的目录和它的根路径名一样,不过并不是一个dentry,他们属于不同的文件系统)
下面把比较重要的量都做个介绍
- struct path path
当前路径
- struct qstr last
last.name 指向最后一个路径分量,在link_path_walk中这个量会不断移动(处理完一个分量就处理下一个)
- struct path root
当前文件系统的根
- int last_type
最后一个路径分量的类型,和last一起在link_path_walk中使用
- struct inode *inode
指向path中当前路径dentry的inode
- struct nameidata *saved
这个被用在restore_nameidata中,saved在追踪路径之前保存当前路径,当路径行走完成时,用来还原原来的路径
可以参考restore_nameidata和set_nameidata函数
path
- struct vfsmount *mnt
指向当前文件系统的vfsmount结构
- struct dentry *dentry
指向当前路径的dentry
vfsmount
- struct dentry mnt_root
指向当前文件系统的根目录
- struct super_block *mnt_sb
指向当前文件系统的super block
mount
这个结构体重点在前面,尤其注意里面的vfsmount mnt,path中的*mnt就是指向这个结构体的mnt的。这个结构体用来记录文件系统的mount情况。
- mount *mnt_parent
一个文件系统一般都是挂载在另外一个文件系统下,这里就是指向父文件系统的mount结构
- dentry *mnt_mountpoint
这里指向挂载点路径,可想而知这个路径是在父文件系统下的,只不过其名与mnt.mnt_root一样,但是所属的文件系统不一样。
经常可以看到用 struct mount *mnt = real_mount(nd->path.mnt); 这样的语句来获取mount结构,vfsmount并没有明确指向mount结构,但是却可以获得mount结构。想想其实并不奇怪,因为有contains_of
contains_of不得不说真的很聪明
对于这两个结构或者文件系统的挂载,如果以后还有混淆的地方,可以参看follow_dotdot_rcu函数(获取上层路径)