内核同步机制总览

本文对应 成长路径 高优先级:在驱动与内核模块开发中 正确选用锁,并会用 lockdep 发现死锁与 IRQ 上下文错误。


学习目标

  • 上下文(进程 / 软中断 / 硬中断)选择锁类型。
  • 理解 RCU 读多写少场景与 宽限期
  • 开启 CONFIG_LOCKDEP 解读典型报告。

按上下文选用(总表)

机制睡眠硬中断软中断典型用途
spinlock是*是*极短临界区、per-CPU
mutex进程上下文长临界
rwsem读多写少、可睡眠
rwlock谨慎谨慎旧代码,倾向 rwsem
RCU读侧无锁特殊读极多、写少
seqlock读无锁写加锁部分部分jiffies、简单计数

* 需使用 spin_lock_irqsave 等正确变体,且临界区 极短


spinlock 要点

spinlock_t lock;
spin_lock_irqsave(&lock, flags);
/* 临界区 */
spin_unlock_irqrestore(&lock, flags);
  • 不可 在持 spinlock 时睡眠(含 copy_from_user 可能 fault)。
  • 死锁:AB-BA、IRQ 嵌套同锁 → 用 lockdep。

mutex 要点

mutex_lock(&dev->lock);
/* 可调度、可访问用户内存 */
mutex_unlock(&dev->lock);

适合 字符设备 file_operations 中较长路径;与 interrupt 不要交叉持锁。


RCU 要点

  • 读侧:rcu_read_lock() / rcu_read_unlock(),无原子阻塞写者。
  • 写侧:分配新结构 → rcu_assign_pointersynchronize_rcu()call_rcu 释放旧数据。
  • 网络栈、路由表、大量 只读遍历 使用 RCU。

lockdep 入门

内核配置 CONFIG_LOCKDEPCONFIG_PROVE_LOCKING

触发后 dmesg 可能出现:

possible circular locking dependency detected

阅读顺序:

  1. 锁链 A → B → C
  2. 上下文 hardirq/softirq/process
  3. 修改:统一加锁顺序、缩短临界区、换 mutexRCU

用户态可配合 CONFIG_DEBUG_ATOMIC_SLEEP 查非法睡眠。


与无锁、DPDK 的边界

环境建议
内核驱动以上锁 + RCU;避免用户态无锁套路
DPDK 数据面rte_ring、per-lcore 变量,见 无锁编程
跨核共享计数内核 atomic_t;DPDK rte_atomic

实践清单

  • 在模块里故意用错上下文(仅 QEMU)观察 lockdep 报告
  • 画一张驱动里 所有锁 的获取顺序图
  • 对照 Linux 内核模块开发实战 检查 probe/remove 对称性

延伸阅读