当前位置: 首页 > news >正文

Linux内核源码详解--缺页异常(Page Fault)处理的核心函数handle_pte_fault

handle_pte_fault 是 Linux 内核中处理缺页异常(Page Fault)的核心函数,负责根据页表项(PTE)的状态和访问权限,分发到不同的子处理逻辑(如匿名页映射、文件页映射、写时复制、NUMA 迁移等)。以下基于代码逻辑和搜索结果详细解析其功能、原理及处理流程。

 

一、功能概述

 

handle_pte_fault 在缺页异常处理流程中被调用(通常由 __handle_mm_fault 触发),用于处理以下场景:

 

 1.首次访问未映射的虚拟地址(PTE 为空)。

 

 2.访问已被换出(Swap Out)的页面(PTE 存在但 PRESENT 位为 0)。

 

 3.写保护触发写时复制(COW)。

 

 4.NUMA 内存页迁移优化。

 

 5.权限检查与页表状态更新。

 

二、代码逻辑分步解析

 

1. 检查 PMD 状态(大页/透明大页处理)

 

if (unlikely(pmd_none(*vmf->pmd))) {

    vmf->pte = NULL; // 延迟 PTE 分配,避免与透明大页冲突

} else if (pmd_devmap_trans_unstable(vmf->pmd)) {

    return 0; // 透明大页不稳定状态,需重试

} else {

    vmf->pte = pte_offset_map(vmf->pmd, vmf->address); // 获取 PTE

    vmf->orig_pte = *vmf->pte;

    barrier();

    if (pte_none(vmf->orig_pte)) { // PTE 为空则解除映射

        pte_unmap(vmf->pte);

        vmf->pte = NULL;

    }

}

 

关键点:

 

 若 PMD 未分配(pmd_none),暂不分配 PTE,避免干扰透明大页(THP)的并发操作。

 

 pmd_devmap_trans_unstable 处理透明大页分裂场景。

 

 

2. 处理 PTE 为空的情况(首次映射) 

 

if (!vmf->pte) {

    if (vma_is_anonymous(vmf->vma))

        return do_anonymous_page(vmf); // 匿名页映射

    else

        return do_fault(vmf); // 文件页/共享内存映射

}

 

static inline bool vma_is_anonymous(struct vm_area_struct *vma)

{

 return !vma->vm_ops;

}

 

分发逻辑:

 

 匿名页(vma->vm_ops == NULL):

 

  读操作:映射到零页(Zero Page)以减少物理内存占用。

 

  写操作:分配新物理页并初始化。

 

 文件页(vma->vm_ops != NULL):

 

  触发文件系统缺页处理(如 filemap_fault),从磁盘读取数据到 Page Cache

 

3. 处理 PTE 存在但 PRESENT 位为 0(已换出)

 

if (!pte_present(vmf->orig_pte))

    return do_swap_page(vmf); // 换回(Swap In)页面

 

原理:

PTE 存储了 Swap Entry(标识磁盘位置),需调用 do_swap_page 将数据从 Swap 分区读回物理内存

 

 

4. 处理 NUMA 迁移优化

 

if (pte_protnone(vmf->orig_pte) && vma_is_accessible(vmf->vma))

    return do_numa_page(vmf); // 迁移页面到当前 NUMA 节点

 

场景:

 

当物理页位于远端 NUMA 节点时,迁移以提升访问性能。

 

5. 写操作与写时复制(COW)

 

if (vmf->flags & FAULT_FLAG_WRITE) {

    if (!pte_write(entry))

        return do_wp_page(vmf); // 触发写时复制

    entry = pte_mkdirty(entry); // 标记脏页

}

 

COW 机制:

 

写只读页时,分配新物理页并复制内容,更新 PTE 指向新页(原页引用计数减 1)

 

若物理页仅被一个进程引用(无共享),则直接设为可写,避免复制。 

 

6. 更新 PTE 与 TLB 刷新

 

entry = pte_mkyoung(entry); // 标记访问位(PTE_AF)

if (ptep_set_access_flags(vma, address, pte, entry, write)) {

    update_mmu_cache(vma, address, pte); // 更新 CPU 缓存

} else if (write) {

    flush_tlb_fix_spurious_fault(vma, address); // 刷新 TLB 伪错误

}

 

关键操作:

 

ptep_set_access_flags:原子更新 PTE 的访问/脏位。

 

TLB 刷新仅在权限变更时触发(避免冗余刷新提升性能)。

 

 

三、处理流程图解

 

