虚拟文件系统(VFS):抽象层,提供统一接口,支持各种文件系统,屏蔽各种文件系统和硬件的差异
各种文件系统:有的不把目录当做文件,有的没有inode(比如文件控制信息和文件内容放一起),有的没有某个数据(如某些文件系统不记录文件的最后访问时间),当然也有些文件系统提供了一些很强大的功能,这些都不要紧,VFS给定了我们内存中需要的数据结构和对其操作的方法,你(某文件系统)只要能在内存中生成这些结构并实现这些方法就可以通过VFS来统一管理。
VFS只访问下面这些数据结构和调用下面方法,你(某文件系统)生成结构并实现方法,某些方法你不想实现(VFS会调用通用函数)
VFS主要数据结构(对象):超级块,目录项,索引节点,文件
超级块对象:struct super_block, 存储特定文件系统信息。文件系统安装时在内存里创建,一般加载磁盘里的创建,基于内存的文件系统必须特定方式创建下
操作/方法:创建,释放,写入,删除索引节点,更新磁盘上的超级块,获取文件系统状态等等
索引节点对象:struct inode, 代表文件/目录/设备/有名管道等(一切皆文件)的元数据,磁盘没有inode怎么办(不管,反正你想办法内存创建下),当然只有文件被访问时才内存创建,含dentry对象链表(快速找到所有硬连接/名字),通过inode得到文件的控制信息和定位到实际内容
操作/方法:给定dentry对象创建inode,创建硬/软(符号)连接,创建删除目录,移动文件等等
目录项对象: struct dentry,含父目录dentry对象,关联的inode对象,使用计数(d_count),名称。
区分目录项对象和目录项字符串,如/bin/vi, /和bin和vi这三个路径分量都是目录项(字符串),在解析到特定路径分量(目录项字符串)会创建目录项对象并缓存此对象。
很明显,磁盘没有此结构,现场创建
状态:
被使用(inode有效,d_count大于0,不能丢弃)
未被使用(inode有效,d_count等于0,VFS当前并未使用它,留在缓存里呗,说不定过会就用到了,当然也可以撤销)
负状态(inode无效,大部分情况可以撤销,反复查找一个不存在文件可以留着,缓存查不到读实际文件去查发现查不到和缓存查到了发现是无效的)
目录项对象缓存(dcache):
1 inode里的dentry对象链表(上述)
2 ‘最近被使用的’双向链表:未被使用和负状态链表,头插尾删
3 散列表(链表解决冲突): 快速查找某个路径的dentry对象,根据父目录dentry对象和路径分量确定位置。
查找/bin/vi 举例:大致假定目录文件的内容是目录项字符串和inode number的映射
若不缓存dentry对象:假设已有bin的inode节点,获取bin目录的内容,遍历内容查找vi对应的inode
缓存查找:假设已找到bin的dentry对象(根据/的dentry对象和bin字符串),根据bin的dentry对象和vi字符串进行散列查找
dentry对象使inode的使用计数为正,保证了inode对象也缓存在内存中
操作/方法:判断dentry对象是否有效(VFS从dcache取出后调用,大部分文件系统不实现,通用实现返回有效),目录项对象释放等。
文件对象:struct file ,代表进程打开的文件,进程直接处理它,open系统调用创建,close撤销
含dentry对象指针(dentry对象含inode对象指针定位到实际文件),含当前偏移,访问模式 ,使用计数f_count(files_struct可能多个位置指向同一file对象)等。多个进程可打开同一文件,进程也可反复打开和关闭同一文件,无对应磁盘数据。
操作/方法:更新偏移,读/写,mmap(文件映射到地址空间,file和vm_area_struct结构体作为参数),open,fsync等
其他与文件系统相关数据结构:
file_system_type: 一种类型一个此结构,含从磁盘读取超级块的方法(安装时读取并内存组建)
vfsmount:一个安装的文件系统一个此结构(安装时创建),代表安装点
与进程相关数据结构:放于task_struct内
files_struct:含file对象数组,数组下标(索引)为文件描述符(从0开始),CLONE_FILES线程共享。
fs_struct:含进程当前工作目录和根目录,CLONE_FS线程共享。
mmt_namespace:含根目录的vfsmount和vfsmount链表,所有进程共享(大家看到的都一样嘛),CLONE_NEWS给单独的命名空间,大部分系统只有一个命名空间。