AI智能摘要
工厂BLMMI工站一台设备死机进dump,经dmesg与任务栈分析,确认是QCOM Apps Watchdog在约67.7秒触发bark/bite,而系统最后一次喂狗停在47.7秒,中间超过20秒未喂狗。期间系统处于s2idle挂起流程中,未正常resume,定时器与调度未运行,导致watchdog无法被喂。 进一步从timer list看到,当前时刻并没有到任何定时器触发点,印证了系统在挂起状态未被唤醒。通过tasks.txt定位到关键卡死线程为......
此摘要由AI分析文章内容生成,仅供参考。

一、问题背景

工厂BLMMI工站出现了一台死机进dump的机器

二、问题分析

2.1 初步定位

dmesg_TZ.txt

[  67.746231][  C0] msm_watchdog f410000.qcom,wdt: QCOM Apps Watchdog bark! Now = 67.746225
[  67.746239][  C0] msm_watchdog f410000.qcom,wdt: QCOM Apps Watchdog last pet at 47.745802

Non-secure Watchdog data
Watchdog enabled
Pet time: 15.0s
Bark time: 20.0s
Watchdog last pet: 4.7e-08
Watchdog next pet: 15.000000047
Watchdog next bark: 20.000000047
Watchdog pet timer not expired
Current jiffies crossed pet_timer expires jiffies
 
Core 0 PC: __delay+9c <ffffffc00900c050>
Core 0 LR: __delay+bc <ffffffc00900c070>
 
[<ffffffc00900c050>] __delay+0x9c
[<ffffffc00900c134>] __const_udelay+0x28
[<ffffffc001558890>] qcom_wdt_trigger_bite[qcom_wdt_core]+0x424
[<ffffffc001559118>] qcom_wdt_bark_handler[qcom_wdt_core]+0xac
[<ffffffc008152b04>] __handle_irq_event_percpu+0xc4
[<ffffffc008152e00>] handle_irq_event+0x48
[<ffffffc0081590d4>] handle_fasteoi_irq+0x124
[<ffffffc00815114c>] generic_handle_domain_irq+0x48
[<ffffffc008010154>] gic_handle_irq+0x4c
[<ffffffc008014968>] call_on_irq_stack+0x3c
[<ffffffc00903a110>] el1_interrupt[jt]+0x98
[<ffffffc00903a090>] el1h_64_irq_handler+0x18
[<ffffffc008011304>] ret_to_kernel[jt]+0x0
[<ffffffc008b91c40>] cpuidle_enter_state+0x1d0
[<ffffffc008b92140>] cpuidle_enter+0x38
[<ffffffc008116dac>] do_idle+0x1f8
[<ffffffc008116ec4>] cpu_startup_entry[jt]+0x30
[<ffffffc00903c0b0>] rest_init+0xe0
[<ffffffc009c2a0a4>] arch_call_rest_init+0x10
[<ffffffc009c2a4b4>] start_kernel+0x40c
[<ffffffc009c22194>] __primary_switched+0xc8

从上面的信息我们可以得到以下的关键信息:

  1. 死机的原因为发生了watchdog
  2. last pet的时间是47.745802s,bark的时间是67.746225s
  3. CPU0发生的watchdog bite

2.2 定位卡死线程

  • 47.745802 秒:最后一次喂狗(last pet)
  • 67.746225 秒:Watchdog bark,然后紧接着 bite

👉 这说明在 20 秒内系统没有“喂狗”,导致 Watchdog 判定系统挂死,进而触发重启。

{% tip success %}

📌 正常情况下系统怎么喂狗?

在高通平台,比如你这个使用的是 msm_watchdog(QCOM Apps Watchdog),喂狗是周期性由某个高优先级内核线程定时器中断完成的。
常见机制如下:

  1. CPU 保持调度活动
  2. 定时器事件及时触发
  3. 关键任务没被阻塞

{% endtip %}

2.2.1 分析这 20 秒为何没喂狗

从日志分析,这 20 秒时间系统**处于挂起(s2idle)**状态且 resume 出现异常:

🚩 证据1:系统进入 suspend(挂起)

[ 47.654971] PM: suspend entry (s2idle)
...
[ 67.746225] msm_watchdog ... bark!

说明系统本意是轻量挂起(s2idle),但挂起过程中出了问题,并没有成功 resume。

🚩 证据2:suspend/resume 中 driver 没正常返回

从日志看,多个设备在执行 suspend:

fg_suspend in sleep
sc853x-charger: Suspend successfully!
NXP PN560 nfc start suspend
__wlan_hdd_bus_suspend
...

