复习:文件系统 API
本次课回答的问题
本次课主要内容
在一个 I/O 设备 (block device) 上实现所有文件系统 API
bread(int id, char *buf);
bwrite(int id, const char *buf);
目录/文件 API
mkdir
, rmdir
, link
, unlink
open
, read
, write
, stat
文件系统就是一个数据结构 (抽象数据类型;ADT)
数据结构课程的假设
文件系统的假设
Block device 提供的设备抽象
struct block blocks[NBLK]; // 磁盘
void bread(int id, struct block *buf) {
memcpy(buf, &blocks[id], sizeof(struct block));
}
void bwrite(int id, const struct block *buf) {
memcpy(&blocks[id], buf, sizeof(struct block));
}
在 bread/bwrite 上实现块的分配与回收 (与 pmm 类似)
int balloc(); // 返回一个空闲可用的数据块
void bfree(int id); // 释放一个数据块
在 balloc/bfree 上实现磁盘的虚拟化
vector<char>
在文件基础上实现目录
vector<char>
解读成 vector<dir_entry>
5.25" 软盘:单面 180 KiB
int balloc(); // 返回一个空闲可用的数据块
void bfree(int id); // 释放一个数据块
vector<struct block *> file; // 文件
// 文件的名称、大小等保存在目录中
注意到这是相当小的文件系统
文件的实现方式
struct block *
的链表哪种方式的缺陷是致命、难以解决的?
集中存储的指针容易损坏?存 $n$ 份就行!
RTFM 得到必要的细节
if (CountofClusters < 4085) {
// Volume is FAT12 (2 MiB for 512B cluster)
} else if (CountofCluster < 65525) {
// Volume is FAT16 (32 MiB for 512B cluster)
} else {
// Volume is FAT32
}
“FAT” 的 “next” 数组
0
: free; 2...MAX
: allocated; ffffff7
: bad cluster; ffffff8-ffffffe
, -1
: end-of-file以普通文件的方式存储 “目录” 这个数据结构
vector<struct block *> file
的头部?首先,观察 “快速格式化” (mkfs.fat
) 是如何工作的
然后,把整个磁盘镜像 mmap 进内存
另一个有趣的问题 (M5 - frecov)
SecPerClus
, BytsPerSec
, FATSz32
, BPB_RootClus
, ...)性能
可靠性
不能 “尽善尽美”,但可以在 “实际 workload” 下尽可能好
Summary | Findings |
---|---|
Most files are small | Roughly 2K is the most common size |
Average file size is growing | Almost 200K is the average |
Most bytes are stored in large files | A few big files use most of the space |
File systems contains lots of files | Almost 100K on average |
File systems are roughly half full | Even as disks grow, file systems remain ~50% full |
Directories are typically small | Many have few entries; most have 20 or fewer |
按对象方式集中存储文件/目录元数据
为大小文件区分 fast/slow path
与 FAT 本质相同:在文件上建立目录的数据结构
大文件的随机读写性能提升明显 ($O(1)$)
但可靠性依然是个很大的问题
本次课回答的问题
Takeaway messages