
2025/12/16 5:52
A kernel bug froze my machine: Debugging an async-profiler deadlock
RSS: https://news.ycombinator.com/rss
要約▶
日本語訳:
QuestDBは、
を介してasync-profilerがアタッチされた際にLinuxカーネル6.17でフリーズする可能性があります。perf_events
問題の根源はカーネルのhrtimerパスです:async‑profilerは
PERF_EVENT_IOC_REFRESH(1)でCPUクロックイベントを設定し、カウンタがゼロに達するとhrtimer_cancel()がブロックします。このとき自身のコールバックがまだ実行中であるため、デッドロックが発生しすべてのCPUが停止 (csd_lock_wait()) し、システム全体がフリーズします。これはUbuntu 25.10におけるカーネル6.17でのみ観測される挙動です。著者はQEMU上でバグを再現しました:
/proc/sys/kernel/perf_event_paranoid を –1 に設定し、KASLR を無効化し、ライブカーネルにGDBをアタッチして、割り込みが無効な状態で送信されるIPI(Inter-Processor Interrupt)に失敗の原因を特定しました。彼は2つの回復策―hrtimer_try_to_cancel() の戻り値を操作することとJavaプロセスのメモリにSIGKILL を注入してデッドロックを部分的に解消する方法―を試みましたが、いずれも実験室限定の手法です。カーネルパッチはブロッキング
hrtimer_cancel() をノンブロッキング hrtimer_try_to_cancel() に置き換え、PERF_HES_STOPPED フラグを追加してタイマー停止を安全に遅延させることで問題を修正します。このパッチがリリースされるまで、QuestDBユーザーは更新待ちか、async-profiler を -e ctimer で起動し、欠陥のある perf_events パスを完全に回避するワークアラウンドを適用すべきです。このフリーズは対象カーネル上で高スループットのQuestDBワークロードの信頼性を脅かし、async‑profiling ツール使用時には慎重な導入と監視が必要であることを強調しています。
改訂された要約はすべての主要ポイントを反映し、不当な推測を避け、明確で簡潔な物語を提示します。
本文
QuestDB は、トレーディング フロアからミッション・コントロールまでの高負荷ワークロード向けに設計されたオープンソース時系列データベースです。
- 低遅延・高スループット
- マルチテアストストレージエンジン
- Parquet と SQL のネイティブサポート(AI‑ready、ベンダーロックインなし)
私の環境
Linux を 90 年代後半から使用しています。Slackware の AMD K6 で始まり、最近は Ubuntu に移行しました。
長年バグに悩まされてきましたが、10 年ほど安定していました。ところが async‑profiler を使うとマシンがフリーズするようになりました。
問題の概要
- QuestDB で CPU ヒートマップを取得したい
- async‑profiler をアタッチすると、キー入力・SSH・TTY が全く応答しない
- ハードリブートが唯一の復旧手段
- 同じ現象が Fedora と Ubuntu 両方で報告されている
結論:Kernel の問題ではないかと推測。Ubuntu 25.10(カーネル 6.17)を使用していたため、カーネルバグに起因する可能性が高い。
async‑profiler と perf_events
- サンプリングプロファイラ:定期的にスレッドを割り込み、スタックトレースを収集
- デフォルトで
(ソフトウェアイベント)を使用perf_events - 具体的には
イベントとハイレゾリューションタイマー(hrtimer)を組み合わせてサンプリングcpu-clock
サンプルフロー
1. 各スレッドに perf_event FD をオープン 2. ioctl(fd, PERF_EVENT_IOC_REFRESH, 1) で 1 回限りのサンプルを設定 3. hrtimer が発火 → シグナル送信 4. シグナルハンドラがスタックトレースを取得し、リセット&再アーム
カーネルバグ(6.17)
何が起きているか
-
が 0 に到達するとPERF_EVENT_IOC_REFRESH(1)
→hrtimer__perf_event_overflow()
→cpu_clock_event_stop()perf_swevent_cancel_hrtimer()
を呼び出し、自身のコールバックが実行中であるためhrtimer_cancel()
はブロッキング(spin)しているhrtimer_cancel()- 再帰的に同じ CPU で待ち続ける → デッドロック
-
デッドロックは interrupt コンテキストで発生し、CPU を完全にハングさせる。
-
複数 CPU が同時に発生するとシステム全体がフリーズ。
修正内容
→hrtimer_cancel()
(非ブロッキング)hrtimer_try_to_cancel()
フラグを導入し、停止要求を遅延させるPERF_HES_STOPPED
static void cpu_clock_event_stop(struct perf_event *event, int flags){ event->hw.state = PERF_HES_STOPPED; perf_swevent_cancel_hrtimer(event); }
が -1 を返すときは「実行中」hrtimer_try_to_cancel()
→ フラグで停止を示し、再帰呼び出しが安全に終了。
カーネルデバッグ手順(QEMU + GDB)
| ステップ | 内容 |
|---|---|
| 1. ISO 取得 & QCOW2 作成 | |
| 2. インストール | |
| 3. QuestDB 起動確認 | → ブラウザで http://localhost:9000 |
| 4. profiler 起動 | (フリーズ確認) |
| 5. perf_event_paranoid を緩和 | |
| 6. 再起動 → VM がフリーズ |
GDB 接続
gdb /usr/lib/debug/boot/vmlinux-$(uname -r) target remote :1234
- KASLR 無効化(nokaslr)でシンボル解決
で CPU スレッド確認info threads
でスタックトレース取得bt
デバッグ結果
- CPU 0,1:
にハング → 他 CPU の IPI 応答待ちcsd_lock_wait() - CPU 2,3:
内に滞留(自己デッドロック)hrtima_try_to_cancel()
スレッド 4 (CPU 3) のスタック
0 hrtimer_try_to_cancel 1 hrtimer_cancel 2 perf_swevent_cancel_hrtimer 3 cpu_clock_event_stop ... 7 __run_hrtimer → hrtimer_interrupt → apic timer interrupt chain
フィールドがfunction
を指しており、自己呼び出しの循環を確認。perf_swevent_hrtimer
「復活」実験(失敗)
- GDB で
に変更 →$eax = 0
のループから抜けるhrtimer_cancel() - しかし他 CPU が
で停止したままcsd_lock_wait() - 結果、システムは依然フリーズ。
まとめ
- カーネルバグ(6.17)により
の hrtimer パスがデッドロックを起こす。perf_events - QuestDB で async‑profiler を使う際は、
オプションで回避可能。-e ctimer - 今後のカーネルアップデートまたは QuestDB バージョンアップ待ち。
ポイント
| 条件 | 推奨設定 |
|---|---|
| カーネル 6.17 以上 | (async‑profiler) |
| 古いカーネル | デフォルトの が安全 |
Tip
Ubuntu のを -1 に設定すると、async‑profiler はデフォルトでperf_event_paranoidパスを使う。perf_events
ただし、問題があるカーネルではフリーズするため、必要に応じてを付与してください。-e ctimer
これで、QuestDB と async‑profiler の環境下で発生したマシンフリーズの原因と回避策を整理しました。
次回、同様の症状が出たら -e ctimer を試してみてください。