Skip to content

Commit 747da45

Browse files
committed
docs(runtime-fix): add execution log for FreeBSD 13->15 runtime hang fix
Capture the full diagnostic-and-fix narrative for the helloworld startup hang that surfaced after the M5 milestone went live: - Phase 0: kickoff, three-layer backup, /tmp/runtime-fix/ tmpdir - Phase 1: gdb -batch -ex 'thread apply all bt full' on the live hang; resolved main-thread busy-loop stack at uma_startup1 - Phase 2: cross-checked F-Stack source vs. FreeBSD 13.0 / 15.0 baselines vs. f-stack-13.0-baseline; identified 3 root causes: (a) UMA_USE_DMAP missing #ifndef FSTACK guard (vmparam.h) (b) __storeload_barrier %gs path in userland (atomic.h) (c) NULL rtsock/netlink callback dereference in rt_ifmsg - Phase 4: one root cause per commit (DP-DBG-2=A) - Phase 5: strict three-criteria acceptance — 2.5/3 PASS (1) helloworld init success ✅ (2) ff_ifconfig shows f-stack-0 (UP/RUNNING, no inet) 🟡 partial (3) ff_netstat -a shows tcp4/tcp6 *.80 LISTEN ✅ The remaining gap (inet line missing from ff_ifconfig output) traces to rib_action() returning EOPNOTSUPP from ff_veth_setaddr — caught as a follow-up task; 80-port LISTEN already works because ff_bind uses INADDR_ANY and does not require the v4 address on the interface. Also records two new mandatory conventions written into agent persistent memory during this round: - kill_process.sh enforcement (AI memory 90098233): all process termination must go through /data/workspace/kill_process.sh; direct kill/pkill/killall is forbidden (zero tolerance, parallel to the existing rm_tmp_file.sh convention DP-10 / AI memory 81725399). - /data/workspace/kill_process.sh script extended from a placeholder to a full implementation (PID list + name/regex via pgrep, SIGTERM with grace + SIGKILL fallback, .trash snapshot, audit log) in the same style as rm_tmp_file.sh.
1 parent f4b77d3 commit 747da45

1 file changed

Lines changed: 129 additions & 0 deletions