🚩 证据3:PM: suspend exit 没有出现

如果系统成功 resume,会出现:

PM: suspend exit
Restarting tasks ...

{% p red, 但这段期间根本没有出现。 %}

这意味着:

系统从 s2idle 醒来失败,resume 回调没被执行或没被唤醒,而且主 CPU 可能处于不可调度状态。

2.2.2 查看当前的所有timer

Timer List Dump

-----------------------------------------------------------------------------------------------------------------------
CPU 0(tvec_base: ffffff80fb713240 timer_jiffies: 4294909085(67.16s) next_timer: 4294909632(69.348s) active_timers: NA)
-----------------------------------------------------------------------------------------------------------------------

+ vectors Timers (3)

	INDEX  TIMER_LIST_ADDR    EXPIRES        EXPIRES(s)     FUNCTION                                 WORK                                                 REMARKS
	187    ffffff80040460b8   4294909614     69.276s        delayed_work_timer_fn                    status_change_work[qpnp_smb5_main]               
	187    ffffff805c8a5828   4294909602     69.228s        delayed_work_timer_fn                    xm_charge_work[xm_smart_chg]                     
	215    ffffff808a3b4ce8   4294913181     83.544s        addrconf_rs_timer                                                                         

-----------------------------------------------------------------------------------------------------------------------------
CPU 1(tvec_base: ffffff80fb731240 timer_jiffies: 4294908993(66.792s) next_timer: 5368650816(4295034.084s) active_timers: NA)
-----------------------------------------------------------------------------------------------------------------------------

+ No vectors Timers found

------------------------------------------------------------------------------------------------------------------------
CPU 2(tvec_base: ffffff80fb74f240 timer_jiffies: 4294909072(67.108s) next_timer: 4294909312(68.068s) active_timers: NA)
------------------------------------------------------------------------------------------------------------------------

+ vectors Timers (3)

	INDEX  TIMER_LIST_ADDR    EXPIRES        EXPIRES(s)     FUNCTION                                 WORK                                                 REMARKS
	114    ffffffc00a0f85b8   4294909326     68.124s        delayed_work_timer_fn                    psi_avgs_work                                    
	182    ffffff8091dce218   4294909282     67.948s        delayed_work_timer_fn                    wb_workfn                                        
	229    ffffffc002f28ca8   4294920216     111.684s       delayed_work_timer_fn                    reg_check_chans_work[cfg80211]                   

-----------------------------------------------------------------------------------------------------------------------------
CPU 3(tvec_base: ffffff80fb76d240 timer_jiffies: 4294908992(66.788s) next_timer: 5368649856(4295030.244s) active_timers: NA)
-----------------------------------------------------------------------------------------------------------------------------

+ No vectors Timers found

-----------------------------------------------------------------------------------------------------------------------------
CPU 4(tvec_base: ffffff80fb78b240 timer_jiffies: 4294908992(66.788s) next_timer: 5368646592(4295017.188s) active_timers: NA)
-----------------------------------------------------------------------------------------------------------------------------

+ No vectors Timers found

-----------------------------------------------------------------------------------------------------------------------------
CPU 5(tvec_base: ffffff80fb7a9240 timer_jiffies: 4294908992(66.788s) next_timer: 5368646029(4295014.936s) active_timers: NA)
-----------------------------------------------------------------------------------------------------------------------------

+ No vectors Timers found

------------------------------------------------------------------------------------------------------------------------
CPU 6(tvec_base: ffffff80fb7c7240 timer_jiffies: 4294909073(67.112s) next_timer: 4294909328(68.132s) active_timers: NA)
------------------------------------------------------------------------------------------------------------------------

+ vectors Timers (3)

	INDEX  TIMER_LIST_ADDR    EXPIRES        EXPIRES(s)     FUNCTION                                 WORK                                                 REMARKS
	114    ffffff8047192c10   4294909322     68.108s        prb_retire_rx_blk_timer_expired                                                           
	219    ffffffc00a33fca8   4294915404     92.436s        delayed_work_timer_fn                    work_fn                                          
	234    ffffffc00a34bf30   4294922903     122.432s       delayed_work_timer_fn                    gc_worker                                        

------------------------------------------------------------------------------------------------------------------------
CPU 7(tvec_base: ffffff80fb7e5240 timer_jiffies: 4294908992(66.788s) next_timer: 4294909888(70.372s) active_timers: NA)
------------------------------------------------------------------------------------------------------------------------

