从零写OS(三十六):ext2 写操作 —— 文件创建、引用计数与 tty 字符设备

前几章文件系统都是只读的。这一章实现 ext2 的写路径,让 echo hello > /tmp/a.txt && cat /tmp/a.txt 能正常工作,且重启后文件仍然存在。过程中还修了 fd 引用计数和 tty 字符设备两个问题。 ext2 磁盘结构回顾 块组 0: [超级块][组描述符][block bitmap][inode bitmap][inode table][数据块...] 关键字段: sb->s_free_inodes_count / gd->bg_free_inodes_count:空闲 inode 计数 sb->s_free_blocks_count / gd->bg_free_blocks_count:空闲 block 计数 gd->bg_inode_bitmap:inode bitmap 所在块号 gd->bg_block_bitmap:block bitmap 所在块号 gd->bg_inode_table:inode table 起始块号 inode 号从 1 开始;前 10 个是系统保留的(root=2,lost+found=11)。 alloc_inode / alloc_block alloc_inode uint32_t alloc_inode(void) { // 1. 读 inode bitmap 块 // 2. 找第一个为 0 的位(bit i → inode i+1) // 3. 置位,写回 bitmap // 4. 更新超级块和组描述符的 free_inodes_count // 5. 返回 inode 号(从 1 开始) } alloc_block uint32_t alloc_block(void) { // 1. 读 block bitmap 块 // 2. 找第一个为 0 的位,跳过 block 0(保留) // 3. 置位,写回 bitmap // 4. 更新超级块和组描述符的 free_blocks_count // 5. 清零新分配的块(避免垃圾数据) // 6. 返回块号 } 注意:block bitmap 的 bit 0 对应 block 0,必须跳过(block 0 不存在)。实际第一个可分配的块由文件系统布局决定(本项目中是 610)。 ...

May 22, 2026 · 3 min · 大飞

从零写OS(十一):文件系统,从磁盘到文件名

到目前为止,内核能跑进程、能做系统调用,但所有数据都在内存里——进程一死,什么都没了。 这一章做文件系统:把数据写到"磁盘"(我们用内存模拟),下次还能读回来。 先把概念搞清楚 动手之前,先理解五件事。 为什么需要文件系统 磁盘本质上就是一个大字节数组。没有文件系统,你只能说"读第 1234 字节",没法说"读 /etc/passwd"。 文件系统做的事就是在这个字节数组上建立一套命名和组织规则,让你可以用路径找到数据,而不是手动记偏移量。 inode:文件名和内容分离 Unix 最重要的设计之一:inode 描述文件内容,目录存文件名,两者分开。 inode 记录的是"这个文件是什么"——大小、权限、数据在磁盘哪几块——但不存文件名。文件名只是一个指向 inode 的标签,存在目录里。 这意味着同一个 inode 可以被多个名字指向,这就是硬链接。重命名文件也不需要移动任何数据,只改目录项。 超级块:文件系统的自我描述 挂载一块磁盘时,内核第一件事是读超级块。超级块告诉内核这个文件系统的结构:inode 区从哪里开始、数据块从哪里开始、总共多少块、还有多少空闲。 超级块损坏 = 整个文件系统不可读。所以 ext4 会在磁盘多个位置备份超级块。 目录是普通文件 目录没有什么神奇的内部结构,它就是一个普通文件,内容是一张表:文件名 → inode 号。 ls 的本质是读这张表然后打印。路径解析 /a/b/c 就是:读根目录找 a 的 inode → 把 a 当目录读,找 b 的 inode → 把 b 当目录读,找 c 的 inode。 空闲管理:位图 磁盘上哪些块被占用、哪些空闲,用位图记录——1 个 bit 对应 1 个块,0 表示空闲,1 表示已用。分配空间就是找第一个 0 位翻成 1。 这五个概念搞清楚,下面的代码就是它们的直接翻译。 文件系统解决什么问题 内存是易失的,文件系统负责两件事: ...

May 6, 2026 · 6 min · 大飞
京ICP备14031575号-3