1.概述
在Linux系统,为了隐藏具体文件系统的实现细节,提供了一个虚拟文件系统,VFS支持的文件系统可以划分为以下三个类型:
(1)基于磁盘的文件系统Ext2, Ms-Dos
(2)网络文件系统,可以通过网络访问其它文件系统上的内容,如NFS,SMB。
(3)特殊的文件系统如/proc,存在内存的文件系统,可以通过通用文件系统接口访问相关信息,这类文件系统不占用磁盘空间。
2. VFS的管理对象
Linux虚拟文件系统主要管理以下几种对象:
(1)超级块对象(superblock object)存放文件系统的相关信息,超级块对象存放于磁盘。
(2)索引节点对象(inode object):存储文件的相关信息,如修改时间,文件大小等元数据,每个索引节点通过惟一的索引节点号标识(inode number),其存放在磁盘上,与磁盘上的文件控制块对应。
(3)目录项对象(dentry object):存放目录项与对应文件链接的信息,通过目录项对象可以查找到索引节点,主要用于查找,存在于内存,不需要写回。主要用于查找!
(4)文件对象(file object):存储进程打开文件的相关信息,存在于内存中,不需要写回。
每个对象都包含一些操作,如super_operations, inode_operations, dentry_operations和file_operations.
文件对象:
struct file
{
struct list_head f_list; /*所有打开的文件形成一个链表*/
struct dentry *f_dentry; /*指向相关目录项的指针*/
struct vfsmount *f_vfsmnt; /*指向VFS安装点的指针*/
struct file_operations *f_op; /*指向文件操作表的指针*/
mode_t f_mode; /*文件的打开模式*/
loff_t f_pos; /*文件的当前位置*/
unsigned short f_flags; /*打开文件时所指定的标志*/
unsigned short f_count; /*使用该结构的进程数*/
unsigned long f_reada, f_ramax, f_raend, f_ralen, f_rawin;/*预读标志、要预读的最多页面数、上次预读后的文件指针、预读的字节数以及预读的页面数*/
int f_owner; /* 通过信号进行异步I/O数据的传送*/
unsigned int f_uid, f_gid; /*用户的UID和GID*/
int f_error; /*网络写操作的错误码*/
unsigned long f_version; /*版本号*/
void *private_data; /* tty驱动程序所需 */
}; 3. 与进程相关的数据结构
(1)系统中的每个进程都有自己打开的一组文件,在的files_struct由进程描述符的files域指向,所有与进程相关如打开文件和文件描述符都存于其中。
structfiles_struct {
atomic_t count; /* 共享该表的进程数 */
rwlock_t file_lock; /* 保护以下的所有域,以免在sk->alloc_lock中的嵌套*/
int max_fds; /*当前文件对象的最大数*/
int max_fdset; /*当前文件描述符的最大数*/
int next_fd; /*已分配的文件描述符加1*/
struct file ** fd; /*指向文件对象指针数组的指针 */
fd_set *close_on_exec; /*指向执行exec( )时需要关闭的文件描述符*/
fd_set *open_fds; /*指向打开文件描述符的指针*/
fd_set close_on_exec_init;/* 执行exec( )时需要关闭的文件描述符的初 值集合*/
fd_set open_fds_init; /*文件描述符的初值集合*/
struct file * fd_array[32];/* 文件对象指针的初始化数组*/
}
fd指向已打开的文件对象列表,即struct file结构体。
(2)与进程相关的第二个结构体是fs_struct,由进程描述符的fs域指向,它包含文件系统和进程的相关信息。定义在
struct fs_struct{
atomic_t count; /*结构的使用计数*/
rwlock_t lock; /*保护该结构的锁*/
int umask; /*默认的文件访问权限*/
struct dentry *root; /*根目录的目录项对象*/
struct dentry *pwd; /*当前工作目录的目录项对象*/
struct dentry *altroot; /*当前可供选择的根目录的目录项对象*/
struct vfsmount *rootmnt; /*根目录的安装点对象*/
struct vfsmount *pwdmnt; /*pwd的安装点对象*/
struct vfsmount *altrootmnt; /*可供选择的根目录的安装点对象*/
}
该结构包含了当前的工作目录和根目录。
在open系统调用打开一个文件时,会将inode节点上的i_fop方法赋值给struct file的f_op指针,这样就可以进行文件的相关操作。并且将进程描述符current->files(struct files_struct)->fd[fd]指向内存的struct file文件对象结构体。这样,就将进程与文件相关联起来。那么inode节点的i_fop指针是何时赋值的?当inode节点由磁盘加载到内存时,将file_operations结构体指针保存在i_fop中。
关系图如下:
4.不同进程打开同一文件
每个进程都有与之相关联的files_struct对象,fd指向了具体的文件对象(struct file),这个结构体包括了文件的访问模式,文件指针的位置。因此,不同的进程打开同一文件时,会建立多个文件对象,而这些文件对象会指向同一个目录项对象(因为路径相同),目录项对象指向同一个inode节点。多个进程共享同一文件,其文件指针的位置是不相同的。
总结:
超级块对象描述文件系统的相关信息。
inode节点描述文件的相关信息(目录也是文件).
目录项对象主要用于查找文件操作,可找到相应的inode节点,多个不同的目录项可对应同一inode节点,即硬连接。
文件对象描述文件的相关信息,进程描述符通过files_struct指向file对象。