第 4 章 文件管理
408 操作系统第 4 章 文件管理复习讲义,涵盖核心概念、重点考点与典型题型。
Last updated on
先把整章压缩成一句话:
用户写文件名
↓
操作系统查目录
↓
目录项找到 inode / FCB
↓
inode / FCB 找到文件的磁盘块
↓
根据文件物理结构访问真正的数据如果这条链理解透了,第 4 章的大部分知识就只是“这条链的不同环节怎样实现”。
一、本章整体框架
| 模块 | 核心问题 | 考试重要度 |
|---|---|---|
| 文件基本概念 | 什么是文件、文件有哪些属性 | ★★ |
| 文件逻辑结构 | 用户眼里的文件如何组织 | ★★★ |
| 文件物理结构 | 数据块实际怎样放在磁盘 | ★★★★★ |
| FCB / inode | 操作系统怎样描述一个文件 | ★★★★★ |
| 目录结构 | 文件名怎样找到文件 | ★★★★ |
| 文件操作 | create/open/read/write/close/delete 怎样实现 | ★★★★ |
| 文件共享 | 硬链接、软链接 | ★★★★★ |
| 文件保护 | 谁能读、写、执行 | ★★★ |
| 文件系统布局 | 磁盘与内存中的文件系统结构 | ★★★★ |
| 空闲空间管理 | 哪些磁盘块还能使用 | ★★★★★ |
| VFS | 如何统一 ext4、NTFS、FAT 等 | ★★★★ |
| 挂载 | 一个文件系统怎样接入目录树 | ★★★ |
二、首先搞懂:文件到底是什么?
文件是存放在持久性存储设备上的信息集合。
从用户角度看,你看到的是:
考研资料.pdf
main.c
hello.txt
video.mp4磁盘实际上完全不知道这些“文件名”是什么意思,它只知道:
0号块
1号块
2号块
3号块
……所以文件系统做的本质工作,是把“零散的磁盘块”抽象为用户可以理解的“文件和目录”。
一个文件可以理解为:
文件
├── 文件内容
└── 文件元数据所谓元数据,就是“描述文件的数据”,包括文件类型、大小、位置、所有者、权限、创建/修改时间以及数据块位置等。
三、文件的逻辑结构
这里一定要先区分两个概念:
逻辑结构回答:
用户怎么看这个文件?
物理结构回答:
这个文件的数据块在磁盘上实际上怎么放?
资料将逻辑文件分成无结构文件和有结构文件。
1. 无结构文件:流式文件
最简单。
操作系统认为文件就是:
byte0 byte1 byte2 byte3 byte4 ...没有“第几条记录”的概念。
例如文本文件、程序文件、可执行文件,本质上都可以视为字节流。
访问依靠文件指针:
当前读写位置
↓
... A B C D E F G ...
↑读一次后,文件指针继续向后移动。
这种结构最大的优点是简单、通用。
四、有结构文件
又叫记录式文件。
例如学生数据:
001 张三 90
002 李四 85
003 王五 92每一行为一条记录。
记录又分为定长记录和变长记录。
如果每条记录长度固定,就可以直接计算第 k 条记录的位置;若长度不固定,一般无法简单通过乘法得到目标位置。
有结构文件进一步有三种典型组织形式:
| 类型 | 核心思想 |
|---|---|
| 顺序文件 | 一条记录接一条记录 |
| 索引文件 | 建索引直接定位记录 |
| 索引顺序文件 | 分组 + 索引 + 组内查找 |
1. 顺序文件
记录顺序排放。
又分成“串结构”和“顺序结构”。
串结构只是按写入时间排列:
记录 A
记录 C
记录 B
记录 F关键字不一定有序。
顺序结构则按照关键字排序:
001
002
003
004
005如果同时满足记录定长 + 按关键字有序,就特别适合快速检索。
2. 索引文件
相当于给记录建立一个“目录”。
索引
001 → 记录位置
002 → 记录位置
003 → 记录位置不需要每次从头查。
代价是:
额外占用索引空间。
这和数据库索引的思想完全一致。
3. 索引顺序文件
这一点题库专门考了。
它和数据结构中的分块查找几乎是一回事:
索引
↓
确定在哪一组
↓
进入该组
↓
组内查找最重要的性质是:
组间必须有序,组内可以无序。
配套模拟题就是直接考这一点,答案为“组间有序,组内可以无序”。
五、★★★★★ 本章最核心:文件的物理结构
这是第 4 章最重要的部分之一。
资料对不同物理结构的特点与比较标出了 2009、2011、2013、2020 等统考考点,连续分配又在 2011、2012、2014 等年份出现。
文件最终一定要被切成磁盘块。
假设:
块大小 = 4KB
文件大小 = 10KB至少需要:
个磁盘块。
问题变成:
这 3 个块到底怎么分配?
三大方法:
连续分配
链接分配
索引分配六、连续分配
例如文件 A 占:
20 21 22 23 24目录只需记:
起始块 = 20
长度 = 5如果文件的第一个逻辑块编号为 0,那么第 i 个逻辑块的位置直接是:
所以它天然支持随机访问。
例如起始块是 100,要找逻辑第 25 块:
直接访问 125 号磁盘块即可。
资料指出连续分配支持顺序和直接访问,而且由于数据块连续,顺序访问速度很快。
为什么快?
磁盘:
20 → 21 → 22 → 23 → 24磁头基本不需要到处跑。
最大问题
不是“读慢”,而是:
扩展困难。
例如:
A:20 21 22
B:23 24 25A 想再加一块,但 23 已经属于 B。
怎么办?
要么:
搬整个 A要么根本扩不进去。
此外连续分配还会产生外部碎片。
所以记住:
连续分配 = 最快,但最不灵活。
七、链接分配
文件的磁盘块可以随便放:
9 → 27 → 3 → 41 → 15每个块记录下一个块在哪里。
这样文件增长就简单很多:
原来:
9 → 27 → 3
新增:
9 → 27 → 3 → 88完全不用找连续空间。
因此没有连续分配那种外部碎片问题。
但有一个严重问题。
假如你要访问第 100 个块:
第1块
↓
第2块
↓
第3块
↓
……
↓
第100块必须沿链逐个找。
所以:
普通隐式链接适合顺序访问,不适合随机访问。
资料的比较表甚至直接总结为:连续分配访问第 n 条记录通常只需一次磁盘访问;普通链接分配可能需要沿链访问到第 n 块。
八、FAT:显式链接
FAT = File Allocation Table,文件分配表。
它是对链接分配的重要改进。
原本:
数据块9中:next = 27
数据块27中:next = 3
数据块3中:next = 41现在把这些 next 信息全部抽出来,放到 FAT:
FAT[9] = 27
FAT[27] = 3
FAT[3] = 41
FAT[41] = EOF这样文件数据块本身就不用保存 next。
更重要的是:
FAT 通常被加载进内存。
于是查链:
9 → 27 → 3 → 41是在内存中的 FAT中完成,而不是每走一步都访问磁盘。
资料强调 FAT 的表项和磁盘块基本是一一对应的,而且 FAT 还可以用特殊值标记空闲块,因此它既负责文件链,也能辅助空闲空间管理。
FAT 的代价
磁盘越大:
磁盘块越多
↓
FAT表项越多
↓
FAT越大
↓
常驻内存成本越高所以 FAT 系统后来引入“簇”。
多个扇区组成一个簇,把分配单位变大。
例如:
原来:1个FAT项 ↔ 1个扇区
现在:1个FAT项 ↔ 8个扇区FAT 表项数量明显减少。
但簇变大之后容易产生更多内部碎片。
九、★★★★★ 索引分配
这是考研最值得掌握的文件分配方式。
核心思想:
不把“下一块地址”分散在各个数据块中,而是单独建立一个索引块。
假设一个文件的数据块是:
13
95
27
8
44索引块:
0 → 13
1 → 95
2 → 27
3 → 8
4 → 44要访问文件逻辑第 3 块:
索引表[3] → 8直接知道数据在 8 号磁盘块。
所以:
索引分配同时实现了离散分配 + 随机访问。
十、单级索引最大文件长度怎么算?
这是非常标准的一类计算题。
假设:
磁盘块大小 = B
一个磁盘地址占 p 字节一个索引块能装的地址数:
因此单级索引能表示的数据量:
即:
资料使用的经典例子:
块大小 = 4KB
地址项 = 4B一个索引块能够容纳:
个磁盘块地址。
所以最大文件长度:
十一、多级索引
单级索引最多 4MB,不够怎么办?
再给“索引块”建一个索引。
一级索引块
↓
多个二级索引块
↓
大量数据块这和第 3 章的多级页表非常像。
仍取:
块大小 = 4KB
地址 = 4B每个索引块可容纳:
个地址。
二级索引可管理的数据块数量:
因此最大文件:
三级则近似:
资料正是用这个例子解释多级索引。
十二、★★★★★ 混合索引
为什么不所有文件都用三级索引?
因为现实中有大量:
1KB
5KB
20KB
50KB的小文件。
假如访问一个 5KB 文件都要:
读一级索引
↓
读二级索引
↓
读三级索引
↓
读数据显然非常浪费。
所以 UNIX 的思想是:
小文件 → 直接地址
中型文件 → 一级间接
大文件 → 二级间接
超大文件 → 三级间接也就是混合索引。
资料中的经典 UNIX inode 示例包含 13 个地址项:
i.addr(0) ~ i.addr(9) :10个直接地址
i.addr(10) :一级间接地址
i.addr(11) :二级间接地址
i.addr(12) :三级间接地址十三、混合索引容量计算——必须会
仍然假设:
块大小 = 4KB
地址项 = 4B每个索引块:
个地址。
10 个直接地址
一个一级间接地址
一个二级间接地址
一个三级间接地址
因此总最大文件大小为:
资料将混合索引相关计算列为 2010、2015、2018、2022 等统考考点,属于本章最应该反复做题的部分之一。
十四、另一个高频:访问一个数据块要几次磁盘 I/O?
关键看:
inode 是否已经在内存。
若 inode 已在内存,不算读取 inode 的次数。
直接地址
inode:
inode → 数据块只读数据块:
一级间接
inode
↓
一级索引块
↓
数据块需要:
二级间接
inode
↓
一级索引块
↓
二级索引块
↓
数据块需要:
三级间接
需要:
题库就有一道非常典型的题:inode 已在内存,12 个直接指针,块大小 4KB;读取第 9876 字节走直接地址,需要 1 次磁盘访问;读取第 543210 字节落在一级间接区,需要先读一级索引块再读数据块,共 2 次。
所以见到这种题先问:
① inode在不在内存?
② 目标字节属于第几个数据块?
③ 落在直接/一级/二级/三级哪个区域?基本就做出来了。
十五、三种物理分配方式最后对比
| 性质 | 连续分配 | 链接分配 | 索引分配 |
|---|---|---|---|
| 是否要求连续空间 | 是 | 否 | 否 |
| 顺序访问 | 很快 | 可以 | 可以 |
| 随机访问 | 很快 | 隐式链接很差 | 很好 |
| 外部碎片 | 有 | 无 | 无 |
| 文件扩展 | 困难 | 容易 | 容易 |
| 额外空间 | 小 | 指针 | 索引块 |
| 典型思想 | 数组 | 链表 | 索引表 |
可以直接类比数据结构:
连续分配 ≈ 顺序表
链接分配 ≈ 链表
索引分配 ≈ 索引查找十六、★★★★★ FCB:操作系统怎么知道“这是一个文件”?
假如磁盘上只有:
100号块
231号块
871号块操作系统并不知道:
这三块属于
/home/a.txt。
所以必须有一个数据结构描述文件。
这就是:
FCB:File Control Block,文件控制块。
FCB 是文件存在和管理的重要依据。
资料中的 FCB 主要包含:
| 类型 | 内容 |
|---|---|
| 基本信息 | 文件名、类型、大小、位置 |
| 存取控制 | 所有者、权限 |
| 使用信息 | 创建时间、修改时间等 |
因此可以理解:
文件内容
↑
│
FCB告诉OS数据在哪里
↑
│
文件名十七、★★★★★ inode 为什么出现?
如果每个目录项里都塞一个完整 FCB:
a.txt + 文件大小 + 权限 + 地址 + 时间 + ...
b.txt + 文件大小 + 权限 + 地址 + 时间 + ...
c.txt + 文件大小 + 权限 + 地址 + 时间 + ...一个目录项会非常大。
但我们查目录时真正首先需要比较的只是:
文件名。
于是 UNIX 把:
文件名和:
文件属性
文件位置
权限
大小
……拆开。
目录变成:
文件名 inode号
a.txt 15
b.txt 27
c.txt 81然后:
inode 15 → a.txt的真正属性和磁盘块地址所以:
目录项主要负责“名字 → inode”;inode 负责描述真正的文件。
这是一条非常重要的理解。
资料把目录项结构相关分析列为 2020、2022 考点。
十八、经典 inode 目录检索计算
题库中的经典题:
磁盘块 = 512B
FCB = 64B
文件名 = 6B
inode编号 = 2B
目录有256项没有 inode
一个块能放:
个目录项。
256 个目录项需要:
个磁盘块。
顺序查找,平均:
次磁盘访问。
引入 inode
目录项只需要:
6B文件名 + 2B inode号所以一项:
每个盘块可以放:
项。
256 项只需:
个盘块。
平均检索目录:
找到目录项后,还要读 inode:
因此减少:
次。
这正是配套题的答案。
这种题的本质
不是考 inode 定义。
而是在考:
inode 把“大量暂时没用的文件属性”从目录项拆出去了,所以目录项更小,一个磁盘块能装更多目录项,目录查找 I/O 更少。
十九、目录到底是什么?
目录本身也可以看成一种特殊文件。
它负责建立:
文件名 → 文件控制信息的映射。
目录管理最核心目标:
按名存取。
即用户给出:
/home/tom/a.txt系统能最终定位到 a.txt 的 inode。
二十、目录结构的发展
单级目录
所有文件放一起:
/
├── a.txt
├── b.txt
├── c.txt
└── d.txt简单,但不同用户不能很好地重名。
两级目录
首先按用户分。
MFD
├── 用户A → UFD_A
└── 用户B → UFD_B用户 A 可以有:
a.txt用户 B 也可以有:
a.txt解决重名问题。
但每个用户内部还是扁平目录。
二十一、树形目录
现代系统最常见。
/
├── home
│ ├── tom
│ │ ├── a.txt
│ │ └── b.txt
│ └── jack
├── bin
└── etc资料强调树形目录中的两个路径概念。
绝对路径
从根开始:
/home/tom/a.txt相对路径
从当前工作目录开始。
假如:
当前目录 = /home/tom那么访问:
docs/a.txt实际上是:
/home/tom/docs/a.txt为什么要有当前目录?
因为如果每次都必须从根目录开始:
/
↓
home
↓
tom
↓
docs
↓
a.txt路径解析很长。
设定当前目录后,可以减少重复目录检索。
二十二、★★★★★ 文件打开 open:一定要理解全过程
这是本章非常重要的一条过程题。
资料明确标出了:
文件打开:2014、2017、2020
文件关闭:2023
文件名与文件描述符:2012、2017、2024假设执行:
open("/home/tom/a.txt")系统先解析路径:
/
↓
home
↓
tom
↓
a.txt找到目录项:
a.txt → inode 57然后查系统打开文件表。
如果 inode 57 对应的文件还没打开:
磁盘 inode
↓
读入内存
↓
创建系统打开文件表项如果已经有人打开:
直接复用系统打开文件表项
open count++然后再:
给当前进程建立一个进程打开文件表项最后返回一个整数:
fd这就是文件描述符。
完整链条:
文件名
↓
目录项
↓
inode
↓
系统打开文件表
↓
进程打开文件表
↓
文件描述符 fd二十三、系统打开文件表 vs 进程打开文件表
这个容易混。
| 数据 | 放哪里 |
|---|---|
| 文件本身共享属性 | 系统打开文件表 |
| 打开计数 | 系统打开文件表 |
| 进程自己的访问模式 | 进程打开文件表 |
| 进程自己的读写状态 | 进程打开文件表 |
| 文件描述符 | 对进程打开文件表项的索引 |
资料使用“两级打开文件表”来解释多个进程访问同一文件的共享和隔离。
二十四、为什么打开以后不再使用文件名?
第一次:
open("/home/tom/a.txt")需要做:
路径解析
↓
目录查找
↓
inode查找很贵。
成功以后返回:
fd = 3后续:
read(3, ...)
write(3, ...)
close(3)直接通过 fd 查内存中的打开文件表即可。
所以:
文件名主要用于 open 阶段;文件打开后主要使用文件描述符。
这是考试非常喜欢设陷阱的地方。
二十五、close 的过程
例如三个进程都打开文件:
open count = 3一个进程关闭:
3 → 2第二个关闭:
2 → 1最后一个关闭:
1 → 0只有到:
open count = 0系统才能把相应的系统打开文件表项释放。
因此:
close()并不是删除磁盘上的文件。
它只是关闭这个打开实例。
二十六、create / delete / read / write
create
核心过程可以理解成:
检查路径、权限、重名
↓
分配 inode / FCB
↓
需要时分配数据块
↓
目录中加入:
文件名 → inode号
↓
更新空闲块、inode等元数据read
已经打开时可以理解为:
fd
↓
打开文件表
↓
inode
↓
根据当前文件指针确定逻辑块
↓
物理分配结构找到磁盘块
↓
读入内存
↓
更新文件指针write
类似:
fd
↓
定位文件
↓
根据写指针找到数据块
↓
写数据若空间不足:
申请新的磁盘块
↓
修改 inode / 索引结构
↓
修改文件大小资料对读写过程也明确强调了“根据当前读写指针定位并更新指针”。
二十七、★★★★★ delete 为什么比想象复杂?
删除绝不是简单:
把文件名删掉资料将文件删除过程标注为 2013、2021 考点。
真正过程大致是:
找到目录项
↓
找到 inode
↓
检查硬链接计数
↓
移除目录项
↓
若引用已经归零
↓
释放 inode
↓
释放数据块
↓
更新空闲空间信息最关键的问题就是:
这个文件有没有其他硬链接?
于是自然进入下一大高频考点。
二十八、★★★★★ 硬链接
假设:
A目录:
hello → inode 25
B目录:
test → inode 25二者虽然文件名不同:
hello
test但:
都指向 inode 25所以实际上是同一个文件。
hello ─┐
├→ inode25 → 数据块
test ──┘inode 中维护一个链接计数:
count = 2资料把硬链接列为 2009、2017 考点。
二十九、删除一个硬链接会发生什么?
当前:
A → inode25
B → inode25
count = 2A 删除自己的文件名:
A ✕
B → inode25
count = 1磁盘数据:
不能删除。
因为 B 还在用。
只有最后一个链接也删除:
count = 0才能真正:
释放inode
+
释放文件数据块因此记住:
硬链接删除的是“一个名字”,不是立即删除“数据”。
三十、★★★★★ 软链接
软链接完全不同。
假设真正文件:
/home/tom/a.txt软链接文件:
b.txtb.txt 自己有:
自己的inode
自己的文件内容其内容类似:
/home/tom/a.txt所以访问:
b.txt实际上是:
找到b.txt
↓
读取里面保存的路径
↓
重新解析 /home/tom/a.txt
↓
找到真正文件资料把软链接相关原理标为 2009、2021 考点。
三十一、硬链接和软链接对比
| 项目 | 硬链接 | 软链接 |
|---|---|---|
| 本质 | 新目录项指向同一 inode | 新建一个保存路径的文件 |
| inode | 相同 | 不同 |
| 数据副本 | 只有一个 | 软链接本身另有少量数据 |
| 原文件名删除后 | 一般仍可访问 | 可能变成悬空链接 |
| 查找速度 | 快 | 较慢 |
| 删除机制 | count 归 0 才真正删除 | 不影响目标 inode 的链接计数 |
| 实现思想 | 指针共享 | 路径共享 |
一句话:
硬链接:指向文件本体
软链接:记住怎么去找文件三十二、文件保护
文件共享之后,就必须解决:
谁有权访问?
常见权限包括:
读
写
执行
添加
删除
列目录资料指出访问控制是文件保护的主要方式,同时口令保护与加密可以作为补充。
三十三、ACL
ACL:
Access-Control List,访问控制列表。
思想就是:
张三:读、写
李四:读
王五:无权限完整 ACL 很灵活,但用户多了列表会很长。
因此 UNIX/Linux 常进一步概括为:
owner
group
others再给每组:
r
w
x例如:
rwxr-xr--理解为:
owner → rwx
group → r-x
others → r--三十四、口令保护和加密保护
口令:
访问文件
↓
输入正确口令
↓
允许访问优点是简单,缺点是安全性有限。
加密:
明文
↓ key
密文访问时再解密。
优点是保密性更好,缺点是存在计算开销。
但要特别注意:
它们并不能很好地区分“可以读但不能写”这种精细权限。
所以不能代替 ACL。
三十五、★★★★★ 文件系统在磁盘中的布局
这是 2022 考纲扩展后很重要的一部分。
资料中给出的典型磁盘结构可以理解为:
磁盘
│
├── MBR
│
└── 分区
├── boot block
├── super block
├── 空闲空间信息
├── inode区
├── 根目录
└── 文件/目录数据区三十六、超级块 superblock
非常重要。
超级块不是描述“某一个文件”。
而是:
描述整个文件系统。
例如记录:
文件系统总块数
块大小
空闲块数量
空闲inode数量
文件系统状态所以常见陷阱是:
inode → 描述一个文件
superblock → 描述整个文件系统文件系统挂载时,超级块的重要信息会读入内存。
三十七、内存中的文件系统结构
磁盘上的结构负责持久保存。
运行过程中,操作系统为了性能,会把大量文件系统信息缓存到内存。
例如:
已挂载文件系统信息
inode缓存
目录项缓存
打开文件表
缓冲区这就是为什么:
第一次打开文件较慢
以后访问可能更快因为很多信息不必重新访问磁盘。
三十八、★★★★★ 外存空闲空间管理
删除文件之后:
原先属于该文件的磁盘块
↓
变空闲操作系统必须记录:
哪些块有人用
哪些块没人用经典方法是:
| 方法 | 核心思想 |
|---|---|
| 空闲表法 | 记录连续空闲区 |
| 空闲链表法 | 空闲块串成链 |
| 位示图法 | 每个块对应一个 bit |
| 成组链接法 | 分组管理大量空闲块 |
三十九、★★★★★ 位示图
例如:
0 1 1 0 0 1 0 ...可以约定:
0 = 空闲
1 = 已分配注意:
0/1 的含义本身不是本质,题目也可能反过来规定。
重要的是根据题目约定判断。
如果有 N 个磁盘块,位图需要:
例如 8192 个块:
四十、位示图行列号计算
假设:
每行 m 位
块号 b
编号从0开始那么:
配套题:
每行32位
盘块号4567则:
所以:
第142行,第23列题库答案正是如此。
这类题一般很送分,注意编号是否从 0 开始即可。
四十一、成组链接法
UNIX 的经典方法。
为什么不用单纯的空闲链表?
如果有几百万个空闲块:
1 → 2 → 3 → 4 → …… → 1000000管理效率不够理想。
成组链接的思想是:
一组一组管理。
例如每组 100 个:
第一组:100个块
↓
其中某块保存下一组100个块的块号
↓
第二组
↓
第三组同时,当前最常用的一组块号会放在内存中的“空闲盘块号栈”。
四十二、成组链接的分配过程
假设内存里现在有:
空闲盘块号栈
┌───────┐
│ 201 │
│ 202 │
│ ... │
│ 299 │
│ 300 │
└───────┘正常时:
从栈里取一个块当这一组快用完:
读特殊索引块
↓
获得下一组空闲块号
↓
装入内存栈继续分配。
四十三、成组链接的回收
普通情况下:
释放一个块
↓
把块号压入空闲块号栈但如果:
栈已经满怎么办?
资料给出的做法是:
把当前栈中的块号信息
↓
写进刚刚回收的那个盘块
↓
让该盘块变成新的索引块然后重新开始一组。
你不需要死背图,只要理解:
成组链接 = 用少量内存保存当前一组,用磁盘块保存下一组信息。
四十四、★★★★★ VFS:虚拟文件系统
这是近年来越来越值得重视的内容,资料明确标注 VFS 原理与特点为 2025 考点。
现实中:
Linux ext4
Windows NTFS
U盘 FAT32
光盘 ISO9660
网络文件系统结构全不一样。
如果应用程序必须写:
ext4_open()
ntfs_open()
fat_open()会非常麻烦。
所以增加:
用户程序
│
open/read/write
│
VFS
┌─────────┼─────────┐
ext4 NTFS FAT用户只调用统一接口:
open()
read()
write()
close()底层到底是 ext4 还是 NTFS,由 VFS 帮你转发。
所以:
VFS 的核心不是存数据,而是提供统一抽象接口。
配套题问“VFS 的主要作用是什么”,正确答案就是:
为不同类型文件系统提供统一的抽象接口。
四十五、VFS 的四种核心对象
资料采用四类对象来解释。
| 对象 | 可以怎么理解 |
|---|---|
| superblock 对象 | 一个已挂载文件系统 |
| vnode 对象 | 一个文件/目录的统一抽象 |
| dentry 目录项对象 | 路径中的一个名字 |
| file 文件对象 | 某进程打开文件后的实例 |
尤其注意:
vnode ≠ inode。
inode 是某种具体文件系统中的实际文件元数据结构。
vnode 是:
VFS 为了把不同文件系统统一起来建立的内存抽象。
四十六、用 write 理解 VFS 全链路
进程执行:
write(fd, buf, n)大致过程:
write(fd)
↓
根据fd找到文件对象
↓
找到vnode
↓
VFS根据vnode中的操作函数
↓
调用具体文件系统的write
↓
缓冲区
↓
设备驱动
↓
磁盘资料就是用 write() 解释 VFS 调度过程。
所以:
VFS = 统一接口层而不是:
VFS = 磁盘上的某一种文件系统资料特别强调:
VFS 本身并不是真正的磁盘文件系统,它主要作为内存中的统一抽象存在。
四十七、文件系统挂载 mount
假如 U 盘里自身有一棵目录树:
/
└── usr
└── bin
└── vim现在把这个文件系统挂载到:
/media/disk那么系统统一目录树里变成:
/media/disk/usr/bin/vim这正是配套题的答案。
所以挂载可以理解成:
把另一个文件系统的根,接到当前目录树的某个目录上。
四十八、本章最容易混淆的几个概念
| 概念 A | 概念 B | 区别 |
|---|---|---|
| 文件逻辑结构 | 文件物理结构 | 用户怎么看 vs 磁盘怎么放 |
| FCB | inode | inode 是把文件名等与主要描述信息分离后的典型实现 |
| 目录项 | inode | 目录项主要完成名字映射,inode 描述文件 |
| 文件名 | 文件描述符 | open 前找文件 vs open 后操作文件 |
| 文件打开计数 | 硬链接计数 | 当前有多少打开引用 vs 有多少目录项指向 inode |
| 连续分配 | 链接分配 | 连续块 vs 离散链 |
| 链接分配 | 索引分配 | 逐块找下一块 vs 集中索引 |
| 硬链接 | 软链接 | 同 inode vs 保存路径 |
| inode | vnode | 具体文件系统元数据 vs VFS 的统一内存抽象 |
| superblock | inode | 整个文件系统 vs 单个文件 |
| VFS | ext4/NTFS | 抽象层 vs 真正文件系统 |
| open | create | 打开已有文件 vs 创建文件 |
| close | delete | 关闭打开实例 vs 删除文件目录引用/数据 |
四十九、第 4 章计算题统一方法
这一章真正需要“算”的主要有三类。
A. inode / 目录项计算
先算:
然后:
顺序查找平均磁盘访问次数,题目若假设等概率,通常再根据目录占用块数分析平均访问位置;若 inode 不在同一目录项中,还应考虑找到目录项后读取 inode 的 I/O。
B. 多级索引计算
第一步:
第二步:
直接地址:
一级间接:
二级间接:
三级间接:
总容量就是相关部分相加。
这是本章最值得练熟的公式框架。
C. 位示图
如果每行 m 位,块号从 0 开始:
如果题目从 1 开始编号,则必须相应调整,不能机械套公式。
五十、最后给你建立一条“真正理解文件系统”的全过程
假设程序:
fd = open("/home/tom/a.txt", READ);
read(fd, buf, 100);
close(fd);你脑中应该自动出现:
open("/home/tom/a.txt")
│
▼
解析路径
/ → home → tom → a.txt
│
▼
找到目录项
a.txt → inode 57
│
▼
读入/查找 inode
│
▼
检查权限
│
▼
建立系统打开文件表项
│
▼
建立进程打开文件表项
│
▼
返回 fd
│
▼
read(fd)
│
▼
找到文件对象/打开文件表
│
▼
根据当前文件指针确定逻辑块
│
▼
根据连续/链接/索引结构
把逻辑块映射到磁盘物理块
│
▼
访问磁盘块
│
▼
数据进入内存
│
▼
更新文件指针
│
▼
close(fd)
│
▼
删除进程表项
open count--
│
▼
若降到0,释放系统打开文件表相关项而如果最后执行的是:
unlink("/home/tom/a.txt")又要走:
目录项
↓
inode
↓
硬链接计数--
↓
是否为0?
├─ 否 → 数据继续保留
└─ 是 → 回收inode和磁盘块如果磁盘块被回收:
位示图修改
或
空闲链表修改
或
成组链接结构更新这时可以发现,第 4 章看似知识点很多,其实从头到尾是在描述同一个文件的一生:
创建
↓
目录登记
↓
inode描述
↓
磁盘分配
↓
open
↓
read/write
↓
共享与保护
↓
close
↓
delete
↓
释放磁盘空间这条主线比单独背几十个概念有效得多。
五十一、考研复习时建议优先掌握什么
按你这套资料里的考点追踪和题库分布,复习优先顺序建议是:
- 第一梯队:必须达到“看到题立即会算”——连续/链接/索引分配;单级、多级、混合索引最大文件长度;直接/一级/二级/三级索引磁盘访问次数;FCB/inode 目录检索计算;硬链接计数;位示图计算。
- 第二梯队:必须达到“能完整讲过程”——
open、close、read、write、delete;文件名与文件描述符;系统打开文件表和进程打开文件表;目录路径解析。 - 第三梯队:必须理解概念差别——逻辑结构和物理结构;树形目录;软链接与硬链接;superblock、inode、vnode;VFS;mount。
- 第四梯队:理解即可但不能完全不看——文件保护、ACL、口令、加密;单级/两级目录;文件系统层次结构等。
尤其是混合索引,资料明确追踪到 2010、2015、2018、2022 等年份;而 open、inode、链接和近年来新增的 VFS 也有持续考查记录,所以这几块应该作为第 4 章的复习核心。
如果把这一章进一步压成考场上的四句话,就是:
目录解决“文件叫什么、在哪个 inode”。 inode/FCB 解决“这个文件是什么、数据块在哪里”。 文件物理结构解决“这些数据块怎么组织”。 文件系统解决“所有文件、目录、磁盘空间怎样统一管理”。