深入解决Linux内存管理之page fault处理

2023-11-17

说明:

  1. Kernel版本:4.14
  2. ARM64处理器,Contex-A53,双核
  3. 使用工具:Source Insight 3.5, Visio

1. 概述

内核实现只是在进程的地址空间建立好了vma区域,并没有实际的虚拟地址到物理地址的映射操作。这部分就是在Page Fault异常错误处理中实现的。

Linux内核中的Page Fault异常处理很复杂,涉及的细节也很多,malloc/mmap的物理内存映射只是它的一个子集功能,下图大概涵盖了出现Page Fault的情况:

下边就开始来啃啃硬骨头吧。

 资料直通车:Linux内核源码技术学习路线+视频教程内核源码

学习直通车:Linux内核源码内存调优文件系统进程管理设备驱动/网络协议栈

2. Arm64处理

Page Fault的异常处理,依赖于体系结构,因此有必要来介绍一下Arm64的处理。代码主要参考:arch/arm64/kernel/entry.S。

Arm64在取指令或者访问数据时,需要把虚拟地址转换成物理地址,这个过程需要进行几种检查,在不满足的情况下都能造成异常:

  1. 地址的合法性,比如以39有效位地址为例,内核地址的高25位为全1,用户进程地址的高25位为全0;
  2. 地址的权限检查,这里边的权限位都位于页表条目中;

从上图中可以看到,最后都会调到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.1do_fault

do_fault函数用于处理文件页异常,包括以下三种情况:

  1. 读文件页错误;
  2. 写私有文件页错误;
  3. 写共享文件页错误;

3.2do_anonymous_page

匿名页的缺页异常处理调用本函数,在以下情况下会触发:

  1. malloc/mmap分配了进程地址空间区域,但是没有进行映射处理,在首次访问时触发;
  2. 用户栈不够的情况下,进行栈区的扩大处理;

3.3do_swap_page

如果访问Swap页面出错(页面不在内存中),则从Swap cache或Swap文件中读取该页面。由于在4.14内核版本中,do_swap_page调用的很多函数都是空函数,无法进一步的了解,大体的流程如下图:

3.4do_wp_page

do_wp_page函数用于处理写时复制(copy on write),会在以下两种情况处理:

  1. 创建子进程时,父子进程会以只读方式共享私有的匿名页和文件页,当试图写的时候,触发页错误异常,从而复制物理页,并创建映射;
  2. 进程创建私有文件映射,读访问后触发异常,将文件页读入到page cache中,并以只读模式创建映射,之后发生写访问后,触发COW;

关键的复制工作是由wp_page_copy完成的:

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

