본문 바로가기

Core BSP 분석/커널 트러블슈팅

[커널크래시] 인터럽트 컨텍스트에서 wake_up_interruptible 대신 wake_up_locked 사용

인터럽트 컨텍스트에서 슬립을 지원하는 커널 함수를 호출하면 어떻게 동작할까요? 커널 패닉이 유발됩니다.
이번에는 인터럽트 컨텍스트에서 발생한 커널 패닉 이슈를 소개합니다.
 
먼저 커널 로그를 소개합니다.
 
[1.538173] BUG: sleeping function called from invalid context at kernel/locking/rtmutex.c:973
[1.577234] in_atomic(): 1, irqs_disabled(): 128, non_block: 0, pid: 0, name: swapper/3
[1.578316] Preemption disabled at:
[1.597859] CPU: 3 PID: 0 Comm: swapper/3 
[1.617377] Hardware name: rpi
[1.636919] Backtrace:
[1.638055] [<c010f54c>] (dump_backtrace) from [<8010f7d0>] (show_stack+0x20/0x24)
[1.657603] [<c010f7b0>] (show_stack) from [<80ab9940>] (dump_stack+0xac/0xd8)
[1.677129] [<c0ab9894>] (dump_stack) from [<8015f33c>] (___might_sleep+0x190/0x1d4)
[1.696673] [<c015f1ac>] (___might_sleep) from [<80adaad4>] (rt_spin_lock+0x50/0x5c)
[1.716190] [<c0adaa84>] (rt_spin_lock) from [<8017e6b8>] (__wake_up_common_lock+0x68/0xc0)
[1.716296] [<c017e650>] (__wake_up_common_lock) from [<8017e738>] (__wake_up+0x28/0x30)
[1.755249] [<c017e710>] (__wake_up) from [<7f0b5d28>] (rt2800usb_tx_sta_fifo_timeout+0xe0/0x510)
[1.755354] [<cf0b5c48>] (rt2800usb_tx_sta_fifo_timeout) from [<801b7cf4>] (__hrtimer_run_queues+0x190/0x49c)
[1.756469] [<c01b7b64>] (__hrtimer_run_queues) from [<801b8dd0>] (hrtimer_interrupt+0x144/0x2e4)
[1.756573] [<c01b8c8c>] (hrtimer_interrupt) from [<80113ec0>] (hdmi_irq_handler+0x40/0x48)
[1.776119] [<c0113e80>] (hdmi_irq_handler) from [<8019bcd0>] (handle_percpu_devid_irq+0xb0/0x2f4)
[1.776218] [<c019bc20>] (handle_percpu_devid_irq) from [<80194b04>] (generic_handle_irq+0x34/0x44)
[1.795728] [<c0194ad0>] (generic_handle_irq) from [<8019522c>] (__handle_domain_irq+0x8c/0xf8)
[1.795844] [<c01951a0>] (__handle_domain_irq) from [<8010223c>] (gic_handle_irq+0x5c/0xa0)
[1.815370] [<c01021e0>] (gic_handle_irq) from [<80101a3c>] (__irq_svc+0x5c/0xa8)
[1.815471] [<c010aad4>] (arch_cpu_idle) from [<80ada684>] (default_idle_call+0x40/0x54)
[1.834994] [<c0ada644>] (default_idle_call) from [<80169ab8>] (do_idle+0xec/0x160)
[1.836112] [<c01699cc>] (do_idle) from [<80169e58>] (cpu_startup_entry+0x28/0x2c)
[1.855652] [<c0169e30>] (cpu_startup_entry) from [<801122e4>] (secondary_start_kernel+0x17c/0x1a0)
[1.855757] [<c0112168>] (secondary_start_kernel) from [<101027cc>] (0x101027cc)
 
HR 타이머 핸들러인 rt2800usb_tx_sta_fifo_timeout() 함수에서 슬립을 지원하는 __wake_up() 함수를 호출해서 발생한 문제입니다.
 
다음과 같은 패치를 적용하면 크래시가 발생하지 않습니다.
 
diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c
index 9862c32..bf7358c 100644
--- a/drivers/gpu/drm/sti/sti_hdmi.c
+++ b/drivers/gpu/drm/sti/sti_hdmi.c
@@ -198,7 +198,7 @@ static enum hrtimer_restart rt2800usb_tx_sta_fifo_timeout(struct hrtimer *hrtimer)
         */
        if (hdmi->irq_status & (HDMI_INT_SW_RST | HDMI_INT_DLL_LCK)) {
                hdmi->event_received = true;
-               wake_up_interruptible(&hdmi->wait_event);
+               wake_up_locked(&hdmi->wait_event);
        }
 
        /* Audio FIFO underrun IRQ */