Arm Linux Kernel Hacks

rousalome.egloos.com

포토로그 Kernel Crash


통계 위젯 (화이트)

11105
637
415734


[리눅스커널][SoftIRQ] 라즈베리파이에서 Soft IRQ 서비스 핸들러 등록 과정 파악하기 6. 인터럽트 후반부 처리

6.6.3 라즈베리파이에서 Soft IRQ 서비스 핸들러 등록 과정 파악하기

이번에는 라즈베리파이에서 Soft IRQ 서비스 등록 과정을 커널 로그로 살펴보는 실습을 하겠습니다. 

실습 패치 소개

먼저 패치 코드를 소개합니다.
diff --git a/kernel/softirq.c b/kernel/softirq.c
index 3f3fbc230..b0e75e8d0 100644
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -433,6 +439,8 @@ void __raise_softirq_irqoff(unsigned int nr)
 void open_softirq(int nr, void (*action)(struct softirq_action *))
 {
  softirq_vec[nr].action = action;
+
+ dump_stack();
 }

open_softirq() 함수 3 번째 줄 다음에 dump_stack() 함수를 추가합시다. dump_stack() 이란 함수는 자신을 호출한 콜스택 정보를 알려 줍니다.

위 패치를 적용하고 커널 빌드를 한 다음 라즈베리안에 설치합니다. 이후 라즈베리파이를 재부팅하고 커널 로그를 받읍시다. 커널 로그를 보면 부팅 과정에서 Soft IRQ 서비스를 등록하는 흐름을 확인할 수 있습니다.

커널 로그를 보겠습니다.
[0.000000] CPU: 0 PID: 0 Comm: swapper/0 Not tainted 4.14.39-v7+ #16
[0.000000] Hardware name: BCM2835
[0.000000] (unwind_backtrace) from (show_stack+0x20/0x24)
[0.000000] (show_stack) from (dump_stack+0xc8/0x10c)
[0.000000] (dump_stack) from (open_softirq+0x24/0x28)
[0.000000] (open_softirq) from (init_sched_fair_class+0x24/0x48)
[0.000000] (init_sched_fair_class) from (sched_init+0x3c8/0x41c)
[0.000000] (sched_init) from (start_kernel+0x21c/0x3e0)
[0.000000] (start_kernel) from  (0x807c)

가장 먼저 init_sched_fair_class() 함수에서 SCHED_SOFTIRQ Soft IRQ 서비스 아이디로 run_rebalance_domains() 이란 Soft IRQ 서비스 핸들러 함수를 등록합니다. 

