Linux内存管理:(五)反向映射RMAP

文章说明:

  • Linux内核版本:5.0

  • 架构:ARM64

  • 参考资料及图片来源:《奔跑吧Linux内核》

  • Linux 5.0内核源码注释仓库地址:

    zhangzihengya/LinuxSourceCode_v5.0_study (github.com)

1. 前置知识:page数据结构中的相关字段

本文主要对反向映射RMAP进行讲解,在讲解之前,我们先了解下page数据结构中与RMAP相关的几个字段:

  • mapping:表示页面所指向的地址空间。内核中的地址空间通常有两个不同的地址空间,—个用于文件映射页面,如在读取文件时,地址空间用于将文件的内容数据与装载数据的存储介质区关联起来;另—个用于匿名映射。内核使用一个简单直接的方式实现了“一个指针,两种用途”,mapping成员的最低两位用于判断是否指向匿名映射或KSM页面的地址空间。如果指向匿名页面,那么mapping成员指向匿名页面的地址空间数据结构anon_vma。
  • _refcount:表示内核中引用该页面的次数。
    • 当_refcount的值为0时,表示该页面为空闲页面或即将要被释放的页面
    • 当_refcount的值大于0时,表示该页面已经被分配且内核正在使用,暂时不会被释放
  • _mapcount:表示这个页面被进程映射的个数,即已经映射了多少个用户PTE。每个用户进 程都拥有各自独立的虚拟空间和一份独立的页表,所以可能出现多个用户进程地址空间同时映射到一个物理页面的情况,RMAP系统就是利用这个特性来实现的。_mapcount主要用于RMAP系统中。
    • 若_mapcount等于-1,表示没有PTE映射到页面
    • 若_mapcount等于0,表示只有父进程映射到页面。匿名页面刚分配时,初始化为0。

2. RMAP的背景

用户进程在使用虚拟内存的过程中,从虚拟内存页面映射到物理内存页面时,PTE保留这个记录,page数据结构中的_mapcount记录有多少个用户PTE映射到物理页面。用户PTE是指用户进程地址空间和物理页面建立映射的PTE,不包括内核地址空间映射物理页面时产生的PTE。有的页面需要迁移,有的页面长时间不使用,需要交换到磁盘。在交换之前,必须找出哪些进程使用这个页面,然后解除这些映射的用户PTE。一个物理页面可以同时被多个进程的虚拟内存映射,但是一个虚拟页面同时只能映射到一个物理页面。

在Linux 2.4内核中,为了确定某一个页面是否被某个进程映射,必须遍历每个进程的页表,因此工作量相当大,效率很低。在Linux2.5内核开发期间,提出了反问映射(Reverse Mapping,RMAP)的概念。

3. RMAP的主要数据结构

RMAP的主要目的是从物理页面的page数据结构中找到有哪些映射的用户PTE,这样页面回收模块就可以很快速和高效地把这个物理页面映射的所有用户PTE都解除并回收这个页面。

为了达到这个目的,内核在页面创建时需要建立RMAP的“钩子”,即建立相关的数据结构,RMAP系统中有两个重要的数据结构:一个是anon_vma,简称AV;另一个是anon_vma_chain,简称AVC。

anon_vma 数据结构:

// 主要用于连接物理页面的 page 数据结构和 VMA 的 vm_area_struct 数据结构
struct anon_vma {// 指向 anon_vma 数据结构的根节点struct anon_vma *root;		/* Root of this anon_vma tree */// 保护 anon_vma 数据结构中链表的读写信号量struct rw_semaphore rwsem;	/* W: modification, R: walking the list */// 引用计数atomic_t refcount;...// 指向父 anon_vma 数据结构struct anon_vma *parent;	/* Parent of this anon_vma */// 红黑树根节点。anon_vma 内部有一颗红黑树struct rb_root_cached rb_root;
};

在这里插入图片描述

anon_vma_chain 数据结构:

