需从锁粒度、持有时间、获取顺序和进程调度四层面干预麒麟系统内核锁死锁,先启用lockdep机制定位环形依赖,再拆分锁、改用rcu、规范加锁顺序、引入超时与可中断锁。

麒麟系统中因多进程频繁争抢同一内核锁(如自旋锁、互斥锁)引发死锁时,需从锁粒度、持有时间、获取顺序和进程调度四个层面切入干预,不能仅依赖重启或kill -9粗暴终止。
定位死锁源头进程与锁对象
执行 dmesg -T | grep -i "deadlock\|lockdep\|possible circular",查看内核是否已启用 lockdep 机制并输出环形依赖路径。若无输出,说明 lockdep 未开启,需重新编译内核或在启动参数中加入 lockdep=1 并重启——【未启用 lockdep 时无法自动检测锁循环,所有后续分析将失去依据】。
运行 cat /proc/locks 查看当前全部锁状态,重点关注 type 字段为 ADVISORY 或 FLOCK 的条目,结合 pid 列反查对应进程命令: ps -p PID -o pid,comm,args。
缩小锁保护范围并替换为更轻量同步原语
方法一:将全局大锁拆分为 per-CPU 或 per-bucket 锁。例如,原代码中对整个哈希表使用单一 mutex,应改用 struct mutex hash_bucket_lock[NR_CPUS],访问 key 时通过 hash(key) % NR_CPUS 映射到对应锁。
方法二:读多写少场景下,用 rcu_read_lock() + rcu_dereference() 替代读侧 mutex,写侧仍用 mutex 但仅在真正修改结构体指针时加锁——这能直接消除读进程间的锁竞争。
方法三:短临界区(mutex_lock() 替换为 spin_lock(),但必须确保临界区内不调用任何可能引起调度或阻塞的函数(如 copy_to_user、kmalloc(GFP_KERNEL)),否则会导致 CPU 占满且不可中断。
统一锁获取顺序并避免嵌套
第一步:列出系统中所有被多个进程共用的锁,按内存地址升序编号(如 &dev->lock → L1,&bus->mutex → L2,&drv->probe_lock → L3)。
第二步:强制所有进程按 L1→L2→L3 顺序申请锁,禁止逆序(如先 L3 后 L1)或跳序(如只申请 L2 和 L3 而跳过 L1)。
第三步:在每个锁申请前插入校验宏:lockdep_assert_held(&L1);(若已持 L1 才允许申请 L2),该宏在 lockdep 开启时生效,编译期不产生开销。
注意:驱动 probe 函数中常见隐式嵌套——platform_driver_register() 内部会持 bus->mutex,若 probe 中又调用 device_lock(dev),而 dev 属于该 bus,则构成天然嵌套。此时应改用 device_lock_interruptible(dev),并在返回 -EINTR 时主动释放已持锁后重试。
调整进程实时性与锁超时策略
对持有锁时间超过 2ms 的关键进程(如实时音视频采集线程),用 chrt -f 50 PID 提升为 SCHED_FIFO 调度策略,防止被普通进程抢占导致锁持有时间不可控。
在用户态服务中,所有 pthread_mutex_lock 改为 pthread_mutex_timedlock,并设置 timeout 为 50ms:struct timespec abs_time; clock_gettime(CLOCK_MONOTONIC, &abs_time); abs_time.tv_sec += 0; abs_time.tv_nsec += 50000000;。超时后记录日志并回滚事务,而非无限等待。
内核模块中禁用 mutex_lock(),一律改用 mutex_lock_interruptible(),并在返回 -EINTR 时立即返回错误码,由上层决定重试或降级处理——【直接调用 mutex_lock() 在信号到来时仍会阻塞,是用户态触发内核死锁的常见入口】。