위 로그에서 open_softirq() 함수를 호출하는 코드는 다음과 같습니다.
[kernel/sched/fair.c]
__init void init_sched_fair_class(void)
{
#ifdef CONFIG_SMP
open_softirq(SCHED_SOFTIRQ, run_rebalance_domains);

커널 로그에서 Soft IRQ 전체 서비스 등록 과정 파악하기

이어서 Soft IRQ 서비스 아이디 별로 커널 로그의 콜스택과 이를 실행한 커널 코드를 같이 확인해 봅시다. 

RCU_SOFTIRQ: rcu_process_callbacks
로그 
[0.000000] (open_softirq) from (rcu_init+0x300/0x374)
[0.000000] (rcu_init) from (start_kernel+0x254/0x3e0)
[0.000000] (start_kernel) from [<0000807c>] (0x807c)

코드: [kernel/rcu/tree.c]
void __init rcu_init(void)
{
...
__rcu_init_preempt();
open_softirq(RCU_SOFTIRQ, rcu_process_callbacks); 

TIMER_SOFTIRQ: run_timer_softirq
로그 
[0.000000] (open_softirq) from (init_timers+0xa0/0xa4)
[0.000000] (init_timers) from (start_kernel+0x268/0x3e0)
[0.000000] (start_kernel) from [<0000807c>] (0x807c)

코드: [kernel/time/timer.c]
void __init init_timers(void)
{
...
open_softirq(TIMER_SOFTIRQ, run_timer_softirq);

TASKLET_SOFTIRQ, HI_SOFTIRQ Soft IRQ 서비스는 softirq_init 함수에서 초기화합니다
TASKLET_SOFTIRQ: tasklet_action
HI_SOFTIRQ: tasklet_hi_action
로그 
[0.000000] (softirq_init) from [<80b00cc4>] (start_kernel+0x270/0x3e0)
[0.000000] (start_kernel) from [<0000807c>] (0x807c)

[0.000000] (softirq_init) from (start_kernel+0x270/0x3e0)
[0.000000] (start_kernel) from (0x807c)

코드 [kernel/softirq.c]
void __init softirq_init(void)
{
...
open_softirq(TASKLET_SOFTIRQ, tasklet_action);
open_softirq(HI_SOFTIRQ, tasklet_hi_action);
}

BLOCK_SOFTIRQ: blk_done_softirq
로그 
[0.059227] (open_softirq) from (blk_softirq_init+0x78/0xac)
[0.059245] (blk_softirq_init) from (do_one_initcall+0x54/0x17c)
[0.059263] (do_one_initcall) from (kernel_init_freeable+0x224/0x2b8)

코드 [block/blk-softirq.c]
static __init int blk_softirq_init(void)
{
...
open_softirq(BLOCK_SOFTIRQ, blk_done_softirq);

NET_TX_SOFTIRQ: net_tx_action
NET_RX_SOFTIRQ: net_rx_action
로그 
[0.070773] (open_softirq) from (net_dev_init+0x1ac/0x214)
[0.070790] (net_dev_init) from (do_one_initcall+0x54/0x17c)
[0.070807] (do_one_initcall) from (kernel_init_freeable+0x224/0x2b8)
[0.070824] (kernel_init_freeable) from (kernel_init+0x18/0x124)
[0.070840] [<8079bfd0>] (kernel_init) from (ret_from_fork+0x14/0x28)

[0.070911] (open_softirq) from (net_dev_init+0x1bc/0x214)
[0.070925] (net_dev_init) from (do_one_initcall+0x54/0x17c)
[0.070940] (do_one_initcall) from (kernel_init_freeable+0x224/0x2b8)
[0.070954] (kernel_init_freeable) from (kernel_init+0x18/0x124)
[0.070968]  (kernel_init) from (ret_from_fork+0x14/0x28)

코드: [net/core/dev.c]
static int __init net_dev_init(void)
{
...
open_softirq(NET_TX_SOFTIRQ, net_tx_action);
open_softirq(NET_RX_SOFTIRQ, net_rx_action);

커널 로그에 담겨 있는 콜스택 정보로 라즈베리안이 부팅하는 과정에서 다음 순서로 Soft IRQ 서비스들을 등록한다는 사실을 알게 됐습니다.
Soft IRQ 서비스 아이디  Soft IRQ 서비스 핸들러
SCHED_SOFTIRQ run_rebalance_domains
RCU_SOFTIRQ rcu_process_callbacks
TIMER_SOFTIRQ run_timer_softirq
TASKLET_SOFTIRQ tasklet_action
HI_SOFTIRQ tasklet_hi_action
BLOCK_SOFTIRQ blk_done_softirq
NET_TX_SOFTIRQ net_tx_action
NET_RX_SOFTIRQ net_rx_action

이렇게 라즈베리안이 부팅하고 난 다음 Soft IRQ 벡터인 softirq_vec 전역 변수는 어떤 모습일까요? Trace32 프로그램으로 라즈베리안의 Soft IRQ 벡터를 확인하니 다음과 같네요.
v.v %t %d %i %y %l softirq_vec 
  (static struct softirq_action [10]) [D:0x80C02080] softirq_vec = (
    [0] = ((void (*)()) [D:0x80C02080] action = 0x80122888 = tasklet_hi_action),
    [1] = ((void (*)()) [D:0x80C02084] action = 0x80181270 = run_timer_softirq),
    [2] = ((void (*)()) [D:0x80C02088] action = 0x80614684 = net_tx_action),
    [3] = ((void (*)()) [D:0x80C0208C] action = 0x80615AB0 = net_rx_action),
    [4] = ((void (*)()) [D:0x80C02090] action = 0x804279B0 = blk_done_softirq),
    [5] = ((void (*)()) [D:0x80C02094] action = 0x0 = ),
    [6] = ((void (*)()) [D:0x80C02098] action = 0x8012299C = tasklet_action),
    [7] = ((void (*)()) [D:0x80C0209C] action = 0x801588EC = run_rebalance_domains),
    [8] = ((void (*)()) [D:0x80C020A0] action = 0x0 = ),
    [9] = ((void (*)()) [D:0x80C020A4] action = 0x8017ABC4 = rcu_process_callbacks))

위 정보는 Trace32로 본 softirq_vec 전역 변수입니다. 각 배열에 Soft IRQ 서비스 핸들러 함수가 저장돼 있습니다. 이후 Soft IRQ 서비스를 실행할 때는 softirq_vec 이란 Soft IRQ 벡터에 등록된 함수를 호출합니다.

이번 절에서는 라즈베리안에서 Soft IRQ 서비스를 어떻게 등록하는지 커널 로그를 통해 확인했습니다. 그리고 실제로 8개의 Soft IRQ 서비스를 등록하고 부팅 후 Soft IRQ 벡터에 등록된 함수 목록도 봤습니다.

다음 절에 이어서 Soft IRQ 서비스를 어떻게 요청하는지 살펴보겠습니다.



    핑백

    덧글

    댓글 입력 영역