关于文件系统的三个易混淆的概念:
创建 以某种方式格式化磁盘的过程就是在其之上建立一个文件系统的过程。创建文现系统时,会在磁盘的特定位置写入关于该文件系统的控制信息。
注册 向内核报到,声明自己能被内核支持。一般在编译内核的时侯注册;也可以加载模块的方式手动注册。注册过程实际上是将表示各实际文件系统的数据结构struct file_system_type 实例化。
安装 也就是我们熟悉的mount操作,将文件系统加入到Linux的根文件系统的目录树结构上;这样文件系统才能被访问。
VFS依靠四个主要的数据结构和一些辅助的数据结构来描述其结构信息,这些数据结构表现得就像是对象;每个主要对象中都包含由操作函数表构成的操作对象,这些操作对象描述了内核针对这几个主要的对象可以进行的操作。
存储一个已安装的文件系统的控制信息,代表一个已安装的文件系统;每次一个实际的文件系统被安装时,内核会从磁盘的特定位置读取一些控制信息来填充内存中的超级块对象。一个安装实例和一个超级块对象一一对应。超级块通过其结构中的一个域s_type记录它所属的文件系统类型。
根据第三部分追踪源代码的需要,以下是对该超级块结构的部分相关成员域的描述,(如下同):
清单1. 超级块
struct super_block { //超级块数据结构
struct list_head s_list;
/*指向超级块链表的指针*/
……
struct file_system_type *s_type;
/*文件系统类型*/
struct super_operations *s_op;
/*超级块方法*/
……
struct list_head
s_instances; /*该类型文件系统*/
……
};
struct super_operations { //超级块方法
……
//该函数在给定的超级块下创建并初始化一个新的索引节点对象
struct inode *(*alloc_inode)(struct super_block *sb);
……
//该函数从磁盘上读取索引节点,并动态填充内存中对应的索引节点对象的剩余部分
void (*read_inode) (struct inode *);
……
};
索引节点对象存储了文件的相关信息,代表了存储设备上的一个实际的物理文件。当一个文件首次被访问时,内核会在内存中组装相应的索引节点对象,以便向内核提供对一个文件进行操作时所必需的全部信息;这些信息一部分存储在磁盘特定位置,另外一部分是在加载时动态填充的。
清单2. 索引节点
struct inode {//索引节点结构
……
struct inode_operations *i_op;
/*索引节点操作表*/
struct file_operations *i_fop; /*该索引节点对应文件的文件操作集*/
struct super_block
*i_sb;
/*相关的超级块*/
……
};
struct inode_operations { //索引节点方法
……
//该函数为dentry对象所对应的文件创建一个新的索引节点,主要是由open()系统调用来调用
int (*create) (struct inode *,struct dentry *,int, struct nameidata *);
//在特定目录中寻找dentry对象所对应的索引节点
struct dentry * (*lookup) (struct inode *,struct dentry *, struct nameidata *);
……
};
引入目录项的概念主要是出于方便查找文件的目的。一个路径的各个组成部分,不管是目录还是普通的文件,都是一个目录项对象。如,在路径/home/source/test.c中,目录 /, home, source和文件 test.c都对应一个目录项对象。不同于前面的两个对象,目录项对象没有对应的磁盘数据结构,VFS在遍历路径名的过程中现场将它们逐个地解析成目录项对象。
清单3. 目录项
struct dentry {//目录项结构
……
struct inode *d_inode;
/*相关的索引节点*/
struct dentry *d_parent;
/*父目录的目录项对象*/
struct qstr d_name;
/*目录项的名字*/
……
struct list_head d_subdirs;
/*子目录*/
……
struct dentry_operations *d_op; /*目录项操作表*/
struct super_block *d_sb;
/*文件超级块*/
……
};
struct dentry_operations {
//判断目录项是否有效;
int (*d_revalidate)(struct dentry *, struct nameidata *);
//为目录项生成散列值;
int (*d_hash) (struct dentry *, struct qstr *);
……
};