操作系统第四章:文件管理
学完本章需要回答的几个问题?
- 文件的逻辑结构?生活中的例子?COG的IFD属于?
- 文件目录实现、结构分类、索引结点?
- 文件的物理结构?
- 文件的存储空间管理方法?
- 文件的基本操作?
- 文件共享
- 文件保护
- 文件系统的层次结构?
- 文件系统布局?
- VFS、文件系统挂载、文件系统对比
初识文件管理
磁盘块
文件的逻辑结构
文件目录
无环图目录结构的应用:硬链接
FCB/目录项
当前目录/根目录的磁盘IO对比
磁盘IO次数对比,文件检索速度更加快捷(索引节点调入内存、外存索引节点、内存索引节点)
需要时从外存调指定目录项的索引结点
文件物理结构
注意页号和内存块号的区别,类比文件的逻辑块和物理块
Q:怎么把逻辑块号转换为物理块号?
连续分配方式
为什么顺序访问速度最快?因为磁头(?)移动间隔很小,开小很小
链接分配方式
0.随机访问与顺序访问
随机访问:物理地址=起始地址+(逻辑索引×元素大小)
虽然显式链接(如 FAT 文件系统)在理论数据结构上仍然是“链表”(意味着你需要顺藤摸瓜),但由于这个链表被提取出来单独存放在内存中,因此在实际效果上,它实现了(近似的)随机访问。
1. 隐式链接(普通链表):必须读盘才能找到路
在隐式链接中,指向下一个块的指针是存储在数据块内部的。
场景: 你要读取文件的第 100 个块。
过程:
读取第 1 块(磁盘 I/O),在末尾拿到第 2 块的地址。
读取第 2 块(磁盘 I/O),在末尾拿到第 3 块的地址。
…
读取第 99 块(磁盘 I/O),在末尾拿到第 100 块的地址。
读取第 100 块。
代价: 你为了找到第 100 块,被迫进行了 99 次磁盘读操作。
结论: 极其缓慢,完全不支持随机访问。
2. 显式链接(FAT):地图在内存里
在显式链接中,所有的指针被提取出来,存放在一张集中的表中(FAT表,File Allocation Table)。关键点在于:系统启动时,这张表通常会被加载到内存中。
场景: 你还是要读取文件的第 100 个块。
过程:
CPU 在内存中的 FAT 表里查看:
Entry[1]指向 5。CPU 继续在内存里看:
Entry[5]指向 12…CPU 瞬间在内存里遍历完这 99 个节点的链条,找到了第 100 块的物理地址是 888。
直接驱动磁头去读取物理块 888。
代价: 99 次内存访问 + 1 次磁盘读操作。
结论:
内存访问的速度是纳秒级(ns)。
磁盘访问的速度是毫秒级(ms)。
两者相差几十万倍。
索引分配方式
逻辑结构VS物理结构
两个典型例子:
逻辑上顺序文件的链式存储在物理上用连续/链接/索引分配
逻辑上索引文件在物理上用索引分配


文件存储空间管理
成组链接超级块常驻内存,怎么进行回收和分配?
分配:分配1块,直接切出去201号磁盘块,100变为99
分配100块,切出整个超级块,把块号300对应的分组拷贝到超级块中
回收:假设上限100,现在回收1块,新增一个分组作为超级块,第一个指向老的超级块,第二个是新的回收的1块
文件的基本操作
文件共享
文件保护
文件系统的层次结构
文件系统布局
文件句柄可以理解为读写时的指针,文件记录号/文件描述符
虚拟文件系统VFS
文件系统对比
我们可以把文件系统分为三类:本地家政(管理硬盘)、远程快递(跨网传输)、逻辑叠罗汉(容器专用)。
| 类型 | 文件系统 | 主要角色 | 核心特点 | 缺点 |
|---|---|---|---|---|
| 本地 | EXT4 | Linux 标准版 | 极其稳定,万金油,兼容性好。 | 大规模并发下性能不如 XFS。 |
| 本地 | XFS | Linux 企业版 | 擅长高并发、海量小文件,Docker 官方最推荐。 | 缩减容量(shrink)非常困难。 |
| 本地 | NTFS | Windows 专用 | 权限控制极其精细,带日志恢复。 | Linux 挂载时性能一般,协议不透明。 |
| 硬件 | UFS | 移动端/嵌入式 | 手机闪存的主流标准,读写延迟极低,省电。 | 主要是硬件接口协议,不适合服务器。 |
| 网络 | NFS | 远程共享 | 像文件夹一样挂载远程服务器,配置极简。 | 依赖网络,不支持硬链接和原子操作。 |
| 逻辑 | Overlay2 | Docker 引擎 | 不直接存数据,而是把上面的系统“叠”起来看。 | 必须跑在支持它的本地系统(EXT4/XFS)上。 |
它们之间的“套娃”关系
在 Docker 的实际运行中,这些系统是层级协作的,而不是互相替代。
最底层(物理层):比如你的手机存储芯片走的是 UFS 协议,或者服务器硬盘格式化成了 XFS。
中间层(宿主层):Linux 内核通过 VFS 识别出这是一块 XFS 硬盘。
应用层(Docker 层):Docker 启动 Overlay2 驱动,在 XFS 的某个文件夹里开始“叠罗汉”(层级镜像)。
数据层(挂载层):如果你想让容器里的数据存到另一台机器,你会通过 NFS 挂载一个远程目录。
不建议在 NFS 上运行 Overlay2 的原因:
1. 硬链接(Hard Link)的一致性问题
Overlay2 在处理镜像层(Layers)时,大量使用了硬链接来节省空间和提高效率。
- NFS 的局限:在网络环境下,保证跨节点的硬链接一致性非常困难。如果网络出现抖动,NFS 客户端和服务器之间关于硬链接计数的同步可能出错,导致 Docker 镜像层损坏。
2. Copy-on-Write (CoW) 的性能极差
当容器修改镜像中的文件时,Overlay2 会执行“写时复制”操作:将文件从低层(LowerDir)拷贝到高层(UpperDir)。
- 网络开销:在本地磁盘(如 EXT4/XFS)上,这只是毫秒级的操作。但在 NFS 上,这意味着大量的小文件读写请求要通过网络往返,延迟(Latency)会放大几十倍。
3. POSIX 兼容性与原子性
POSIX是Linux VFS的特性
Overlay2 依赖于底层文件系统的某些高级 POSIX 特性,例如 whiteout(白点文件,用于标记删除)。
- 不完整支持:许多 NFS 配置(尤其是旧版本或非标准的 NAS 设备)对 POSIX 特性的支持并不完美。这会导致 Docker 在删除文件或合并层时出现不可预知的报错,最常见的表现就是容器启动时提示
storage driver overlay2: failed to...。
4. 常见的架构对比
| 特性 | 本地文件系统 (EXT4/XFS) | 网络文件系统 (NFS) |
|---|---|---|
| 访问速度 | 极快 (直接访问内存/总线) | 慢 (受限于带宽和网络延迟) |
| 原子性保证 | 强 (内核层面保证) | 弱 (受网络同步机制影响) |
| Overlay2 兼容性 | 完美原生支持 | 极其不稳定,经常报错 |