云计算百科
云计算领域专业知识百科平台

第12章: MMU notifier内核演进与未来方向

12.1 历史演进

12.1.1 mmu_notifier诞生(2008年)

原始mmu_notifier设计(2008年引入):

  • Copyright © 2008 Qumranet, Inc.
  • Copyright © 2008 SGI
  • Author: Christoph Lameter cl@linux.com

早期设计目标 :

  • 为KVM虚拟化提供shadow page table同步机制
  • 支持RDMA内存注册失效通知
  • 为未来异构内存管理奠定基础
  • 初始实现特点:

    • 全局通知模型(通知整个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 动机:

  • GPU驱动需要跟踪大量小区间
  • 全局扫描开销太大
  • 需要更精确的失效通知
  • HMM需要高效的range跟踪
  • /* 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演进轨迹:

  • 2008年: 基础框架,全局通知
  • 2010-2018年: 渐进改进,优化性能
  • 2019年: interval notifier革命性突破
  • 2020年+: 双状态优化,持续演进
  • 未来方向:

    • 硬件加速集成
    • 异构内存统一管理
    • 性能持续优化
    • 跨子系统协作

    关键趋势:

    • 从全局到局部(interval tree)
    • 从同步到异步(可能的方向)
    • 从软件到硬件(ATS/PASID)
    • 从单一到协同(HMM/CXL)

    本专栏到此已完结。如果内核有upstream,会及时更新,请持续关注。


    🔗 导航

    • 上一章: 第11章: 性能分析与调优
    • 附录A:API快速参考
    • 返回目录: Linux MMU Notifier 机制与应用系列目录
    赞(0)
    未经允许不得转载:网硕互联帮助中心 » 第12章: MMU notifier内核演进与未来方向
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!