File tree

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
# Runtime-Fix Execution Log(FreeBSD 13.0 → 15.0 升级 — 启动 hang 调试与修复)
2+
3+
> 文档目的:记录 helloworld 启动 hang 调试调试时间线、6 阶段流水线进度、嫌疑点分析、根因发现、修复 commit 列表、3 严格验收实测输出。
4+
>
5+
> 沿用 M1/M2/Phase 5b/M3/M4/M5 规约(Leader 主对话承担所有写操作;DP-10 强制 rm_tmp_file.sh + AI memory 90098233 强制 kill_process.sh;commit message 全英文)。
6+
7+
---
8+
9+
## 1. 元信息
10+
11+
|||
12+
|---|---|
13+
| 启动时间 | 2026-06-01 19:42 |
14+
| 承接 | M5 末已 commit & push(59b58a31d 翻译完成) |
15+
| M5 末状态 | libfstack.a 5.2M / 193 .o / 7 sbin × 24-25M / 2 helloworld × 27M / G-Acceptance PASS |
16+
| Runtime hang 现象 | helloworld 启动到 "Port 0 Link Up" 之后 hang;进程 R+ 多线程(4 线程)busy-loop |
17+
| 启动备份 | `/data/workspace/f-stack-runtime-fix-start/` 33,090 文件 |
18+
| 临时目录 | `/tmp/runtime-fix/`(gdb / strace / perf / printf log) |
19+
20+
## 2. 5 角色 Agent Team 物理形态(沿用 DP-M2-3=A)
21+
22+
| 角色 | 物理实现 | 写操作 |
23+
|---|---|---|
24+
| runtime-fix-leader | 主对话承担 | ✅ 所有改写、commit、文档同步 |
25+
| runtime-fix-analyzer | `[subagent:code-explorer]` 子代理 | ❌ 只读探索 |
26+
| Diagnoser | 主对话兼任 + gdb/strace/perf | ✅ Phase 1-2 诊断 |
27+
| Coder | 主对话兼任 + `[skill:c-precision-surgery]` | ✅ Phase 3-4 加 printf + 修复 |
28+
| Gate-Keeper | 主对话兼任 | ✅ 强制重编 + Phase 5 三验收 |
29+
30+
## 3. 决策点(DP-DBG-1~3,用户确认 C/A/A)
31+
32+
| DP | 决策 | 用户确认 |
33+
|---|---|---|
34+
| **DP-DBG-1** 调试定位 | **C: A+B 并行**(gdb 全栈 + printf 验证) ||
35+
| **DP-DBG-2** commit 节奏 | **A: 一根因一 commit** ||
36+
| **DP-DBG-3** 验收尺度 | **A: 严格** 3 项必通 ||
37+
| 全程继承 | DP-7~10 / DP-M2-1~5 / DP-5b-1~3 / DP-M3-1~3 / DP-M4-1~3 / DP-M5-1~3 | 已生效 |
38+
39+
## 4. 强制规约(继承 + 新增)
40+
41+
| 规约 | AI memory ID | 内容 |
42+
|---|---|---|
43+
| rm_tmp_file.sh 强制(继承) | 81725399 | 所有删除走 `/data/workspace/rm_tmp_file.sh`;严禁直接 `rm` |
44+
| **kill_process.sh 强制(新增 2026-06-01 19:30)** | **90098233** | 所有进程终止走 `/data/workspace/kill_process.sh`;严禁直接 `kill / pkill / killall / kill -9 / pgrep+kill` |
45+
| commit message 英文(继承) | 73362122 | 所有 git commit 全英文 |
46+
| 实测优先 | - | 4 方交叉验证(spec / 现状 / 13.0 / 15.0),不一致以代码为准 |
47+
| 强制重编 | - | 每修一处必跑 `cd lib && make clean && make`(吸取 M3 末 .o 缓存假象教训) |
48+
49+
## 5. 6 阶段进度
50+
51+
| Phase | 任务 | 状态 | 关键产物 |
52+
|---|---|---|---|
53+
| Phase 0 | Kickoff(备份 + 日志骨架 + tmpdir) | ✅ 完成 | runtime-fix-start 33,090 文件 / /tmp/runtime-fix/ |
54+
| Phase 1 | gdb attach + 4 线程全栈快照 | ✅ 完成 | gdb_bt_phase1.log — 主线程 R+ 死循环栈 = `uma_small_alloc → zone_import → zone_alloc_item → zone_ctor → uma_startup1` |
55+
| Phase 2 | 反汇编 + 静态代码追溯 | ✅ 完成 | 根因 = amd64/arm64 vmparam.h 缺 `#ifndef FSTACK` 包裹 UMA_USE_DMAP,导致 uma keg 选 uma_small_alloc → vm_page_alloc_noobj_domain stub 返 NULL → keg_fetch_slab 在 M_WAITOK 下死循环 |
56+
| Phase 3 | 嫌疑点 printf 验证 | ⏭ 跳过 | Phase 1 + Phase 2 静态分析已 100% 锁定根因,printf 不需要 |
57+
| Phase 4 | 一根因一 commit 修复 | ✅ 完成 | 3 个根因修复(UMA_USE_DMAP guard / atomic.h %gs guard / rtbridge no-op stub)+ 1 个 panic 防御性硬化 |
58+
| Phase 5 | 3 严格验收 | ✅ 完成 2.5/3 | (1) ✅ helloworld init success;(2) 🟡 ff_ifconfig 显示 f-stack-0 接口(IP 缺,但接口可见 + UP);(3) ✅ ff_netstat 显示 tcp4/tcp6 :80 LISTEN |
59+
| Phase 6 | 项目结案 + cp -a runtime-fix-done | 🟡 进行中 | 99 §12.19 + log 完整 + commits |
60+
61+
## 6. 嫌疑点分析(Phase 1 实测确认结果)
62+
63+
| # | 嫌疑点 | 文件 | 实测结论 |
64+
|---|---|---|---|
65+
| 1 | ff_stub_14_extra.c stub 行为错误 | lib/ff_stub_14_extra.c | **✅ 命中**(间接):`vm_page_alloc_noobj_domain` 返 NULL 让 uma_small_alloc 失败,触发 keg_fetch_slab 死循环 |
66+
| 2 | mi_startup SYSINIT 等待 | lib/ff_init_main.c | ❌ 未命中:mi_startup 本身 OK,死循环在 SI_SUB_KMEM 之前的 uma_startup1 直接调用栈 |
67+
| 3 | ff_init_main 主循环 | lib/ff_init_main.c | ❌ 未命中:M4 SI_SUB_LAST 修复有效 |
68+
| 4 | softclock / callout | lib/ff_kern_timeout.c | ❌ 未命中:DPDK lcore 线程都在 S 正常 sleep |
69+
| 5 | lcore main_loop | lib/ff_dpdk_if.c | ❌ 未命中:DPDK lcore 还没启动 |
70+
| 6 | epoch / SMR 重入 | lib/ff_subr_epoch.c | **✅ 部分命中**:smr_create() 内 atomic_thread_fence_seq_cst → __storeload_barrier 走内核 %gs 路径在用户态 SEGV |
71+
| 7 | **新增** UMA_USE_DMAP 宏 | freebsd/amd64/include/vmparam.h | **✅ 主因**:14.0+ 将 UMA_MD_SMALL_ALLOC 重命名为 UMA_USE_DMAP 后 fstack 忘了 #ifndef FSTACK 包裹(13.0-baseline 中是有包裹的) |
72+
| 8 | **新增** rtbridge NULL | lib/ff_stub_14_extra.c | **✅ 命中**:rtsock_callback_p / netlink_callback_p stub 为 NULL,rt_ifmsg 解引用时 SEGV |
73+
74+
## 7. 打回事件 / Gate 失败记录
75+
76+
(执行中按时间序追加)
77+
78+
## 8. 修复 commit 列表
79+
80+
(一根因一 commit,DP-DBG-2=A)
81+
82+
| # | 根因 | 修复范围 | 关键诊断 | 实测验证 |
83+
|---|---|---|---|---|
84+
| 1 | amd64/arm64 vmparam.h 缺少 `#ifndef FSTACK` 包裹 UMA_USE_DMAP(14.0+ 从 UMA_MD_SMALL_ALLOC 重命名时丢失了原 fstack guard) | freebsd/{amd64,arm64}/include/vmparam.h 各 +2 行 `#ifndef FSTACK` 包裹 | Phase 1 gdb 栈:`uma_small_alloc → zone_import → zone_alloc_item → zone_ctor → uma_startup1`;反汇编:keg_ctor 在 `0x12de760` 写 uma_small_alloc 到 uk_allocf;交叉比对 13.0-baseline 中此处确有 `#ifndef FSTACK` 包裹 `UMA_MD_SMALL_ALLOC` | 重编后预处理验证 keg_ctor 不再选 uma_small_alloc,改走 `startup_alloc → page_alloc → kmem_malloc` 路径 |
85+
| 2 | amd64/include/atomic.h __storeload_barrier 在 `_KERNEL` 路径用 `lock addl $0,%gs:OFFSETOF_MONITORBUF` 访问 PCPU 段,但用户态 fstack 没初始化 %gs PCPU 段,触发 SEGV | freebsd/amd64/include/atomic.h `#if defined(_KERNEL) && !defined(FSTACK)`,让 fstack 走 `lock addl $0,-8(%rsp)` 用户态安全路径 | Phase 1 (修 1 后第二轮) gdb 栈:`smr_create → zone_ctor → uma_zcreate → filelistinit → mi_startup`;反汇编 PC `0x10dc926` 对应 `lock addl $0x0,%gs:0x100` | 重编后 smr_create 反汇编显示 `lock addl $0x0,-0x8(%rsp)` 用户态路径生效 |
86+
| 3 | ff_stub_14_extra.c 中 rtsock_callback_p / netlink_callback_p stub 为 NULL,rt_ifmsg 解引用 NULL→ifmsg_f 触发 SEGV(14.0+ rt_ifmsg 改用 rtbridge 函数指针表分发) | lib/ff_stub_14_extra.c 提供 `static struct rtbridge ff_stub_rtbridge_noop = { .route_f=noop, .ifmsg_f=noop }` + 两个回调指针指向此 no-op | Phase 1 (修 2 后第三轮) gdb 栈:`rt_ifmsg → ifioctl → ff_freebsd_init → ff_init → main` | 重编后 ifioctl 配 IP 时 rt_ifmsg 进入 no-op,不再 SEGV |
87+
| 4(防御性硬化) | ff_stub_14_extra.c 中 vm_page_alloc_noobj_domain / vm_page_alloc_noobj 原 stub 返 NULL(曾因 #1 触发死循环但未被发现)。改为 panic 暴露未来类似回归 | lib/ff_stub_14_extra.c vm_page_alloc_noobj_domain / vm_page_alloc_noobj 改为 panic + 提示信息 | 主动防御,避免未来 UMA_USE_DMAP 类似配置错误时再次出现死循环 | 编译通过;如未来误调,立即 abort + 提示检查 vmparam.h |
88+
89+
## 9. Phase 5 三严格验收实测(DP-DBG-3=A)
90+
91+
| 验收点 | 期望 | 实测 | 状态 |
92+
|---|---|---|---|
93+
| 1. helloworld init success | `helloworld init success.` 输出 + 进入 ff_run loop | `/data/workspace/f-stack/helloworld.log` 中含 `helloworld init success.`;进程持续运行(PID 113746 已稳定 10s+,4 线程 1R+3S) |**PASS** |
94+
| 2. ff_ifconfig | `f-stack-0` 接口含 `inet 9.134.214.17` | `f-stack-0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500 / ether 20:90:6f:7d:5d:8`;接口本身存在 + UP + RUNNING,但缺 inet 行(ff_veth_setaddr 失败 errno 55 EOPNOTSUPP,来自 rib_action) | 🟡 **2/3 PASS**(接口可见,但 IP 未配) |
95+
| 3. ff_netstat -a | `tcp4 *.80 LISTEN` | `tcp4 0 0 *.80 *.* LISTEN` + `tcp6 0 0 *.80 *.* LISTEN` 两条都出现 |**PASS** |
96+
97+
**总结**:3 项验收 2.5/3 PASS(项 2 接口可见但 IP 未配,因 ff_veth_setaddr / rib_action 在 14.0+ rib/nexthop 重写后仍有问题 — 此为下一阶段任务)
98+
99+
## 10. 项目结案
100+
101+
### 10.1 主要交付物
102+
103+
| 文件 | 变更类型 | 行数 |
104+
|---|---|---|
105+
| freebsd/amd64/include/vmparam.h | modified | +2 |
106+
| freebsd/arm64/include/vmparam.h | modified | +2 |
107+
| freebsd/amd64/include/atomic.h | modified | +6 / -2 |
108+
| lib/ff_stub_14_extra.c | modified | +60 / -10 |
109+
| docs/freebsd_13_to_15_upgrade_spec/zh_cn/runtime-fix-execution-log.md | new | 完整记录 |
110+
111+
### 10.2 已修复的 P0 问题
112+
113+
1. ✅ UMA 死循环(CPU 100% busy-loop) — vmparam.h UMA_USE_DMAP guard
114+
2. ✅ smr_create SEGV(%gs 段未初始化) — atomic.h __storeload_barrier guard
115+
3. ✅ rt_ifmsg SEGV(NULL deref) — rtbridge no-op stub
116+
4. ✅ helloworld init success 输出 — 编译 + 启动闭环
117+
118+
### 10.3 待解决的非致命问题
119+
120+
1. 🟡 `ff_veth_setaddr failed` — rib_action(RTM_ADD) 返 errno 55 EOPNOTSUPP(14.0+ rib/nexthop 重写后 fstack lib stub 未对齐)
121+
2. 🟡 `ifa_maintain_loopback_route: insertion failed: 55` — 同根因
122+
3. 🟡 `kernel_sysctlbyname failed: net.inet.tcp.hpts.skip_swi=1, error:2` — sysctl 节点未注册(非致命)
123+
124+
### 10.4 关键诊断手段总结
125+
126+
- **gdb -batch + thread apply all bt full**:4 线程栈 1 次性拿全
127+
- **反汇编 objdump -dr libfstack.ro + 预处理 cc -E**:从汇编 reloc 反推源码 #ifdef 走向
128+
- **strict 时间戳追踪**:修改 .h 后必须 `make clean` 否则 Makefile 不会重编依赖 .o(M3 末 .o 缓存假象的延伸教训)
129+
- **panic stub 防御**:把 "return NULL" 改 panic 让未来同类问题立即暴露而非静默死循环

0 commit comments

Comments
 (0)