• Home
  • About
    • Ruinan photo

      Ruinan

      Something interesting.

    • Learn More
    • Email
    • Github
  • Posts
    • All Posts
    • All Tags
  • Recent Project
  • Problem List

文件系统Preview

20 Nov 2019

最近追完了open系统调用,感觉东西很杂。文件系统在整体上比较好理解,但是并不好看懂,杂糅在一起的有很多函数,很多宏,以及很多结构体。在这里,我们首先对结构体做一个简单的介绍。

以下所有的源码都选自linux kernel 4.18.16,可以参考Bootlin。

nameidata

struct nameidata {
	struct path	path;
	struct qstr	last;
	struct path	root;
	struct inode	*inode; /* path.dentry.d_inode */
	unsigned int	flags;
	unsigned	seq, m_seq;
	int		last_type;
	unsigned	depth;
	int		total_link_count;
	struct saved {
		struct path link;
		struct delayed_call done;
		const char *name;
		unsigned seq;
	} *stack, internal[EMBEDDED_LEVELS];
	struct filename	*name;
	struct nameidata *saved;
	struct inode	*link_inode;
	unsigned	root_seq;
	int		dfd;
} __randomize_layout;

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 path {
	struct vfsmount *mnt;
	struct dentry *dentry;
} __randomize_layout;
  • struct vfsmount *mnt

指向当前文件系统的vfsmount结构

  • struct dentry *dentry

指向当前路径的dentry

vfsmount

struct vfsmount {
	struct dentry *mnt_root;	/* root of the mounted tree */
	struct super_block *mnt_sb;	/* pointer to superblock */
	int mnt_flags;
} __randomize_layout;
  • struct dentry mnt_root

指向当前文件系统的根目录

  • struct super_block *mnt_sb

指向当前文件系统的super block

mount

struct mount {
	struct hlist_node mnt_hash;
	struct mount *mnt_parent;
	struct dentry *mnt_mountpoint;
	struct vfsmount mnt;
	union {
		struct rcu_head mnt_rcu;
		struct llist_node mnt_llist;
	};
#ifdef CONFIG_SMP
	struct mnt_pcp __percpu *mnt_pcp;
#else
	int mnt_count;
	int mnt_writers;
#endif
	struct list_head mnt_mounts;	/* list of children, anchored here */
	struct list_head mnt_child;	/* and going through their mnt_child */
	struct list_head mnt_instance;	/* mount instance on sb->s_mounts */
	const char *mnt_devname;	/* Name of device e.g. /dev/dsk/hda1 */
	struct list_head mnt_list;
	struct list_head mnt_expire;	/* link in fs-specific expiry list */
	struct list_head mnt_share;	/* circular list of shared mounts */
	struct list_head mnt_slave_list;/* list of slave mounts */
	struct list_head mnt_slave;	/* slave list entry */
	struct mount *mnt_master;	/* slave is on master->mnt_slave_list */
	struct mnt_namespace *mnt_ns;	/* containing namespace */
	struct mountpoint *mnt_mp;	/* where is it mounted */
	struct hlist_node mnt_mp_list;	/* list mounts with the same mountpoint */
	struct list_head mnt_umounting; /* list entry for umount propagation */
#ifdef CONFIG_FSNOTIFY
	struct fsnotify_mark_connector __rcu *mnt_fsnotify_marks;
	__u32 mnt_fsnotify_mask;
#endif
	int mnt_id;			/* mount identifier */
	int mnt_group_id;		/* peer group identifier */
	int mnt_expiry_mark;		/* true if marked for expiry */
	struct hlist_head mnt_pins;
	struct fs_pin mnt_umount;
	struct dentry *mnt_ex_mountpoint;
} __randomize_layout;

这个结构体重点在前面,尤其注意里面的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函数(获取上层路径)



File system Like Tweet