文件系统实现
典型的文件控制块FCB
FCB与文件一一对应。
- 文件权限
- 文件日期(创建、访问、写入)
- 文件所有者、组、ACL
- 文件大小
- 文件数据块或它的指针
打开文件的流程
-
系统调用open()将文件名传送到逻辑文件系统
-
搜索该文件是否已被其他进程适用
- 如果是,则在单个进程的打开文件表中创建一个指向现有整个系统的打开文件表的条目
- 如果不是,则根据文件名搜索目录结构找到文件,将其FCB复制到内存的整个系统的开放文件表中,再在单个进程的打开文件表中创建一个指向它的条目
打开文件表的条目在UNIX中称为文件描述符,在Windows中称为文件句柄。
关闭文件的流程
当进程关闭文件时,它的打开文件表的条目会被删除,整个系统的条目的打开数量会被递减。当所有用户都关闭它该文件时,更新的元数据会写回磁盘,整个系统的打开文件表的该条目会被删除。
目录实现
线性列表
- 采用文件名称和数据块指针构成线性列表
- 编程简单,但执行费时:查找文件需要线性搜索
哈希表
- 根据文件名称算得哈希值,返回存储位置的指针
- 搜索时间短
- 需要避免碰撞,可以采用优质的哈希函数或者拉链法
- 入口的数量通常是固定的,如果需要增大,必须更换哈希函数
分配方法
如何为存储在磁盘上的文件灵活分配空间?
连续分配
- 每个文件在磁盘上占有一组连续的块
- 记录<文件,起始点,长度>三元组即可表示一个文件的存储区域
- 可以进行随机访问
- 外部碎片问题
- 难以确认应分配的空间大小,过小则文件难以增长,过大则有内部碎片
链接分配
- 每个文件是磁盘块的链表
- 解决了外部碎片和大小声明的问题
- 只要还有空闲的文件块,就可以链接到链表尾部,供文件增长使用
- 只能有效用于顺序访问文件,如果要随机访问第i块,需要从头开始跟着指针直到该块
- 可以按簇分配来减少指针占用的空间,但可能增加内部碎片
- 簇:多个块聚合成簇
- 可靠性问题:如果指针丢失或者毁坏?
索引分配
-
将所有指针放在一起形成索引块
-
每个文件都有自己的索引块,第i个条目指向第i个块的位置
-
支持随机访问(直接访问),并且没有外部碎片问题
-
问题:索引块应该为多大?
-
某些文件只有一两块,但必须分配整个索引块的大小
-
通常,索引块要尽可能小。但是过小的索引块不能为大文件存储提供足够多的指针
-
有如下几种机制来解决该问题:
-
链接方案:多个索引块进行链接
-
多级索引:第一级索引块指向第二级索引块…直到最后一级指向文件块
-
UNIX的组合方案:在inode的索引块不分,分为直接块、一级间接、二级间接…
-
-
文件分配表FAT
- 链接分配的一个重要变种
- 在每个卷(Windows分区)的开头部分存储该表
- FCB存储开始索引号,通过在FAT中反复查询获得所有块号,直到查到0
- 通常需要对FAT进行缓存,避免大量的磁头寻道时间
- FAT的空间消耗通常比UNIX组合方案要大。因为FAT大小正比于磁盘大小,inode大小正比于打开的文件数
空闲空间管理
为了跟踪空闲的磁盘空间,系统需要维护一个空闲空间列表。
Bit Map
通过一串Bit(如0表示占用,1表示可用,一位表示一块)描述磁盘的可用情况。
通常将BitMap完全保存在内存中效率才够高。
链表
将所有空闲块用链表连接起来,将指向第一空闲块的指针保存在磁盘的特殊位置。
通常操作系统只需一个空闲块分配给文件,因此不需要遍历空闲列表,效率有保证。
其他方法
- 组:将空闲块信息直接放在块内
- 计数:通常,多个连续块会同时分配或释放,因此可以记录第一块的地址和连续块的数量
恢复
- 一致性检查
- 基于日志,面向事务
- 完全备份、增量备份