+ vectors Timers (4)

	INDEX  TIMER_LIST_ADDR    EXPIRES        EXPIRES(s)     FUNCTION                                 WORK                                                 REMARKS
	191    ffffffc00f4bbcf8   4294909829     70.136s        process_timeout                                                                           
	208    ffffff80041e44e8   4294909807     70.048s        addrconf_rs_timer                                                                         
	240    ffffffc00a256360   4294926229     135.736s       delayed_work_timer_fn                    check_lifetime                                   
	425    ffffffc00a1a01a8   4305692338     43200.172s     delayed_work_timer_fn                    wakeup_dirtytime_writeback  

以CPU0的timer list为例子

CPU 0
tvec_base: ffffff80fb713240
timer_jiffies: 4294909085   --> 对应时间:67.16s
next_timer:     4294909632   --> 对应时间:69.348s

基本信息解析:

  • tvec_base: ffffff80fb713240,这个为struct timer_base
  • timer_jiffies: 4294909085,是当前的 tick 值,映射为 67.16 秒
  • next_timer 是最近将要触发的 timer,发生在 69.348 秒

表明当前(67.16s)并没有到触发任何定时器的时候

INDEX触发时间(秒)FUNCTION说明
18769.276sdelayed_work_timer_fnstatus_change_work[qpnp_smb5_main]SMB5充电器状态工作线程
18769.228sdelayed_work_timer_fnxm_charge_work[xm_smart_chg]小米智能充电策略
21583.544saddrconf_rs_timer网络自动配置定时器

从 47s 到 69s 之间,没有任何 active timer 被调度执行,自然也没有机会触发喂狗逻辑。

2.2.3 为什么 watchdog 没被喂?

❗️系统进入了 suspend 状态,但没有正确 resume,也没有任何中断或 wake source 触发,导致 CPU 停止调度定时器,喂狗任务未执行。

2.3 查找阻塞的进程

目前我们可以初步定位是某个进程在suspend后,没有resume起来。

查看tasks.txt,并查找pm_suspend函数。

Process: irq/141-pmic_pw, [affinity: 0xff] cpu: 5 pid: 693 start: 0xffffff8047c3cb00
=====================================================
    Task name: irq/141-pmic_pw  [affinity: 0xff] pid:    693 tgid:    693 cpu: 5 prio: 49 start: 0xffffff8047c3cb00
    state: 0x2[D] exit_state: 0x0 stack base: 0xffffffc00e648000
    Last_enqueued_ts:      47.729509516 Last_sleep_ts:      47.729527797
    Stack:
    [<ffffffc009041410>] __switch_to+0x164
    [<ffffffc009041c14>] __schedule+0x624
    [<ffffffc009042084>] schedule+0x84
    [<ffffffc00868d7c0>] __bio_queue_enter[jt]+0x7c
    [<ffffffc00869d174>] blk_mq_submit_bio+0x134
    [<ffffffc00868f850>] __submit_bio+0xbc
    [<ffffffc00868de78>] submit_bio_noacct_nocheck+0x1fc
    [<ffffffc00868e1cc>] submit_bio_noacct[jt]+0x350
    [<ffffffc00868e538>] submit_bio+0x124
    [<ffffffc00841a294>] submit_bh_wbc.llvm.9013634744024665527+0x134
    [<ffffffc00841b67c>] block_read_full_folio+0x434
    [<ffffffc008684fd8>] blkdev_read_folio.llvm.18044127471816345542+0x1c
    [<ffffffc0082da234>] filemap_read_folio+0x6c
    [<ffffffc0082dafac>] do_read_cache_folio.llvm.15198525227592925442+0x144
    [<ffffffc0082db1c4>] read_cache_page+0x1c
    [<ffffffc00222f9f4>] block2mtd_write[block2mtd]+0xb8
    [<ffffffc0021e0258>] mtd_write_oob[mtd]+0x1a4
    [<ffffffc0021e007c>] mtd_write[mtd]+0x40
    [<ffffffc0021bd3ec>] mtdoops_write[mtdoops]+0xe4
    [<ffffffc0021bde40>] mtdoops_do_dump[mtdoops]+0x278
    [<ffffffc0021bd910>] pwrkey_long_press_irq_event[mtdoops]+0x14
    [<ffffffc0080f0508>] raw_notifier_call_chain+0x58
    [<ffffffc001ef9838>] pm8941_pwrkey_irq[pm8941_pwrkey][jt]+0x1b0
    [<ffffffc008156e44>] irq_thread_fn+0x44
    [<ffffffc008156bf0>] irq_thread+0x164
    [<ffffffc0080ee6c4>] kthread+0x10c
    [<ffffffc00801491c>] ret_from_fork+0x10