深入解决Linux内存管理之page fault处理 的相关文章

  • Google BQ:运行参数化查询,其中参数变量是 BQ 表目标

    我正在尝试从 Linux 命令行为 BQ 表目标运行 SQL 此 SQL 脚本将用于多个日期 客户端和 BQ 表目标 因此这需要在我的 BQ API 命令行调用中使用参数 标志 parameter 现在 我已经点击此链接来了解参数化查询 h
  • 我们真的应该使用 Chef 来管理 sudoers 文件吗?

    这是我的问题 我担心如果 Chef 破坏了 sudoers 文件中的某些内容 可能是 Chef 用户错误地使用了说明书 那么服务器将完全无法访问 我讨厌我们完全失去客户的生产服务器 因为我们弄乱了 sudoers 文件并且无法再通过 ssh
  • tcpdump 是否受 iptables 过滤影响?

    如果我的开发机器有iptables规则到FORWARD一些数据包 这些数据包是否被 tcpdump 捕获 我有这个问题 因为我知道存在其他链称为INPUT如果数据包路由到 它会过滤发往应用程序的数据包FORWARD链 它会到达吗tcpdum
  • Linux 上的 Pervasive ODBC 错误 [01000][unixODBC][驱动程序管理器]无法打开 lib '/usr/local/psql/lib/odbcci.so':找不到文件

    我正在尝试让 Pervasive v10 客户端 ODBC 在 Centos 6 上运行 据我所知 没有 64 位 ODBC 客户端 因此我必须使用 32 位客户端 我终于成功安装了它 但尝试使用时出现以下错误 isql v mydsn 0
  • 使用循环在 C 中管道传输两个或多个 shell 命令

    我正在尝试执行ls wc l通过 C 语言程序 而不是使用命令行 这是我当前的工作代码 int main int pfds 2 pipe pfds pid t pid fork if pid 0 The child process clos
  • Bash - 在与当前终端分开的另一个终端中启动命令的新实例

    我有一个简单的 bash 脚本 test sh 设置如下 bin bash args if args 0 check capture then watch n 1 ls lag home user capture0 watch n 1 ls
  • 与 pthread 的进程间互斥

    我想使用一个互斥体 它将用于同步对两个不同进程共享的内存中驻留的某些变量的访问 我怎样才能做到这一点 执行该操作的代码示例将非常感激 以下示例演示了 Pthread 进程间互斥体的创建 使用和销毁 将示例推广到多个进程作为读者的练习 inc
  • Intel 上的 gcc 中的 _mm_pause 用法

    我参考过这个网页 https software intel com en us articles benefitting power and performance sleep loops https software intel com
  • Mac OS X 上的 /proc/self/cmdline / GetCommandLine 等效项是什么?

    如何在不使用 argc argv 的情况下访问 Mac OS X 上的命令行 在 Linux 上 我会简单地阅读 proc self cmdline or use GetCommandLine在 Windows 上 但我找不到 Mac OS
  • 如何查找哪个 Yocto 项目配方填充图像根文件系统上的特定文件

    我经常与 Yocto 项目合作 一个常见的挑战是确定文件为何 或来自什么配方 包含在 rootfs 中 这有望从构建系统的环境 日志和元数据中得出 理想情况下 一组命令将允许将文件链接回源 即配方 我通常的策略是对元数据执行搜索 例如gre
  • Apache 访问 Linux 中的 NTFS 链接文件夹

    在 Debian jessie 中使用 Apache2 PHP 当我想在 Apache 的文档文件夹 var www 中创建一个新的小节时 我只需创建一个指向我的 php 文件所在的外部文件夹的链接 然后只需更改该文件夹的所有者和权限文件夹
  • 这种文件锁定方法可以接受吗?

    我们有 10 个 Linux 机器 每周必须运行 100 个不同的任务 这些计算机主要在我们晚上在家时执行这些任务 我的一位同事正在开发一个项目 通过使用 Python 自动启动任务来优化运行时间 他的程序将读取任务列表 抓取一个打开的任务
  • cdc_acm:无法设置 dtr/rts - 无法与 USB cdc 设备通信

    我试图使用 pic24fj128gb206 枚举 usb cdc 设备 设备似乎已正确枚举 但是当我将设备连接到 Linux PC 时 我从内核收到以下警告消息 cdc acm 1 8 1 6 7 1 0 failed to set dtr
  • 复制目录内容

    我想将目录 tmp1 的内容复制到另一个目录 tmp2 tmp1 可能包含文件和其他目录 我想使用C C 复制tmp1的内容 包括模式 如果 tmp1 包含目录树 我想递归复制它们 最简单的解决方案是什么 我找到了一个解决方案来打开目录并读
  • 使用自定义堆的类似 malloc 的函数

    如果我希望使用自定义预分配堆构造类似 malloc 的功能 那么 C 中最好的方法是什么 我的具体问题是 我有一个可映射 类似内存 的设备 已将其放入我的地址空间中 但我需要获得一种更灵活的方式来使用该内存来存储将随着时间的推移分配和释放的
  • 无法显示 Laravel 欢迎页面

    我的服务器位于 DigitalOcean 云上 我正在使用 Ubuntu 和 Apache Web 服务器 我的家用计算机运行的是 Windows 7 我使用 putty 作为终端 遵循所有指示https laracasts com ser
  • [A-Z] 表示 [A-Za-z] 是怎么回事?

    我已经注意到 至少在我使用的一些基于 Unix 的系统上 ls A Z 已经给了我预期的结果ls A Za z 让我无法轻松获得以大写字母开头的该死的文件列表 我刚刚遇到了同样的事情grep 我无法让它停止与小写字母匹配 A Z 直到我最终
  • 如何在文件中搜索多行模式?

    我需要找到包含特定字符串模式的所有文件 我想到的第一个解决方案是使用find管道与xargs grep find iname py xargs grep e YOUR PATTERN 但是 如果我需要查找跨越多行的模式 我就会陷入困境 因为
  • 如何找到进程启动时使用的原始用户名?

    有一个 perl 脚本需要以 root 身份运行 但我们必须确保运行该脚本的用户最初没有以用户 foo 身份登录 因为它将在脚本运行期间被删除 那么 我如何查明自登录以来可能已多次起诉的用户是否在该链中的任何时间都没有模拟过 foo 我发现
  • 从另一个 python 脚本获取返回信息

    我在 Linux 上 我有一个 python 脚本 我想从另一个 python 脚本调用它 我不想将其作为模块导入 为了一层安全性 现在为了学术练习 因为我想弄清楚这一点 我实际上想让一个脚本使用 os system 或另一个类似的函数 并

