尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

Linux do_page_fault 处理流程

Linux do_page_fault 处理流程 Linux 内核的缺页异常处理函数do_page_fault是一个庞大而精密的系统它根据不同场景兵分两路一路是为用户态进程服务另一路则是为内核自身“排忧解难”。整个处理流程就像一次精心策划的“案件处理”可以分解为以下几个核心步骤。1. 案发与初步侦查当CPU触发缺页异常会跳转到do_page_fault函数。函数做的第一件事是从CR2寄存器中获取导致异常的虚拟地址并接收一个包含详细信息的错误码以此作为初步排查的依据。2. 关键分岔路口来自用户态还是内核态这是整个流程中最关键的一次分流处理逻辑从这里分道扬镳。场景A异常发生在用户态寻找“合法身份” (VMA)内核会尝试在进程的虚拟内存区域VMA链表中查找包含该错误地址的VMA。VMA记录了进程地址空间的每一块合法区域如堆、栈、内存映射文件。判决有罪地址非法如果找不到对应的VMA或者访问权限不匹配如在只读区域执行写操作这意味着程序访问了它不该碰的内存。内核会判定这是一个段错误Segmentation Fault向进程发送SIGSEGV信号将其终结。无罪地址合法如果找到了对应的VMA且权限检查通过则进入“执行判决”即good_area标签处。场景B异常发生在内核态这种情况更复杂因为内核自身也可能出错也有“打盹”的时候。内核的“自保”机制 (Exception Tables)内核在访问用户空间内存时例如通过get_user()宏知道这些操作可能会失败。因此编译器会生成一个特殊的异常表__ex_table里面记录了“可能出错的指令地址”和对应的“修复代码地址”。判决可修复do_page_fault会查询异常表。如果当前出错的指令地址在表中它会直接修改返回地址让程序跳转到对应的“修复代码”处继续执行。修复代码通常只是简单地返回一个错误码如-EFAULT。这是内核访问用户内存失败的标准处理方式。不可修复如果查不到那就是一个真正的内核错误如解引用空指针。此时内核会绝望地打印出“Oops”消息并尝试终结当前进程或使系统崩溃。3. 真正的“判决执行”handle_mm_fault当确认地址合法且来自用户态或内核的 vmalloc 区内核会调用核心函数handle_mm_fault来实际“解决问题”。这个函数会根据页表项的状态分情况处理匿名页 (Anonymous Page)如果这是一个从未被映射过的地址pte_none内核会调用do_anonymous_page为其分配一个物理页框。文件映射页 (File-mapped Page)如果这是一个映射自文件的页内核会调用do_linear_fault或类似的函数根据VMA中记录的文件操作将数据从磁盘读入内存。被换出的页 (Swapped-out Page)如果页表项表明该页被换出到了交换分区内核会调用do_swap_page将数据从磁盘交换区重新读回内存。写时复制 (Copy-on-Write, COW)如果是写操作触发了只读页的异常意味着要进行写时复制。内核会创建该页的一个副本并将页表项更新为指向新副本然后允许写入。统计与善后在处理完缺页后内核会记录这次异常的类型主缺页错误 (Major Fault)需要从磁盘如文件或交换区读取数据开销巨大。次缺页错误 (Minor Fault)仅需要分配物理页或在内存中进行页表操作开销较小。这些统计数据可以通过perf等工具观察到。
返回列表