운영 체제 -Linux 커널 교착 상태 감지 (간단한 교착 상태 데모 작성)

문제 설명

    실제 제품 작동 중에 Linux 시스템이 멈추고 화면에 유효한 직렬 포트 인쇄 정보가 없으며 네트워크가 중단되고 키보드와 마우스가 응답하지 않습니다.
    이 오류 현상은 Linux 커널의 교착 상태로 인해 발생할 수 있습니다. 유효한 인쇄 정보가없고 커널 로그에 기록이 없기 때문에 오류의 근본 원인을 찾을 수 없습니다.
    
 교착 상태가 발생하기 전에 Linux 커널이 관련 정보를 인쇄하도록하는 방법은 문제 위치에 특히 중요합니다. 효과적인 방법 중 하나는 "Kernel Hacking"옵션을 설정 한 다음 커널을 다시 컴파일하는 것입니다. Linux (3.14.28) 커널 교착 상태에 유용한 몇 가지 구성 옵션은 다음과 같습니다.

   Kernel hacking  --->Debug Lockups and Hangs  --->      

                               [*] Detect Hard and Soft Lockups                                                                                     
                               [*]   Panic (Reboot) On Soft Lockups             
                               [*] Detect Hung Tasks                                                                                                 
                              (120) Default timeout for hung task detection (in seconds)                                      
                               [*]   Panic (Reboot) On Hung Tasks   

소프트 락 업과 하드 락업?

소프트 락업 : 선점이 장기간 종료되어 프로세스를 예약 할 수 없습니다.
하드 락업 : 인터럽트가 장기간 종료되어 더 심각한 문제를 유발합니다.
이 락업의 핵심 감지 원리는 추후 분석 될 것입니다.

