1

I/O要求が別のワーカースレッドに渡されるようにブロックデバイスドライバーを作成しようとしています。ワーカースレッドはリクエストの取得を待機してから、実際のI/Oを実行します。

ワーカースレッドと転送要求関数の間の同期に完全な構造を使用しています。ワーカースレッドは、リクエストを続行する前にwait_for_completionを実行し、転送リクエストがリクエストを取得するとウェイクアップされます。

ただし、insmodを実行しようとすると、システムがハングします。これは、各CPUでのバックトレースの外観です。

[  152.036031] BUG: soft lockup - CPU#0 stuck for 22s! [mount:1752]
[  152.036046] CPU 0
[  152.036046] Call Trace:
[  152.036046]  [<ffffffff8108d3e3>] smp_call_function+0x33/0x60
[  152.036046]  [<ffffffff8108d443>] on_each_cpu+0x33/0xa0
[  152.036046]  [<ffffffff81189e95>] __blkdev_put+0x185/0x1f0
[  152.036046]  [<ffffffff8115570a>] __fput+0xaa/0x200
[  152.036046]  [<ffffffff81151f3f>] filp_close+0x5f/0x90
[  152.036046]  [<ffffffff8115201d>] sys_close+0xad/0x120
[  152.036046]  [<ffffffff815a7312>] system_call_fastpath+0x16/0x1b

[  158.233026] INFO: rcu_preempt_state detected stalls on CPUs/tasks: { 2} (detected by 0, t=60002 jiffies)
[  158.233031] sending NMI to all CPUs:

[  158.233031] NMI backtrace for cpu 0
[  158.233031] CPU 0 
[  158.233031] Call Trace:
[  158.233031]  [<ffffffff8102018f>] arch_trigger_all_cpu_backtrace+0x4f/0x90
[  158.233031]  [<ffffffff810ca429>] print_other_cpu_stall+0x159/0x1c0
[  158.233031]  [<ffffffff810cb5e1>] __rcu_pending+0x31/0x180
[  158.233031]  [<ffffffff810cbb4a>] rcu_check_callbacks+0x11a/0x190
[  158.233031]  [<ffffffff8106505f>] update_process_times+0x3f/0x80
[  158.233031]  [<ffffffff8108772b>] tick_sched_timer+0x5b/0xc0
[  158.233031]  [<ffffffff8107a2ce>] __run_hrtimer+0x6e/0x240
[  158.233031]  [<ffffffff8107acf5>] hrtimer_interrupt+0xe5/0x200
[  158.233031]  [<ffffffff8101efb3>] smp_apic_timer_interrupt+0x63/0xa0
[  158.233031]  [<ffffffff815a7e5e>] apic_timer_interrupt+0x6e/0x80
[  158.233031]  [<ffffffff8108d30e>] smp_call_function_many+0x1fe/0x2a0
[  158.233031]  [<ffffffff8108d3e3>] smp_call_function+0x33/0x60
[  158.233031]  [<ffffffff8108d443>] on_each_cpu+0x33/0xa0
[  158.233031]  [<ffffffff81189e95>] __blkdev_put+0x185/0x1f0
[  158.233031]  [<ffffffff8115570a>] __fput+0xaa/0x200
[  158.233031]  [<ffffffff81151f3f>] filp_close+0x5f/0x90
[  158.233031]  [<ffffffff8115201d>] sys_close+0xad/0x120
[  158.233031]  [<ffffffff815a7312>] system_call_fastpath+0x16/0x1b

[  158.233291] CPU 3 and CPU 1
[  158.233347] Call Trace:
[  158.233352]  [<ffffffff8101eb68>] lapic_next_event+0x18/0x20
[  158.233356]  [<ffffffff81087288>] tick_dev_program_event+0x38/0x100
[  158.233360]  [<ffffffff8107ad2d>] hrtimer_interrupt+0x11d/0x200
[  158.233363]  [<ffffffff8101efb3>] smp_apic_timer_interrupt+0x63/0xa0
[  158.233366]  [<ffffffff815a7e5e>] apic_timer_interrupt+0x6e/0x80
[  158.233371]  [<ffffffff81029aa2>] native_safe_halt+0x2/0x10
[  158.233374]  [<ffffffff8100a67d>] default_idle+0x4d/0x2a0
[  158.233378]  [<ffffffff810011a6>] cpu_idle+0x86/0xd0

[  137.645911] CPU 2 
[  137.645911] Call Trace:
[  137.645911]  [<ffffffff8159d766>] wait_for_common+0x26/0x150
[  137.645911]  [<ffffffffa01674e2>] tsdd_worker_thread+0x72/0x1b0 [tsdd]
[  137.645911]  [<ffffffff81075eee>] kthread+0x7e/0x90
[  137.645911]  [<ffffffff815a94f4>] kernel_thread_helper+0x4/0x10`

...そして最終的にシステムがハングします。

ここで何が起こっているのか漠然と理解しています。(tsdd)ワーカースレッドはCPU 2で実行されており、wait_for_completion()を待機しています。CPU0では、クローズシステムコールがあります。他のすべてのCPUからの応答を待っているようです。CPU2を除くすべてから応答を取得します。待機時間が長すぎて(バグ:ソフトロックアップ-CPU#0が22秒間スタックしました!)、タイマー割り込みが発生します。

これで、この割り込みはすべてのCPUにブロードキャストされます。wait_for_completion()関数は、CPU2上のスレッドをcompletion_doneまで待機させます。割り込みが発生してもスレッドをウェイクアップしません。この場合のようにタイマー割り込みがある場合、割り込みはCPU2を含むすべてのCPUに送信され、スレッドはwait_for_completion()でスタックします。割り込みを処理できなくなり、システムは最終的にハングします。

この観察は正しいですか、それとももっと何かが起こっていますか?

以下は簡単な擬似コードです。

static struct request *sch_req = NULL;  //global
static struct complete *comp = NULL;    // initialized in module_init

void transfer_req(req_queue) {
    req = blk_fetch_request(req_queue);
    served = 0;
    while (!served) {
        if (completion_done(comp))
            continue;
        sch_req = req;
        sch_queue = req_queue;
        complete(comp);
        served = 1;
    }
}

void worker_thread() {
    while (!kthread_should_stop()) {
        if (wait_for_completion(comp))
            continue;
        while (sch_req) {
            perform_IO(sch_req);
            sch_req = blk_fetch_req(sch_queue);
        }
        init_completion(comp);
    }
}

誰かがここで何が悪いのかを理解するのを手伝ってもらえますか?また、問題を解決する方法についていくつかの洞察を得たいと思います。wait_for_completion_interruptibleを使用してみましたが、問題が解決しないようです。

ありがとう

PS-長い投稿でごめんなさい(ログファイルを添付する方法はありません)

4

1 に答える 1