随机推荐

  • Blender学习笔记(1)快捷键

    鼠标中键 转动视角 shift 中键 平移视角 ctrl 中键上下移动 缩放画面 shift 左键 多选 a是全选 b是多选 在编辑模式下是挤出 ctrl 右键 套索工具 ctrl shift 右键 diselect 中间滚轮滚动 缩放画面
  • Qt Creator 常见问题记录

    1 资源文件不显示 由于不小心删除了工程目录中的qrc文件 重新加回去后 发现项目树中Resources不见了 如下图 图中是显示的 解决办法 选择项目右键 清除 再重新缩放项目 即可看到 2 多个项目 如何选择某个项目作为启动项 VS中可
  • C++ SFINAE简介和std::enable_if_t的简单使用

    最近整理代码时发现了有人常会使用std enable if t 据说这个是C 14才支持的写法 因此再次勾起了我的整理欲 但要是熟悉std enable if的话其实也没啥太大难度 自认为这种使用方式主要提供了一种通过模板偏特化来实现的类型
  • 字符设备驱动相关函数

    Linux内核中 a 使用cdev结构体来描述字符设备 b 通过其成员dev t来定义设备号 分为主 次设备号 以确定字符设备的唯一性 c 通过其成员file operations来定义字符设备驱动提供给VFS的接口函数 如常见的open
  • ubuntu 与 windows terminal zsh 美化教程

    ubuntu 与 windows terminal zsh 美化教程 安装 zsh 和 oh my zsh 选择与安装主题 使用自带的主题 安装 powerlevel10k 主题 1 下载 p10k 主题 2 下载 Meslo LG M R
  • io使用率高运行堵塞怎么解决?linux系统由io使用率高引起的运行堵塞的解决方法

    1 在宝塔查看服务器负载100 而cpu和内存使用率都正常 输入top命令查看平均负载 查看结果负载果然很高 2 接着查看io使用情况 使用iotop工具 安装 yum install iotop 运行命令 iotop 如果安装不上是因为i
  • 实体类(VO,DO,DTO)的划分

    经常会接触到VO DO DTO的概念 本文从领域建模中的实体划分和项目中的实际应用情况两个角度 对这几个概念进行简析 得出的主要结论是 在项目应用中 VO对应于页面上需要显示的数据 表单 DO对应于数据库中存储的数据 数据表 DTO对应于除
  • Spring学习笔记2:注解开发、AOP思想、整合Mybatis、事务

    文章目录 7 使用注解开发 7 1 属性如何注入 1 Component 2 Value 7 2 衍生的注解 7 3 自动装配 7 4 作用域 1 Scope singleton 7 5 小结 9 使用java的方式配置Spring 9 1
  • flink连接kafka报:org.apache.kafka.common.errors.TimeoutException: Timeout expired while fetching topic

    报错信息 Caused by org apache flink runtime JobException Recovery is suppressed by NoRestartBackoffTimeStrategy at org apach
  • 跑通SOLOV1-V2实例分割代码,并训练自己的数据集。

    系统平台 Ubuntu18 04 硬件平台 RTX2080 super cuda和cudnn版本 cuda10 0 cudnn 7 5 6 pytorch版本 pytorch1 2 0 环境安装 创建solo虚拟环境 conda creat
  • 图(一)之邻接表Adjacency List

    开始攻克图的算法 先从最简单的存储开始实现 本文关于邻接表的实现 邻接表是图的存储中最简单也是最基本的存储结构 基于链表的思想实现的 在邻接表中 对于中的每个顶点建立一个单链表 第i个单链表中的节点表示依附于顶点的vi的边 每个节点由3个域
  • Android进阶之光:Dagger2原理简要分析

    Dagger2注入框架原理简要分析 使用Dagger2需要的依赖 implementation com google dagger dagger android 2 46 implementation com google dagger d
  • 实训九 网络服务的基本配置

    实训九 网络服务的基本配置 2017 年 4 月 16 日 今日公布 实训目标 完成本次实训 将能够 配置网卡 配置xinetd超级服务器 实训准备 两台计算机 其中一台安装RHEL6系统 该系统出来root账号外 至少还有一个普通账号 另
  • 【Linux系统编程】静态库和共享库

    个人博客 https blog csdn net Newin2020 spm 1011 2415 3001 5343 专栏地址 Linux系统编程 专栏定位 整理一下 C 相关的知识点 供大家学习参考 如果有收获的话 欢迎点赞 收藏 您的支
  • YOLOv5小目标检测(方法与评价)

    问题 当我们在对小目标数据集进行检测时 发现无论如何都有一些漏检的 其中我们也添加一些模块 以及其他的一些改进方法 如注意力 激活函数等等 结果始终不会令人满意 map也没有丝毫的提升 目的 增加对小目标的检测能力 不能产生漏检 自述 许多
  • ARM芯片学习(S5PV210开发)——GPIO控制LED

    1 GPIO介绍 GPIO general purpose input output 通用输入输出 GPIO就是芯片的引脚 是比较特殊的引脚 可以通过代码来操作 控制引脚的高低电平以及工作模式 与GPIO相对的就是固定功能的引脚 我们不能通
  • FPGA笔记8——串口通信(回环实验)

    目录 串口通信原理 串行通信基础知识 处理器与外部设备通信的两种方式 串行通信的通信方式 串行通信的传输方向 常见的串行通信接口 异步串口通信UART基础知识 数据格式 传输速率 接口标准 RS232接口 串口通信实验RS 232 实验任务
  • LeetCode-斐波那契数列

    class Solution public int Fibonacci int n if n 0 return 0 if n 1 return 1 return Fibonacci n 1 Fibonacci n 2 int a 0 b 1
  • 1 RocketMQ简介

    简介 RocketMQ是由阿里捐赠给Apache的一款低延迟 高并发 高可用 高可靠的分布式消息中间件 经历了淘宝双十一的洗礼 RocketMQ既可为分布式应用系统提供异步解耦和削峰填谷的能力 同时也具备互联网应用所需的海量消息堆积 高吞吐
  • 深入解决Linux内存管理之page fault处理

    说明 Kernel版本 4 14 ARM64处理器 Contex A53 双核 使用工具 Source Insight 3 5 Visio 1 概述 内核实现只是在进程的地址空间建立好了vma区域 并没有实际的虚拟地址到物理地址的映射操作