fault injection機能が埋まっている箇所のソースを読む
この記事は
Linux kernelのfalult injection機能の(特にNVMe SSDに関連する部分について)
ソースを読んだり、実際に使ってみたりする記事のうちの一つ
記事一覧
その1:fault injectionってなあに
その2:fault injection機能が埋まっている箇所のソースを読む ★今回はこれ
その3:NVMe SSDにfault injectionしてみる
fault injection機能が埋まっている箇所のソースを読む
なお、ここで読んでいくソースはUbuntu 22.04.3(6.2.0-39-generic)のものです
お目当ての処理をどうやって探そうか?
Linux Kernelのドキュメントのfault-injectionのページによると、
fault injection機能を新規に追加したい開発者向けに、以下のマクロが準備されている
- DECLARE_FAULT_ATTR()
また、関数レベルでのfault injectionを新規に追加*1 したい開発者向けに、以下のマクロが準備されている
- ALLOW_ERROR_INJECTION()
と、いうことで、
このあたりにエラー注入できたりしないかな/エラー注入は具体的に何をどうしているのかな、と探すときは
以下くらいでgrepするとよさそう
- DECLARE_FAULT_ATTR
- ALLOW_ERROR_INJECTION
*1 fail_function機能の一部として、関数の戻り値の差し替えを実装するということ
NVMe SSDのfault injection機能が埋まっている箇所を探す
DECLARE_FAULT_ATTRでgrepしてみると、以下が見つかった
drivers/nvme/host/fault_inject.c
static DECLARE_FAULT_ATTR(fail_default_attr);
ファイル名からして、まさにこれです、私が欲しかったのは、という感じがする
NVMe SSDのfault injection機能周りを読んでみる
Makefile
drivers/nvme/host/fault_inject.c と同じ階層にあるMakefileを見てみると
CONFIG_FAULT_INJECTION_DEBUG_FSがy以外の場合には
fault_inject.oは使用しない設定になっている
(Ubuntu 22.04.3では使用しない設定)
drivers/nvme/host/Makefile
nvme-core-$(CONFIG_FAULT_INJECTION_DEBUG_FS) += fault_inject.o
実際に使ってみるにはKernelのビルドが必要
エラーの注入処理
drivers/nvme/host/fault_inject.cにある
nvme_should_fail()がエラー注入の箇所そのものの様子
リクエストのステータスとしてNVME_SC_INVALID_OPCODE | NVME_SC_DNR
を設定する
(初期化時に、fault_inject->statusにはNVME_SC_INVALID_OPCODEが設定されるため)
void nvme_should_fail(struct request *req) { struct gendisk *disk = req->q->disk; struct nvme_fault_inject *fault_inject = NULL; u16 status; if (disk) { struct nvme_ns *ns = disk->private_data; if (ns) fault_inject = &ns->fault_inject; else WARN_ONCE(1, "No namespace found for request\n"); } else { fault_inject = &nvme_req(req)->ctrl->fault_inject; } if (fault_inject && should_fail(&fault_inject->attr, 1)) { /* inject status code and DNR bit */ status = fault_inject->status; if (fault_inject->dont_retry) status |= NVME_SC_DNR; nvme_req(req)->status = status; } }
このnvme_should_fail()は、nvme_try_complete_req()からのみコールされており
nvme_try_complete_req()は名前からして、ストレージに書き込みが完了した後にコールされるような雰囲気
ストレージにはIO発行しているけど、ステータスとしては失敗したように見せるのか
(NVMeのIO周りは土地勘がなくて確実なところは言えないけど)
追記:NVMe SSDにfault injectionしてみるで見えたCall stackより、
ストレージ書き込み完了後のHw割り込み延長でエラー注入で間違いなさそう
12月 26 01:47:47 nodoguro-VirtualBox kernel: CPU: 4 PID: 0 Comm: swapper/4 Tainted: G W OE 6.2.16 #1 12月 26 01:47:47 nodoguro-VirtualBox kernel: Hardware name: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006 12月 26 01:47:47 nodoguro-VirtualBox kernel: Call Trace: 12月 26 01:47:47 nodoguro-VirtualBox kernel: <IRQ> 12月 26 01:47:47 nodoguro-VirtualBox kernel: dump_stack_lvl+0x48/0x70 12月 26 01:47:47 nodoguro-VirtualBox kernel: dump_stack+0x10/0x20 12月 26 01:47:47 nodoguro-VirtualBox kernel: should_fail_ex+0x1ab/0x1b0 12月 26 01:47:47 nodoguro-VirtualBox kernel: should_fail+0xb/0x20 12月 26 01:47:47 nodoguro-VirtualBox kernel: nvme_should_fail+0x46/0xd0 [nvme_core] 12月 26 01:47:47 nodoguro-VirtualBox kernel: nvme_poll_cq+0x16e/0x390 [nvme] 12月 26 01:47:47 nodoguro-VirtualBox kernel: ? srso_alias_return_thunk+0x5/0x7f 12月 26 01:47:47 nodoguro-VirtualBox kernel: nvme_irq+0x40/0x90 [nvme] 12月 26 01:47:47 nodoguro-VirtualBox kernel: __handle_irq_event_percpu+0x4f/0x1b0 12月 26 01:47:47 nodoguro-VirtualBox kernel: handle_irq_event+0x39/0x80 12月 26 01:47:47 nodoguro-VirtualBox kernel: handle_fasteoi_irq+0x7d/0x1d0 12月 26 01:47:47 nodoguro-VirtualBox kernel: __common_interrupt+0x52/0x110 12月 26 01:47:47 nodoguro-VirtualBox kernel: common_interrupt+0x9f/0xb0 12月 26 01:47:47 nodoguro-VirtualBox kernel: </IRQ> 12月 26 01:47:47 nodoguro-VirtualBox kernel: <TASK> 12月 26 01:47:47 nodoguro-VirtualBox kernel: asm_common_interrupt+0x27/0x40