从零写OS(三十五):getdents64 + chdir + 内存屏障 Bug
上一章 ls 能运行了,但打印出来的目录内容是空的——因为还没有实现 getdents64。这一章把目录列表、cd、pwd 全部补齐,同时碰到了一个 -O2 下内存乱序导致的调度器死循环 Bug。 SYS_GETDENTS64 Linux 接口 int getdents64(int fd, struct linux_dirent64 *dirp, unsigned int count); 每个条目的结构: struct linux_dirent64 { uint64_t d_ino; // inode 号 int64_t d_off; // 到下一条目的偏移(可用递增序号代替) uint16_t d_reclen; // 本条目总字节数(含填充,8 字节对齐) uint8_t d_type; // 文件类型(4=目录,8=普通文件) char d_name[]; // 文件名(null 结尾) }; d_reclen 必须 8 字节对齐,计算方式: uint16_t reclen = (uint16_t)((19 + namelen + 1 + 7) & ~7); // ↑固定头部 ↑名字 ↑null ↑对齐 内核实现 在 VFS 层实现 vfs_getdents,遍历 ext2 目录的所有条目,逐个填写 linux_dirent64 并写入用户缓冲区: int vfs_getdents(int fd, uint64_t uva, uint32_t count) { // 1. 检查 fd 是否为目录 // 2. 从 offset 开始遍历 ext2 目录 // 3. 跳过 "." 和 ".."(busybox ls 不显示它们) // 4. 每个条目:填 d_ino、d_type、d_name、d_reclen // 5. 通过 copy_to_user 写入用户空间 // 6. 更新 file->offset,返回写入的总字节数 } 关键:返回 0 表示目录已读完(EOF),busybox ls 据此停止调用。 ...