故事背景:前天晚上,在极客星球的群里,有人提出一个问题:
他的问题(场景)可以理解为这样:当一个进程要访问的文件物理页已经被其他进程加载进系统了(类似场景:共享内存,加载共享lib库等),那么这个进程自己第一次访问文件页时(读或者写),是否发生缺页中断?
球友们各抒已见,发现问题涉及的细节很多,随着讨论深入,很多基础概念理解大家都得到了加深。
最后我们都会总结一下问题和答案(问题闭环), 今天先分享一篇经典图解缺页中断处理文章给大家,希望大家喜欢,可以为后续掌握Linux内存子系统核心知识打良好基础。
对问题感兴趣的同学,也可以加入极客星球一起来学习讨论,加深理解。
1. 概述
Linux内核中的Page Fault
异常处理很复杂,涉及的细节也很多,虚拟地址到物理地址的映射操作。这部分就是在Page Fault
异常错误处理中实现的。malloc/mmap
的物理内存映射只是它的一个子集功能,下图大概涵盖了出现Page Fault
的情况:
下边就开始来啃啃硬骨头吧。
分析环境:
Kernel版本:4.14
ARM64处理器,Contex-A53,双核
使用工具:Source Insight 3.5, Visio
2. Arm64处理
Page Fault
的异常处理,依赖于体系结构,因此有必要来介绍一下Arm64
的处理。代码主要参考:arch/arm64/kernel/entry.S
。
Arm64在取指令或者访问数据时,需要把虚拟地址转换成物理地址,这个过程需要进行几种检查,在不满足的情况下都能造成异常:
地址的合法性,比如以39有效位地址为例,内核地址的高25位为全1,用户进程地址的高25位为全0;
地址的权限检查,这里边的权限位都位于页表条目中;
从上图中可以看到,最后都会调到do_mem_abort
函数,这个函数比较简单,直接看代码,位于arch/arm64/mm/fault.c
:
/*
* Dispatch a data abort to the relevant handler.
*/
asmlinkage void __exception do_mem_abort(unsigned long addr, unsigned int esr,
struct pt_regs *regs)
{
const struct fault_info *inf = esr_to_fault_info(esr);
struct siginfo info;
if (!inf->fn(addr, esr, regs))
return;
pr_alert("Unhandled fault: %s (0x%08x) at 0x%016lx\n",
inf->name, esr, addr);
mem_abort_decode(esr);
info.si_signo = inf->sig;
info.si_errno = 0;
info.si_code = inf->code;
info.si_addr = (void __user *)addr;
arm64_notify_die("", regs, &info, esr);
}
该函数中关键的处理:根据传进来的esr
获取fault_info
信息,从而去调用函数。struct fault_info
用于错误状态下对应的处理方法,而内核中也定义了全局结构fault_info
,存放了所有的情况。主要的错误状态和处理函数对应如下:
static const struct fault_info fault_info[] = {
{ do_bad, SIGBUS, 0, "ttbr address size fault" },
{ do_bad, SIGBUS, 0, "level 1 address size fault" },
{ do_bad, SIGBUS, 0, "level 2 address size fault" },
{ do_bad, SIGBUS, 0, "level 3 address size fault" },
{ do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 0 translation fault" },
{ do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 1 translation fault" },
{ do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 2 translation fault" },
{ do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 3 translation fault" },
{ do_bad, SIGBUS, 0, "unknown 8" },
{ do_page_fault, SIGSEGV, SEGV_ACCERR, "level 1 access flag fault" },
{ do_page_fault, SIGSEGV, SEGV_ACCERR, "level 2 access flag fault" },
{ do_page_fault, SIGSEGV, SEGV_ACCERR, "level 3 access flag fault" },
{ do_bad, SIGBUS, 0, "unknown 12" },
{ do_page_fault, SIGSEGV, SEGV_ACCERR, "level 1 permission fault" },
{ do_page_fault, SIGSEGV, SEGV_ACCERR, "level 2 permission fault" },
{ do_page_fault, SIGSEGV, SEGV_ACCERR, "level 3 permission fault" },
...
};
从代码中可以看出:
出现0/1/2/3级页表转换错误时,会调用
do_translation_fault
,实际中do_translation_fault
最终也会调用到do_page_fault
;出现1/2/3级页表访问权限的时候,会调用
do_page_fault
;其他的错误则调用
do_bad
,其中未列出来的部分还包括do_sea
等操作函数;
do_translation_fault
do_page_fault
do_page_fault
函数为页错误异常处理的核心函数,与体系结构相关,上图中的handle_mm_fault
函数为通用函数,也就是不管哪种处理器结构,最终都会调用到该函数。
3. handle_mm_fault
handle_mm_fault
用于处理用户空间的页错误异常:
进程在用户模式下访问用户虚拟地址,触发页错误异常;
进程在内核模式下访问用户虚拟地址,触发页错误异常;从
do_page_fault
函数的流程图中也能看出来,当触发异常的虚拟地址属于某个vma
,并且拥有触发页错误异常的权限时,会调用到handle_mm_fault
函数,而handle_mm_fault
函数的主要逻辑是通过__handle_mm_fault
来实现的。
流程如下图:
3.1 do_fault
do_fault
函数用于处理文件页异常,包括以下三种情况:
读文件页错误;
写私有文件页错误;
写共享文件页错误;
3.2 do_anonymous_page
匿名页的缺页异常处理调用本函数,在以下情况下会触发:
malloc/mmap分配了进程地址空间区域,但是没有进行映射处理,在首次访问时触发;
用户栈不够的情况下,进行栈区的扩大处理;
3.3 do_swap_page
如果访问Swap页面
出错(页面不在内存中),则从Swap cache
或Swap文件
中读取该页面。由于在4.14内核
版本中,do_swap_page
调用的很多函数都是空函数,无法进一步的了解,大体的流程如下图:
3.4 do_wp_page
do_wp_page
函数用于处理写时复制(copy on write
),会在以下两种情况处理:
创建子进程时,父子进程会以只读方式共享私有的匿名页和文件页,当试图写的时候,触发页错误异常,从而复制物理页,并创建映射;
进程创建私有文件映射,读访问后触发异常,将文件页读入到
page cache
中,并以只读模式创建映射,之后发生写访问后,触发COW
;
关键的复制工作是由wp_page_copy
完成的:
机会总是留给有准备的人,欢迎大家加入极客星球,极客星球是一个全面提升技术的社区,极客星球会分享很多核心技术的理解,相互交流,帮助大家快速成长,学习和掌握后台核心技术,深入理解Linux系统,理解技术核心概念,夯实基本功,扩展技术视野,疑难解答,带领大家长期坚持学习,掌握核心技术,努力成为技术专家,对星球感兴趣的,点击查看-> 极客星球:
- END -
看完一键三连在看,转发,点赞
是对文章最大的赞赏,极客重生感谢你
推荐阅读
你好,这里是极客重生,我是阿荣,大家都叫我荣哥,从华为->外企->到互联网大厂,目前是大厂资深工程师,多次获得五星员工,多年职场经验,技术扎实,专业后端开发和后台架构设计,热爱底层技术,丰富的实战经验,分享技术的本质原理,希望帮助更多人蜕变重生,拿BAT大厂offer,培养高级工程师能力,成为技术专家,实现高薪梦想,期待你的关注!点击蓝字查看我的成长之路。
校招/社招/简历/面试技巧/大厂技术栈分析/后端开发进阶/优秀开源项目/直播分享/技术视野/实战高手等, 极客星球希望成为最有技术价值星球,尽最大努力为星球的同学提供面试,跳槽,技术成长帮助!详情查看->极客星球
求点赞,在看,分享三连