12.1 历史演进
12.1.1 mmu_notifier诞生(2008年)
原始mmu_notifier设计(2008年引入):
- Copyright © 2008 Qumranet, Inc.
- Copyright © 2008 SGI
- Author: Christoph Lameter cl@linux.com
早期设计目标 :
初始实现特点:
- 全局通知模型(通知整个mm)
- 简单的链表结构
- 回调驱动的事件模型
/* 早期mmu_notifier_ops结构(简化版) */
struct mmu_notifier_ops_v1 {
/* 页表清除时通知 */
void (*invalidate_page)(struct mmu_notifier *mn,
struct mm_struct *mm,
unsigned long address);
/* 范围失效开始 */
void (*invalidate_range_start)(struct mmu_notifier *mn,
struct mm_struct *mm,
unsigned long start,
unsigned long end);
/* 范围失效结束 */
void (*invalidate_range_end)(struct mmu_notifier *mn,
struct mm_struct *mm,
unsigned long start,
unsigned long end);
/* 进程退出时通知 */
void (*release)(struct mmu_notifier *mn,
struct mm_struct *mm);
};
/*
* 早期限制:
* – 无法精确跟踪特定地址范围
* – 回调粒度粗(整个mm级别)
* – 性能开销大(需要扫描全部映射)
* – 并发控制简单
*/
12.1.2 改进阶段(2010-2018年)
关键改进点: 2010年: 引入invalidate_range() – 在页表锁外通知 – 提高并发性
2012年: 改进阻塞语义 – 引入non-blocking标志 – 支持trylock模式
2014年: 添加clear_flush_young() – 优化页面老化 – 减少TLB刷新开销
2015年: 引入mmu_notifier_range – 统一事件描述 – 添加事件类型标志
2016年: 优化锁机制 – 引入SRCU (Sleepable RCU) – 减少锁竞争
/* 改进后的mmu_notifier_range */
struct mmu_notifier_range {
struct mm_struct *mm;
unsigned long start;
unsigned long end;
unsigned flags;
enum mmu_notifier_event event; // 新增事件类型
void *owner; // 新增owner字段
};
/* 事件类型枚举 */
enum mmu_notifier_event {
MMU_NOTIFY_UNMAP = 0,
MMU_NOTIFY_CLEAR,
MMU_NOTIFY_PROTECTION_VMA,
MMU_NOTIFY_PROTECTION_PAGE,
MMU_NOTIFY_SOFT_DIRTY,
MMU_NOTIFY_RELEASE,
MMU_NOTIFY_MIGRATE,
MMU_NOTIFY_DEVICE_EXCLUSIVE,
MMU_NOTIFY_EXCLUSIVE,
};
/*
* 性能优化:
* – 减少不必要的回调
* – 更细粒度的事件分类
* – 支持设备私有页
*/
12.1.3 mmu_interval_notifier革命(2019年)
2019年重大突破: 引入mmu_interval_notifier 动机:
/* mmu_interval_notifier核心设计 */
struct mmu_interval_notifier {
struct interval_tree_node interval_tree; // interval tree节点
const struct mmu_interval_notifier_ops *ops;
struct mm_struct *mm;
struct hlist_node deferred_item;
unsigned long invalidate_seq; // 序列号同步
};
/* interval tree优势 */
/*
* 数据结构: 红黑树 + 区间查询
* 复杂度: O(log N + K)
* – N: 总区间数
* – K: 重叠区间数
*
* 对比传统方案:
* 传统: O(N) – 扫描所有notifier
* 新方案: O(log N + K) – 只查询相关区间
*
* 性能提升:
* 100个区间: 100x -> 7x (14倍提升)
* 1000个区间: 1000x -> 10x (100倍提升)
* 10000个区间: 10000x -> 14x (700倍提升)
*/
/* 序列号同步机制 */
/*
* 创新点: 无锁冲突检测
*
* 序列号协议:
* 偶数 = 空闲状态
* 奇数 = 正在进行invalidate
*
* 使用模式:
* seq = read_begin() // 记录起始序列号
* … 访问页表 …
* if (read_retry(seq)) // 检测冲突
* retry; // 重试
*
* 优势:
* – 无需持锁检查
* – 高并发友好
* – 适合长时间操作
*/
12.1.4 双状态优化(2020年)
2020年优化: 双状态invalidate机制 问题: 即使没有interval notifier,也要操作interval tree 解决: 区分两种invalidate状态
// mm/mmu_notifier.c
struct mmu_notifier_subscriptions {
struct hlist_head list;
bool has_itree; // 是否有interval notifier
spinlock_t lock;
unsigned long invalidate_seq; // 序列号
unsigned long active_invalidate_ranges; // 活跃invalidate计数
struct rb_root_cached itree; // interval tree
wait_queue_head_t wq;
struct hlist_head deferred_list;
};
/*
* 状态机设计:
*
* 完全排他状态 (Full Exclusion):
* – invalidate_seq & 1 == 1 (奇数)
* – 不允许修改interval tree
* – 用于遍历回调期间
*
* 部分排他状态 (Partial Exclusion):
* – invalidate_seq & 1 == 0 (偶数)
* – 允许修改interval tree
* – 用于无interval notifier场景
*
* 优化效果:
* 无interval notifier时避免昂贵的tree加锁
* 减少invalidate_end开销
*/
/* 状态检查函数 */
static bool
mn_itree_is_invalidating(struct mmu_notifier_subscriptions *subscriptions)
{
lockdep_assert_held(&subscriptions->lock);
return subscriptions->invalidate_seq & 1; // 奇数=正在invalidate
}
/*
* 性能提升:
* – KVM场景: 10-20% invalidate_end开销降低
* – GPU场景: 15-30% 整体性能提升
*/
12.2 当前内核版本改进
12.2.1 6.x内核特性
Linux 6.0+ 主要改进:
统一的mmu_notifier_range
- 所有回调使用相同参数
- 简化驱动实现
改进的死锁检测
- lockdep注解增强
- 运行时验证
设备私有页支持
- DEVICE_PRIVATE页类型
- 设备独占模式
/* 当前mmu_notifier_ops完整版 */
struct mmu_notifier_ops {
/* 释放通知 */
void (*release)(struct mmu_notifier *subscription,
struct mm_struct *mm);
/* 范围失效 */
int (*invalidate_range_start)(struct mmu_notifier *subscription,
const struct mmu_notifier_range *range);
void (*invalidate_range_end)(struct mmu_notifier *subscription,
const struct mmu_notifier_range *range);
/* 页面老化 */
int (*clear_flush_young)(struct mmu_notifier *subscription,
struct mm_struct *mm,
unsigned long start,
unsigned long end);
int (*clear_young)(struct mmu_notifier *subscription,
struct mm_struct *mm,
unsigned long start,
unsigned long end);
int (*test_young)(struct mmu_notifier *subscription,
struct mm_struct *mm,
unsigned long address);
/* 页变脏通知 */
void (*change_pte)(struct mmu_notifier *subscription,
struct mm_struct *mm,
unsigned long address,
pte_t pte);
/* 辅助TLB失效 */
void (*arch_invalidate_secondary_tlbs)(
struct mmu_notifier *subscription,
struct mm_struct *mm,
unsigned long start,
unsigned long end);
};
/* interval notifier完整版 */
struct mmu_interval_notifier_ops {
bool (*invalidate)(struct mmu_interval_notifier *interval_sub,
const struct mmu_notifier_range *range,
unsigned long cur_seq);
};
12.2.2 SRCU优化
// mm/mmu_notifier.c
/*
* SRCU (Sleepable Read-Copy Update) 使用
*
* 优势:
* – 允许回调中阻塞
* – 更好的可扩展性
* – 减少锁争用
*/
/* 全局SRCU域 */
DEFINE_STATIC_SRCU(srcu);
/* SRCU保护的遍历 */
static int mn_hlist_invalidate_range_start(
struct mmu_notifier_subscriptions *subscriptions,
struct mmu_notifier_range *range)
{
struct mmu_notifier *subscription;
int ret = 0;
int id;
/* SRCU读侧临界区 */
id = srcu_read_lock(&srcu);
hlist_for_each_entry_rcu(subscription, &subscriptions->list,
hlist, srcu_read_lock_held(&srcu)) {
if (subscription->ops->invalidate_range_start) {
ret = subscription->ops->invalidate_range_start(
subscription, range);
if (ret)
break;
}
}
srcu_read_unlock(&srcu, id);
return ret;
}
/*
* SRCU vs RCU对比:
*
* RCU:
* – 读侧不能阻塞
* – 更快的读性能
* – 适合短临界区
*
* SRCU:
* – 读侧可以阻塞
* – 稍慢的读性能
* – 适合长临界区
* – 更好的CPU隔离
*
* MMU notifier选择SRCU原因:
* – 回调可能需要等待硬件
* – 可能需要获取锁
* – 操作时间不确定
*/
12.2.3 Lockdep集成
// mm/mmu_notifier.c
#ifdef CONFIG_LOCKDEP
/* lockdep注解 */
struct lockdep_map __mmu_notifier_invalidate_range_start_map = {
.name = "mmu_notifier_invalidate_range_start"
};
#endif
/*
* Lockdep检测场景:
*
* 1. 锁顺序违反
* invalidate回调中不当的锁操作
*
* 2. 递归invalidate
* 回调中触发新的page fault
*
* 3. 死锁路径
* 与GUP或其他mm锁的冲突
*/
/* 使用示例 */
int __mmu_notifier_invalidate_range_start(struct mmu_notifier_range *range)
{
struct mm_struct *mm = range->mm;
int ret;
/* Lockdep检查点 */
lock_map_acquire(&__mmu_notifier_invalidate_range_start_map);
/* 执行invalidate */
ret = mn_itree_invalidate(mm->notifier_subscriptions, range);
ret = mn_hlist_invalidate_range_start(mm->notifier_subscriptions, range);
lock_map_release(&__mmu_notifier_invalidate_range_start_map);
return ret;
}
/*
* 调试技巧:
*
* 启用lockdep:
* CONFIG_LOCKDEP=y
* CONFIG_PROVE_LOCKING=y
* CONFIG_LOCK_STAT=y
*
* 查看锁统计:
* cat /proc/lock_stat
*
* 追踪锁依赖:
* echo 1 > /proc/sys/kernel/lock_stat
*/
12.3 未来发展方向
12.3.1 硬件加速趋势
新硬件特性:
ATS (Address Translation Services)
- PCIe设备直接查询CPU页表
- 减少软件同步开销
- 硬件自动失效
PASID (Process Address Space ID)
- 多进程地址空间隔离
- IOMMU原生支持
- 更精确的TLB管理
CCIX/CXL (Cache Coherent Interconnect)
- 硬件缓存一致性
- 减少软件通知需求
- 更低延迟
/* 未来API设计考虑 */
struct mmu_notifier_ops_future {
/* 支持硬件加速路径 */
bool (*supports_hardware_invalidate)(struct mmu_notifier *mn);
/* PASID支持 */
int (*bind_pasid)(struct mmu_notifier *mn, u32 pasid);
void (*unbind_pasid)(struct mmu_notifier *mn, u32 pasid);
/* 批量操作 */
int (*invalidate_ranges)(struct mmu_notifier *mn,
struct mmu_notifier_range *ranges,
unsigned int count);
};
/*
* 优化方向:
* – 硬件感知的通知路径
* – 自适应批量处理
* – 零拷贝数据传输
*/
12.3.2 异构内存管理增强
HMM未来演进:
统一内存架构
- CPU/GPU/加速器共享地址空间
- 透明页面迁移
- 自动负载平衡
多层内存支持
- DRAM + NVM + Device Memory
- 自动分层策略
- 性能优先放置
细粒度保护
- 子页粒度保护
- 灵活的访问权限
- 硬件加速检查
/* 概念性未来接口 */
struct hmm_range_v2 {
struct mmu_interval_notifier *notifier;
unsigned long notifier_seq;
/* 多段支持 */
struct {
unsigned long start;
unsigned long end;
unsigned long *hmm_pfns;
} segments[HMM_MAX_SEGMENTS];
unsigned int nr_segments;
/* 扩展标志 */
unsigned long flags;
#define HMM_RANGE_MULTI_DEVICE BIT(0) // 多设备协同
#define HMM_RANGE_PREFAULT BIT(1) // 预先fault
#define HMM_RANGE_ASYNC BIT(2) // 异步处理
/* 设备列表 */
void **devices;
unsigned int nr_devices;
};
/*
* 研究方向:
* – 机器学习驱动的页面放置
* – 预测性预取
* – 自适应迁移策略
*/
12.3.3 性能优化方向
持续优化目标:
减少延迟
- 更快的interval tree查询
- 无锁快速路径
- 批量处理优化
提高并发
- Per-CPU数据结构
- 细粒度锁
- Lock-free算法
降低内存开销
- 压缩interval tree
- 共享公共数据
- 按需分配
/* 可能的优化实现 */
/* Per-CPU interval tree */
struct per_cpu_itree {
struct rb_root_cached tree;
spinlock_t lock;
} ____cacheline_aligned;
/* 分区设计 */
struct partitioned_notifier_subscriptions {
/* 全局notifier(保持向后兼容) */
struct hlist_head global_list;
/* Per-CPU interval tree */
struct per_cpu_itree __percpu *per_cpu_trees;
/* 统计信息 */
atomic64_t total_intervals;
atomic64_t invalidate_count;
};
/*
* 预期效果:
* – 50%+ 并发性能提升
* – 30%+ 延迟降低
* – 20%+ 内存节省
*/
12.3.4 标准化和协同
跨子系统协作:
与io_uring集成
- 异步invalidate通知
- 批量I/O优化
- 零拷贝路径
与eBPF集成
- 可编程策略
- 运行时调优
- 监控和追踪
与cgroup集成
- 资源限制
- QoS保证
- 隔离性增强
/* 概念性eBPF程序 */
/*
SEC("mmu_notifier/invalidate")
int mmu_notifier_invalidate_prog(struct mmu_notifier_range *range)
{
// 用户定义的策略
if (should_skip_invalidate(range))
return 0;
// 自定义预处理
preprocess_range(range);
// 继续标准处理
return 1;
}
*/
/*
* 标准化工作:
* – 跨架构API统一
* – 设备驱动最佳实践
* – 性能基准测试
* – 互操作性指南
*/
12.4 社区讨论热点
活跃提案:
异步invalidate通知
- 允许延迟处理
- 减少阻塞时间
- 提高响应性
细粒度事件过滤
- 只接收相关事件
- 减少噪音通知
- 优化性能
统计和监控API
- 标准化性能计数器
- 运行时诊断接口
- 问题定位工具
12.4.1 当前提案
/* 提案: 异步invalidate */
struct mmu_notifier_ops_async {
/* 同步路径(快速) */
int (*invalidate_range_start_fast)(
struct mmu_notifier *subscription,
const struct mmu_notifier_range *range);
/* 异步路径(慢速) */
void (*invalidate_range_start_async)(
struct mmu_notifier *subscription,
const struct mmu_notifier_range *range,
struct work_struct *work);
};
/* 提案: 事件过滤 */
struct mmu_notifier_filter {
unsigned long event_mask; // 感兴趣的事件
unsigned long addr_min; // 地址范围最小值
unsigned long addr_max; // 地址范围最大值
bool (*should_notify)(const struct mmu_notifier_range *range);
};
12.4.2 争议点
社区争议:
性能 vs 正确性
- 延迟通知的安全性
- 弱序内存模型影响
- Race condition风险
复杂度 vs 灵活性
- API简单性
- 驱动实现难度
- 维护成本
通用性 vs 特化
- 为特定硬件优化
- 保持架构中立
- 平衡取舍
12.5 小结
MMU notifier演进轨迹:
未来方向:
- 硬件加速集成
- 异构内存统一管理
- 性能持续优化
- 跨子系统协作
关键趋势:
- 从全局到局部(interval tree)
- 从同步到异步(可能的方向)
- 从软件到硬件(ATS/PASID)
- 从单一到协同(HMM/CXL)
本专栏到此已完结。如果内核有upstream,会及时更新,请持续关注。
🔗 导航
- 上一章: 第11章: 性能分析与调优
- 附录A:API快速参考
- 返回目录: Linux MMU Notifier 机制与应用系列目录
网硕互联帮助中心





评论前必须登录!
注册