armhf 커널 5.4의 커널 "교착 상태"를 이해하는 데 도움이 필요합니다.

armhf 커널 5.4의 커널 "교착 상태"를 이해하는 데 도움이 필요합니다.

드물게 발생하는 상황(MTBF는 몇 주에서 몇 달 단위로 측정됨)을 이해하려고 노력하고 있지만, 발생하면 치명적인 커널 잠금이 발생할 수 있습니다.

환경은 AMD/Xilinx Zynq 7020 SoC의 듀얼 코어 ARM A9 32비트(armhf) 프로세서에서 실행되는 커널 5.4.0입니다. 저는 Xilinx Vitis 시스템 디버거를 사용하여 실패한 두 장치의 스택 추적을 검사할 수 있었습니다. 두 경우 모두 두 코어 모두 동일한 스핀 잠금을 기다리고 있습니다(잠금을 시도). 스핀 잠금은 스레드의 IRQ 처리기와 관련된 구조의 구성원입니다 pi_lock.struct task_struct

코어 #0은 인터럽트에 응답하고 IRQ 핸들러 스레드를 깨우려고 유휴 프로세스를 실행 중입니다. 코어 #1은 IRQ 핸들러 스레드와 연관된 sysfs 의사 파일을 읽고 있습니다( /proc/<PID>/stat요청에 대한 응답으로 호출로 표시되는 모든 sysfs 의사 파일을 읽는 동안)./proc/<PID>/statpidofsessioncleanapache2

한 장치에서 처리되는 인터럽트는 BQ25890 배터리 충전기(초당 약 0~10회 지정)용이고 다른 장치에서는 사용자 지정 커널 모듈(초당 약 100회)용으로 두 인터럽트 모두 기본 기본 IRQ 처리기가 사용됩니다.

현재 가설은 두 가지가 동시에 발생하는 것이 아니라 코어 #0이 먼저 고착되고 얼마 후 코어 #1도 고착된다는 것입니다. 그러나 이는 단지 추측일 뿐입니다.

다음은 장치 중 하나에 대한 두 코어 및 스레드 IRQ 처리기 소스에 대한 스택 추적입니다.

질문

무엇이 잘못되었는지에 대한 단서를 제공할 만큼 스택 추적에 충분한 정보가 있습니까? 그렇다면 무엇이 잘못되었나요? 그렇지 않다면 어떤 추가 정보가 필요합니까? 장치 중 하나는 여전히 사용 가능하며 일부(전부는 아님) 변수를 조사할 수 있습니다. 인터럽트가 비활성화된다는 사실(두 코어 모두 cpsr.i == 1)이 중요합니까?

블랙박스 테스트 기술(즉, 결과를 관찰하기 위해 변경하는 것)은 실패 사이의 시간이 매우 길기 때문에 실용적이지 않습니다.

ARM Cortex-A9 MPCore #0(일시 중단됨)

0x80165d68: ./include/linux/compiler.h, line 199
0x80165d68 arch_spin_lock(): .../arch/arm/include/asm/spinlock.h, line 75
0x8076f774: ./include/linux/spinlock.h, line 193
0x8076f774: ...include/linux/spinlock_api_smp.h, line 119
0x8076f774 _raw_spin_lock_irqsave(): kernel/locking/spinlock.c, line 159
0x8014a394 try_to_wake_up(): kernel/sched/core.c, line 2551
0x8014a724 wake_up_process(): kernel/sched/core.c, line 2667
0x8016f600 __irq_wake_thread(): kernel/irq/handle.c, line 134
0x8016f820 __handle_irq_event_percpu(): kernel/irq/handle.c, line 167
0x8016f888 handle_irq_event_percpu(): kernel/irq/handle.c, line 189
0x8016f924 handle_irq_event(): kernel/irq/handle.c, line 206
0x80174230 handle_level_irq(): kernel/irq/chip.c, line 650
0x8016e808: ./include/linux/irqdesc.h, line 156
0x8016e808 generic_handle_irq(): kernel/irq/irqdesc.c, line 644
0x80447a20: drivers/gpio/gpio-zynq.c, line 632
0x80447a20 zynq_gpio_irqhandler(): drivers/gpio/gpio-zynq.c, line 661
0x8016e808: ./include/linux/irqdesc.h, line 156
0x8016e808 generic_handle_irq(): kernel/irq/irqdesc.c, line 644
0x8016eec4 __handle_domain_irq(): kernel/irq/irqdesc.c, line 681
0x80102300: ./include/linux/irqdesc.h, line 174
0x80102300 gic_handle_irq(): drivers/irqchip/irq-gic.c, line 383
0x80101a70 __irq_svc(): arch/arm/kernel/entry-armv.S, line 212
0x805827c0 cpuidle_enter_state(): .../arch/arm/include/asm/irqflags.h, line 39
0x805829d8 cpuidle_enter(): drivers/cpuidle/cpuidle.c, line 344
0x8014ecf0: kernel/sched/idle.c, line 117
0x8014ecf0: kernel/sched/idle.c, line 201
0x8014ecf0 do_idle(): kernel/sched/idle.c, line 263
0x8014eeac cpu_startup_entry(): kernel/sched/idle.c, line 355
0x80769828 rest_init(): init/main.c, line 451
0x80c00b30 arch_call_rest_init(): init/main.c, line 572
0x80c00f78 start_kernel(): init/main.c, line 784
0x00000000
0x00000000

