前面介绍了超级块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_id | mount实例id | |
mnt_group_id | mount组id | |
mnt_expiry_mark | mount过期标志 | |
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)
链接:查看原图
图示说明:
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挂载点
参考文档:官方文档
《009 Linux文件系统数据结构详解:挂载点mount和vfsmount》有一个想法