我想寫一個塊設備驅動程序的方式,I/O請求交給一個單獨的工作線程。工作線程等待獲取請求,然後執行實際的I/O。cpu掛在insmod
我正在使用完整的結構進行工作線程和傳輸請求函數之間的同步。工作線程在繼續請求之前執行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之外的所有響應。它等待時間過長(BUG:軟鎖定 - CPU#0卡住22秒!)並且有一個定時器中斷。
現在這個中斷被廣播給所有的CPU。 wait_for_completion()函數使得CPU2上的線程一直等到completion_done。即使在中斷的情況下也不會喚醒線程。當在這種情況下有一個定時器中斷時,中斷被髮送到所有的CPU,包括CPU2,在那裏我們的線程停留在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,但這似乎不能解決問題。
謝謝
P.S. - 對於長帖子(無法附加日誌文件)感到抱歉