lockdep 교착 상태 감지 모듈

    가장 단순한 ABBA 교착 상태의 형성을 도입했습니다. 주제로 돌아가서 커널로 돌아 가면 수천 개의 잠금이 있으며 복잡하고 모든 개발자가 spin_lock, spin_lock_irq, spin_lock_irqsave, spin_lock_nested의 차이점에 익숙해 지도록 요구할 수 없습니다. 따라서 락업이 발생하기 전에 치료보다는 예방을 잘하고 문제가 발생하기 전에 예방하고 실제 사망이 발생할 때까지 기다리지 않고 사전에 개발 단계에서 잠재적 인 교착 상태 위험을 발견하고 해결하도록 노력해야합니다. 잠금 시간은 사용자에게 나쁜 경험을 제공합니다. lockdep 교착 상태 감지 모듈은 2006 년에 커널에 도입되었습니다 (https://lwn.net/Articles/185666/).

相关内核配置选项
    CONFIG_DEBUG_RT_MUTEXES=y
    检测rt mutex的死锁,并自动报告死锁现场信息。

    CONFIG_DEBUG_SPINLOCK=y
    检测spinlock的未初始化使用等问题。配合NMI watchdog使用,能发现spinlock死锁。

    CONFIG_DEBUG_MUTEXES=y
    检测并报告mutex错误

    CONFIG_DEBUG_WW_MUTEX_SLOWPATH=y
    检测wait/wound类型mutex的slowpath测试。
     
    CONFIG_DEBUG_LOCK_ALLOC=y
    检测使用中的锁(spinlock/rwlock/mutex/rwsem)被释放,或者使用中的锁被重新初始化,或者在进程退出时持有锁。
     
    CONFIG_PROVE_LOCKING=y
    使内核能在死锁发生前报告死锁详细信息。参见/proc/lockdep_chains。

    CONFIG_LOCKDEP=y
    整个Lockdep的总开关。参见/proc/lockdep、/proc/lockdep_stats。

    CONFIG_LOCK_STAT=y
    记锁持有竞争区域的信息,包括等待时间、持有时间等等信息。参见/proc/lock_stat。

    CONFIG_DEBUG_LOCKDEP=y
    会对Lockdep的使用过程中进行更多的自我检测,会增加很多额外开销。

    CONFIG_DEBUG_ATOMIC_SLEEP=y
    在atomic section中睡眠可能造成很多不可预测的问题,这些atomic section包括spinlock持锁、rcu读操作、禁止内核抢占部分、中断处理中等等。

교착 상태 문제 분석

    교착 상태는 여러 프로세스 (스레드)가 다른 프로세스가 필요한 리소스를 차지할 때까지 기다리기 때문에 차단
    되는 상태 입니다. 교착 상태가 형성되면 프로세스 자체를 해결할 수 없으며이를 수행하려면 외부 승격이 필요합니다. 해결해야 할 가장 중요한 것은 교착 상태가 프로세스 비즈니스에 영향을 줄뿐만 아니라 시스템 리소스를 차지하고 다른 프로세스에도 영향을 미친다는 것입니다.
    따라서 커널에 커널 교착 상태 감지 메커니즘이 설계되어 교착 상태 프로세스가 발견되면 OS가 다시 시작되고 문제가 신속하게 해결됩니다.
    재시작 트릭을 사용하는 이유는 분산 시스템이 단일 충돌 지점을 허용 할 수 있고 단일 프로세스 계산 비정상 지점을 허용 할 수 없기 때문입니다. 그렇지 않으면 교착 상태를 감지하고 OS를 다시 시작하는 것이 손실의 가치가 없습니다.

 

교착 상태는 무엇입니까

    뮤텍스 잠금은 스레드간에 (또는 프로세스간에) 상호 배타적이지 않도록 중요한 리소스를 보호합니다. 스레드가 잠금을 얻고 해제하지 않으면 다른 스레드가이를 적용 할 때 기다려야합니다.
    여러 스레드가 리소스를두고 경쟁하여 교착 상태 (서로 대기)를 유발할 때 이러한 프로세스는 도움이되지 않으면 영원히 기다립니다.
    간단히 말해서 두 개 이상의 프로세스가 끝없이 대기하고 조건이 설정되지 않는 시스템 상태입니다.

 

교착 상태의 원인

    ① 불충분 한 시스템 자원 : 시스템의 자원 수가 스레드 운영의 요구를 충족시키기에 충분하지 않아 운영 중 자원 경쟁으로 교착 상태가됩니다.
    ② 쓰레드 간 진행 순서가 잘못됨 : 쓰레드 간 적용 및 해제 순서가 동작 중 불법이다.
    ③ 부적절한 자원 할당.

 

교착 상태에 대한 네 가지 조건

    상호 배타적 조건 : 일정 시간 내에 특정 자원은 한 스레드 만 점유 할 수 있습니다. 이때 다른 스레드가 적용되면 현재 스레드가 사용 및 해제 될 때까지 기다려야합니다.
    양도 할 수없는 조건 : 리소스가 사용되기 전에 스레드를 선점 할 수 없습니다.
    요청을 해제하고 사용 후 조건 유지할 있습니다. 스레드가 이미 리소스를 소유하고 있으며 현재 새 리소스에 적용됩니다. 새 리소스가 다음과 같은 경우 다른 스레드가 차지하고 현재 스레드가 차단하고 대기하지만 획득 한 리소스를 유지합니다.
    루프 대기 조건 : 교착 상태가 발생하면 루프 체인이 있어야합니다. 즉, 스레드 세트 {T0, T1, T2, ..., Tn } T0은 T1이 차지하는 리소스를 기다리고, T1은 T2가 차지하는 리소스를 기다리고, ..., Tn은 Tn이 차지하는 리소스를 기다리고 있습니다.

 

흔한 실수

    AA : 반복적으로 잠그기
    ABBA : 잠그기 위해 AB 시퀀스를 사용한 다음, 잠그기 위해 BA를 사용
    했습니다. ABBCCA :이 유형은 ABBA의 확장입니다. AB 주문, AB 주문, CA 주문. 이러한 종류의 잠금은 수동으로 찾기가 어렵습니다.
    여러 번 잠금 해제

 

교착 상태 감지 및 복구

    자원의 경우
        선점, 자원 회수
        롤 안전한 상태로 백업, 복구
    프로세스에 대한
        명, 프로세스 복구

    
참조 기사 :
    https://blog.csdn.net/ccwzhu/article/details/81171092

하나, D 상태 교착 상태 감지

이른바 D 상태 교착 상태 : 프로세스가 오랜 시간 동안 TASK_UNINTERRUPTIBLE 절전 상태에 있습니다 (시스템 기본 구성은 120 초).이 상태에서 프로세스는 비동기 신호에 응답하지 않습니다. 예 : 프로세스와 주변 하드웨어 간의 상호 작용 (예 : 읽기),이 상태는 일반적으로 프로세스와 장치 간의 상호 작용이 중단되지 않도록하는 데 사용됩니다. 그렇지 않으면 장치가 제어 할 수없는 상태에있을 수 있습니다.

커널 D 상태 교착 상태 감지는 hung_task 메커니즘이며 기본 코드는 kernel / hung_task.c 파일에 있습니다.

구체적인 실현 원리 :

1. 일반 수준의 khungtaskd 커널 스레드를 만들고 무한 루프에서 모든 sysctl_hung_task_timeout_secs 시간을 확인하고 schedule_timeout을 시간에 사용합니다 (타이머로 낭비되는 CPU 절약).

2. do_each_thread, while_each_thread 매크로를 호출하여 모든 프로세스 정보를 탐색합니다. D 상태 프로세스가있는 경우 최근 전환 횟수가 작업 계산과 일치하는지, 즉 최근에 스케줄링 전환이 있었는지 확인합니다. 일관성이 있으면 전환이 없습니다. sysctl_hung_task_panic 스위치는 재시작 여부를 결정합니다.

사용자 모드 제어에 해당하는 proc 인터페이스는
/ proc / sys / kernel / hung_task_timeout_secs, hung_task_panic 등입니다.        
    
    
둘째, R 상태 교착 상태 감지

소위 R 상태 교착 상태 : 프로세스가 전환없이 CPU를 독점하기 위해 오랜 시간 (기본적으로 60 초) TASK_RUNNING 상태에 있습니다. 일반적으로 프로세스는 작업을 위해 오랫동안 닫히고 선점됩니다. 때로는 프로세스가 닫히고 선점 된 후 무한 루프에있을 수 있습니다. 수면 후 시스템 이상이 발생합니다.

추가 : lockdep은 소위 교착 상태가 아닙니다.

커널 R 상태 교착 상태 감지 메커니즘은 lockdep 메커니즘이고 항목은 lockup_detector_init 함수입니다.

1. cpu_callback 함수를 통해 watchdog_enable을 호출하여 각 CPU 코어의 SCHED_FIFO 수준에서 실시간 스레드 감시를 생성합니다. hrtimer 타이머를 사용하여 검사주기를 제어합니다.

2. hrtimer 타이머는 watchdog_timer_fn을 호출하여 dog clear 시간을 확인하고 스레드는 dog clear 시간을 매번 재설정합니다. watchdog_timer_fn이 현재 시간부터 dog의 reset 시간이 위험하다고 판단되면 스위치에 따라 패닉 처리를 수행합니다.

사용자 모드 제어에 해당하는 proc 인터페이스는 다음과 같습니다.

/ proc / sys / kernel / watchdog_thresh , softlockup_panic 等。

 

잠금 정보보기

    /proc/sys/kernel/lock_stat  /* 置位则可以查看/proc/lock_stat统计信息,清除则关闭lockdep统计信息。 */
    /proc/lock_stat             /* 关于锁的使用统计信息 */
    /proc/lockdep               /* 存在依赖关系的锁 */
    /proc/lockdep_stats         /* 存在依赖关系锁的统计信息 */
    /proc/lockdep_chains        /* 依赖关系锁链表 */
    /proc/locks                 /*  */
    /proc/sys/kernel/prove_locking
    /proc/sys/kernel/max_lock_depth
    /sys/kernel/debug/tracing/events/lock  /* 内核提供了Tracepoint协助发现锁的使用问题 */

간단한 교착 상태 데모 작성

#include <linux/module.h>
#include <linux/kernel.h>

static spinlock_t hack_spinA;
static spinlock_t hack_spinB;

void hack_spinAB(void)
{
  printk("hack_lockdep:A->B\n");
  spin_lock(&hack_spinA);
  spin_lock(&hack_spinB);
}

void hack_spinBA(void)
{
  printk("hack_lockdep:B->A\n");
  spin_lock(&hack_spinB);
  spin_lock(&hack_spinA);
}

static int __init lockdep_test_init(void)
{
  printk("al: lockdep error test init\n");
  spin_lock_init(&hack_spinA);
  spin_lock_init(&hack_spinB);

  hack_spinAB();
  hack_spinBA();
  return 0;
}

module_init(lockdep_test_init);

해당 Makefile

obj-m:=spin_lock_deadlock.o

#声明当前的架构,这里用户需要根据实际情况选择架构类型
export ARCH=arm
#声明交叉编译工具链,这里用户需要根据实际情况选择对应的工具链
export CROSS_COMPILE=arm-himix200-linux-

#源码目录变量,这里用户需要根据实际情况选择路径
#下面作者是将Linux的源码目录
KERDIR := /home1/zhugeyifan/source/K5/3519av100/packages/linux_lsp/kernel/linux-4.9.37/

#当前目录变量
CURDIR := $(shell pwd)

#make命名默认寻找第一个目标
#make -C就是指调用执行的路径
#$(KERDIR)Linux源码目录,作者这里指的是.../linux-4.9.37/
#$(CURDIR)当前目录变量
#modules要执行的操作
#注意!假如复制到Makefile后,下行提示红色,把 all:下面一行的make前面的空格删除后添加(Tab)制表符
all:
	make -C $(KERDIR) M=$(CURDIR) modules

#make clean执行的操作是删除后缀为o的文件
#注意!假如复制到Makefile后,下行提示红色,把 clean:下面一行的make前面的空格删除后添加(Tab)制表符
clean:
	make -C $(KERDIR) M=$(CURDIR) clean

오류를보고하면 다음 기사를 읽어 보시기 바랍니다. 운영 체제 -Linux는 간단한 ko 모듈을 컴파일합니다.

 

생성

해당 ko 모듈을 생성합니다.

spin_lock_deadlock.ko

 

수행

위의 교착 상태 감지 모듈이 작동하는지 테스트

오류를 실행하고보고합니다. 이는 교착 상태 감지 모듈이 적용되었음을 의미합니다.

watchdog: BUG: soft lockup - CPU#0 stuck for 22s! [insmod:306]
Modules linked in: spin_lock_deadlock(PO+) hi_user(O) hi_mipi_rx(O) hi3519av100_acodec(PO) hi3519av100_adec(PO) hi3519av100_aenc(PO) hi3519av100_ao(PO) hi3519av100_ai(PO) hi3519av100_aio(PO) hi3519av100_hdmi(PO) hi_sensor_spi(O) hi_sensor_i2c(O) hi_piris(O) hi_pwm(O) hi3519av100_dpu_match(PO) hi3519av100_dpu_rect(PO) hi3519av100_dsp(PO) hi3519av100_nnie(PO) hi_ipcm(O) hi3519av100_ive(PO) hi3519av100_vdec(PO) hi3519av100_vfmw(PO) hi3519av100_jpegd(PO) hi3519av100_jpege(PO) hi3519av100_h265e(PO) hi3519av100_h264e(PO) hi3519av100_vedu(PO) hi3519av100_chnl(PO) hi3519av100_venc(PO) hi3519av100_rc(PO) hifb(O) hi3519av100_vo(PO) hi3519av100_avs(PO) hi3519av100_vpss(PO) hi3519av100_vi(PO) hi3519av100_isp(PO) hi3519av100_dis(PO) hi3519av100_vgs(PO) hi3519av100_gdc(PO) hi3519av100_rgn(PO) hi3519av100_tde(PO) hi3519av100_sys(PO) hi3519av100_base(PO) hi_osal(O) sys_config(O)
CPU: 0 PID: 306 Comm: insmod Tainted: P           O    4.9.37 #402
Hardware name: Generic DT based system
task: d47ace40 task.stack: d470c000
PC is at _raw_spin_lock+0x2c/0x40
LR is at hack_spinBA+0x20/0x2c [spin_lock_deadlock]
pc : [<c06a4a04>]    lr : [<bf00204c>]    psr: 80000013
sp : d470ddf8  ip : 00000000  fp : 00000024
r10: 00000000  r9 : bf002100  r8 : 00000000
r7 : d47a3000  r6 : d47a3ec0  r5 : ffffe000  r4 : bf002300
r3 : 00000000  r2 : 00000001  r1 : 00000000  r0 : bf002304
Flags: Nzcv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment none
Control: 10c5383d  Table: 238dc06a  DAC: 00000051
CPU: 0 PID: 306 Comm: insmod Tainted: P           O    4.9.37 #402
Hardware name: Generic DT based system
[<c010f8b8>] (unwind_backtrace) from [<c010b4e0>] (show_stack+0x10/0x14)
[<c010b4e0>] (show_stack) from [<c0380bbc>] (dump_stack+0x84/0x98)
[<c0380bbc>] (dump_stack) from [<c0194ff8>] (watchdog_timer_fn+0x248/0x2c0)
[<c0194ff8>] (watchdog_timer_fn) from [<c016f534>] (__hrtimer_run_queues+0x128/0x1bc)
[<c016f534>] (__hrtimer_run_queues) from [<c016f71c>] (hrtimer_interrupt+0xa8/0x204)
[<c016f71c>] (hrtimer_interrupt) from [<c054b594>] (arch_timer_handler_phys+0x28/0x30)
[<c054b594>] (arch_timer_handler_phys) from [<c0163688>] (handle_percpu_devid_irq+0x74/0x134)
[<c0163688>] (handle_percpu_devid_irq) from [<c015eb30>] (generic_handle_irq+0x24/0x34)
[<c015eb30>] (generic_handle_irq) from [<c015f054>] (__handle_domain_irq+0x5c/0xb4)
[<c015f054>] (__handle_domain_irq) from [<c0101438>] (gic_handle_irq+0x48/0x8c)
[<c0101438>] (gic_handle_irq) from [<c010bfcc>] (__irq_svc+0x6c/0x90)
Exception stack(0xd470dda8 to 0xd470ddf0)
dda0:                   bf002304 00000000 00000001 00000000 bf002300 ffffe000
ddc0: d47a3ec0 d47a3000 00000000 bf002100 00000000 00000024 00000000 d470ddf8
dde0: bf00204c c06a4a04 80000013 ffffffff
[<c010bfcc>] (__irq_svc) from [<c06a4a04>] (_raw_spin_lock+0x2c/0x40)
[<c06a4a04>] (_raw_spin_lock) from [<bf00204c>] (hack_spinBA+0x20/0x2c [spin_lock_deadlock])
[<bf00204c>] (hack_spinBA [spin_lock_deadlock]) from [<d47a3ec0>] (0xd47a3ec0)
INFO: rcu_sched self-detected stall on CPU
	0-...: (59672 ticks this GP) idle=4c3/140000000000001/0 softirq=34656/34656 fqs=14660 
	 (t=60000 jiffies g=2778 c=2777 q=166)
Task dump for CPU 0:
insmod          R  running task        0   306    218 0x00000003
[<c010f8b8>] (unwind_backtrace) from [<c010b4e0>] (show_stack+0x10/0x14)
[<c010b4e0>] (show_stack) from [<c019857c>] (rcu_dump_cpu_stacks+0xa8/0xc4)
[<c019857c>] (rcu_dump_cpu_stacks) from [<c016bf54>] (rcu_check_callbacks+0x714/0x890)
[<c016bf54>] (rcu_check_callbacks) from [<c016e780>] (update_process_times+0x34/0x5c)
[<c016e780>] (update_process_times) from [<c017eaf0>] (tick_sched_timer+0x68/0x268)
[<c017eaf0>] (tick_sched_timer) from [<c016f534>] (__hrtimer_run_queues+0x128/0x1bc)
[<c016f534>] (__hrtimer_run_queues) from [<c016f71c>] (hrtimer_interrupt+0xa8/0x204)
[<c016f71c>] (hrtimer_interrupt) from [<c054b594>] (arch_timer_handler_phys+0x28/0x30)
[<c054b594>] (arch_timer_handler_phys) from [<c0163688>] (handle_percpu_devid_irq+0x74/0x134)
[<c0163688>] (handle_percpu_devid_irq) from [<c015eb30>] (generic_handle_irq+0x24/0x34)
[<c015eb30>] (generic_handle_irq) from [<c015f054>] (__handle_domain_irq+0x5c/0xb4)
[<c015f054>] (__handle_domain_irq) from [<c0101438>] (gic_handle_irq+0x48/0x8c)
[<c0101438>] (gic_handle_irq) from [<c010bfcc>] (__irq_svc+0x6c/0x90)
Exception stack(0xd470dda8 to 0xd470ddf0)
dda0:                   bf002304 00000000 00000001 00000000 bf002300 ffffe000
ddc0: d47a3ec0 d47a3000 00000000 bf002100 00000000 00000024 00000000 d470ddf8
dde0: bf00204c c06a4a04 80000013 ffffffff
[<c010bfcc>] (__irq_svc) from [<c06a4a04>] (_raw_spin_lock+0x2c/0x40)
[<c06a4a04>] (_raw_spin_lock) from [<bf00204c>] (hack_spinBA+0x20/0x2c [spin_lock_deadlock])
[<bf00204c>] (hack_spinBA [spin_lock_deadlock]) from [<d47a3ec0>] (0xd47a3ec0)

 


참조 기사

    https://blog.csdn.net/ccwzhu/article/details/81171092 교착 상태 Linux 교착 상태 감지 모듈
    의 형성
   Lockdep 소개  

 

추천

출처blog.csdn.net/Ivan804638781/article/details/100740857