Linux文件系统对象之间的关系可以概括为文件系统类型、超级块、inode、dentry和vfsmount之间的关系。
文件系统类型规定了某种类型文件系统的行为,它存在的主要目的是为了构造这种类型文件系统的实例,或者被称为超级块实例。
超级块反映了文件系统整体的控制信息,超级块以多种方式存在。对于基于磁盘的文件系统,它以特定格式存在于磁盘的固定区域(取决于文件系统类型),为磁盘上的超级块。在文件系统被装载时,其内容被读入内存,构建内存中的超级块。其中某些信息为各种类型的文件系统所共有,被提炼成VFS的超级块结构。如果某些文件系统不具有磁盘上超级块和内存中超级块形式,则它们必须负责从零构造出VFS的超级块。
inode反映了某个文件系统对象的一般元信息,dentry反映了某个文件系统对象在文件系统树中的位置。同超级块一样,inode和dentry也有磁盘上、内存中以及VFS三种形式,其中VFSinode和VFS dentry是被提炼出来,为各种类型文件系统共有的,而磁盘上、内存中inode和dentry则为具体文件系统特有,根据实际情况,也可能根本不需要。
Linux有一棵全局文件系统树,反映了Linux VFS对象之间的关系。文件系统要被用户空间使用,必须先装载到这棵树上。每一次装载被称为一个装载实例,某些文件系统只在内核中使用,也需要这样一个装载实例。每个文件系统装载实例有四个必备元素:vfsmount、超级块、根inode和根dentry。
需要强调一下文件系统类型、超级块实例以及装载实例之间的关系。一个文件系统类型可能有多个超级块实例,而每个超级块实例又可以有多个装载实例。
设想分区/dev/sda1和/dev/sda2都被格式化为Minix文件系统类型。当/dev/sda1和/dev/sda2上的文件系统实例先后被装载到系统中时,假设在/mnt/d10和/mnt/d2下,则会有两个超级块实例,分别对应一个装载实例。透过/mnt/d10和/mnt/d2所作的改动(例如创建文件)分别反映到/dev/sda1和/dev/sda2上的文件系统实例中。
然后,/dev/sda1再次被装载到/mnt/d11下,则依然还是两个超级块实例,但是/dev/sda1对应的超级块实例将对应两个装载实例,一个对应在/mnt/d10上的装载,另一个对应在/mnt/d11上的装载。透过/mnt/d10和/mnt/d11所做的改动(例如创建文件)都会被反映到/dev/sda1上的文件系统实例中。
Linux支持多种文件系统,每种文件系统对应一个文件系统类型(file_system_type)结构。是编译到内核,还是作为模块动态装载,文件系统类型需要调用register_filesystem向VFS核心进行注册。如果该文件系统类型不再使用,应该调用unregister_filesystem从VFS核心中注销。上述两个函数都在文件fs/filesystems.c实现。
file_system_type结构中的域(来自文件include/linux/fs.h)
struct file_system_type {
const char *name;
int fs_flags;
#define FS_REQUIRES_DEV 1
#define FS_BINARY_MOUNTDATA 2
#define FS_HAS_SUBTYPE 4
#define FS_USERNS_MOUNT 8 /* Can be mounted by userns root */
#define FS_USERNS_DEV_MOUNT 16 /* A userns mount does not imply MNT_NODEV */
#define FS_RENAME_DOES_D_MOVE 32768 /* FS will handle d_move() during rename() internally. */
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;
struct lock_class_key s_lock_key;
struct lock_class_key s_umount_key;
struct lock_class_key s_vfs_rename_key;
struct lock_class_key s_writers_key[SB_FREEZE_LEVELS];
struct lock_class_key i_lock_key;
struct lock_class_key i_mutex_key;
struct lock_class_key i_mutex_dir_key;
};
文件系统类型注册的主要目的是向Linux VFS提供mount和kill_sb回调函数,分别在Linux装载或卸载这种类型的文件系统实例时被调用。
根据文件系统类型的不同,在Linux内核中可以有一个或多个这种类型的文件系统超级块实例。比如,对于sysfs,只能有一个超级块实例;
文件系统类型将所有超级块实例组成一个链表,链表的表头为fs_supers。超级块对象通过s_instances链接到所属文件系统类型的超级块实例链表中。
比较重要的域是
struct dentry *(*mount) (struct file_system_type *, int,
const char *, void *);
1.mount系统调用流程
2.sys_mount-->file_system_type.mount
//入参:mount -t kingfs /dev/sda /mnt
//dev_name:/dev/sda dir_name:/mnt type:kingfs
SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name,
char __user *, type, unsigned long, flags, void __user *, data)
{
ret = do_mount(kernel_dev, kernel_dir->name, kernel_type, flags,
(void *) data_page);
}
-->
static int do_new_mount(struct path *path, const char *fstype, int flags,
int mnt_flags, const char *name, void *data)
-->
struct vfsmount *
vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data)
-->
struct dentry *
mount_fs(struct file_system_type *type, int flags, const char *name, void *data)
{
root = type->mount(type, flags, name, data);
}
比如mount命令操作:mount -t proc proc /mnt/
static struct file_system_type proc_fs_type = {
.name = "proc",
.mount = proc_mount,
.kill_sb = proc_kill_sb,
.fs_flags = FS_USERNS_MOUNT,
};
static struct dentry *proc_mount(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data)
{
struct super_block *sb;
//获取超级块sb
sb = sget(fs_type, proc_test_super, proc_set_super, flags, ns);
//填充超级块成员域
err = proc_fill_super(sb);
}
//umount的时候调用
static void proc_kill_sb(struct super_block *sb)
文件系统如何加入到系统。调用register_filesystem向VFS核心进行注册。
int register_filesystem(struct file_system_type * fs)
{
struct file_system_type ** p;
p = find_filesystem(fs->name, strlen(fs->name));
}