009 Linux文件系统数据结构详解:挂载点mount和vfsmount

前面介绍了超级块super_block、索引节点inode、目录项dentry等核心数据结构,接下来介绍文件系统挂载相关的mount和vfsmount结构体。

文件系统挂载就是将一个文件系统安装到全局文件结构树的一个分支上,文件系统挂载能力是VFS对外提供的统一的接口,实际挂载时会调用具体文件系统的实现(mount函数),这个具体实现逻辑是注册文件系统时,通过文件系统类型file_system_type结构体传递给VFS。挂载文件系统,VFS会回调具体文件系统的挂载函数mount(),mount()函数会构造超级块和根dentry,函数的返回值就是根dentry指针。

struct file_system_type {
	const char *name;
	int fs_flags;
	int (*init_fs_context)(struct fs_context *);
	const struct fs_parameter_spec *parameters;
	struct dentry *(*mount) (struct file_system_type *, int,
		       const char *, void *);
	void (*kill_sb) (struct super_block *);
	struct module *owner;
	struct file_system_type * next;
	struct hlist_head fs_supers;
        ......
};

一、挂载实例结构体

mount和vfsmount结构体都在mount.h中声明,mount结构体代表一个文件系统挂载实例,每挂载一次将会产生一个实例。

老版本只有vfsmount,新版本把vfsmount改为mount,同时将mount中的mnt_root、mnt_sb、mnt_flags成员移到vfsmount结构体中,也就是vfsmount结构体是mount的核心部分,vfsmount的使用频率更高,可以满足大部分需求

一个文件系统可以挂装载到不同的挂载点,所以文件系统树的一个位置要由<mount, dentry>二元组(或者说<vfsmount, dentry>)来确定。

1.vfsmount实例

1)mnt_root:根dentry,由文件系统类型的mount()函数返回

2)mnt_sb:超级块super_block,由文件系统类型的mount()函数生成,由根dentry的d_sb获取

3)mnt_flag:挂在标志位,在mount.h中定义

4)mnt_userns:用户命名空间

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

2.mount实例

以下是一个mount结构体,mount结构体信息更丰富,其中包含了vfsmount实例,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 */
	union {
		struct hlist_node mnt_mp_list;	/* list mounts with the same mountpoint */
		struct hlist_node mnt_umount;
	};
	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 hlist_head mnt_stuck_children;
} __randomize_layout;
字段涵义使用说明
mnt_hash链接到全局已挂载文件系统的哈希表namespace.h
struct hlist_head *mount_hashtable __read_mostly;
mnt_parent指向此文件系统的挂载点所属的文件系统,即父文件系统
mnt_mountpoint指向此文件系统的挂载点的dentry父文件系统的目录项
mnt指向此文件系统的vfsmount实例
mnt_mounts在此文件系统下的所有子文件系统的链表的表头,下面的节点都是mnt_child
mnt_child链接到父文件系统的mnt_mounts上
mnt_instance链接到超级块sb->s_mounts上的一个mount实例
mnt_devname设备名,如/dev/sdb1
mnt_list链接到进程namespace层次,已挂载文件系统中,表头为mnt_namespace的list域
mnt_expire链接到一些文件系统专有的过期链表,如NFS, CIFS等
mnt_share链接到共享挂载的循环链表中
mnt_slave_list此文件系统的slave mount链表的表头
mnt_slave连接到master文件系统的mnt_slave_list
mnt_master指向此文件系统的master文件系统
mnt_ns指向包含这个文件系统的进程的namespace
mnt_mp挂载点信息
mnt_umounting
mnt_idmount实例id
mnt_group_idmount组id
mnt_expiry_markmount过期标志
mnt_pins
mnt_stuck_children

二、挂载实例关系图

以下是一个挂载目录树,以这个树形结构为例,来展示mount实例之间关系

/mnt
---- abc (ext4,mount-point,/dev/sda)
---- ---- jkl(xfs,mount-point,/dev/sdb)
---- ---- ---- pqr(btrfs,mount-point,/dev/sdc)
---- ---- uvw(xfs,mount-point,/dev/sdd)
mount实例之间关系
mount实例之间关系

链接:查看原图

图示说明:

1)首先所有mount点实例链接到mount_hashtable(蓝色线条部分),这是一个全局哈希表,保存所有mount信息

2)mount点/mnt/abc的设备名为/dev/sda,它的mnt_mounts域包含了两个mount实例,一个是/mnt/abc/jkl,另一个是/mnt/abc/uvw

3)mount点/mnt/abc/jkl的设备名为/dev/sdc,它的mnt_mounts域包含一个mount实例/mnt/abc/jkl/pqr;它的mnt_child域指向父mount实例的mnt_mounts域

4)同理,可以分析/mnt/abc/uvw挂载点和/mnt/abc/jkl/pqr挂载点

上一篇:Linux文件系统数据结构详解:目录项dentry

参考文档:官方文档

《009 Linux文件系统数据结构详解:挂载点mount和vfsmount》有一个想法

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注