导引:点亮什么与为什么
002/003 的 ramdisk 证明「文件抽象」成立,但它只读、数据还是构建期嵌进内核的——不算真正的文件系统。这一章我们上真家伙:在 001 那块 AHCI 磁盘上,实现一个 ext2 文件系统驱动。它从磁盘读超块、块组描述符、inode、目录项,能按路径找到文件、读出内容。完成后,内核挂载的就是一块「磁盘上、按 ext2 标准布局」的真文件系统,ramdisk 这条线正式被它取代。先说边界:这一章的 ext2 是只读的(写是 006 的事),而且因为 ext2 是个有标准的成熟格式,我们重点讲「Cinux 怎么把它读出来」,格式的每个字段细节会引规范、不逐一铺开。
这一章我们要点亮什么
把 003 定义的 FileSystem 接口,用一个真实磁盘文件系统实现出来。四件事:
第一,认 ext2 的磁盘布局:超块(全局元数据)、块组描述符表(每组一块的索引)、inode(每个文件的元信息+数据块指针)、目录项(目录里「名字 → inode 号」的变长记录)。
第二,从 AHCI 盘上把这些结构读进内存:每次读一个块,经 001 的 ahci.read 走 DMA。
第三,挂载:读超块、验 magic、算出块大小/块组数等参数、读块组描述符表、拿到根目录(inode 2),把 ext2 注册进 003 的 VFS 挂载表。
第四,找文件 + 读内容:lookup 按路径逐级钻进目录、ext2_file_read 通过 inode 的数据块指针(直接块、单间接块)把文件内容读出来。
验收点是启动时的一串 [EXT2] 日志(magic 有效、块大小、块组数),以及把 ext2 挂到 / 后,通过 VFS 能读出磁盘上 /hello.txt 的内容。能从磁盘读出文件,这一章就成了。
为什么现在需要它
为什么紧跟 003。003 把 VFS 的骨架搭好了(inode、FileSystem 接口、挂载表),但唯一实现这个接口的后端是 ramdisk——一个只读、数据嵌在内核镜像里的「玩具」文件系统。要证明 VFS 这套抽象真有用,得有个正经后端实现它:数据在磁盘上、按公认格式布局、能被标准的 mkfs 工具创建。ext2 就是这个后端。这一章让 003 的 VFS 第一次接上真实存储。
为什么是 ext2 而不是别的。ext2 是经典、文档齐全、格式相对简单(没有日志、没有 B 树目录),又足够「真」(Linux 早期就用它、mkfs.ext2 现成)。它正好是教学文件系统的甜点:既有真实文件系统的全部要素(块组、inode、间接块、变长目录项),又没有 ext3/ext4 的复杂度(日志、extent、HTree)。我们读它,等于把「文件系统怎么工作」这件事走一遍标准流程。
还有一笔关于「复用」的账。这一章几乎不发明新东西:块 I/O 走 001 的 AHCI、文件对象和操作表用 003 的 inode + InodeOps、挂载走 003 的 vfs_mount_add。ext2 这个类要做的,就是实现 003 那两个虚方法(mount/lookup)和几个 InodeOps 函数。这正好验证 003 的设计目标——「换个后端,上层一行不改」。实际上 main.cpp 里把 vfs_mount_add("/", &ramdisk) 换成 vfs_mount_add("/", &ext2),004 的 cat/ls 立刻就能读 ext2 盘上的文件了。