Task name: irq/141-pmic_pw   (PID 693)
CPU: 5, 状态: D(不可中断睡眠)

这说明它是 电源键(PMIC_PWRKEY)中断线程,也就是 pm8941_pwrkey 驱动的中断处理线程,它现在 卡在了某个阻塞点,未完成执行

如此我们可以确定卡住的线程为irq/141-pmic_pw

三、根本原因分析

🔍栈回溯分析重点

从你贴出的内核栈,我们可以还原出这个线程的逻辑路径:

pm8941_pwrkey_irq()           <-- 电源键中断处理
  ↳ mtdoops_do_dump()         <--- 中断处理函数的notifier回调函数
    ↳ block2mtd_write()
      ↳ submit_bio()         <-- 向 block 层提交 IO 写操作
        ↳ schedule()         <-- 卡在 bio 提交等待(D 状态)

它正在尝试在 PM suspend 阶段执行mtdoops dump(异常写入),但是提交的 bio 操作阻塞了,线程状态为 D(不可中断睡眠),无法被唤醒。

而在 suspend/resume 流程中:

🌧️ 任意一个线程处于不可中断睡眠状态(D)且未完成 resume,都会阻塞整个系统 resume 流程,导致无法喂狗。

💣 进一步的根因推测:

这个线程中断发生时系统正在 suspend,中断触发写入(mtdoops_do_dump)流程,而底层 block device(比如 eMMC 或 UFS)已经挂起或者 IO 通道被冻结,因此:

  • 提交 bio 时卡在 block queue,无法继续执行
  • thread 被锁死在不可中断状态
  • 所以 resume 无法完成,watchdog 20 秒后触发 bite!

四、解决方案

当前调用链结构

pm8941_pwrkey_irq()                          // IRQ handler
    └─ raw_notifier_call_chain()             // 通知链调用
        └─ pwrkey_long_press_irq_event()     // mtdoops 中注册的回调
            └─ mtdoops_do_dump()             // 💥直接在中断上下文中执行 dump(有 IO)

问题在于:你在 IRQ thread 里调用了 mtdoops_do_dump(),而 do_dump() 内部会提交阻塞的 bio 写操作,一旦 block 层 suspend,就必然死锁。

那我们就可以想办法避免 suspend 时执行 mtdoops_do_dump

延迟执行 mtdoops_do_dump() 到 resume 之后

我们将:

  1. pwrkey_long_press_irq_event()仅设置一个标志
  2. 在系统 resume 后 通过 workqueue 异步触发 dump

////mtdoops.c

1️⃣ 在 mtdoops.c 中定义全局状态:

#include <linux/pm.h>
#include <linux/workqueue.h>

static atomic_t dump_pending = ATOMIC_INIT(0);
static struct work_struct deferred_dump_work;

2️⃣ 替换 pwrkey_long_press_irq_event() 函数

static int pwrkey_long_press_irq_event(struct notifier_block *this, unsigned long event,
                                       void *ptr)
{
    pr_info("pwrkey irq: deferring mtdoops dump until resume\n");
    atomic_set(&dump_pending, 1);
    return NOTIFY_DONE;
}

3️⃣ 添加 resume 通知钩子

static void do_deferred_dump(struct work_struct *work)
{
    struct mtdoops_context *cxt = &oops_cxt;
    pr_info("Executing deferred mtdoops dump after resume\n");
    mtdoops_do_dump(&cxt->dump, MTD_DUMP_LONG_PRESS);
}

static int mtdoops_pm_notifier(struct notifier_block *nb, unsigned long action, void *data)
{
    if (action == PM_POST_SUSPEND) {
        if (atomic_read(&dump_pending)) {
            atomic_set(&dump_pending, 0);
            schedule_work(&deferred_dump_work);
        }
    }
    return NOTIFY_OK;
}

static struct notifier_block mtdoops_resume_nb = {
    .notifier_call = mtdoops_pm_notifier,
};

4️⃣ 在 mtdoops_init() 初始化中添加

INIT_WORK(&deferred_dump_work, do_deferred_dump);
register_pm_notifier(&mtdoops_resume_nb);

五、效果

  • 在电源键中断触发时,不再执行阻塞的 dump
  • 系统 resume 完成后,再通过内核线程安全地 dump
  • 完全避免 suspend 卡死
  • 非侵入性修改,兼容性强

六、测试建议

  1. 在按电源键时打印 defer dump 日志是否出现
  2. 挂起后唤醒,看是否出现 Executing deferred mtdoops dump after resume
  3. 观察是否还会触发 watchdog bite