まれに発生する状況(MTBFは数週間から数ヶ月単位で測定)を理解しようとしていますが、発生すると致命的なカーネルロックが発生する可能性があります。
環境は、AMD / Xilinx Zynq 7020 SoCのデュアルコアARM A9 32ビット(armhf)プロセッサで実行されるカーネル5.4.0です。私はXilinx Vitisシステムデバッガを使用して、失敗した2つのデバイスのスタックトレースを調べることができました。どちらの場合も、両方のコアは同じスピンロックを待っています(ロックを試みます)。スピンロックは、スレッドのIRQハンドラに関連する構造のメンバーですpi_lock
。struct task_struct
コア#0は割り込みに応答し、IRQハンドラスレッドを起動しようとしてアイドルプロセスを実行しています。コア#1は、IRQハンドラスレッドに関連付けられているsysfs擬似ファイルを読み込んでいます(/proc/<PID>/stat
要求に応答して呼び出しとして表示されるすべてのsysfs擬似ファイルを読み込んでいます)。/proc/<PID>/stat
pidof
sessionclean
apache2
1つのデバイスで処理される割り込みはBQ25890バッテリ充電器(毎秒約0〜10回指定)用で、他のデバイスではカスタムカーネルモジュール(毎秒約100回)用に両方の割り込みがデフォルトのデフォルトIRQハンドラを使用します。
現在の仮説は、2つが同時に発生するのではなく、コア#0が最初に固定され、しばらくしてコア#1も固定されるということです。しかし、これは単なる推測です。
以下は、デバイスの1つの2つのコアとスレッドのIRQハンドラソースのスタックトレースです。
質問
何が間違っているかについての手がかりを提供するのに十分なスタックトレースに十分な情報がありますか?それでは、何が間違っていますか?そうでない場合、どのような追加情報が必要ですか?デバイスの1つはまだ利用可能であり、一部(すべてではない)変数を調べることができます。割り込みが無効になるという事実(どちらのコアも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が目を覚ますしようとしているコードです。
デバイスの1つから:
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
プロセッサステータスレジスタ
失敗したシステムの1つ以上で、この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