불법 자물쇠

lock    arch_spinlock_t *   {{slock=0x94449440, tickets={owner=0x9440, next=0x9444}}}   
    slock   u32 0x94449440  
    tickets struct __raw_tickets    {owner=0x9440, next=0x9444} 
        owner   u16 0x9440  
        next    u16 0x9444  

스레드 IRQ 처리기 소스

이 코드는 호출 스택에 나타나지 않지만 스레드 코어 #0이 깨어나려고 하는 코드입니다.

장치 중 하나에서:

static irqreturn_t bq25890_irq_handler_thread(int irq, void *private)
{
    struct bq25890_device *bq = private;
    int ret;
    struct bq25890_state state;

    ret = bq25890_get_chip_state(bq, &state);
    if (ret < 0)
        goto handled;

    if (!bq25890_state_changed(bq, &state))
        goto handled;

    bq25890_handle_state_change(bq, &state);

    mutex_lock(&bq->lock);
    bq->state = state;
    mutex_unlock(&bq->lock);

    power_supply_changed(bq->charger);

handled:
    return IRQ_HANDLED;
}

다른 기기에서:

static irqreturn_t core100_irq_handler( int irq, void* data )
{
    struct core100_drvdata* p_info;
    struct core100_block_header* next;
    unsigned long iflags;
    p_info = ( struct core100_drvdata* ) data;
    if ( ( p_info->state != state_reading ) && ( p_info->state != state_writing ) )
    {
        return IRQ_HANDLED;
    }
    next = &p_info->current_block->next->header;
    next->count_at_pps = read_register( p_info->count_pps_register );
    next->frc_at_pps = read_register( p_info->frc_pps_register );
    next->count = adc_counter();
    next->frc = free_running_counter();
    spin_lock_irqsave( &p_info->state_lock, iflags );
    p_info->dma_head += bytes_per_block( p_info );
    if ( p_info->dma_head - p_info->dma_tail > bytes_per_buffer( p_info ) )
    {
        p_info->dma_tail = p_info->dma_head - bytes_per_buffer( p_info );
    }
    p_info->current_block = p_info->current_block->next;
    wake_up_interruptible( &p_info->wq );
    spin_unlock_irqrestore( &p_info->state_lock, iflags );
    return IRQ_HANDLED;
}

커널 소스 코드: [struct task_struct][1]

ARM Cortex-A9 MPCore #1(일시 중단됨)

0x80165d68: ./include/linux/compiler.h, line 199
0x80165d68 arch_spin_lock(): .../arch/arm/include/asm/spinlock.h, line 75
0x8076f774: ./include/linux/spinlock.h, line 193
0x8076f774: ...include/linux/spinlock_api_smp.h, line 119
0x8076f774 _raw_spin_lock_irqsave(): kernel/locking/spinlock.c, line 159
0x80148914 task_rq_lock(): kernel/sched/core.c, line 109
0x8014e22c: kernel/sched/cputime.c, line 281
0x8014e22c thread_group_cputime(): kernel/sched/cputime.c, line 326
0x8014e650 thread_group_cputime_adjusted(): kernel/sched/cputime.c, line 678
0x802ccb5c do_task_stat(): fs/proc/array.c, line 510
0x802cdaf4 proc_tgid_stat(): fs/proc/array.c, line 632
0x802c7c0c proc_single_show(): fs/proc/base.c, line 756
0x80281b18 seq_read(): fs/seq_file.c, line 229
0x8025dd1c __vfs_read(): fs/read_write.c, line 425
0x8025de60 vfs_read(): fs/read_write.c, line 461
0x8025e088 ksys_read(): fs/read_write.c, line 587
0x8025e0ec: fs/read_write.c, line 597
0x8025e0ec __se_sys_read(): fs/read_write.c, line 595
0x80101000 __idmap_text_end()
0x76e627e6
0x76edc616

이는 호출 프로세스와 관련된 호출 스택을 보여주는 또 다른 보기입니다. "Swaper"는 유휴 프로세스를 가리키는 오래된 용어입니다.

Kernel  
    0 swapper/0        (Suspended), ARM Cortex-A9 MPCore #0 
        0x80165d68: ./include/linux/compiler.h, line 199    
        0x80165d68 arch_spin_lock(): .../arch/arm/include/asm/spinlock.h, line 75   
        0x8076f774: ./include/linux/spinlock.h, line 193    
        0x8076f774: ...include/linux/spinlock_api_smp.h, line 119   
        0x8076f774 _raw_spin_lock_irqsave(): kernel/locking/spinlock.c, line 159    

