Linux下的文件系统中宏观上主要分为三层:一是上层的文件系统的系统调用;二是虚拟文件系统VFS(Virtual File System)层,三是挂载到VFS中的各种实际文件系统。
VFS是一种软件机制,只存在于内存中,每次系统初始化期间Linux都会先在内存中构造一棵VFS的目录树(也就是源码中的namespace)。VFS主要的作用是对上层应用屏蔽底层不同的调用方法,提供一套统一的调用接口,二是便于对不同的文件系统进行组织管理。因此,VFS其实就是文件系统组织管理中的一个抽象层。
一个典型的VFS目录组织方式如下图所示:
而对于磁盘上的文件系统,结构大概如下:
1 super_block
Superblock: 是一个文件系统的头部,一般在一个文件系统的第一个block里,存储着文件系统的最主要信息,如文件系统名称,大小,块大小,inode大小,有多少inode已用和未用,有多少空闲block等等。对于存储于物理磁盘上的文件系统,与on-disk的superblock对应。而有些文件系统只存在于ram中,那么为这些文件系统构建的Superblock则只是为对接vfs文件系统而存在。
2 inode
inode: 一个inode对应一个客体文件(或目录),携带这个文件的所有元信息,包括文件属性、占用空间等信息。对于在磁盘上有物理实体的文件系统,其与On-disk的inode对应。
3 dentry
dentry: 是directory entry的缩写,是一个抽象话概念,不对应On-disk结构(或者你把路径信息理解成dentry,当然这个不严谨)。从其字面意思也可以看出它是内核为构建和访问目录树形结构服务的,是目录与其下文件的缓存,主要信息包括文件名和其parent目录名。一个dentry链表常常是可以从一个文件向上追踪其每一个parent directory,直到root。注意,在内核中可能出现多个dentries结构对应一个inode,比如硬链接就是两个不同名的文件对应一个inode。
dentry和inode大概关系如下:
VFS文件系统中的inode与实际文件系统的inode有一定的关系,但不能等同。真实磁盘文件的inode是存在于物理外存上的,但VFS中的inode是存在于内存中的,系统读取外存中的inode信息进行一定加工后,生成内存中的inode。虚拟的文件系统也具有inode结构,只是这是系统根据相应的规则生成的,不存在于实际外存中。dentry则只存在于内存中,在磁盘上没有相应文件。
4 file_system_type
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_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;
};
name: 文件系统的名字,如xfs, ext2等
fs_flags: 说明文件系统的类型,下面的宏定义代表了它的几种类型:
- FS_REQUIRES_DEV: 文件系统必须在物理设备上。
- FS_BINARY_MOUNTDATA: mount此文件系统时(参见mount_fs函数 - fs/super.c)需要使用二进制数据结构的mount data(如每个位域都有固定的位置和意义),常见的nfs使用这种mount data(参见struct nfs_mount_data结构 - include/uapi/linux/nfs_mount.h)。
- FS_HAS_SUBTYPE: 文件系统含有子类型,最常见的就是FUSE,FUSE本是不是真正的文件系统,所以要通过子文件系统类型来区别通过FUSE接口实现的不同文件系统。
- FS_USERNS_MOUNT: 文件系统每次挂载都后都是不同的user namespace,如用于devpts。
- FS_RENAME_DOES_D_MOVE: 文件系统将把重命名操作reame()直接按照移动操作d_move()来处理,主要用于网络文件系统。
mount: 代替早期的get_sb(),用户挂载此文件系统时使用的回调函数。
kill_sb: 删除内存中的super block,在卸载文件系统时使用。
owner: 指向实现这个文件系统的模块,通常为THIS_MODULE宏。
next: 指向文件系统类型链表的下一个文件系统类型。
fs_supers: 此文件系统类型的文件系统超级块结构都串连在这个表头下。