graph TD

    A[handle_pte_fault] --> B{PMD 有效?}

    B -- Yes --> C[获取 PTE]

    B -- No --> D[延迟 PTE 分配]

    C --> E{PTE 为空?}

    E -- Yes --> F{匿名页?}

    F -- Yes --> G[do_anonymous_page]

    F -- No --> H[do_fault]

    E -- No --> I{PTE Present?}

    I -- No --> J[do_swap_page]

    I -- Yes --> K{NUMA 迁移?}

    K -- Yes --> L[do_numa_page]

    K -- No --> M{写操作且只读?}

    M -- Yes --> N[do_wp_page]

    M -- No --> O[更新 PTE 标志]

    O --> P[刷新 TLB/缓存]

 

四、关键设计思想

 

延迟与优化:

 

 延迟 PTE 分配以避免透明大页冲突。

 

 零页映射节省匿名页首次读的内存

 

 

分层处理:

 

 按 PTE 状态(空/换出/写保护)分发给专用子函数,确保逻辑清晰。

 

并发控制:

 

 通过 spin_lock(vmf->ptl) 锁定页表,防止并行修改

 

性能优化:

 

 减少 TLB 刷新(仅在权限变更时触发)。

 

 区分 major/minor fault(是否涉及磁盘 I/O) 

 

五、典型场景与子函数对照表

 

场景 触发条件 处理函数 说明

 

匿名页首次访问 vmf->pte == NULL & 匿名 VMA do_anonymous_page 读:零页;写:分配新页

 

文件页首次映射 vmf->pte == NULL & 文件 VMA do_fault 读文件到 Page Cache

 

页面已换出 !pte_present(entry) do_swap_page 从 Swap 分区读回数据

 

写只读页(COW) write & !pte_write(entry) do_wp_page 复制页面或直接设可写

 

NUMA 优化迁移 pte_protnone(entry) do_numa_page 迁移页面至本地 NUMA 节点

 

页表更新 权限变更(如脏页/访问位) ptep_set_access_flags 更新 PTE 并刷新 TLB 

 

 

六、总结

 

handle_pte_fault 是 Linux 虚拟内存管理的核心枢纽,通过状态机式的分发逻辑处理各类缺页异常:

 

匿名/文件页:按需分配物理页或读取文件数据。

 

COW 机制:平衡内存共享与写操作性能。

 

Swap 与 NUMA:优化内存不足和跨节点访问场景。

其设计充分体现了 “懒加载”(Lazy Allocation)和 “最小化开销”(如零页、延迟刷新 TLB)的原则,确保高效管理复杂的内存访问需求。 

http://www.dtcms.com/a/342856.html

相关文章:

  • Maven(三)
  • Class A 包含字段 x Class B 也包含字段 x,如果判断List<A> lista 和 List<B> listb 有相同的 x?
  • 基于websocket聊天室的基本点
  • SQL中的游标
  • html ajax前端页面
  • 51单片机-驱动直流电机模块教程
  • 单片机\物联网\51单片机\嵌入式开发\软硬件结合的基于STM32的电梯管理系统的设计/基于STM32的电梯运行系统的设计
  • 【华为OD-C卷-020 -关联端口组合并 100分(python、java、c++、js、c)】
  • 解决 uniapp 修改index.html文件不生效的问题
  • PCB文件怎么快速判断是通孔还是盲孔呢?
  • Git 2.15.0 64位安装步骤Windows详细教程从下载到验证(附安装包下载)
  • 14、外部中断
  • 【科普向-第三篇】汽车电子MCU操作系统详解:CP AUTOSAR与FreeRTOS
  • 1688电商商品大数据采集之路 技术篇
  • 嵌入式接口通识知识之PWM接口
  • 机器学习聚类与集成算法全解析:从 K-Means 到随机森林的实战指南
  • 从系统漏洞归零到候诊缩短20%:一个信创样本的效能革命
  • 播放器视频后处理实践(一)
  • 视频加水印 视频加水印软件 视频加动态水印
  • 音视频面试题集锦第 29 期
  • 如何有效防止视频在浏览器播放时被录屏?
  • 全媒体人才培育对接会:国际数字影像产业园赋能企业发展
  • 如何学习编程
  • 完全背包(模板)
  • Mysql基础(③事务)
  • [ Servlet 服务器]
  • LTM框架Letta
  • Java项目:基于SpringBoot和VUE的在线拍卖系统(源码+数据库+文档)
  • 【leetcode】202. 快乐数
  • IKE工作过程