11950 pidof 
    11950 (Suspended), ARM Cortex-A9 MPCore #1  
        0x80165d68: ./include/linux/compiler.h, line 199    
        0x80165d68 arch_spin_lock(): .../arch/arm/include/asm/spinlock.h, line 75   
        0x8076f774: ./include/linux/spinlock.h, line 193    
        0x8076f774: ...include/linux/spinlock_api_smp.h, line 119   
        0x8076f774 _raw_spin_lock_irqsave(): kernel/locking/spinlock.c, line 159    

RCU 구성

# RCU Subsystem
CONFIG_PREEMPT_RCU=y
# CONFIG_RCU_EXPERT is not set
CONFIG_SRCU=y
CONFIG_TREE_SRCU=y
CONFIG_TASKS_RCU=y
CONFIG_RCU_STALL_COMMON=y
CONFIG_RCU_NEED_SEGCBLIST=y
# end of RCU Subsystem
# RCU Debugging
# CONFIG_RCU_PERF_TEST is not set
# CONFIG_RCU_TORTURE_TEST is not set
CONFIG_RCU_CPU_STALL_TIMEOUT=21
# CONFIG_RCU_TRACE is not set
# CONFIG_RCU_EQS_DEBUG is not set
# end of RCU Debugging

커널 스레드 우선순위

# ps -eo pid,tid,class,rtprio,ni,pri,wchan:14,comm | grep -E '(PID|bq25890|raw_dma)'
  PID   TID CLS RTPRIO  NI PRI WCHAN          COMMAND
  214   214 FF      50   -  90 irq_thread     irq/59-bq25890_
  229   229 FF      50   -  90 irq_thread     irq/60-raw_dma

프로세서 상태 레지스터 실패한 시스템 중 하나 이상에서 이 interrupt disable비트가 두 프로세서 모두에 설정되었습니다. fast interrupt disable비트가 아직 설정되지 않았지만 이는 잘못된 것 같습니다 . 작업 시스템에 중단점을 설정하면 arch_spin_lock()인터럽트 비활성화 비트가 설정되지 않습니다. 스핀록을 해제하는 유일한 방법은 인터럽트에 응답하는 것인 것 같습니다. 두 코어 모두 이 작업을 수행하는 활성 스레드가 없기 때문입니다.

Core #0
cpsr    200f0193    537854355   
    n   0   0   Negative condition code flag    
    z   0   0   Zero condition code flag    
    c   1   1   Carry condition code flag   
    v   0   0   Overflow condition code flag    
    q   0   0   Cumulative saturation flag  
    it  00  0   If-Then execution state bits    
    j   0   0   Jazelle bit 
    ge  f   15  SIMD Greater than or Equal flags    
    e   0   0   Endianness execution state bit  
    a   1   1   Asynchronous abort disable bit  
    i   1   1   Interrupt disable bit   
    f   0   0   Fast interrupt disable bit  
    t   0   0   Thumb execution state bit   
    m   13  19  Mode field  
irq 
    sp  80d94400    2161722368  
    lr  80101e20    2148539936  
    spsr    200f0193    537854355   
        n   0   0   Negative condition code flag    
        z   0   0   Zero condition code flag    
        c   1   1   Carry condition code flag   
        v   0   0   Overflow condition code flag    
        q   0   0   Cumulative saturation flag  
        it  00  0   If-Then execution state bits    
        j   0   0   Jazelle bit 
        ge  f   15  SIMD Greater than or Equal flags    
        e   0   0   Endianness execution state bit  
        a   1   1   Asynchronous abort disable bit  
        i   1   1   Interrupt disable bit   
        f   0   0   Fast interrupt disable bit  
        t   0   0   Thumb execution state bit   
        m   13  19  Mode field  

Core #1
cpsr    200f0093    537854099   
    n   0   0   Negative condition code flag    
    z   0   0   Zero condition code flag    
    c   1   1   Carry condition code flag   
    v   0   0   Overflow condition code flag    
    q   0   0   Cumulative saturation flag  
    it  00  0   If-Then execution state bits    
    j   0   0   Jazelle bit 
    ge  f   15  SIMD Greater than or Equal flags    
    e   0   0   Endianness execution state bit  
    a   0   0   Asynchronous abort disable bit  
    i   1   1   Interrupt disable bit   
    f   0   0   Fast interrupt disable bit  
    t   0   0   Thumb execution state bit   
    m   13  19  Mode field  
irq 
    sp  80d94440    2161722432  
    lr  80101a00    2148538880  
    spsr    60030193    1610809747  
        n   0   0   Negative condition code flag    
        z   1   1   Zero condition code flag    
        c   1   1   Carry condition code flag   
        v   0   0   Overflow condition code flag    
        q   0   0   Cumulative saturation flag  
        it  00  0   If-Then execution state bits    
        j   0   0   Jazelle bit 
        ge  3   3   SIMD Greater than or Equal flags    
        e   0   0   Endianness execution state bit  
        a   1   1   Asynchronous abort disable bit  
        i   1   1   Interrupt disable bit   
        f   0   0   Fast interrupt disable bit  
        t   0   0   Thumb execution state bit   
        m   13  19  Mode field  

관련 정보