2014년 9월 27일 토요일

[Linux Kernel] 71주차(2014.09.27)

ARM10C 71주차 후기

일시 : 2014.09.27 (71주차)
모임명 : NAVER개발자커뮤니티지원_IAMROOT.ORG_10차ARM-C
장소 : 토즈 타워점
장소지원 : NAVER 개발자 커뮤니티 지원 프로그램
참여인원 : 3명

스터디 진도 :

  • rcu_init()

main.c::start_kernel()

  • rcu_init()을 분석합니다.
  • start_kernel()부터 rcu_init() 전에 어떤 일을 했는지 간추려서 보겠습니다.
asmlinkage void __init start_kernel(void)
{
    char * command_line;
    extern const struct kernel_param __start___param[], __stop___param[];

...

    local_irq_disable();
    // IRQ를 disable한다.
    early_boot_irqs_disabled = true;

    boot_cpu_init()
    // 현재 cpu(core id)를 얻어서 cpu_XXX_bits[] 의 cpu를 셋한다.

    page_address_init();
    // 128개의 page_address_htable 배열을 초기화

    pr_notice("%s", linux_banner);
    // 배너:
    //  Linux version 2.6.37_DM385_IPNC_3.50.00
    //  (a0875405@bangvideoapps01) (gcc version 4.5.3 20110311 
    //  (prerelease) (GCC) ) #1 Fri Dec 21 17:27:08 IST 2012

    setup_arch(&command_line);
    // ARM 아키텍쳐에 맞게 초기화한다.

    setup_nr_cpu_ids();
    setup_per_cpu_areas();
    // pcpu 구조체를 만들어 줌 (mm/percpu.c)

    smp_prepare_boot_cpu(); /* arch-specific boot-cpu hooks */
    // boot cpu 0의 pcpu 영역의 base주소를 core register에 설정해줌

...
    pidhash_init();
    // pidhash의 크기를 16kB만큼 할당 받고 4096개의 hash list를 만듬

    vfs_caches_init_early();
    // Dentry cache, Inode-cache용 hash를 위한 메모리 공간을 각각 512kB, 256kB만큼 할당 받고,
    // 131072, 65536개 만큼 hash table을 각각 만듬

...
    mm_init();
    // buddy와 slab 을 활성화 하고 기존 할당 받은 bootmem 은 buddy,
    // pcpu 메모리, vmlist 는 slab으로 이관

    sched_init();
    // scheduler가 사용하는 자료 구조 초기화, idle_threads를 init_task로 세팅

    /*
     * Disable preemption - early bootup scheduling is extremely
     * fragile until we cpu_idle() for the first time.
     */
    preempt_disable();
    // preempt count를 증가시켜 preemption 못하도록 막음

    // irqs_disabled(): 1
    if (WARN(!irqs_disabled(), "Interrupts were enabled *very* early, fixing it\n"))
        local_irq_disable();

    idr_init_cache();
    // integer ID management로 사용하는 idr_layer_cache에 kmem_cache#21 을 생성 및 초기화 후 할당

    rcu_init(); 
  • mm_init()에서 buddy와 slab을 활성화하고 sched_init()을 실행한다.
  • sched_init()에서 rq를 초기화하고 // scheduler_running: 1
  • integer ID management로 사용하는 idr_layer_cache에 kmem_cache#21 을 생성 및 초기화 후 할당 *

tree.c::rcu_init()

  • rcu_bootup_announce();
    • "Preemptible hierarchical RCU implementation." 출력
  • rcu_init_geometry();
    • // jiffies_till_first_fqs: 1
    • // jiffies_till_next_fqs: 1
  • rcu_init_one(&rcu_bh_state, &rcu_bh_data);
    • // (&rcu_bh_state)->levelcnt[0]: 1
    • // (&rcu_bh_state)->levelspread[0]: 4
    • // &((&rcu_bh_state)->level[0])->lock 사용한 spinlock 초기화
    • // &((&rcu_bh_state)->level[0])->fqslock 사용한 spinlock 초기화
    • // ((&rcu_bh_state)->level[0])->completed: 0xfffffed4
    • // ((&rcu_bh_state)->level[0])->qsmask: 0
    • // ((&rcu_bh_state)->level[0])->qsmaskinit: 0
    • // ((&rcu_bh_state)->level[0])->grplo: 0
    • // ((&rcu_bh_state)->level[0])->grphi: 3
    • // ((&rcu_bh_state)->level[0])->gpnum: 0
    • // ((&rcu_bh_state)->level[0])->grpmask: 0
    • // ((&rcu_bh_state)->level[0])->parent: NULL
    • // ((&rcu_bh_state)->level[0])->level: 0
    • // &((&rcu_bh_state)->level[0])->blkd_tasks 을 사용한 list 초기화
    • // (&rcu_bh_state)->rda: &rcu_bh_data
    • // &(&(&rcu_bh_state)->gp_wq)->lock을 사용한 spinlock 초기화
    • // &(&(&rcu_bh_state)->gp_wq)->task_list를 사용한 list 초기화
    • // (&(&rcu_bh_state)->wakeup_work)->flags: 0
    • // (&(&rcu_bh_state)->wakeup_work)->func: rsp_wakeup
    • //
    • // (&rcu_bh_state)->level[0]
    • //
    • // pcp0->mynode: (&rcu_bh_state)->level[0]
    • // pcp1->mynode: (&rcu_bh_state)->level[0]
    • // pcp2->mynode: (&rcu_bh_state)->level[0]
    • // pcp3->mynode: (&rcu_bh_state)->level[0]
    • //
    • // pcp0->grpmask: 1
    • // pcp0->nxtlist: NULL
    • // pcp0->nxttail[0...3]: [pcp0] &(&rcu_bh_data)->nxtlist
    • // pcp0->qlen_lazy: 0
    • // pcp0->qlen: 0
    • // pcp0->dynticks: [pcp0] &rcu_dynticks
    • // pcp0->cpu: 0
    • // pcp0->rsp: &rcu_bh_state
    • // pcp1->grpmask: 2
    • // pcp1->nxtlist: NULL
    • // pcp1->nxttail[0...3]: [pcp0] &(&rcu_bh_data)->nxtlist
    • // pcp1->qlen_lazy: 0
    • // pcp1->qlen: 0
    • // pcp1->dynticks: [pcp1] &rcu_dynticks
    • // pcp1->cpu: 1
    • // pcp1->rsp: &rcu_bh_state
    • // pcp2->grpmask: 4
    • // pcp2->nxtlist: NULL
    • // pcp2->nxttail[0...3]: [pcp2] &(&rcu_bh_data)->nxtlist
    • // pcp2->qlen_lazy: 0
    • // pcp2->qlen: 0
    • // pcp2->dynticks: [pcp2] &rcu_dynticks
    • // pcp2->cpu: 2
    • // pcp2->rsp: &rcu_bh_state
    • // pcp3->grpmask: 8
    • // pcp3->nxtlist: NULL
    • // pcp3->nxttail[0...3]: [pcp3] &(&rcu_bh_data)->nxtlist
    • // pcp3->qlen_lazy: 0
    • // pcp3->qlen: 0
    • // pcp3->dynticks: [pcp3] &rcu_dynticks
    • // pcp3->cpu: 3
    • // pcp3->rsp: &rcu_bh_state
    • //
    • // rcu_struct_flavors에 (&rcu_bh_state)->flavors를 list 추가
  • rcu_init_one(&rcu_sched_state, &rcu_sched_data);
    • // (&rcu_sched_state)->levelcnt[0]: 1
    • // (&rcu_sched_state)->levelspread[0]: 4
    • // &((&rcu_sched_state)->level[0])->lock 사용한 spinlock 초기화
    • // &((&rcu_sched_state)->level[0])->fqslock 사용한 spinlock 초기화
    • // ((&rcu_sched_state)->level[0])->completed: 0xfffffed4
    • // ((&rcu_sched_state)->level[0])->qsmask: 0
    • // ((&rcu_sched_state)->level[0])->qsmaskinit: 0
    • // ((&rcu_sched_state)->level[0])->grplo: 0
    • // ((&rcu_sched_state)->level[0])->grphi: 3
    • // ((&rcu_sched_state)->level[0])->gpnum: 0
    • // ((&rcu_sched_state)->level[0])->grpmask: 0
    • // ((&rcu_sched_state)->level[0])->parent: NULL
    • // ((&rcu_sched_state)->level[0])->level: 0
    • // &((&rcu_sched_state)->level[0])->blkd_tasks 을 사용한 list 초기화
    • //
    • // (&rcu_sched_state)->rda: &rcu_sched_data
    • // &(&(&rcu_sched_state)->gp_wq)->lock을 사용한 spinlock 초기화
    • // &(&(&rcu_sched_state)->gp_wq)->task_list를 사용한 list 초기화
    • // (&(&rcu_sched_state)->wakeup_work)->flags: 0
    • // (&(&rcu_sched_state)->wakeup_work)->func: rsp_wakeup
    • //
    • // (&rcu_sched_state)->level[0]
    • //
    • // pcp0->mynode: (&rcu_sched_state)->level[0]
    • // pcp1->mynode: (&rcu_sched_state)->level[0]
    • // pcp2->mynode: (&rcu_sched_state)->level[0]
    • // pcp3->mynode: (&rcu_sched_state)->level[0]
    • //
    • // pcp0->grpmask: 1
    • // pcp0->nxtlist: NULL
    • // pcp0->nxttail[0...3]: [pcp0] &(&rcu_sched_data)->nxtlist
    • // pcp0->qlen_lazy: 0
    • // pcp0->qlen: 0
    • // pcp0->dynticks: [pcp0] &rcu_dynticks
    • // pcp0->cpu: 0
    • // pcp0->rsp: &rcu_sched_state
    • // pcp1->grpmask: 2
    • // pcp1->nxtlist: NULL
    • // pcp1->nxttail[0...3]: [pcp0] &(&rcu_sched_data)->nxtlist
    • // pcp1->qlen_lazy: 0
    • // pcp1->qlen: 0
    • // pcp1->dynticks: [pcp1] &rcu_dynticks
    • // pcp1->cpu: 1
    • // pcp1->rsp: &rcu_sched_state
    • // pcp2->grpmask: 4
    • // pcp2->nxtlist: NULL
    • // pcp2->nxttail[0...3]: [pcp2] &(&rcu_sched_data)->nxtlist
    • // pcp2->qlen_lazy: 0
    • // pcp2->qlen: 0
    • // pcp2->dynticks: [pcp2] &rcu_dynticks
    • // pcp2->cpu: 2
    • // pcp2->rsp: &rcu_sched_state
    • // pcp3->grpmask: 8
    • // pcp3->nxtlist: NULL
    • // pcp3->nxttail[0...3]: [pcp3] &(&rcu_sched_data)->nxtlist
    • // pcp3->qlen_lazy: 0
    • // pcp3->qlen: 0
    • // pcp3->dynticks: [pcp3] &rcu_dynticks
    • // pcp3->cpu: 3
    • // pcp3->rsp: &rcu_sched_state
    • //
    • // rcu_struct_flavors에 (&rcu_sched_state)->flavors를 list 추가
  • open_softirq(RCU_SOFTIRQ, rcu_process_callbacks);
    • // softirq_vec[9].action: rcu_process_callbacks
  • cpu_notifier(rcu_cpu_notify, 0);
    • // (&cpu_chain)->head: rcu_cpu_notify_nb 포인터 대입
    • // (&rcu_cpu_notify_nb)->next은 (&sched_ilb_notifier_nb)->next로 대입
  • pm_notifier(rcu_pm_notify, 0);
    • // (&pm_chain_head)->head: rcu_pm_notify_nb 포인터 대입
    • // n->next: (&rcu_pm_notify_nb)->next: NULL
  • for_each_online_cpu(cpu)
// ARM10C 20140920
void __init rcu_init(void)
{
    int cpu;

    rcu_bootup_announce();
    rcu_init_geometry();
    // jiffies_till_first_fqs: 1
    // jiffies_till_next_fqs: 1

// 2014/09/20 종료
// 2014/09/27 시작

    rcu_init_one(&rcu_bh_state, &rcu_bh_data);
    // (&rcu_bh_state)->levelcnt[0]: 1
    // (&rcu_bh_state)->levelspread[0]: 4
    // &((&rcu_bh_state)->level[0])->lock 사용한 spinlock 초기화
    // &((&rcu_bh_state)->level[0])->fqslock 사용한 spinlock 초기화
    // ((&rcu_bh_state)->level[0])->completed: 0xfffffed4
    // ((&rcu_bh_state)->level[0])->qsmask: 0
    // ((&rcu_bh_state)->level[0])->qsmaskinit: 0
    // ((&rcu_bh_state)->level[0])->grplo: 0
    // ((&rcu_bh_state)->level[0])->grphi: 3
    // ((&rcu_bh_state)->level[0])->gpnum: 0
    // ((&rcu_bh_state)->level[0])->grpmask: 0
    // ((&rcu_bh_state)->level[0])->parent: NULL
    // ((&rcu_bh_state)->level[0])->level: 0
    // &((&rcu_bh_state)->level[0])->blkd_tasks 을 사용한 list 초기화
    //
    // (&rcu_bh_state)->rda: &rcu_bh_data
    // &(&(&rcu_bh_state)->gp_wq)->lock을 사용한 spinlock 초기화
    // &(&(&rcu_bh_state)->gp_wq)->task_list를 사용한 list 초기화
    // (&(&rcu_bh_state)->wakeup_work)->flags: 0
    // (&(&rcu_bh_state)->wakeup_work)->func: rsp_wakeup
    //
    // (&rcu_bh_state)->level[0]
    //
    // [pcp0] (&rcu_bh_data)->mynode: (&rcu_bh_state)->level[0]
    // [pcp1] (&rcu_bh_data)->mynode: (&rcu_bh_state)->level[0]
    // [pcp2] (&rcu_bh_data)->mynode: (&rcu_bh_state)->level[0]
    // [pcp3] (&rcu_bh_data)->mynode: (&rcu_bh_state)->level[0]
    //
    // [pcp0] (&rcu_bh_data)->grpmask: 1
    // [pcp0] (&rcu_bh_data)->nxtlist: NULL
    // [pcp0] (&rcu_bh_data)->nxttail[0...3]: [pcp0] &(&rcu_bh_data)->nxtlist
    // [pcp0] (&rcu_bh_data)->qlen_lazy: 0
    // [pcp0] (&rcu_bh_data)->qlen: 0
    // [pcp0] (&rcu_bh_data)->dynticks: [pcp0] &rcu_dynticks
    // [pcp0] (&rcu_bh_data)->cpu: 0
    // [pcp0] (&rcu_bh_data)->rsp: &rcu_bh_state
    //
    // rcu_struct_flavors에 (&rcu_bh_state)->flavors를 list 추가

    rcu_init_one(&rcu_sched_state, &rcu_sched_data);
    // (&rcu_sched_state)->levelcnt[0]: 1
    // (&rcu_sched_state)->levelspread[0]: 4
    // &((&rcu_sched_state)->level[0])->lock 사용한 spinlock 초기화
    // &((&rcu_sched_state)->level[0])->fqslock 사용한 spinlock 초기화
    // ((&rcu_sched_state)->level[0])->completed: 0xfffffed4
    // ((&rcu_sched_state)->level[0])->qsmask: 0
    // ((&rcu_sched_state)->level[0])->qsmaskinit: 0
    // ((&rcu_sched_state)->level[0])->grplo: 0
    // ((&rcu_sched_state)->level[0])->grphi: 3
    // ((&rcu_sched_state)->level[0])->gpnum: 0
    // ((&rcu_sched_state)->level[0])->grpmask: 0
    // ((&rcu_sched_state)->level[0])->parent: NULL
    // ((&rcu_sched_state)->level[0])->level: 0
    // &((&rcu_sched_state)->level[0])->blkd_tasks 을 사용한 list 초기화
    //
    // (&rcu_sched_state)->rda: &rcu_sched_data
    // &(&(&rcu_sched_state)->gp_wq)->lock을 사용한 spinlock 초기화
    // &(&(&rcu_sched_state)->gp_wq)->task_list를 사용한 list 초기화
    // (&(&rcu_sched_state)->wakeup_work)->flags: 0
    // (&(&rcu_sched_state)->wakeup_work)->func: rsp_wakeup
    //
    // (&rcu_sched_state)->level[0]
    //
    // [pcp0] (&rcu_sched_data)->mynode: (&rcu_sched_state)->level[0]
    // [pcp1] (&rcu_sched_data)->mynode: (&rcu_sched_state)->level[0]
    // [pcp2] (&rcu_sched_data)->mynode: (&rcu_sched_state)->level[0]
    // [pcp3] (&rcu_sched_data)->mynode: (&rcu_sched_state)->level[0]
    //
    // [pcp0] (&rcu_sched_data)->grpmask: 1
    // [pcp0] (&rcu_sched_data)->nxtlist: NULL
    // [pcp0] (&rcu_sched_data)->nxttail[0...3]: [pcp0] &(&rcu_sched_data)->nxtlist
    // [pcp0] (&rcu_sched_data)->qlen_lazy: 0
    // [pcp0] (&rcu_sched_data)->qlen: 0
    // [pcp0] (&rcu_sched_data)->dynticks: [pcp0] &rcu_dynticks
    // [pcp0] (&rcu_sched_data)->cpu: 0
    // [pcp0] (&rcu_sched_data)->rsp: &rcu_sched_state
    // [pcp1] (&rcu_sched_data)->grpmask: 2
    // [pcp1] (&rcu_sched_data)->nxtlist: NULL
    // [pcp1] (&rcu_sched_data)->nxttail[0...3]: [pcp0] &(&rcu_sched_data)->nxtlist
    // [pcp1] (&rcu_sched_data)->qlen_lazy: 0
    // [pcp1] (&rcu_sched_data)->qlen: 0
    // [pcp1] (&rcu_sched_data)->dynticks: [pcp1] &rcu_dynticks
    // [pcp1] (&rcu_sched_data)->cpu: 1
    // [pcp1] (&rcu_sched_data)->rsp: &rcu_sched_state
    // [pcp2] (&rcu_sched_data)->grpmask: 4
    // [pcp2] (&rcu_sched_data)->nxtlist: NULL
    // [pcp2] (&rcu_sched_data)->nxttail[0...3]: [pcp2] &(&rcu_sched_data)->nxtlist
    // [pcp2] (&rcu_sched_data)->qlen_lazy: 0
    // [pcp2] (&rcu_sched_data)->qlen: 0
    // [pcp2] (&rcu_sched_data)->dynticks: [pcp2] &rcu_dynticks
    // [pcp2] (&rcu_sched_data)->cpu: 2
    // [pcp2] (&rcu_sched_data)->rsp: &rcu_sched_state
    // [pcp3] (&rcu_sched_data)->grpmask: 8
    // [pcp3] (&rcu_sched_data)->nxtlist: NULL
    // [pcp3] (&rcu_sched_data)->nxttail[0...3]: [pcp3] &(&rcu_sched_data)->nxtlist
    // [pcp3] (&rcu_sched_data)->qlen_lazy: 0
    // [pcp3] (&rcu_sched_data)->qlen: 0
    // [pcp3] (&rcu_sched_data)->dynticks: [pcp3] &rcu_dynticks
    // [pcp3] (&rcu_sched_data)->cpu: 3
    // [pcp3] (&rcu_sched_data)->rsp: &rcu_sched_state
    //
    // rcu_struct_flavors에 (&rcu_sched_state)->flavors를 list 추가

    __rcu_init_preempt();
    // __rcu_init_preempt 한일:
    // (&rcu_preempt_state)->levelcnt[0]: 1
    // (&rcu_preempt_state)->levelspread[0]: 4
    // &((&rcu_preempt_state)->level[0])->lock 사용한 spinlock 초기화
    // &((&rcu_preempt_state)->level[0])->fqslock 사용한 spinlock 초기화
    // ((&rcu_preempt_state)->level[0])->completed: 0xfffffed4
    // ((&rcu_preempt_state)->level[0])->qsmask: 0
    // ((&rcu_preempt_state)->level[0])->qsmaskinit: 0
    // ((&rcu_preempt_state)->level[0])->grplo: 0
    // ((&rcu_preempt_state)->level[0])->grphi: 3
    // ((&rcu_preempt_state)->level[0])->gpnum: 0
    // ((&rcu_preempt_state)->level[0])->grpmask: 0
    // ((&rcu_preempt_state)->level[0])->parent: NULL
    // ((&rcu_preempt_state)->level[0])->level: 0
    // &((&rcu_preempt_state)->level[0])->blkd_tasks 을 사용한 list 초기화
    //
    // (&rcu_preempt_state)->rda: &rcu_preempt_data
    // &(&(&rcu_preempt_state)->gp_wq)->lock을 사용한 spinlock 초기화
    // &(&(&rcu_preempt_state)->gp_wq)->task_list를 사용한 list 초기화
    // (&(&rcu_preempt_state)->wakeup_work)->flags: 0
    // (&(&rcu_preempt_state)->wakeup_work)->func: rsp_wakeup
    //
    // (&rcu_preempt_state)->level[0]
    //
    // [pcp0] (&rcu_preempt_data)->mynode: (&rcu_preempt_state)->level[0]
    // [pcp1] (&rcu_preempt_data)->mynode: (&rcu_preempt_state)->level[0]
    // [pcp2] (&rcu_preempt_data)->mynode: (&rcu_preempt_state)->level[0]
    // [pcp3] (&rcu_preempt_data)->mynode: (&rcu_preempt_state)->level[0]
    //
    // [pcp0] (&rcu_preempt_data)->grpmask: 1
    // [pcp0] (&rcu_preempt_data)->nxtlist: NULL
    // [pcp0] (&rcu_preempt_data)->nxttail[0...3]: [pcp0] &(&rcu_preempt_data)->nxtlist
    // [pcp0] (&rcu_preempt_data)->qlen_lazy: 0
    // [pcp0] (&rcu_preempt_data)->qlen: 0
    // [pcp0] (&rcu_preempt_data)->dynticks: [pcp0] &rcu_dynticks
    // [pcp0] (&rcu_preempt_data)->cpu: 0
    // [pcp0] (&rcu_preempt_data)->rsp: &rcu_preempt_state
    // [pcp1] (&rcu_preempt_data)->grpmask: 2
    // [pcp1] (&rcu_preempt_data)->nxtlist: NULL
    // [pcp1] (&rcu_preempt_data)->nxttail[0...3]: [pcp0] &(&rcu_preempt_data)->nxtlist
    // [pcp1] (&rcu_preempt_data)->qlen_lazy: 0
    // [pcp1] (&rcu_preempt_data)->qlen: 0
    // [pcp1] (&rcu_preempt_data)->dynticks: [pcp1] &rcu_dynticks
    // [pcp1] (&rcu_preempt_data)->cpu: 1
    // [pcp1] (&rcu_preempt_data)->rsp: &rcu_preempt_state
    // [pcp2] (&rcu_preempt_data)->grpmask: 4
    // [pcp2] (&rcu_preempt_data)->nxtlist: NULL
    // [pcp2] (&rcu_preempt_data)->nxttail[0...3]: [pcp2] &(&rcu_preempt_data)->nxtlist
    // [pcp2] (&rcu_preempt_data)->qlen_lazy: 0
    // [pcp2] (&rcu_preempt_data)->qlen: 0
    // [pcp2] (&rcu_preempt_data)->dynticks: [pcp2] &rcu_dynticks
    // [pcp2] (&rcu_preempt_data)->cpu: 2
    // [pcp2] (&rcu_preempt_data)->rsp: &rcu_preempt_state
    // [pcp3] (&rcu_preempt_data)->grpmask: 8
    // [pcp3] (&rcu_preempt_data)->nxtlist: NULL
    // [pcp3] (&rcu_preempt_data)->nxttail[0...3]: [pcp3] &(&rcu_preempt_data)->nxtlist
    // [pcp3] (&rcu_preempt_data)->qlen_lazy: 0
    // [pcp3] (&rcu_preempt_data)->qlen: 0
    // [pcp3] (&rcu_preempt_data)->dynticks: [pcp3] &rcu_dynticks
    // [pcp3] (&rcu_preempt_data)->cpu: 3
    // [pcp3] (&rcu_preempt_data)->rsp: &rcu_preempt_state
    //
    // rcu_struct_flavors에 (&rcu_preempt_state)->flavors를 list 추가

    // RCU_SOFTIRQ: 9,
    open_softirq(RCU_SOFTIRQ, rcu_process_callbacks);
    // open_softirq에서 한일:
    // softirq_vec[9].action: rcu_process_callbacks

    /*
     * We don't need protection against CPU-hotplug here because
     * this is called early in boot, before either interrupts
     * or the scheduler are operational.
     */
    cpu_notifier(rcu_cpu_notify, 0);
    // cpu_notifier에서 한일:
    // (&cpu_chain)->head: rcu_cpu_notify_nb 포인터 대입
    // (&rcu_cpu_notify_nb)->next은 (&sched_ilb_notifier_nb)->next로 대입

    pm_notifier(rcu_pm_notify, 0);
    // pm_notifier에서 한일:
    // (&pm_chain_head)->head: rcu_pm_notify_nb 포인터 대입
    // n->next: (&rcu_pm_notify_nb)->next: NULL

    for_each_online_cpu(cpu)
    // for ((cpu) = -1; (cpu) = cpumask_next((cpu), (cpu_online_mask)), (cpu) < nr_cpu_ids; )

        // CPU_UP_PREPARE: 0x0003, cpu: 0
        // rcu_cpu_notify(NULL, 0x0003, 0): NOTIFY_OK: 0x0001
        // CPU_UP_PREPARE: 0x0003, cpu: 1
        // rcu_cpu_notify(NULL, 0x0003, 1): NOTIFY_OK: 0x0001
        // CPU_UP_PREPARE: 0x0003, cpu: 2
        // rcu_cpu_notify(NULL, 0x0003, 2): NOTIFY_OK: 0x0001
        // CPU_UP_PREPARE: 0x0003, cpu: 3
        // rcu_cpu_notify(NULL, 0x0003, 3): NOTIFY_OK: 0x0001
        rcu_cpu_notify(NULL, CPU_UP_PREPARE, (void *)(long)cpu);
        // rcu_cpu_notify에서 한일:
        // [pcp0...3] (&rcu_bh_data)->beenonline: 1
        // [pcp0...3] (&rcu_bh_data)->preemptible: 0
        // [pcp0...3] (&rcu_bh_data)->len_last_fqs_check: 0
        // [pcp0...3] (&rcu_bh_data)->n_force_qs_snap: 0
        // [pcp0...3] (&rcu_bh_data)->blimit: 10
        // [pcp0...3] (&rcu_bh_data)->nxtlist: NULL
        // [pcp0...3] (&rcu_bh_data)->nxttail[0...3]: [pcp0...3] &(&rcu_bh_data)->nxtlist
        // [pcp0...3] (&rcu_bh_data)->dynticks->dynticks_nesting: 0x140000000000000
        // [pcp0...3] (&rcu_bh_data)->dynticks->dynticks: 1
        // [pcp0...3] ((&rcu_bh_state)->level[0])->qsmaskinit: [pcp0] 1, [pcp1] 2, [pcp2] 4, [pcp3] 8
        // [pcp0...3] (&rcu_bh_data)->gpnum: 0xfffffed4
        // [pcp0...3] (&rcu_bh_data)->passed_quiesce: 0
        // [pcp0...3] (&rcu_bh_data)->qs_pending: 0
        //
        // [pcp0...3] (&rcu_sched_data)->beenonline: 1
        // [pcp0...3] (&rcu_sched_data)->preemptible: 0
        // [pcp0...3] (&rcu_sched_data)->len_last_fqs_check: 0
        // [pcp0...3] (&rcu_sched_data)->n_force_qs_snap: 0
        // [pcp0...3] (&rcu_sched_data)->blimit: 10
        // [pcp0...3] (&rcu_sched_data)->nxtlist: NULL
        // [pcp0...3] (&rcu_sched_data)->nxttail[0...3]: [pcp0...3] &(&rcu_sched_data)->nxtlist
        // [pcp0...3] (&rcu_sched_data)->dynticks->dynticks_nesting: 0x140000000000000
        // [pcp0...3] (&rcu_sched_data)->dynticks->dynticks: 1
        // [pcp0...3] ((&rcu_sched_state)->level[0])->qsmaskinit: [pcp0] 1, [pcp1] 2, [pcp2] 4, [pcp3] 8
        // [pcp0...3] (&rcu_sched_data)->gpnum: 0xfffffed4
        // [pcp0...3] (&rcu_sched_data)->passed_quiesce: 0
        // [pcp0...3] (&rcu_sched_data)->qs_pending: 0
        //
        // [pcp0...3] (&rcu_preempt_data)->beenonline: 1
        // [pcp0...3] (&rcu_preempt_data)->preemptible: 1
        // [pcp0...3] (&rcu_preempt_data)->len_last_fqs_check: 0
        // [pcp0...3] (&rcu_preempt_data)->n_force_qs_snap: 0
        // [pcp0...3] (&rcu_preempt_data)->blimit: 10
        // [pcp0...3] (&rcu_preempt_data)->nxtlist: NULL
        // [pcp0...3] (&rcu_preempt_data)->nxttail[0...3]: [pcp0...3] &(&rcu_preempt_data)->nxtlist
        // [pcp0...3] (&rcu_preempt_data)->dynticks->dynticks_nesting: 0x140000000000000
        // [pcp0...3] (&rcu_preempt_data)->dynticks->dynticks: 1
        // [pcp0...3] ((&rcu_preempt_state)->level[0])->qsmaskinit: [pcp0] 1, [pcp1] 2, [pcp2] 4, [pcp3] 8
        // [pcp0...3] (&rcu_preempt_data)->gpnum: 0xfffffed4
        // [pcp0...3] (&rcu_preempt_data)->passed_quiesce: 0
        // [pcp0...3] (&rcu_preempt_data)->qs_pending: 0

// 2014/09/27 종료
}

tree_plugin.h::rcu_bootup_announce();

// ARM10C 20140920
static void __init rcu_bootup_announce(void)
{
    pr_info("Preemptible hierarchical RCU implementation.\n");
    rcu_bootup_announce_oddness();
}

tree_plugin.h::rcu_bootup_annouce_oddness()

// ARM10C 20140920
static void __init rcu_bootup_announce_oddness(void)
{
#ifdef CONFIG_RCU_TRACE // CONFIG_RCU_TRACE=n
    pr_info("\tRCU debugfs-based tracing is enabled.\n");
#endif

// CONFIG_64BIT=n, CONFIG_RCU_FANOUT=32
#if (defined(CONFIG_64BIT) && CONFIG_RCU_FANOUT != 64) || (!defined(CONFIG_64BIT) && CONFIG_RCU_FANOUT != 32)
    pr_info("\tCONFIG_RCU_FANOUT set to non-default value of %d\n",
           CONFIG_RCU_FANOUT);
#endif
#ifdef CONFIG_RCU_FANOUT_EXACT // CONFIG_RCU_FANOUT_EXACT=n
    pr_info("\tHierarchical RCU autobalancing is disabled.\n");
#endif

#ifdef CONFIG_RCU_FAST_NO_HZ // CONFIG_RCU_FAST_NO_HZ=n
    pr_info("\tRCU dyntick-idle grace-period acceleration is enabled.\n");
#endif

#ifdef CONFIG_PROVE_RCU // CONFIG_PROVE_RCU=n
    pr_info("\tRCU lockdep checking is enabled.\n");
#endif

#ifdef CONFIG_RCU_TORTURE_TEST_RUNNABLE // CONFIG_RCU_TORTURE_TEST_RUNNABLE=n
    pr_info("\tRCU torture testing starts during boot.\n");
#endif

// CONFIG_TREE_PREEMPT_RCU=y, CONFIG_RCU_CPU_STALL_VERBOSE=y
#if defined(CONFIG_TREE_PREEMPT_RCU) && !defined(CONFIG_RCU_CPU_STALL_VERBOSE)
    pr_info("\tDump stacks of tasks blocking RCU-preempt GP.\n");
#endif

#if defined(CONFIG_RCU_CPU_STALL_INFO) // CONFIG_RCU_CPU_STALL_INFO=n
    pr_info("\tAdditional per-CPU info printed with stalls.\n");
#endif

#if NUM_RCU_LVL_4 != 0 // NUM_RCU_LVL_4: 0
    pr_info("\tFour-level hierarchy is enabled.\n");
#endif
    // rcu_fanout_leaf: 16, CONFIG_RCU_FANOUT_LEAF: 16
    if (rcu_fanout_leaf != CONFIG_RCU_FANOUT_LEAF)
        pr_info("\tBoot-time adjustment of leaf fanout to %d.\n", rcu_fanout_leaf);

    // nr_cpu_ids: 4, NR_CPUS: 4
    if (nr_cpu_ids != NR_CPUS)
        pr_info("\tRCU restricting CPUs from NR_CPUS=%d to nr_cpu_ids=%d.\n", NR_CPUS, nr_cpu_ids);

#ifdef CONFIG_RCU_NOCB_CPU // CONFIG_RCU_NOCB_CPU=n
#ifndef CONFIG_RCU_NOCB_CPU_NONE // CONFIG_RCU_NOCB_CPU_NONE=n
    if (!have_rcu_nocb_mask) {
        zalloc_cpumask_var(&rcu_nocb_mask, GFP_KERNEL);
        have_rcu_nocb_mask = true;
    }
#ifdef CONFIG_RCU_NOCB_CPU_ZERO // CONFIG_RCU_NOCB_CPU_ZERO=n
    pr_info("\tOffload RCU callbacks from CPU 0\n");
    cpumask_set_cpu(0, rcu_nocb_mask);
#endif /* #ifdef CONFIG_RCU_NOCB_CPU_ZERO */
#ifdef CONFIG_RCU_NOCB_CPU_ALL // CONFIG_RCU_NOCB_CPU_ALL=n
    pr_info("\tOffload RCU callbacks from all CPUs\n");
    cpumask_copy(rcu_nocb_mask, cpu_possible_mask);
#endif /* #ifdef CONFIG_RCU_NOCB_CPU_ALL */
#endif /* #ifndef CONFIG_RCU_NOCB_CPU_NONE */
    if (have_rcu_nocb_mask) {
        if (!cpumask_subset(rcu_nocb_mask, cpu_possible_mask)) {
            pr_info("\tNote: kernel parameter 'rcu_nocbs=' contains nonexistent CPUs.\n");
            cpumask_and(rcu_nocb_mask, cpu_possible_mask,
                    rcu_nocb_mask);
        }
        cpulist_scnprintf(nocb_buf, sizeof(nocb_buf), rcu_nocb_mask);
        pr_info("\tOffload RCU callbacks from CPUs: %s.\n", nocb_buf);
        if (rcu_nocb_poll)
            pr_info("\tPoll for callbacks from no-CBs CPUs.\n");
    }
#endif /* #ifdef CONFIG_RCU_NOCB_CPU */
}

rcu_init_geometry();

  • rcu_init_geometry에서 한일:
    • // jiffies_till_first_fqs: 1
    • // jiffies_till_next_fqs: 1
// ARM10C 20140920
static void __init rcu_init_geometry(void)
{
    ulong d;
    int i;
    int j;

    // nr_cpu_ids: 4
    int n = nr_cpu_ids;
    // n: 4

    // MAX_RCU_LVLS: 4
    int rcu_capacity[MAX_RCU_LVLS + 1];

    /*
     * Initialize any unspecified boot parameters.
     * The default values of jiffies_till_first_fqs and
     * jiffies_till_next_fqs are set to the RCU_JIFFIES_TILL_FORCE_QS
     * value, which is a function of HZ, then adding one for each
     * RCU_JIFFIES_FQS_DIV CPUs that might be on the system.
     */
    // RCU_JIFFIES_TILL_FORCE_QS: 1, nr_cpu_ids: 4, RCU_JIFFIES_FQS_DIV: 256
    d = RCU_JIFFIES_TILL_FORCE_QS + nr_cpu_ids / RCU_JIFFIES_FQS_DIV;
    // d: 1

    // jiffies_till_first_fqs: 0xFFFFFFFF, ULONG_MAX: 0xFFFFFFFF
    if (jiffies_till_first_fqs == ULONG_MAX)
        // d: 1
        jiffies_till_first_fqs = d;
        // jiffies_till_first_fqs: 1

    // jiffies_till_next_fqs: 0xFFFFFFFF, ULONG_MAX: 0xFFFFFFFF
    if (jiffies_till_next_fqs == ULONG_MAX)
        // d: 1
        jiffies_till_next_fqs = d;
        // jiffies_till_next_fqs: 1

    /* If the compile-time values are accurate, just leave. */
    // rcu_fanout_leaf: 16, CONFIG_RCU_FANOUT_LEAF: 16, nr_cpu_ids: 4, NR_CPUS: 4
    if (rcu_fanout_leaf == CONFIG_RCU_FANOUT_LEAF &&
        nr_cpu_ids == NR_CPUS)
        return;
        // return 수행

    /*
     * Compute number of nodes that can be handled an rcu_node tree
     * with the given number of levels.  Setting rcu_capacity[0] makes
     * some of the arithmetic easier.
     */
    rcu_capacity[0] = 1;
    rcu_capacity[1] = rcu_fanout_leaf;
    for (i = 2; i <= MAX_RCU_LVLS; i++)
        rcu_capacity[i] = rcu_capacity[i - 1] * CONFIG_RCU_FANOUT;

    /*
     * The boot-time rcu_fanout_leaf parameter is only permitted
     * to increase the leaf-level fanout, not decrease it.  Of course,
     * the leaf-level fanout cannot exceed the number of bits in
     * the rcu_node masks.  Finally, the tree must be able to accommodate
     * the configured number of CPUs.  Complain and fall back to the
     * compile-time values if these limits are exceeded.
     */
    if (rcu_fanout_leaf < CONFIG_RCU_FANOUT_LEAF ||
        rcu_fanout_leaf > sizeof(unsigned long) * 8 ||
        n > rcu_capacity[MAX_RCU_LVLS]) {
        WARN_ON(1);
        return;
    }

    /* Calculate the number of rcu_nodes at each level of the tree. */
    for (i = 1; i <= MAX_RCU_LVLS; i++)
        if (n <= rcu_capacity[i]) {
            for (j = 0; j <= i; j++)
                num_rcu_lvl[j] =
                    DIV_ROUND_UP(n, rcu_capacity[i - j]);
            rcu_num_lvls = i;
            for (j = i + 1; j <= MAX_RCU_LVLS; j++)
                num_rcu_lvl[j] = 0;
            break;
        }

    /* Calculate the total number of rcu_node structures. */
    rcu_num_nodes = 0;
    for (i = 0; i <= MAX_RCU_LVLS; i++)
        rcu_num_nodes += num_rcu_lvl[i];
    rcu_num_nodes -= n;
}
  • rcu_init_one(&rcu_bh_state)한일:
    • // (&rcu_bh_state)->levelcnt[0]: 1
    • // (&rcu_bh_state)->levelspread[0]: 4
    • // &((&rcu_bh_state)->level[0])->lock 사용한 spinlock 초기화
    • // &((&rcu_bh_state)->level[0])->fqslock 사용한 spinlock 초기화
    • // ((&rcu_bh_state)->level[0])->completed: 0xfffffed4
    • // ((&rcu_bh_state)->level[0])->qsmask: 0
    • // ((&rcu_bh_state)->level[0])->qsmaskinit: 0
    • // ((&rcu_bh_state)->level[0])->grplo: 0
    • // ((&rcu_bh_state)->level[0])->grphi: 3
    • // ((&rcu_bh_state)->level[0])->gpnum: 0
    • // ((&rcu_bh_state)->level[0])->grpmask: 0
    • // ((&rcu_bh_state)->level[0])->parent: NULL
    • // ((&rcu_bh_state)->level[0])->level: 0
    • // &((&rcu_bh_state)->level[0])->blkd_tasks 을 사용한 list 초기화
    • //
    • // (&rcu_bh_state)->rda: &rcu_bh_data
    • // &(&(&rcu_bh_state)->gp_wq)->lock을 사용한 spinlock 초기화
    • // &(&(&rcu_bh_state)->gp_wq)->task_list를 사용한 list 초기화
    • // (&(&rcu_bh_state)->wakeup_work)->flags: 0
    • // (&(&rcu_bh_state)->wakeup_work)->func: rsp_wakeup
    • //
    • // (&rcu_bh_state)->level[0]
    • //
    • // pcp0->mynode: (&rcu_bh_state)->level[0]
    • // pcp1->mynode: (&rcu_bh_state)->level[0]
    • // pcp2->mynode: (&rcu_bh_state)->level[0]
    • // pcp3->mynode: (&rcu_bh_state)->level[0]
    • //
    • // pcp0->grpmask: 1
    • // pcp0->nxtlist: NULL
    • // pcp0->nxttail[0...3]: [pcp0] &(&rcu_bh_data)->nxtlist
    • // pcp0->qlen_lazy: 0
    • // pcp0->qlen: 0
    • // pcp0->dynticks: [pcp0] &rcu_dynticks
    • // pcp0->cpu: 0
    • // pcp0->rsp: &rcu_bh_state
    • // pcp1->grpmask: 2
    • // pcp1->nxtlist: NULL
    • // pcp1->nxttail[0...3]: [pcp0] &(&rcu_bh_data)->nxtlist
    • // pcp1->qlen_lazy: 0
    • // pcp1->qlen: 0
    • // pcp1->dynticks: [pcp1] &rcu_dynticks
    • // pcp1->cpu: 1
    • // pcp1->rsp: &rcu_bh_state
    • // pcp2->grpmask: 4
    • // pcp2->nxtlist: NULL
    • // pcp2->nxttail[0...3]: [pcp2] &(&rcu_bh_data)->nxtlist
    • // pcp2->qlen_lazy: 0
    • // pcp2->qlen: 0
    • // pcp2->dynticks: [pcp2] &rcu_dynticks
    • // pcp2->cpu: 2
    • // pcp2->rsp: &rcu_bh_state
    • // pcp3->grpmask: 8
    • // pcp3->nxtlist: NULL
    • // pcp3->nxttail[0...3]: [pcp3] &(&rcu_bh_data)->nxtlist
    • // pcp3->qlen_lazy: 0
    • // pcp3->qlen: 0
    • // pcp3->dynticks: [pcp3] &rcu_dynticks
    • // pcp3->cpu: 3
    • // pcp3->rsp: &rcu_bh_state
    • //
    • // rcu_struct_flavors에 (&rcu_bh_state)->flavors를 list 추가
// ARM10C 20140927
// &rcu_bh_state, &rcu_bh_data
static void __init rcu_init_one(struct rcu_state *rsp,
        struct rcu_data __percpu *rda)
{
    static char *buf[] = { "rcu_node_0",
                   "rcu_node_1",
                   "rcu_node_2",
                   "rcu_node_3" };  /* Match MAX_RCU_LVLS */
    static char *fqs[] = { "rcu_node_fqs_0",
                   "rcu_node_fqs_1",
                   "rcu_node_fqs_2",
                   "rcu_node_fqs_3" };  /* Match MAX_RCU_LVLS */
    int cpustride = 1;
    // cpustride: 1
    int i;
    int j;
    struct rcu_node *rnp;

    // MAX_RCU_LVLS: 4, ARRAY_SIZE(buf): 4
    BUILD_BUG_ON(MAX_RCU_LVLS > ARRAY_SIZE(buf));  /* Fix buf[] init! */

    /* Silence gcc 4.8 warning about array index out of range. */
    // rcu_num_lvls: 1, RCU_NUM_LVLS: 1
    if (rcu_num_lvls > RCU_NUM_LVLS)
        panic("rcu_init_one: rcu_num_lvls overflow");

    /* Initialize the level-tracking arrays. */

    // rcu_num_lvls: 1
    for (i = 0; i < rcu_num_lvls; i++)
        // i:0, rsp->levelcnt[0]: (&rcu_bh_state)->levelcnt[0], num_rcu_lvl[0]: 1
        rsp->levelcnt[i] = num_rcu_lvl[i];
        // rsp->levelcnt[0]: (&rcu_bh_state)->levelcnt[0]: 1

    // rcu_num_lvls: 1
    for (i = 1; i < rcu_num_lvls; i++)
        rsp->level[i] = rsp->level[i - 1] + rsp->levelcnt[i - 1];

    // rsp: &rcu_bh_state
    rcu_init_levelspread(rsp);
    // rcu_init_levelspread에서 한일:
    // rsp->levelspread[0]: (&rcu_bh_state)->levelspread[0]: 4

    /* Initialize the elements themselves, starting from the leaves. */

    // rcu_num_lvls: 1
    for (i = rcu_num_lvls - 1; i >= 0; i--) {
        // i: 0, cpustride: 1, rsp->levelspread[0]: (&rcu_bh_state)->levelspread[0]: 4
        cpustride *= rsp->levelspread[i];
        // cpustride: 4

        // i: 0, rsp->level[0]: (&rcu_bh_state)->level[0]
        rnp = rsp->level[i];
        // rnp: (&rcu_bh_state)->level[0]: &rcu_bh_state.node[0]

        // i: 0, rsp->levelcnt[0]: (&rcu_bh_state)->levelcnt[0]: 1
        for (j = 0; j < rsp->levelcnt[i]; j++, rnp++) {
            // &rnp->lock: &((&rcu_bh_state)->level[0])->lock
            raw_spin_lock_init(&rnp->lock);
            // &((&rcu_bh_state)->level[0])->lock 사용한 spinlock 초기화

            // &rnp->lock: &((&rcu_bh_state)->level[0])->lock,
            // i: 0, rcu_node_class[0], buf[0]: "rcu_node_0"
            lockdep_set_class_and_name(&rnp->lock,
                           &rcu_node_class[i], buf[i]); // null function

            // &rnp->fqslock: &((&rcu_bh_state)->level[0])->fqslock
            raw_spin_lock_init(&rnp->fqslock);
            // &((&rcu_bh_state)->level[0])->fqslock 사용한 spinlock 초기화

            // &rnp->fqslock: &((&rcu_bh_state)->level[0])->fqslock,
            // i: 0, rcu_fqs_class[0], fqs[0]: "rcu_node_fqs_0"
            lockdep_set_class_and_name(&rnp->fqslock,
                           &rcu_fqs_class[i], fqs[i]); // null function

            // rnp: ((&rcu_bh_state)->level[0])->gpnum,
            // rsp->gpnum: (&rcu_bh_state)->gpnum: 0xfffffed4
            rnp->gpnum = rsp->gpnum;
            // rnp->gpnum: ((&rcu_bh_state)->level[0])->gpnum: 0xfffffed4

            // rnp->completed: ((&rcu_bh_state)->level[0])->completed,
            // rsp->completed: (&rcu_bh_state)->completed: 0xfffffed4
            rnp->completed = rsp->completed;
            // rnp->completed: ((&rcu_bh_state)->level[0])->completed: 0xfffffed4

            // rnp->qsmask: ((&rcu_bh_state)->level[0])->qsmask
            rnp->qsmask = 0;
            // rnp->qsmask: ((&rcu_bh_state)->level[0])->qsmask: 0

            // rnp->qsmaskinit: ((&rcu_bh_state)->level[0])->qsmaskinit
            rnp->qsmaskinit = 0;
            // rnp->qsmaskinit: ((&rcu_bh_state)->level[0])->qsmaskinit: 0

            // rnp->grplo: ((&rcu_bh_state)->level[0])->grplo, j: 0, cpustride: 4
            rnp->grplo = j * cpustride;
            // rnp->grplo: ((&rcu_bh_state)->level[0])->grplo: 0

            // rnp->grphi: ((&rcu_bh_state)->level[0])->grphi, j: 0, cpustride: 4
            rnp->grphi = (j + 1) * cpustride - 1;
            // rnp->grphi: ((&rcu_bh_state)->level[0])->grphi: 3

            // rnp->grphi: ((&rcu_bh_state)->level[0])->grphi: 3, NR_CPUS: 4
            if (rnp->grphi >= NR_CPUS)
                rnp->grphi = NR_CPUS - 1;

            // i: 0
            if (i == 0) {
                // rnp->gpnum: ((&rcu_bh_state)->level[0])->gpnum: 0xfffffed4
                rnp->grpnum = 0;
                // rnp->gpnum: ((&rcu_bh_state)->level[0])->gpnum: 0

                // rnp->grpmask: ((&rcu_bh_state)->level[0])->grpmask
                rnp->grpmask = 0;
                // rnp->grpmask: ((&rcu_bh_state)->level[0])->grpmask: 0

                // rnp->parent: ((&rcu_bh_state)->level[0])->parent
                rnp->parent = NULL;
                // rnp->parent: ((&rcu_bh_state)->level[0])->parent: NULL
            } else {
                rnp->grpnum = j % rsp->levelspread[i - 1];
                rnp->grpmask = 1UL << rnp->grpnum;
                rnp->parent = rsp->level[i - 1] +
                          j / rsp->levelspread[i - 1];
            }
            // rnp->level: ((&rcu_bh_state)->level[0])->level, i: 0
            rnp->level = i;
            // rnp->level: ((&rcu_bh_state)->level[0])->level: 0

            // &rnp->blkd_tasks: &((&rcu_bh_state)->level[0])->blkd_tasks
            INIT_LIST_HEAD(&rnp->blkd_tasks);
            // &rnp->blkd_tasks: &((&rcu_bh_state)->level[0])->blkd_tasks 을 사용한 list 초기화

            // rnp: (&rcu_bh_state)->level[0]
            rcu_init_one_nocb(rnp); // null function
        }
    }

    // rsp->rda: (&rcu_bh_state)->rda, rda: &rcu_bh_data
    rsp->rda = rda;
    // rsp->rda: (&rcu_bh_state)->rda: &rcu_bh_data

    // &rsp->gp_wq: &(&rcu_bh_state)->gp_wq
    init_waitqueue_head(&rsp->gp_wq);
    // init_waitqueue_head에서 한일:
    // &q->lock: &(&(&rcu_bh_state)->gp_wq)->lock을 사용한 spinlock 초기화
    // &q->task_list: &(&(&rcu_bh_state)->gp_wq)->task_list를 사용한 list 초기화

    // &rsp->wakeup_work: &(&rcu_bh_state)->wakeup_work
    init_irq_work(&rsp->wakeup_work, rsp_wakeup);
    // init_irq_work에서 한일:
    // work->flags: (&(&rcu_bh_state)->wakeup_work)->flags: 0
    // work->func: (&(&rcu_bh_state)->wakeup_work)->func: rsp_wakeup

    // rcu_num_lvls: 1, rsp->level[0]: (&rcu_bh_state)->level[0]
    rnp = rsp->level[rcu_num_lvls - 1];
    // rnp: (&rcu_bh_state)->level[0]

    for_each_possible_cpu(i) {
    // for ((i) = -1; (i) = cpumask_next((i), (cpu_possible_mask)), (i) < nr_cpu_ids; )

        // i: 0, rnp->grphi: ((&rcu_bh_state)->level[0])->grphi: 3
        while (i > rnp->grphi)
            rnp++;

        // rsp->rda: (&rcu_bh_state)->rda: &rcu_bh_data, i: 0
        // per_cpu_ptr(&rcu_bh_data, 0)->mynode: [pcp0] (&rcu_bh_data)->mynode,
        // rnp: (&rcu_bh_state)->level[0]
        per_cpu_ptr(rsp->rda, i)->mynode = rnp;
        // per_cpu_ptr(&rcu_bh_data, 0)->mynode: [pcp0] (&rcu_bh_data)->mynode: (&rcu_bh_state)->level[0]

        // i: 0, rsp: &rcu_bh_state
        rcu_boot_init_percpu_data(i, rsp);
        // rcu_boot_init_percpu_data(0) 에서 한일:
        // rdp->grpmask: [pcp0] (&rcu_bh_data)->grpmask: 1
        // rdp->nxtlist: [pcp0] (&rcu_bh_data)->nxtlist: NULL
        // rdp->nxttail[0...3]: [pcp0] (&rcu_bh_data)->nxttail[0...3]: [pcp0] &(&rcu_bh_data)->nxtlist
        // rdp->qlen_lazy: [pcp0] (&rcu_bh_data)->qlen_lazy: 0
        // rdp->qlen: [pcp0] (&rcu_bh_data)->qlen: 0
        // rdp->dynticks: [pcp0] (&rcu_bh_data)->dynticks: [pcp0] &rcu_dynticks
        // rdp->cpu: [pcp0] (&rcu_bh_data)->cpu: 0
        // rdp->rsp: [pcp0] (&rcu_bh_data)->rsp: &rcu_bh_state
        //
        // rcu_boot_init_percpu_data(1) 에서 한일:
        // rdp->grpmask: [pcp1] (&rcu_bh_data)->grpmask: 2
        // rdp->nxtlist: [pcp1] (&rcu_bh_data)->nxtlist: NULL
        // rdp->nxttail[0...3]: [pcp1] (&rcu_bh_data)->nxttail[0...3]: [pcp0] &(&rcu_bh_data)->nxtlist
        // rdp->qlen_lazy: [pcp1] (&rcu_bh_data)->qlen_lazy: 0
        // rdp->qlen: [pcp1] (&rcu_bh_data)->qlen: 0
        // rdp->dynticks: [pcp1] (&rcu_bh_data)->dynticks: [pcp1] &rcu_dynticks
        // rdp->cpu: [pcp1] (&rcu_bh_data)->cpu: 1
        // rdp->rsp: [pcp1] (&rcu_bh_data)->rsp: &rcu_bh_state
        //
        // rcu_boot_init_percpu_data(2) 에서 한일:
        // rdp->grpmask: [pcp2] (&rcu_bh_data)->grpmask: 4
        // rdp->nxtlist: [pcp2] (&rcu_bh_data)->nxtlist: NULL
        // rdp->nxttail[0...3]: [pcp2] (&rcu_bh_data)->nxttail[0...3]: [pcp2] &(&rcu_bh_data)->nxtlist
        // rdp->qlen_lazy: [pcp2] (&rcu_bh_data)->qlen_lazy: 0
        // rdp->qlen: [pcp2] (&rcu_bh_data)->qlen: 0
        // rdp->dynticks: [pcp2] (&rcu_bh_data)->dynticks: [pcp2] &rcu_dynticks
        // rdp->cpu: [pcp2] (&rcu_bh_data)->cpu: 2
        // rdp->rsp: [pcp2] (&rcu_bh_data)->rsp: &rcu_bh_state
        //
        // rcu_boot_init_percpu_data(3) 에서 한일:
        // rdp->grpmask: [pcp3] (&rcu_bh_data)->grpmask: 8
        // rdp->nxtlist: [pcp3] (&rcu_bh_data)->nxtlist: NULL
        // rdp->nxttail[0...3]: [pcp3] (&rcu_bh_data)->nxttail[0...3]: [pcp3] &(&rcu_bh_data)->nxtlist
        // rdp->qlen_lazy: [pcp3] (&rcu_bh_data)->qlen_lazy: 0
        // rdp->qlen: [pcp3] (&rcu_bh_data)->qlen: 0
        // rdp->dynticks: [pcp3] (&rcu_bh_data)->dynticks: [pcp3] &rcu_dynticks
        // rdp->cpu: [pcp3] (&rcu_bh_data)->cpu: 3
        // rdp->rsp: [pcp3] (&rcu_bh_data)->rsp: &rcu_bh_state
    }

    // rsp->flavors: (&rcu_bh_state)->flavors
    list_add(&rsp->flavors, &rcu_struct_flavors);
    // rcu_struct_flavors에 (&rcu_bh_state)->flavors를 list 추가
}

tree_plugin.h::__rcu_init_preempt()

static void __init __rcu_init_preempt(void)
{
    rcu_init_one(&rcu_preempt_state, &rcu_preempt_data);
    // rcu_init_one(&rcu_preempt_state)한일:
    // (&rcu_preempt_state)->levelcnt[0]: 1
    // (&rcu_preempt_state)->levelspread[0]: 4
    // &((&rcu_preempt_state)->level[0])->lock 사용한 spinlock 초기화
    // &((&rcu_preempt_state)->level[0])->fqslock 사용한 spinlock 초기화
    // ((&rcu_preempt_state)->level[0])->completed: 0xfffffed4
    // ((&rcu_preempt_state)->level[0])->qsmask: 0
    // ((&rcu_preempt_state)->level[0])->qsmaskinit: 0
    // ((&rcu_preempt_state)->level[0])->grplo: 0
    // ((&rcu_preempt_state)->level[0])->grphi: 3
    // ((&rcu_preempt_state)->level[0])->gpnum: 0
    // ((&rcu_preempt_state)->level[0])->grpmask: 0
    // ((&rcu_preempt_state)->level[0])->parent: NULL
    // ((&rcu_preempt_state)->level[0])->level: 0
    // &((&rcu_preempt_state)->level[0])->blkd_tasks 을 사용한 list 초기화
    //
    // (&rcu_preempt_state)->rda: &rcu_preempt_data
    // &(&(&rcu_preempt_state)->gp_wq)->lock을 사용한 spinlock 초기화
    // &(&(&rcu_preempt_state)->gp_wq)->task_list를 사용한 list 초기화
    // (&(&rcu_preempt_state)->wakeup_work)->flags: 0
    // (&(&rcu_preempt_state)->wakeup_work)->func: rsp_wakeup
    //
    // (&rcu_preempt_state)->level[0]
    //
    // [pcp0] (&rcu_preempt_data)->mynode: (&rcu_preempt_state)->level[0]
    // [pcp1] (&rcu_preempt_data)->mynode: (&rcu_preempt_state)->level[0]
    // [pcp2] (&rcu_preempt_data)->mynode: (&rcu_preempt_state)->level[0]
    // [pcp3] (&rcu_preempt_data)->mynode: (&rcu_preempt_state)->level[0]
    //
    // [pcp0] (&rcu_preempt_data)->grpmask: 1
    // [pcp0] (&rcu_preempt_data)->nxtlist: NULL
    // [pcp0] (&rcu_preempt_data)->nxttail[0...3]: [pcp0] &(&rcu_preempt_data)->nxtlist
    // [pcp0] (&rcu_preempt_data)->qlen_lazy: 0
    // [pcp0] (&rcu_preempt_data)->qlen: 0
    // [pcp0] (&rcu_preempt_data)->dynticks: [pcp0] &rcu_dynticks
    // [pcp0] (&rcu_preempt_data)->cpu: 0
    // [pcp0] (&rcu_preempt_data)->rsp: &rcu_preempt_state
    // [pcp1] (&rcu_preempt_data)->grpmask: 2
    // [pcp1] (&rcu_preempt_data)->nxtlist: NULL
    // [pcp1] (&rcu_preempt_data)->nxttail[0...3]: [pcp0] &(&rcu_preempt_data)->nxtlist
    // [pcp1] (&rcu_preempt_data)->qlen_lazy: 0
    // [pcp1] (&rcu_preempt_data)->qlen: 0
    // [pcp1] (&rcu_preempt_data)->dynticks: [pcp1] &rcu_dynticks
    // [pcp1] (&rcu_preempt_data)->cpu: 1
    // [pcp1] (&rcu_preempt_data)->rsp: &rcu_preempt_state
    // [pcp2] (&rcu_preempt_data)->grpmask: 4
    // [pcp2] (&rcu_preempt_data)->nxtlist: NULL
    // [pcp2] (&rcu_preempt_data)->nxttail[0...3]: [pcp2] &(&rcu_preempt_data)->nxtlist
    // [pcp2] (&rcu_preempt_data)->qlen_lazy: 0
    // [pcp2] (&rcu_preempt_data)->qlen: 0
    // [pcp2] (&rcu_preempt_data)->dynticks: [pcp2] &rcu_dynticks
    // [pcp2] (&rcu_preempt_data)->cpu: 2
    // [pcp2] (&rcu_preempt_data)->rsp: &rcu_preempt_state
    // [pcp3] (&rcu_preempt_data)->grpmask: 8
    // [pcp3] (&rcu_preempt_data)->nxtlist: NULL
    // [pcp3] (&rcu_preempt_data)->nxttail[0...3]: [pcp3] &(&rcu_preempt_data)->nxtlist
    // [pcp3] (&rcu_preempt_data)->qlen_lazy: 0
    // [pcp3] (&rcu_preempt_data)->qlen: 0
    // [pcp3] (&rcu_preempt_data)->dynticks: [pcp3] &rcu_dynticks
    // [pcp3] (&rcu_preempt_data)->cpu: 3
    // [pcp3] (&rcu_preempt_data)->rsp: &rcu_preempt_state
    //
    // rcu_struct_flavors에 (&rcu_preempt_state)->flavors를 list 추가
}

tree.c:: RCU_STATE_INITIALIZER(sname, sabbr, cr)

#define RCU_STATE_INITIALIZER(sname, sabbr, cr) \
static char sname##_varname[] = #sname; \
static const char *tp_##sname##_varname __used __tracepoint_string = sname##_varname; \
struct rcu_state sname##_state = { \
    .level = { &sname##_state.node[0] }, \
    .call = cr, \
    .fqs_state = RCU_GP_IDLE, \
    .gpnum = 0UL - 300UL, \
    .completed = 0UL - 300UL, \
    .orphan_lock = __RAW_SPIN_LOCK_UNLOCKED(&sname##_state.orphan_lock), \
    .orphan_nxttail = &sname##_state.orphan_nxtlist, \
    .orphan_donetail = &sname##_state.orphan_donelist, \
    .barrier_mutex = __MUTEX_INITIALIZER(sname##_state.barrier_mutex), \
    .onoff_mutex = __MUTEX_INITIALIZER(sname##_state.onoff_mutex), \
    .name = sname##_varname, \
    .abbr = sabbr, \
}; \
DEFINE_PER_CPU(struct rcu_data, sname##_data)

RCU_STATE_INITIALIZER(rcu_sched, 's', call_rcu_sched);
RCU_STATE_INITIALIZER(rcu_bh, 'b', call_rcu_bh);

softirq.c::open_softirq()

// ARM10C 20140927
// RCU_SOFTIRQ: 9, rcu_process_callbacks
void open_softirq(int nr, void (*action)(struct softirq_action *))
{
    // nr: 7, action: run_rebalance_domains
    // nr: 9, action: rcu_process_callbacks
    softirq_vec[nr].action = action;
    // softirq_vec[7].action: run_rebalance_domains
    // softirq_vec[9].action: rcu_process_callbacks
}

cpu.h::cpu_notifier()

// ARM10C 20140927
// cpu_notifier(rcu_cpu_notify, 0):
// {
//  static struct notifier_block rcu_cpu_notify_nb =
//      { .notifier_call = rcu_cpu_notify, .priority = 0 };
//  register_cpu_notifier(&rcu_cpu_notify_nb);
// }
#define cpu_notifier(fn, pri) {                 \
    static struct notifier_block fn##_nb =          \
        { .notifier_call = fn, .priority = pri };   \
    register_cpu_notifier(&fn##_nb);            \
}

suspend.h::pm_notifier()

// ARM10C 20140927
// #define pm_notifier(rcu_pm_notify, 0):
// {
//  static struct notifier_block rcu_pm_notify_nb =
//      { .notifier_call = rcu_pm_notify, .priority = 0 };
//  register_pm_notifier(&rcu_pm_notify_nb);
// }
#define pm_notifier(fn, pri) {              \
    static struct notifier_block fn##_nb =          \
        { .notifier_call = fn, .priority = pri };   \
    register_pm_notifier(&fn##_nb);         \
}

wait.c::init_waitqueue_head()

#define init_waitqueue_head(q)              \
    do {                        \
        static struct lock_class_key __key; \
                            \
        __init_waitqueue_head((q), #q, &__key); \
    } while (0)

irq_work.h::init_irq_work()

  • &work
static inline
void init_irq_work(struct irq_work *work, void (*func)(struct irq_work *))
{
    work->flags = 0;
    work->func = func;
}

tree.c::rcu_boot_init_percpu_data()

static void __init
rcu_boot_init_percpu_data(int cpu, struct rcu_state *rsp)
{
    unsigned long flags;
    struct rcu_data *rdp = per_cpu_ptr(rsp->rda, cpu);

    struct rcu_node *rnp = rcu_get_root(rsp);
    // rn

    /* Set up local state, ensuring consistent view of global state. */
    raw_spin_lock_irqsave(&rnp->lock, flags);

    rdp->grpmask = 1UL << (cpu - rdp->mynode->grplo);
    // rdp->grpmask: [pcp0] &rcu_bh_data->grpmask

    // rdp: [pcp0] &rcu_bh_data
    init_callback_list(rdp);

    // rdp->qlen_lazy: [pcp0] (&rcu_bh_data)->qlen_lazy
    rdp->qlen_lazy = 0;
    // rdp->qlen_lazy: [pcp0] (&rcu_bh_data)->qlen_lazy:0

    ACCESS_ONCE(rdp->qlen) = 0;

    // cpu:0 [pcp0] &per_cpu((&rcu_bh_data)->dynticks, 0 )
    rdp->dynticks = &per_cpu(rcu_dynticks, cpu);


    WARN_ON_ONCE(rdp->dynticks->dynticks_nesting != DYNTICK_TASK_EXIT_IDLE);
    WARN_ON_ONCE(atomic_read(&rdp->dynticks->dynticks) != 1);

    rdp->cpu = cpu;
    // [pcp0] (&rcu_bh_data)->cpu: cpu: 0

    rdp->rsp = rsp;
    // [pcp0] (&rcu_bh_data)->rsp: rsp: &rcu_bh_state

    rcu_boot_init_nocb_percpu_data(rdp);
    // null function

    raw_spin_unlock_irqrestore(&rnp->lock, flags);
}

notifier.c::blocking_notifier_chain_register()

int blocking_notifier_chain_register(struct blocking_notifier_head *nh,
        struct notifier_block *n)
{
    int ret;

    /*
     * This code gets used during boot-up, when task switching is
     * not yet working and interrupts must remain disabled.  At
     * such times we must not call down_write().
     */
    if (unlikely(system_state == SYSTEM_BOOTING))
        return notifier_chain_register(&nh->head, n);

    down_write(&nh->rwsem);
    ret = notifier_chain_register(&nh->head, n);
    up_write(&nh->rwsem);
    return ret;
}
EXPORT_SYMBOL_GPL(blocking_notifier_chain_register);

cpumask.h::for_each_online_cpu()

  • for_each_online_cpu(cpu) rcu_cpu_notify(NULL, CPU_UP_PREPARE, (void *)(long)cpu);
#define for_each_online_cpu(cpu)   for_each_cpu((cpu), cpu_online_mask)
// #define for_each_cpu(i, cpu_online_mask)
//  for ((i) = -1; (i) = cpumask_next((i), (cpu_online_mask)), (i) < nr_cpu_ids; )

tree.c::rcu_cpu_notify()

static int rcu_cpu_notify(struct notifier_block *self,
                    unsigned long action, void *hcpu)
{
    // hcpu: 0
    long cpu = (long)hcpu;
    // cpu: 0

    // rcu_state->rda: (&rcu_preempt_state)->rda: &rcu_preempt_data, cpu: 0
    // per_cpu_ptr(&rcu_preempt_data, 0): [pcp0] &rcu_preempt_data
    struct rcu_data *rdp = per_cpu_ptr(rcu_state->rda, cpu);
    // rdp: [pcp0] &rcu_preempt_data

    // rdp->mynode: [pcp0] (&rcu_preempt_data)->mynode: (&rcu_preempt_state)->level[0]: &rcu_preempt_state.node[0]
    struct rcu_node *rnp = rdp->mynode;
    // rnp: (&rcu_preempt_state)->level[0]

    struct rcu_state *rsp;

    trace_rcu_utilization(TPS("Start CPU hotplug"));

    // action: CPU_UP_PREPARE: 0x0003
    switch (action) {
    case CPU_UP_PREPARE:
    case CPU_UP_PREPARE_FROZEN:
        // cpu: 0
        rcu_prepare_cpu(cpu);

        // cpu: 0
        rcu_prepare_kthreads(cpu); // null function

        break;
    case CPU_ONLINE:
    case CPU_DOWN_FAILED:
        rcu_boost_kthread_setaffinity(rnp, -1);
        break;
    case CPU_DOWN_PREPARE:
        rcu_boost_kthread_setaffinity(rnp, cpu);
        break;
    case CPU_DYING:
    case CPU_DYING_FROZEN:
        for_each_rcu_flavor(rsp)
            rcu_cleanup_dying_cpu(rsp);
        break;
    case CPU_DEAD:
    case CPU_DEAD_FROZEN:
    case CPU_UP_CANCELED:
    case CPU_UP_CANCELED_FROZEN:
        for_each_rcu_flavor(rsp)
            rcu_cleanup_dead_cpu(cpu, rsp);
        break;
    default:
        break;
    }
    trace_rcu_utilization(TPS("End CPU hotplug"));
    return NOTIFY_OK;
}

tree.c::rcu_prepare_cpu()

  • rcu_prepare_cpu에서 한일: // pcp0->beenonline: 1 // pcp0->preemptible: 0 // pcp0->len_last_fqs_check: 0 // pcp0->n_force_qs_snap: 0 // pcp0->blimit: 10 // pcp0->nxtlist: NULL // pcp0->nxttail[0...3]: [pcp0] &(&rcu_bh_data)->nxtlist // pcp0->dynticks->dynticks_nesting: 0x140000000000000 // pcp0->dynticks->dynticks: 1 // pcp0->qsmaskinit: 1 // pcp0->gpnum: 0xfffffed4 // pcp0->passed_quiesce: 0 // pcp0->qs_pending: 0 // // pcp0->beenonline: 1 // pcp0->preemptible: 0 // pcp0->len_last_fqs_check: 0 // pcp0->n_force_qs_snap: 0 // pcp0->blimit: 10 // pcp0->nxtlist: NULL // pcp0->nxttail[0...3]: [pcp0] &(&rcu_sched_data)->nxtlist // pcp0->dynticks->dynticks_nesting: 0x140000000000000 // pcp0->dynticks->dynticks: 1 // pcp0->qsmaskinit: 1 // pcp0->gpnum: 0xfffffed4 // pcp0->passed_quiesce: 0 // pcp0->qs_pending: 0 // // pcp0->beenonline: 1 // pcp0->preemptible: 1 //pcp0->len_last_fqs_check: 0 // pcp0->n_force_qs_snap: 0 // pcp0->blimit: 10 // pcp0->nxtlist: NULL // pcp0->nxttail[0...3]: [pcp0] &(&rcu_preempt_data)->nxtlist // pcp0->dynticks->dynticks_nesting: 0x140000000000000 //pcp0->dynticks->dynticks: 1 // pcp0->qsmaskinit: 1 // pcp0->gpnum: 0xfffffed4 // pcp0->passed_quiesce: 0 //pcp0->qs_pending: 0
// ARM10C 20140927
// cpu: 0
static void rcu_prepare_cpu(int cpu)
{
    struct rcu_state *rsp;

    for_each_rcu_flavor(rsp)
    // for (rsp = list_first_entry(&rcu_struct_flavors, typeof(*rsp), flavors);
    //     &rsp->flavors != (&rcu_struct_flavors); rsp = list_next_entry(rsp, flavors))

        // cpu: 0, rsp: &rcu_bh_state, rsp->name: (&rcu_bh_state)->name: "rcu_bh", strcmp("rcu_bh", "rcu_preempt"): -1
        // cpu: 0, rsp: &rcu_sched_data, rsp->name: (&rcu_bh_state)->name: "rcu_sched", strcmp("rcu_sched", "rcu_preempt"): -1
        // cpu: 0, rsp: &rcu_preempt_data, rsp->name: (&rcu_preempt_state)->name: "rcu_preempt", strcmp("rcu_preempt", "rcu_preempt"): 0
        rcu_init_percpu_data(cpu, rsp,
                     strcmp(rsp->name, "rcu_preempt") == 0);
}

tree.c::rcu_init_percpu_data()

// ARM10C 20140927
// cpu: 0, rsp: &rcu_bh_state, 0
static void
rcu_init_percpu_data(int cpu, struct rcu_state *rsp, int preemptible)
{
    unsigned long flags;
    unsigned long mask;

    // rsp->rda: (&rcu_bh_state)->rda: &rcu_bh_data, cpu: 0
    // per_cpu_ptr(&rcu_bh_data, 0): [pcp0] &rcu_bh_data
    struct rcu_data *rdp = per_cpu_ptr(rsp->rda, cpu);
    // rdp: [pcp0] &rcu_bh_data

    // rsp: &rcu_bh_state, rcu_get_root(&rcu_bh_state): &(&rcu_bh_state)->node[0]
    struct rcu_node *rnp = rcu_get_root(rsp);
    // rnp: &(&rcu_bh_state)->node[0]

    /* Exclude new grace periods. */
    // &rsp->onoff_mutex: &(&rcu_bh_state)->onoff_mutex
    mutex_lock(&rsp->onoff_mutex);
    // &rsp->onoff_mutex: &(&rcu_bh_state)->onoff_mutex을 사용한 mutex lock 수행

    /* Set up local state, ensuring consistent view of global state. */
    // &rnp->lock: &(&(&rcu_bh_state)->node[0])->lock
    raw_spin_lock_irqsave(&rnp->lock, flags);
    // &rnp->lock: &(&(&rcu_bh_state)->node[0])->lock을 사용한 spinlock을 걸고 cpsr을 flags에 저장

    // rdp->beenonline: [pcp0] (&rcu_bh_data)->beenonline
    rdp->beenonline = 1;     /* We have now been online. */
    // rdp->beenonline: [pcp0] (&rcu_bh_data)->beenonline: 1

    // rdp->preemptible: [pcp0] (&rcu_bh_data)->preemptible, preemptible: 0
    rdp->preemptible = preemptible;
    // rdp->preemptible: [pcp0] (&rcu_bh_data)->preemptible: 0

    // rdp->len_last_fqs_check: [pcp0] (&rcu_bh_data)->len_last_fqs_check
    rdp->qlen_last_fqs_check = 0;
    // rdp->len_last_fqs_check: [pcp0] (&rcu_bh_data)->len_last_fqs_check: 0

    // rdp->n_force_qs_snap: [pcp0] (&rcu_bh_data)->n_force_qs_snap
    // rsp->n_force_qs: (&rcu_bh_state)->n_force_qs: 0
    rdp->n_force_qs_snap = rsp->n_force_qs;
    // rdp->n_force_qs_snap: [pcp0] (&rcu_bh_data)->n_force_qs_snap: 0

    // rdp->blimit: [pcp0] (&rcu_bh_data)->blimit, blimit: 10
    rdp->blimit = blimit;
    // rdp->blimit: [pcp0] (&rcu_bh_data)->blimit: 10

    // rdp: [pcp0] &rcu_bh_data
    init_callback_list(rdp);  /* Re-enable callbacks on this CPU. */
    // init_callback_list에서 한일:
    // [pcp0] (&rcu_bh_data)->nxtlist: NULL
    // [pcp0] (&rcu_bh_data)->nxttail[0...3]: [pcp0] &(&rcu_bh_data)->nxtlist

    // rdp->dynticks->dynticks_nesting: [pcp0] (&rcu_bh_data)->dynticks->dynticks_nesting,
    // DYNTICK_TASK_EXIT_IDLE: 0x140000000000000
    rdp->dynticks->dynticks_nesting = DYNTICK_TASK_EXIT_IDLE;
    // rdp->dynticks->dynticks_nesting: [pcp0] (&rcu_bh_data)->dynticks->dynticks_nesting: 0x140000000000000

    // rdp->dynticks: [pcp0] (&rcu_bh_data)->dynticks
    rcu_sysidle_init_percpu_data(rdp->dynticks); // null function

    // &rdp->dynticks->dynticks: [pcp0] (&rcu_bh_data)->dynticks->dynticks: 1,
    // atomic_read((&rcu_bh_data)->dynticks->dynticks): 1
    atomic_set(&rdp->dynticks->dynticks,
           (atomic_read(&rdp->dynticks->dynticks) & ~0x1) + 1);
    // &rdp->dynticks->dynticks: [pcp0] (&rcu_bh_data)->dynticks->dynticks: 1

    // &rnp->lock: &(&(&rcu_bh_state)->node[0])->lock
    raw_spin_unlock(&rnp->lock);        /* irqs remain disabled. */
    // &rnp->lock: &(&(&rcu_bh_state)->node[0])->lock을 사용한 spinlock을 풀고 flags에 저장된 cpsr을 복원

    /* Add CPU to rcu_node bitmasks. */
    // rdp->mynode: [pcp0] (&rcu_bh_data)->mynode: (&rcu_bh_state)->level[0]
    rnp = rdp->mynode;
    // rnp: [pcp0] (&rcu_bh_state)->level[0]

    // rdp->grpmask: [pcp0] (&rcu_bh_data)->grpmask: 1
    mask = rdp->grpmask;
    // mask: 1

    do {
        /* Exclude any attempts to start a new GP on small systems. */
        // &rnp->lock: [pcp0] &((&rcu_bh_state)->level[0])->lock
        raw_spin_lock(&rnp->lock);  /* irqs already disabled. */
        // &rnp->lock: [pcp0] &((&rcu_bh_state)->level[0])->lock을 사용한 spinlock 수행

        // rnp->qsmaskinit: [pcp0] ((&rcu_bh_state)->level[0])->qsmaskinit: 0, mask: 1
        rnp->qsmaskinit |= mask;
        // rnp->qsmaskinit: [pcp0] ((&rcu_bh_state)->level[0])->qsmaskinit: 1

        // rnp->grpmask: [pcp0] ((&rcu_bh_state)->level[0])->grpmask: 0, mask: 1
        mask = rnp->grpmask;
        // mask: 0

        // rnp: [pcp0] (&rcu_bh_state)->level[0],
        // rdp->mynode: [pcp0] (&rcu_bh_data)->mynode: (&rcu_bh_state)->level[0]
        if (rnp == rdp->mynode) {
            /*
             * If there is a grace period in progress, we will
             * set up to wait for it next time we run the
             * RCU core code.
             */
            // rdp->gpnum: [pcp0] (&rcu_bh_data)->gpnum,
            // rnp->completed: [pcp0] ((&rcu_bh_state)->level[0])->completed: 0xfffffed4
            rdp->gpnum = rnp->completed;
            // rdp->gpnum: [pcp0] (&rcu_bh_data)->gpnum: 0xfffffed4

            // rdp->completed: [pcp0] (&rcu_bh_data)->completed,
            // rnp->completed: [pcp0] ((&rcu_bh_state)->level[0])->completed: 0xfffffed4
            rdp->completed = rnp->completed;
            // rdp->completed: [pcp0] (&rcu_bh_data)->completed: 0xfffffed4

            // rdp->passed_quiesce: [pcp0] (&rcu_bh_data)->passed_quiesce
            rdp->passed_quiesce = 0;
            // rdp->passed_quiesce: [pcp0] (&rcu_bh_data)->passed_quiesce: 0

            // rdp->qs_pending: [pcp0] (&rcu_bh_data)->qs_pending
            rdp->qs_pending = 0;
            // rdp->qs_pending: [pcp0] (&rcu_bh_data)->qs_pending: 0

            // rsp->name: (&rcu_bh_state)->name: "rcu_bh", rdp->gpnum: [pcp0] (&rcu_bh_data)->gpnum: 0xfffffed4
            trace_rcu_grace_period(rsp->name, rdp->gpnum, TPS("cpuonl")); // null function
        }
        // &rnp->lock: [pcp0] &((&rcu_bh_state)->level[0])->lock
        raw_spin_unlock(&rnp->lock); /* irqs already disabled. */
        // &rnp->lock: [pcp0] &((&rcu_bh_state)->level[0])->lock을 사용한 spin unlock 수행

        // rnp->parent: (&(&rcu_bh_state)->node[0])->parent: NULL
        rnp = rnp->parent;
        // rnp: NULL

        // rnp: NULL, rnp->qsmaskinit: (&(&rcu_bh_state)->node[0])->qsmaskinit: 1, mask: 0
    } while (rnp != NULL && !(rnp->qsmaskinit & mask));

    local_irq_restore(flags);
    // flags에 저장된 cpsr을 복원

    // &rsp->onoff_mutex: &(&rcu_bh_state)->onoff_mutex
    mutex_unlock(&rsp->onoff_mutex);
    // &rsp->onoff_mutex: &(&rcu_bh_state)->onoff_mutex을 사용한 mutex unlock 수행
}