本文是对<Linux Kernel Development(Third Edition)>中 第13章的部分内容进行翻译。
VFS(Virtual File System) 是文件系统的抽象层,它是用户层与底层文件系统之间的接口,使得用户不必关系底层文件系统或存储设备,只要使用标准文件操作接口即可实现文件的读写、创建、删除等,甚至是跨文件系统的数据拷贝,这在DOS时代是无法想象的事情。
具体的文件系统对于VFS层或其他内核层看起来是一样的,它们支持文件或目录这样的描述,也支持创建及删除文件等这样的操作。
VFS使得内核更容易地支持更多地文件系统类型。
---------------VFS 四种主要的结构体及相应的操作结构体概要描述---------------
VFS中四个主要的类型
file:
从进程的角度,表示一个打开的文件
dentries:
文件被组织在目录中,目录还可以包含子目录,目录可以互相嵌套形成路径。路径的每个部分被称作directory entry。
Example:
/home/wolfman/butter
/, home, wolfman 和文件butter都是directory entry,简称为dentries
目录对于VFS来说其实就是一个文件,因此操作文件的操作也可以用于操作目录。
File metadata:
Unix文件系统通常会将文件内容及文件相关信息分开存储,例如,权限、大小、拥有者和创建时间等,这类信息被称作file metadata,存储在inode中(index node)。
superblock:
上面的所有信息与文件系统的控制信息紧紧相连,文件系统的控制信息存储在superblock中。
与上面四种主要的结构类型相关的操作结构体,每个结构体都是由一组指向函数的指针构成。如果通用方法满足应用的话,则文件系统不必复写这些方法,如果不能满足,则文件系统可自定义方法,然后让函数指针指向它。
super_operations
Inode_operations
dentry_operations
file_operations
除了以上四个主要的结构类型,VFS还有其它的结构类型,如file_system_type(表示已注册的文件系统),vfsmount(表示mount point),fs_struct(表示与进程相关的文件系统)等。
---------------VFS 四种主要的结构体及相应的操作结构体详细描述---------------
Superblock(定义在linux/fs.h, 创建管理销毁此对象的方法定义在fs/super.c>
struct super_block{
…
struct super_operations s_op; /* superblock methods */
...
}
Super_operations(定义在linux/fs.h)
struct super_operations{
struct inode *(*alloc_inode)(structsuper_block *sb); /* 在指定的superblock上创建和初始化一个新的inode结构*/
...
}
VFS层通过如下方式进行调用
sb->s_op->alloc_inode(sb)
inode(定义在linux/fs.h)
struct inode{
…
struct timespec i_atime; /* 最后读取时间*/
…
struct inode_operations *i_op;
...
union {
struct pipe_inode_info *i_pipe;
struct block_device *i_bdev;
struct cdev *i_cdev;
}
...
}
每个inode结构会关联一种设备信息。该结构中有的属性是有些文件系统不支持的,可以设置为0,或者不被flush到磁盘上。
inode_operations(定义在linux/fs.h)
struct inode_operations{
int (*create) (struct inode *,struct dentry *,int, struct nameidata*);
...
}
VFS层通过create 或 open system call来调用create。
i->i_op->create(I,…)
dentry(定义在linux/dcache.h)
struct dentry{
…
struct dentry_operations *d_op;
…
}
这个结构体与super_block及inode的区别在于,前者不会与存储在磁盘上数据进行关联,因为dentry结构不会存储到磁盘中。
Dentry state
有三种状态 ,分别为 used、unused和negative.
Used状态的dentry,d_inode指向有效的inode,d_count是正数(表示有一个或多个人在使用)。不能被丢弃。
unused状态的dentry,d_inode指向有效的inode,d_count是0(表示没有人在使用)。这种状态的dentry可被认为是cached,将来使用时可直接拿来使用,如果需要重新声明,则可以先丢弃该dentry再声明。
negative状态的dentry,d_inode是NULL,由于inode被删除或者路径不存在。
Dentry cache
1.inode中的i_dentry 存放了一个列表,用于存放与它相关的dentry 结构。
2.双向列表用于存放最近最少使用的unsed和negative dentry。从head加入,从tail删除。
3.将路径与dentry用hash table关联起来。
dentry_operations(定义在linux/dcache.h)
struct dentry_operations{
…
Int (*d_hash)(struct dentry *, structqstr *); /*根据给定的dentry创建一个hash值*/
…
}
File(定义在linux/fs.h>)
Struct file{
…
Struct path f_path;
#definef_dentry f_path.dentry
Struct file_operations *f_op;
...
}
对于同一个文件,可能存在多个进程打开的情况,因此file结构会有多个。
这个结构体与dentry相似,不会与存储在磁盘上数据进行关联。
file_operations(定义在linux/fs.h>)
Struct file_operations{
…
Ssize_t (*read) (struct file *, char__user *,size_t, loff_t *);
Ssize_t (*write) (struct file *, char__user *,size_t, loff_t *);
...
}
该结构中的方法名称与system call中的非常相似,具体文件系统可以选择去实现自己的上述方法,也可以使用通用的方法。
file_system_type(定义在linux/fs.h>)
由于内核支持很多文件系统,因此需要一个结构来描述每个文件系统的行为及能力,这个结构体就是file_system_type
Struct file_system_type{
Const char *name; /*文件系统的名称*/
Int fs_flags; /*文件系统的类型*/
Struct super_block *(*get_sb)(structfile_system_type *, int, char *, void *);/*从磁盘读取superblock*/
...
}
每个文件系统只有一个file_system_type结构。当这个文件系统被mount时,vfsmount结构体就被创建出来。
files_struct(linux/fdtable.h),Fs_struct(linux/fs_struct.h),namespace(linux/mnt_namespace.h)
每个进程都有一个所打开的文件list、根文件系统list、当前工作目录list、mount pointlist等等。通过3个数据结构将VFS层及进程关联起来。
files_struct,进程描述符中的files entry指向它,用于存放打开的文件的进程信息及文件的描述。
fs_struct,进程描述符中的fs指向它,用于存放文件系统的信息
namespace,进程描述符中的mnt_namespace指向它,使得进程能够感知到被mount的文件系统的层次结构
通常情况下,进程与files_struct或者fs_struct是一一对应的,除非该进程是通过CLONE_FILES或CLONE_FS标记克隆出来的,files_struct或者fs_struct结构是被多个进程共享的。而namespace默认是被所有进程共享的,除非该进程是通过CLONE_NEWNS标记克隆出来的。