// 起枢纽的作用,比如连接父子进程间的 struct anon_vma 数据结构
struct anon_vma_chain {// 指向 VMA。可以指向父进程的 VMA,也可以指向子进程的 VMA,具体情况需要具体分析struct vm_area_struct *vma;// 指向 anon_vma 数据结构。可以指向父进程的 anon_vma,也可以指向子进程的 anon_vma,具体情况需要具体分析struct anon_vma *anon_vma;// 链表节点,通常把 anon_vma_chain 添加到 vma->anon_vma_chain 链表中struct list_head same_vma;   /* locked by mmap_sem & page_table_lock */// 红黑树节点,通常把 anon_vma_chain 添加到 anon_vma->rb_root 的红黑树中struct rb_node rb;			/* locked by anon_vma->rwsem */...
};

4. 父进程产生匿名页面

父进程为自己的进程地址空间VMA分配物理内存时,通常会产生匿名页面。例如:

用户态malloc()分配虚拟内存→ 用户进程写内存→ 内核发生缺页异常→ do_anonymous_page()

父进程产生匿名页面时的状态如下图所示:

在这里插入图片描述

  • 父进程的每个VMA中有一个anon_vma数据结构(下文用AVp来表示),vma->anon_vma指向AVp
  • 和VMAp相关的物理页面page->mapping都指向AVp
  • 有一个anon_vma_chain数据结构,其中avc->vma指向VMAp,avc->av指向AVp
  • 把anon_vma_chain添加到VMAp->anon_vma_chain链表中
  • 把anon_vma_chain添加到AVp->anon_vma红黑树中

5. 根据父进程创建子进程

父进程通过fork()系统调用创建子进程时,子进程会复制父进程的VMA数据结构的内容,并且会复制父进程的PTE内容到子进程的页表中,实现父、子进程共享页表。多个不同子进程中的虚拟页面会同时映射到同一个物理页面。另外,多个不相干的进程的虚拟页面可以通过KSM机制映射到同—个物理页面中,这里暂时只讨论前者。为了实现RMAP系统,在子进程复制父进程的VMA时,需要添加RMAP“钩子”。

父进程通过fork调用创建子进程时,RMAP机制的流程如下图所示:

在这里插入图片描述

为了使读者有更真切的理解,下文将根据流程图围绕源代码进行讲解这个过程:

父进程fork子进程->do_fork()->copy_process()->copy_mm()->dup_mm()->dup_mmap()

// 复制父进程的地址空间
static __latent_entropy int dup_mmap(struct mm_struct *mm,struct mm_struct *oldmm)
{...// 遍历父进程所有的 VMAfor (mpnt = oldmm->mmap; mpnt; mpnt = mpnt->vm_next) {struct file *file;...// 新建一个临时用的 VMA 数据结构 tmp,复制父进程 VMA 数据结构的内容到 tmptmp = vm_area_dup(mpnt);...tmp->vm_mm = mm;...// anon_vma_fork() 为子进程创建相应的 anon_vma 数据结构} else if (anon_vma_fork(tmp, mpnt))...// 把 tmp 添加到子进程的红黑树中__vma_link_rb(mm, tmp, rb_link, rb_parent);...// 复制父进程的 PTE 到子进程页表中retval = copy_page_range(mm, oldmm, mpnt);...
}

父进程fork子进程->do_fork()->copy_process()->copy_mm()->dup_mm()->dup_mmap()->anon_vma_fork

