《第八章》虚拟文件系统
VFS的层次
文件系统实现与用户进程(或C库)之间。
文件系统分类
基于磁盘的文件系统(ext2/3 fat iso9660…)、虚拟文件系统(proc)、网络文件系统(nfs)
通用文件模型
VFS提供一种结构模型,包含了一个强大的文件系统所应具备的所有组件。所有的文件系统实现,都必须提供与VFS定义的结构配合的例程,以弥补两种试图之间的差异。
文件描述符
一个整数,在用户层所有有关文件的操作中用于标识一个文件,在打开文件时由内核创建,特定于进程。
inode
linode是什么?
²inode用来存放文件的元数据(例如,文件的创建者、文件的创建日期、文件的大小等等)
²注意inode并不包含文件名。
linode的内容
inode包含文件的元信息,具体来说有以下内容:
²文件的size、文件属主的User ID、Group ID
²文件的读、写、执行权限
²文件的时间戳,:ctime(inode上一次变动的时间)、mtime(文件内容上一次变动的时间)、atime(文件上一次打开的时间)。
²链接数,即有多少文件名指向这个inode。
²文件数据分布在哪些磁盘Block。
linode的状态
每个inode处于三种状态中的一个:
²inode位于内存中,未关联到文件;(inode_unused)
²inode位于内存中,由一个或多个进程使用,已与磁盘同步;(inode_in_used)
²inode处于活动使用状态,与磁盘上内容未同步,脏inode;
linode是如何组织的?
²内核使用两种方式组织inode。
²链表:每个inode都有一个i_list成员,可将inode存储在链表中。(inode出现在特定于超级块的链表中i_sb_list,同时出现在特定于状态的链表中,例如inode_in_used)
²散列:每个inode同时出现在一个散列表中(根据inode号快速访问inode)。
l目录是什么?
²Linux下,目录也是文件,也有inode和数据部分,其数据部分内容如下:
第一部分表示对应inode的编号(系统内唯一),第二部分表示文件或目录的名字。
内核如何访问/user/bin/emacs
首先读取根目录(这个在内核中一直被维护,),在根目录文件的数据部分查找user这个目录项,根据其中的inode编号,获取inode。bin的查找类似,一直到查找到emacs,找到emacs对应的inode,该inode的数据部分即emacs这个文件(普通数据文件)的内容。
图示:
目录项缓存dentry:
l引入dentry
上述访问/user/bin/emacs过程非常耗时,需要不断地读取inode和对应的数据部分。为了加速,内核将之前访问过的目录或文件(统称为目录项)缓存起来,下次再访问同样的目录项(例如,/user/bin/vi的/user/bin/部分)时,可以直接找到对应的inode(上图中为10号)。
ldentry的目的:
dentry的主要用途是建立文件名和inode之间的关联。
所以该结构体包括两个最主要的字段,d_inode和d_name。
其中,d_name为文件名。qstr是内核对字符串的封装(可以理解为带有散列值的char*)。
d_inode是与该文件名对应的inode。
ldentry结构体:
structdentry {
…
/* Where the name belongs to - NULL is negative */
structinode *d_inode;
structqstrd_name;
structdentry *d_parent;/* parent directory */
union{
structlist_headd_child;/* child of parent list */
structrcu_headd_rcu;
}d_u;
structlist_headd_subdirs;/* our children */
structdentry_operations *d_op;
structsuper_block *d_sb;/* The root of the dentry tree */
unsignedchard_iname[DNAME_INLINE_LEN_MIN];/* small names */
…
};
l什么时候创建
在VFS(以及文件系统实现)读取一个目录项(目录或普通文件)后,则创建一个dentry来缓存找到的数据。
l内存中这些dentry如何组织管理
²结构:各个dentry实例组成了一个网络,例如,当前dentry实例对应的所有文件和子目录相关联的dentry都归入到d_subdirs中。
²组织方式一:内核所有活动的dentry实例都保存在一个散列表中,该散列表使用dentry_hashtable实现(全局dentry散列表)。
²组织方式二:LRU链表,长时间不使用的dentry会被删除。
链接link
l两类链接:符号链接(软链接)和硬链接。
l符号链接(软链接)文件使用自己的inode,该inode的数据部分包含了一个字符串,给出了链接目标的路径。
l硬链接创建时,使用了已有的inode编号。硬链接建立以后,无法区分原来的文件和新建的硬链接文件。这种情况下,inode使用计数器来确保文件删除操作中,当没有其他文件使用该inode时,才能真正删除该inode。
示意图:
特定于进程的信息
structtask_struct {
...
/*进程的文件系统相关的信息*/
structfs_struct *fs;
/*该进程打开的文件*/
structfiles_struct *files;
...
}
structfiles_struct {
...
structfdtablefdtab;
structfile *fd_array[NR_OPEN_DEFAULT];
};
structfile {
...
structpath *f_path;
loff_t f_pos;
...
};
structfile_operations {
...
ssize_t (*write) (structfile *,constchar__user *, size_t, loff_t *);
int(*readdir) (structfile *,void*, filldir_t);
unsignedint(*poll) (structfile *,structpoll_table_struct *);
int(*ioctl) (structinode *,structfile *,unsignedint,unsignedlong);
int(*mmap) (structfile *,structvm_area_struct *);
int(*open) (structinode *,structfile *);
...
};
structfile_operations->open函数实质上是将一个file对象关联到一个inode。
poll函数也在其中。
从task到dentry/inode