摘要
本次训练营我的工作主线是:围绕 StarryOS 的 Linux 语义兼容与 systemd 启动链路,持续做「问题复现 -> 根因定位 -> 最小修复 -> 回归测试固化」。
阶段性成果可以概括为三点:
- 完成 System V 共享内存一致性测试与内核语义修复,补齐
shmget/shmat/shmdt/shmctl关键行为。 - 推动 systemd 分阶段支持,连续修复
execveat、PID 1、mount API 回退、/sys/fs/cgroup挂载点、/dev/kmsg写侧等阻塞问题。 - 启动共享内核日志环建设(dmesg / /dev/kmsg / journald 共用后端),为后续日志子系统统一打基础。
一、训练营阶段工作
1.1 第一阶段:System V 共享内存语义完善
我在第一阶段以 Linux man-pages 与内核行为为基准,系统梳理了 System V 共享内存接口语义,并围绕 StarryOS 编写了一致性测试。
具体工作
- 建立语义基线
- 对照 Linux 文档逐条梳理
shmget/shmat/shmdt/shmctl的行为与错误码。 - 把“正常路径”和“错误路径”都转为可断言的检查项,避免只验证 happy path。
- 落地 conformance 测试
test-shm-family
- 组织 11 段测试、70 条断言,覆盖:
shmget的IPC_CREAT/IPC_EXCL/ENOENT/EEXIST/EINVAL。shmat的只读附加、跨进程共享、错误shmid。shmdt的“必须精确传回原始附加地址”语义。shmctl的IPC_STAT/IPC_SET/IPC_RMID与延迟销毁。
- 增加
fork读写验证,确保共享段在进程间真正共享,而非单进程假通过。
- 修复内核实现偏差(以测试失败驱动修复)
- 修复前问题:
- 未正确处理
IPC_CREAT/IPC_EXCL组合。 - 对已有段 size 检查过严,偏离 Linux 语义。
- 未正确处理
- 修复后行为:
- key 不存在且无
IPC_CREAT返回ENOENT。 IPC_CREAT|IPC_EXCL命中已有 key 返回EEXIST。- 仅在请求 size 大于现有段时返回
EINVAL。
- key 不存在且无
- 多架构验证
- 在 x86_64/riscv64/aarch64/loongarch64 QEMU 跑通回归。
- 将“测试可发现、可自动执行”作为合入前门槛,而不是手工验证截图。
对应 issue / PR
- 方案记录(Open):https://github.com/rcore-os/tgoskits/issues/767
- 测试与修复(Merged):https://github.com/rcore-os/tgoskits/pull/865
关键结果
- 测例形成了可复用的 conformance 思路:先在 Linux 验证测试,再用同一测试验证 StarryOS。
- 将
IPC_CREAT/IPC_EXCL/size等关键语义对齐,避免「功能可用但行为不兼容」的问题。
1.2 第二阶段:systemd 分阶段支持
在这一阶段,我围绕「让 Debian trixie 的 systemd 作为 PID 1 启动」持续打通阻塞链路。工作方式是:每发现一个失败点,就把它拆成独立、可回归验证的小修复。
主线 issue
- 方案二主线(Open,持续更新):https://github.com/rcore-os/tgoskits/issues/1126
关键修复与重构
execveat(2)支持与语义落地
- 现象:systemd 相关路径需要
execveat,缺失会直接阻塞启动流程。 - 第一阶段实现:补齐 syscall 分发、
dirfd + path + flags解析、错误码返回与回归测试。 - 评审中暴露的深层问题:
- 主可执行文件在已解析后又被“按路径二次解析”,导致
AT_SYMLINK_NOFOLLOW语义被覆盖。
- 主可执行文件在已解析后又被“按路径二次解析”,导致
- 关键重构:
- 把 loader 改为“解析一次、按 Location 对象加载”,对齐 Linux 的对象加载模型。
- 保留 shebang 与
.sh解释器路径的按路径解析(这部分应当 follow 链接)。
- 结果:
execveat不只是“能调用”,而是关键 flag 语义可正确端到端生效。
相关 PR:
- https://github.com/rcore-os/tgoskits/pull/1144 (Merged)
- https://github.com/rcore-os/tgoskits/pull/1193 (Merged)
- 让 init 成为真实 PID 1
- 现象:
/proc/1看起来是 1,但getpid()不是 1,systemd 会按“非 system manager”路径退出。 - 根因:用户可见 pid/tid 与调度器内部 id 混用,procfs 只是“显示层伪装”。
- 修复:
- init 进程固定用户可见 pid/tid 为 1。
TASK_TABLE、kill、clone、set_child_tid、未实现 syscall 日志等路径统一使用用户可见 tid。
- 回归:新增 PID 1 语义测试(如
kill(1,0)、getpgid(1)、getsid(1))。 - 结果:PID 1 从“显示为 1”变成“语义上真实为 1”。
相关 PR:
- 修复新 mount API 误导探测
- 现象:
fsopen返回假成功 fd,systemd 误判内核支持新 mount API,然后在后续未实现接口失败,且不回退。 - 修复策略:
- 对未实现入口
fsopen/fspick/open_tree明确返回ENOSYS(而非 dummy fd)。 - 与
fsconfig/fsmount/move_mount的未实现语义保持一致。
- 对未实现入口
- 回归:新增用例直接断言三个调用返回
-1且errno=ENOSYS。 - 结果:systemd 能走回退路径,复用已可用的
mount(2)链路。
相关 PR:
- 补齐
/sys/fs/cgroup挂载点
- 现象:即使回退到经典 mount,仍因
/sys/fs/cgroup不存在导致ENOENT。 - 根因:sysfs 挂载后会覆盖 rootfs 的同名目录,而自建 sysfs 树缺少
fs/cgroup节点。 - 修复:在 sysfs 树显式补齐
fs/cgroup空目录。 - 回归:扩展 sysfs 测试,校验目录存在性与 tmpfs 挂载/卸载成功。
- 结果:cgroup 层级挂载链路被完整打通。
相关 PR:
- 新增
/dev/kmsg写侧设备
- 背景:journald 在早期启动阶段依赖 kmsg 写入通道。
- 实现:
- 新增
char 1:11设备节点。 - 每次
write()视作一条记录,解析可选<priority>前缀并映射到日志级别。 - 读侧暂按 EOF 语义返回,先保证写侧可用。
- 新增
- 回归:新增测试覆盖设备号、带/不带前缀写入、无换行写入与读侧 EOF。
- 结果:systemd/journald 早期日志有了可用落点。
相关 PR:
1.3 第三阶段:共享内核日志环(进行中)
在前面 systemd 启动链路基本可用后,我开始把日志子系统从「多处各自缓存」收敛到「统一日志环」。目标是让 dmesg、/dev/kmsg 读端、journald 共用一套后端。
当前进展
- 在 axlog 的统一落点捕获每条记录(级别、时间、消息体),避免多条日志链路各自格式化与缓存。
- 新增
ring.rs作为当前可用后端,提供push/read_all/read_record/latest_seq等基础能力,优先保证接口稳定与可接入。 - 并行引入
prb.rs(printk ringbuffer 风格)作为下一阶段后端,当前完成主干结构与核心路径,但尚未切换为默认实现。 - 已明确后续里程碑:
- 完成
prb接线与替换。 - 做 SMP 场景并发压测,验证一致性与开销。
- 再把 StarryOS 侧
/dev/kmsg读端、syslog(2)接到共享环上,形成完整闭环。
- 完成
相关 PR:
二、方法与经验
2.1 我在本次训练营中形成的方法
- 先语义后实现:先明确 Linux 基线行为,再写代码。
- 先测试后修复:先用最小失败样例钉住问题,再做实现。
- 小步合并:每个 PR 只解决一个明确问题,避免多变量叠加。
- 回归前置:每修一个 bug 都补可自动执行的回归用例,防止未来重现。
2.2 典型教训
- 「看起来能跑」不等于兼容:像 mount API 假成功这类问题,短期可通过,长期会误导上层。
- 系统调用标志位语义不能只做“接受参数”:必须确保 end-to-end 语义真正生效。
- 路径层重构往往是功能正确性的前提:
execveat问题本质上是 loader 模型偏差。
三、产出索引
3.1 方案 issue
3.2 PR 列表
- https://github.com/rcore-os/tgoskits/pull/865
- https://github.com/rcore-os/tgoskits/pull/1144
- https://github.com/rcore-os/tgoskits/pull/1193
- https://github.com/rcore-os/tgoskits/pull/1233
- https://github.com/rcore-os/tgoskits/pull/1241
- https://github.com/rcore-os/tgoskits/pull/1243
- https://github.com/rcore-os/tgoskits/pull/1377
- https://github.com/rcore-os/tgoskits/pull/1394
四、后续计划
- 继续推进共享日志环方案:补齐
prb接线、并发压测与切换验证。 - 补齐
/dev/kmsg读侧与syslog(2)路径对接,形成完整日志闭环。 - 继续以回归测试驱动 systemd 兼容缺口,逐步提升发行版可启动、可运行范围。
结营总结
这次训练营对我最大的提升,不只是“写了多少代码”,而是工程方法上的变化:我更重视语义对齐、证据链和回归护栏,也更能把一个复杂问题拆成可验证的小问题逐步推进。
从共享内存一致性到 systemd 启动链路,再到日志子系统统一,我逐步体会到操作系统开发里「小差异会放大成大故障」的现实,也因此建立了更稳健的开发节奏。后续我会继续沿着这条路径,把已完成的阶段成果打磨成可持续迭代的基础能力。