// 主要作用是把 VMA 绑定到子进程的 anon_vma 数据结构中
// 参数 vma 表示子进程的 VMA
// 参数 pvma 表示父进程的 VMA
int anon_vma_fork(struct vm_area_struct *vma, struct vm_area_struct *pvma)
{...// 若父进程没有 anon_vma 数据结构,就不需要绑定了if (!pvma->anon_vma)return 0;// anon_vma_clone() 函数:// 遍历父进程VMA中的anon_vma_chain链表寻找anon_vma_chain实例,这里称这个实例为pavc;// 分配一个新的anon_vma_chain数据结构,这里称为anon_vma_chain枢纽;// 通过pavc找到父进程VMA中的anon_vma;// 把这个anon_vma_chain枢纽挂入子进程的VMA的anon_vma_chain链表中,同时把anon_vma_chain枢纽添加到属于父进程的anon_vma->rb_root的红黑树中,使子进程和父进程的VMA之间有一个联系的纽带;error = anon_vma_clone(vma, pvma);if (error)return error;// 若子进程的 VMA 已经创建了 anon_vma 数据结构,说明绑定已经完成if (vma->anon_vma)return 0;// 分配属于子进程的 anon_vma 和 anon_vma_chainanon_vma = anon_vma_alloc();...// get_anon_vma() 增加 anon_vma 数据结构中的 refcount,注意这里增加的是父进程的 anon_vma 中的引用计数get_anon_vma(anon_vma->root);...// 把 anon_vma_chain 挂入子进程的 vma->anon_vma_chain 链表中,同时把 anon_vma_chain 加入子进程的 anon_vma->rb_root 红黑树中// 至此,子进程的 VMA 和父进程的 VMA 之间的纽带建立成功anon_vma_chain_link(vma, avc, anon_vma);...
}

6. 子进程发生写时复制

如果子进程的VMA发生写时复制,那么page->mmapmg指针指向子进程VMA对应的anon_vma数据结构。在do_wp_page()函数中处理写时复制的情况。流程如下图所示:

子进程和父进程共享的匿名页面,子进程的VMA发生写时复制->缺页中断发生->handle_pte_fault()->do_wp_page()->wp_page_copy()->分配一个新的匿名页面->page_add_new_anon_rmap()->__page_set_anon_rmap()使用子进程的anon_vma来设置page->mapping

子进程发生写时复制时,RMAP机制的流程如下图所示:

在这里插入图片描述

7. RMAP的应用

RMAP的典型应用场景如下:

  • kswapd内核线程为了回收页面,需要断开所有映射到该匿名页面的用户PTE
  • 页面迁移时,需要断开所有映射到匿名页面的用户PTE

RMAP的核心函数是try_to_unmap(),内核中的其他模块会调用此函数来断开一个页面的所有映射:

bool try_to_unmap(struct page *page, enum ttu_flags flags)
{struct rmap_walk_control rwc = {.rmap_one = try_to_unmap_one,.arg = (void *)flags,.done = page_mapcount_is_zero,.anon_lock = page_lock_anon_vma_read,};...if (flags & TTU_RMAP_LOCKED)rmap_walk_locked(page, &rwc);elsermap_walk(page, &rwc);// 判断 page 的 _mapcount:// 若 _mapcount 为 -1,说明所有映射到这个页面的用户 PTE 都已经解除完毕,因此返回 true// 否则返回 truereturn !page_mapcount(page) ? true : false;
}

rmap_walk_control 数据结构:

// 用于统一管理 unmap 操作
struct rmap_walk_control {void *arg;// 表示具体断开某个 VMA 上映射的 PTEbool (*rmap_one)(struct page *page, struct vm_area_struct *vma,unsigned long addr, void *arg);// 表示判断一个页面是否断开成功int (*done)(struct page *page);// 实现一个锁机制struct anon_vma *(*anon_lock)(struct page *page);// 表示跳过无效的 VMAbool (*invalid_vma)(struct vm_area_struct *vma, void *arg);
};

以匿名页面为例来介绍RMAP的应用:

try_to_unmap()->rmap_walk()->rmap_walk_anon()

