核心概念區分
| 特徵 | Crash (崩潰/沖突) | Hang (停滯/凍結) |
| 定義 | 核心偵測到不可恢復錯誤,主動停止執行 (panic/oops) | 系統仍在執行,但特定進程/核心路徑無法推進 |
| 範圍 | 核心級:全系統;使用者級:單進程 (SIGSEGV/SIGABRT) | 核心級:全系統凍結;使用者級:單進程/執行緒阻塞 |
| 診斷時機 | 事後分析 (core dump, vmcore, kmsg) | 即時分析 (活系統觀測) |
| 關鍵證據 | Call trace、registers、memory map、crash utility | Stack trace、lock holder、wait queue、scheduler stats |
| 典型原因 | Null pointer、buffer overflow、hardware error、kernel BUG() | Deadlock、livelock、resource starvation、priority inversion、uninterruptible sleep (D state) |
一、Crash 根因分類與應對
1. 核心 Panic / Oops
- Null pointer dereference:驅動程式、檔案系統、網路堆疊未檢查指標
- General protection fault / Page fault:記憶體存取違規,常見於模組開發
- Stack overflow:遞迴過深、大型區域變數、中斷上下文佔用
- Hardware machine check (MCE):CPU 快取/記憶體/匯流排硬體錯誤
2. 使用者空間 Crash (Segmentation Fault)
- 記憶體管理錯誤 (use-after-free, double free, buffer overflow)
- 動態連結庫版本不匹配 (ABI 破壞)
- Stack clash、Heap corruption
3. Crash 現場保存與分析
# 1. 啟用 core dump
ulimit -c unlimited
echo "/var/crash/core.%e.%p.%h.%t" > /proc/sys/kernel/core_pattern
# 或 systemd-coredump (現代預設)
coredumpctl list
coredumpctl debug # 自動載入 gdb + debuginfo
# 2. 核心 vmcore (kdump)
dnf install kdump-tools
systemctl enable --now kdump
# /etc/kdump.conf 設定目標 (本機磁碟/NFS/SSH)
# Crash 後重啟進入 capture kernel 自動儲存 vmcore
# 3. 分析工具
crash /usr/lib/debug/lib/modules/$(uname -r)/vmlinux /var/crash/vmcore
# crash> bt, ps, files, kmem, dev, irq, timer, ...
# 使用者空間
gdb /path/to/binary /var/crash/core.xxx
(gdb) bt full
(gdb) info registers
(gdb) x/20i $pc
二、Hang 根因分類與即時診斷
1. 核心級 Hang (全系統無回應)
- Hard lockup:CPU 在核心態長時間未重新調度 (NMI watchdog 偵測) —
kernel.watchdog=1
- Soft lockup:CPU 在核心態超過
kernel.watchdog_thresh (預設 20s) 未讓出
- RCU stall:Read-Copy-Update 同步機制阻塞,常因長關中斷/preempt_disable 區段
- Hung task:進程 D state (TASK_UNINTERRUPTIBLE) 超過 120s —
kernel.hung_task_timeout_secs
2. 使用者級 Hang (單應用凍結)
- Deadlock:雙向鎖等待 (A→B, B→A)、鎖順序反轉
- Livelock:持續重試但無進展 (自旋鎖爭用、CAS 失敗循環)
- Priority inversion:低優先級持有鎖,中優先級搶佔,高優先級等待 — 需 Priority Inheritance (PI) mutex
- Resource exhaustion:檔案描述符耗盡、記憶體 OOM、inode 滿、PID 滿
- I/O wait (D state):磁碟故障、NFS 掛載失效、多徑路徑切換
3. Hang 即時診斷工具鏈
| 層級 | 工具 | 關鍵指令/用法 |
| 核心 | Magic SysRq | Alt+SysRq+t (顯示所有任務堆疊)、w (阻塞任務)、p (CPU 狀態) |
| 核心 | crash (live) | crash /proc/kcore (需 CONFIG_PROC_KCORE) |
| 核心 | perf | perf top -g, perf record -a -g -- sleep 30 |
| 核心 | ftrace / trace-cmd | echo function_graph > current_tracer; cat trace |
| 核心 | bpftrace | bpftrace -e 'kprobe:mutex_lock { @[kstack] = count() }' |
| 使用者 | gdb | gdb -p ; (gdb) thread apply all bt |
| 使用者 | pstack / gstack | pstack (快速列印所有執行緒堆疊) |
| 使用者 | strace | strace -p -f -s 200 (系統呼叫追蹤) |
| 使用者 | lsof | lsof -p (開啟檔案/網路連線) |
| 系統 | pidstat | pidstat -w -p 1 (context switch 統計) |
| 系統 | vmstat | vmstat 1 (r, b, si, so, cs, in) |
4. 關鍵診斷流程:Hung Task 為例
# 1. 確認 hung task 訊息
dmesg -T | grep -i "blocked for more than"
# 2. 取得堆疊
# 若已配置 kernel.hung_task_panic=1 會觸發 panic 產生 vmcore
# 否則用 SysRq-t 或 crash live
# 3. 分析堆疊
# 典型 D state 堆疊:
# __schedule -> schedule -> io_schedule -> wait_on_page_bit ->
# filemap_fdatawait -> generic_file_read_iter -> vfs_read -> ksys_read -> sys_read
# 向上找等待的物件: page, inode, buffer_head, bio
# 4. 找持有者
# 若等待 page lock -> 找持有 page lock 的任務 (通常是 writeback/kswapd)
# 若等待 inode lock -> 找持有 i_mutex/i_rwsem 的任務
# 若等待 bio -> 檢查 block layer, request queue, device driver
# 5. 根因分類
# - 磁碟壞軌/效能差 -> iowait 高, iostat %util 100, await 大
# - NFS server down -> 掛載選項需加 soft,timeo,retrans
# - 記憶體壓力 -> kswapd 狂掃描, direct reclaim 導致分配者睡眠
# - 檔案系統 bug -> 升級 kernel, 檢查已知 CVE
三、預防與最佳實踐
- 核心參數強化:
# /etc/sysctl.d/99-hardening.conf
kernel.panic = 10 # Panic 後 10 秒重啟
kernel.panic_on_oops = 1 # Oops 視為 Panic
kernel.unknown_nmi_panic = 1
kernel.panic_on_unrecovered_nmi = 1
kernel.panic_on_io_nmi = 1
kernel.hardlockup_panic = 1
kernel.softlockup_panic = 0 # 僅告警
kernel.hung_task_panic = 1
kernel.watchdog = 1
kernel.nmi_watchdog = 1
- 自動化收集:
kdump + systemd-coredump + sosreport (RHEL) / ubuntu-bug (Ubuntu) 一鍵打包
- 靜態分析:
sparse, smatch, coccinelle 核心程式碼掃描
- 動態測試:
ltp (Linux Test Project), kselftest, syzkaller (fuzzing)
- 應用層防禦:
mutex 加超時、pthread_mutexattr_setrobust、pthread_mutexattr_setprotocol(PTHREAD_PRIO_INHERIT)、避免在鎖內呼叫外部函式
- 事後複盤:建立事故時間線、根因分類 (CVE/配置/程式碼/硬體)、修正驗證、知識庫沉澱
四、工具選型決策樹
系統無回應 (無法 SSH)
├─ 有 Console/IPMI/KVM 存取?
│ ├─ 是 → SysRq-t 取得堆疊 → 判斷 Hard/Soft lockup / Hung task
│ └─ 否 → 等待 kdump/vmcore / 硬體重啟 (IPMI power cycle)
│
使用者程式 Hang
├─ gdb -p PID → thread apply all bt
│ ├─ 多執行緒等待同一鎖 → Deadlock → 原始碼檢查鎖順序
│ ├─ 單執行緒 D state → strace -p PID / lsof -p PID → 找阻塞系統呼叫
│ └─ CPU 100% 且無系統呼叫 → perf top -p PID / bpftrace uprobe → 計算密集/活鎖
│
核心 Panic/Oops
├─ kdump 已配置 → crash vmcore → bt, log, ps, files
└─ 無 kdump → 串列主控台 / netconsole / pstore (UEFI 變數儲存) 擷取最後訊息
核心心法:Crash 留現場 (core/vmcore),Hang 看當下 (stack/lock/wait),事後必複盤,知識入庫。