// 断开一个匿名页面的所有映射
// 参数 page 表示需要解除映射的物理页面的 page 数据结构
// 参数 rwc 表示 rmap_walk_control 数据结构
// 参数 locked 表示是否已经加锁
static void rmap_walk_anon(struct page *page, struct rmap_walk_control *rwc,bool locked)
{...if (locked) {// 若 locked 已经加锁// 调用 page_anon_vma() 函数来获取 anon_vma 数据结构anon_vma = page_anon_vma(page);/* anon_vma disappear under us? */VM_BUG_ON_PAGE(!anon_vma, page);} else {// 若 locked 没有加锁// rmap_walk_anon_lock() 函数除了要取回 anon_vma 数据结构外,还会申请一个锁anon_vma = rmap_walk_anon_lock(page, rwc);}...// 遍历 anon_vma->rb_root 红黑树中的 anon_vma_chain,从 anon_vma_chain 中可以// 得到相应的 VMA,然后调用 rmap_one() 来解除用户 PTEanon_vma_interval_tree_foreach(avc, &anon_vma->rb_root,pgoff_start, pgoff_end) {...}...
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/598573.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

目标检测-One Stage-YOLOv2

文章目录 前言一、YOLOv2的网络结构和流程二、YOLOv2的创新点预处理网络结构训练 总结 前言 根据前文目标检测-One Stage-YOLOv1可以看出YOLOv1的主要缺点是: 和Fast-CNN相比,速度快,但精度下降。(边框回归不加限制)…

企业传输大文件时在企业网盘和文件传输平台之间该怎么选?

在当今数字化时代,企业常常需要传输大量文件,包括设计图纸、视频、音乐、数据集等。这些文件可能很大,往往需要高效、安全地传输。对于企业来说,选择合适的工具至关重要。在企业网盘和文件传输平台之间,如何做出正确的…

微信怎么做小程序店铺?如何制作微信小程序店铺

在这个数字化的时代,拥有一个属于自己的线上店铺已经成为了一种趋势。而微信小程序,作为微信平台上的一种轻应用,无疑成为了许多人开店的首选。那么,如何利用微信小程序开设自己的店铺呢?下面就让我来为大家详细解析一…

(03)光刻——半导体电路的绘制

01、绘制精细电路的第一步 金属-氧化物半导体场效应晶体管(MOSFET)的革命,让我们可以在相同面积的晶圆上同时制造出更多晶体管。MOSFET体积越小,单个 MOSFET的耗电量就越少,还可以制造出更多的晶体管,让其发挥作用,可谓是一举多得。可见,制造更小的MOSFET成了关键因素…

专属定制适合个人的知识付费平台,打造个性化品牌与自主管理体验

明理信息科技知识付费saas租户平台 在当今数字化时代,知识付费平台已经成为人们获取专业知识、提升自身素质的重要渠道。然而,公共知识付费平台虽然内容丰富,但难以满足个人或企业个性化的需求和品牌打造。因此,我们提出了专属定…

锂电池寿命预测 | Matlab基于LSTM长短期记忆神经网络的锂电池寿命预测

目录 预测效果基本介绍程序设计参考资料 预测效果 基本介绍 锂电池寿命预测 | Matlab基于LSTM长短期记忆神经网络的锂电池寿命预测 程序设计 完整程序和数据获取方式:私信博主回复Matlab基于LSTM长短期记忆神经网络的锂电池寿命预测。 参考资料 [1] http://t.csdn…

CentOS 7 安装 PPTP

环境: 阿里云试用机: 外网IP:114.55.80.150 内网IP:172.28.11.92 一、服务器安装 PPTP 1、安装 yum install epel-release -y 2、安装pptp yum install pptpd iptables-services -y 3、修改配置 vim /etc/pptpd.conf# 最…

CAAC无人机操作证考证报名流程及白底证件照片制作方法

在这个无人机技术日新月异的时代,拥有一张CAAC民用无人机操作证不仅意味着你能够合法地在天空翱翔,也象征着你对飞行技术的尊重和对规章制度的遵守。如果你怀揣着成为无人机飞行员的梦想,那么,让我们一起揭开CAAC民用无人机操作证…

静态网页设计——美食杰官网(HTML+CSS+JavaScript)

前言 声明:该文章只是做技术分享,若侵权请联系我删除。!! 使用技术:HTMLCSSJS 主要内容:仿照美食杰官网 主要内容 1、首页 首页用html标签分割成多个区域,使用css设置样式,精准…

《软件项目接口安全设计规范》

1.token授权机制 2.https传输加密 3.接口调用防滥用 4.日志审计里监控 5.开发测试环境隔离,脱敏处理 6.数据库运维监控审计 软件全套文档:软件开发全套资料-CSDN博客

RA8803SA 车载用实时时钟模块

内置32.768kHz 晶体单元(频率精度调整完毕)和DTCXO1/100s精度的时间寄存器接口类型:I2C-Bus接口(400kHz)工作电压范围:1.6V to 5.5V温度补偿电压:2.2V to 5.5V计时(保持)电压范围:1.6V to 5.5V可选择输出频率为32.768kHz, 1024Hz,…

书生浦语大模型概述

github 地址:https://github.com/InternLM/tutorial 一、大模型简介 二、书生浦语 介绍 2.1 简介 2.2 模型到应用 如上图所示,从模型到应用通过共需要经过以下4个步骤: 模型评测:选择适合自己需求的模型。 不同的大模型&#x…

YOLOv7独家原创改进:新颖的Shape IoU结合 Inner-IoU,基于辅助边框的IoU损失的同时关注边界框本身的形状和尺度,小目标实现高效涨点

💡💡💡本文改进:一种新的Shape IoU方法结合 Inner-IoU,基于辅助边框的IoU损失的同时,更加关注边界框本身的形状和尺度来计算损失 💡💡💡对小目标检测涨点明显,在VisDrone2019、PASCAL VOC均有涨点 💡💡💡本文改进:一种新的Shape IoU方法,该方法可以通过…

MySQL报错1054 - Unknown column ‘24023A00000‘ in ‘field list‘

MySQL 向表中插入数据时报错: 1054 - Unknown column 24023A00000 in field list 表的设计是: 执行插入数据sql语句后报错: 解决方法: 我设计表时是有id字段的,怎么报错显示字段不在表中??查找了很多资料…

对话小仙炖副总裁张勇:内容价值将成为直播电商的核心趋势和竞争力

“ 激活中医典籍里的智慧,坚持内容化之路,服务好消费者。” 整理 | 飞族 编辑 | 渔舟 出品|极新&北京电子商务协会 随着直播电商的影响力越来越大,对品牌而言,直播不仅是一种单纯的卖货渠道,…

如何使用Pyxamstore快速解析Xamarin AssemblyStore文件

关于Pyxamstore Pyxamstore是一款针对Xamarin AssemblyStore文件(assemblies.blob)的强大解析工具,该工具基于纯Python 2.7开发,支持从一个APK文件中解包并重封装assemblies.blob和assemblies.manifest Xamarin文件。 什么是ass…

nodejs发送消息给钉钉机器人

1.钉钉添加机器人 1.1 新建一个群 --> 群设置 --> 机器人 1.2 机器人管理 --> 添加机器人 1.3 机器人--> 自定义-->添加 1.4 配置信息 备注1:密钥复制出来SEC2c689174c4a8ed49c8a7309a490cd98e0e7f7bc788bb7232d53c738eb5f5d008 备注2:…

深度学习框架TensorFlow2快速入门教程

01 深度学习框架TensorFlow2快速入门教程 目录结构 01 概述 02 准备OVF虚拟机镜像 03 导入Ubuntu22的初始化环境 04 使用VMWare拍摄快照进行备份 05 Docker环境的测试和使用 06 安装Nvidia容器工具包 07 GPU支持的TensorFlow的环境搭建和踩坑 08 拉取非GPU支持的TensorFlow镜…

[ffmpeg系列 02] 音视频基本知识

一 视频 RGB&#xff1a; AV_PIX_FMT_RGB24, ///< packed RGB 8:8:8, 24bpp, RGBRGB… Y&#xff1a;明亮度, Luminance或luma, 灰阶图&#xff0c; UV&#xff1a;色度&#xff0c;Chrominance或Chroma。 YCbCr: Cb蓝色分量&#xff0c;Cr是红色分量。 取值范围&#xff…

一文搞懂Python Web开发 Django

简介 Django是一个主流的Python Web框架&#xff0c;用于快速开发 Web 应用程序。功能强大&#xff0c;Python Web应用开发的第一选择。 特点 ORM&#xff08;对象关系映射&#xff09;&#xff1a; Django 提供了一个强大的 ORM&#xff0c;允许开发者通过 Python 代码来定义…