Linux内存管理 —— 通过实验学习和理解CoW(2)

文章目录

  • 作者
  • 环境
  • 概述
  • 正文
    • 父进程执行fork时将可写的页面设置成只读
      • copy_mm
      • dup_mm
      • dup_mmap
      • copy_page_range
    • 父进程首先写时,触发CoW
      • handle_pte_fault
      • do_wp_page
      • wp_page_copy
    • 子进程随后在写时触发缺页

作者

pengdonglin137@163.com

环境

Linux-6.5 + ARM64

概述

前一篇通过实验的方法理解了一下CoW,下面大致分析一下Linux内核源码实现。

我们知道,CoW是父进程在fork时,将自己的私有可写的页面的映射属性设置为只读,然后映射信息跟子进程共享,后面fork完成后,父子进程先发起写操作的一方会触发CoW,而后发起的也会触发缺页,但是不会CoW,而是复用已有的页面。

正文

下面分成几个小题进行分析,为了方便理解,对函数具体实现进行了精简。

父进程执行fork时将可写的页面设置成只读

执行fork时,内核的trace日志,可以点这里查看。

在执行clone的时候,会调用copy_mm复制父进程的地址空间给子进程:

copy_mm

static int copy_mm(unsigned long clone_flags, struct task_struct *tsk)
{struct mm_struct *mm, *oldmm;tsk->min_flt = tsk->maj_flt = 0;tsk->nvcsw = tsk->nivcsw = 0;tsk->mm = NULL;tsk->active_mm = NULL;oldmm = current->mm;/* 如何要clone一个内核线程,不需要创建mm_struct,因为内核线程会借用普通进程的mm_struct */if (!oldmm)return 0;/* 如果指定了CLONE_VM标志,表示要创建的时一个普通的用户线程(如通过pthread_create),进程内部的所有线程共享mm_struct,所以这里只需要增加mm_struct的引用计数即可*/if (clone_flags & CLONE_VM) {mmget(oldmm);mm = oldmm;} else {// 要创建的是一个普通的进程(或者理解为普通的用户主线程)mm = dup_mm(tsk, current->mm);}// 对于普通的进程,mm和active_mm的内容相同。对于内核线程,mm是NULL,active_mm指向被借用的哪个进程的mm_structtsk->mm = mm;tsk->active_mm = mm;...return 0;
}

dup_mm

这个函数用来根据传入的task和mm_struct,创建一个新的mm_struct,也就是子进程的地址空间。

static struct mm_struct *dup_mm(struct task_struct *tsk,struct mm_struct *oldmm)
{struct mm_struct *mm;int err;// 从slub中分配一个mm_structmm = allocate_mm();// 先继承父进程的mm_struct,然后再根据实际情况重新初始化部分成员memcpy(mm, oldmm, sizeof(*mm));// 重新初始化子进程的mm_struct的部分成员,如分配pgd等mm_init(mm, tsk, mm->user_ns);// 拷贝父进程的地址空间err = dup_mmap(mm, oldmm);...return mm;
}

dup_mmap

父进程调用这个函数给子进程拷贝自己的地址空间。

static __latent_entropy int dup_mmap(struct mm_struct *mm,struct mm_struct *oldmm)
{struct vm_area_struct *mpnt, *tmp;int retval;unsigned long charge = 0;LIST_HEAD(uf);VMA_ITERATOR(old_vmi, oldmm, 0);VMA_ITERATOR(vmi, mm, 0);mmap_write_lock_killable(oldmm);mmap_write_lock_nested(mm, SINGLE_DEPTH_NESTING);// 继承parent的计数mm->total_vm = oldmm->total_vm;mm->data_vm = oldmm->data_vm;mm->exec_vm = oldmm->exec_vm;mm->stack_vm = oldmm->stack_vm;...// 根据需要的entry数给maple树分配空间retval = vma_iter_bulk_alloc(&vmi, oldmm->map_count);// 遍历parent的mm_struct中的vmafor_each_vma(old_vmi, mpnt) {struct file *file;// VM_DONTCOPY表示在fork时不允许拷贝if (mpnt->vm_flags & VM_DONTCOPY) {// 既然不允许拷贝,那么就从parent那里继承过来的计数减去不允许拷贝的字节数vm_stat_account(mm, mpnt->vm_flags, -vma_pages(mpnt));continue;}// 到这里,说明parent的vma可以拷贝charge = 0;if (mpnt->vm_flags & VM_ACCOUNT) {unsigned long len = vma_pages(mpnt);charge = len;}// 复制parent的vma结构体到新的vma中,然后对部分成员重新初始化,返回给tmptmp = vm_area_dup(mpnt);// 复制parent的vma的内存策略retval = vma_dup_policy(mpnt, tmp);tmp->vm_mm = mm;// VM_WIPEONFORK 表示在fork时清除child的vma信息if (tmp->vm_flags & VM_WIPEONFORK) {  /** VM_WIPEONFORK gets a clean slate in the child.* Don't prepare anon_vma until fault since we don't* copy page for current vma.*/tmp->anon_vma = NULL;} else if (anon_vma_fork(tmp, mpnt))  // 建立匿名页反向映射数据结构goto fail_nomem_anon_vma_fork;// 如果是文件映射,file指向被映射的文件的file结构file = tmp->vm_file;if (file

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

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

相关文章

Rust---有关介绍

目录 Rust---有关介绍变量的操作Rust 数值库:num某些基础数据类型序列(Range)字符类型单元类型 发散函数表达式(! 语句) Rust—有关介绍 得益于各种零开销抽象、深入到底层的优化潜力、优质的标准库和第三方库实现,Ru…

蚁剑流量分析

蚁剑流量分析 在靶机上面上传一个一句话木马&#xff0c;并使用蚁剑连接&#xff0c;进行抓包, 一句话木马内容 <?php eval($_POST[1]); defalut编码器 在使用蚁剑连接的时候使用default编码器 连接之后进行的操作行为是查看当前目录(/var/www/html)下的文件&#xff0…

数据结构进阶篇 之 【插入排序】详细讲解(直接插入排序,希尔排序)

千万不要因为一件事不会做而失去信心&#xff0c;你又不是只有这一件事不会&#xff0c;你还有很多呢 一、插入排序 1.直接插入排序 InsertSort 1.1 基本思想 1.2 实现原理 1.3 代码实现 1.4 直接插入排序的特性总结 2.希尔排序 ShellSort 2.1 基本思想 2.2 实现原理 …

Sora 基础作品之 DiT:Scalable Diffusion Models with Transformer

Paper name Scalable Diffusion Models with Transformers (DiT) Paper Reading Note Paper URL: https://arxiv.org/abs/2212.09748 Project URL: https://www.wpeebles.com/DiT.html Code URL: https://github.com/facebookresearch/DiT TL;DR 2022 年 UC Berkeley 出…

罗克韦尔AB的PLC协议和西门子PLC协议转换网关

下面是罗克韦尔(AB)的Compact系列的PLC与西门子S7-1500之间的通讯的配置&#xff0c;实现AB的标签数组与西门子DB数据块之间通讯。 首先在AB的PLC内建立输入和输出数组&#xff0c;用于接收和写入S7-1500的PLC数据&#xff0c;名称分别是IN_INT16、OUT_OUT16&#xff0c;输入80…

为“自研”的KV数据库编写JDBC驱动

一觉醒来&#xff0c;受到梦的启发&#xff0c;自研了一套K/V数据库系统&#xff0c;因为"客户"一直催促我提供数据库的JDBC驱动&#xff0c;无奈之下&#xff0c;只好花费一个上午的时间为用户编写一个。 我们知道&#xff0c;JDBC只定义一系列的接口, 具体的实现需…

6个黑科技网站,永久免费

1、http://mfsc123.com https://www.mfsc123.com 一个非常赞的免费商用素材导航网站。 收集了各种免费、免版权的图片、插画、视频、视频模板、音乐、音效、字体、图标网站。 再也不用担心版权问题&#xff0c;都能免费商用&#xff0c;自媒体作者必备。 而且还在每个网站…

WeekPaper:GraphTranslator将知识图谱与大模型对齐

GraphTranslator: 将图模型与大型语言模型对齐&#xff0c;用于开放式任务。 将基于图的结构和信息与大型语言模型的能力整合在一起&#xff0c;以提高在涉及复杂和多样数据的任务中的性能。其目标是利用图模型和大型语言模型的优势&#xff0c;解决需要处理和理解结构化和非结…

Python深度学习034:cuda的环境如何配置

文章目录 1.安装nvidia cuda驱动CMD中看一下cuda版本:下载并安装cuda驱动2.创建虚拟环境并安装pytorch的torch_cuda3.测试附录1.安装nvidia cuda驱动 CMD中看一下cuda版本: 注意: 红框的cuda版本,是你的显卡能装的最高的cuda版本,所以可以选择低于它的版本。比如我的是11…

Prometheus+grafana环境搭建redis(docker+二进制两种方式安装)(四)

由于所有组件写一篇幅过长&#xff0c;所以每个组件分一篇方便查看&#xff0c;前三篇 Prometheusgrafana环境搭建方法及流程两种方式(docker和源码包)(一)-CSDN博客 Prometheusgrafana环境搭建rabbitmq(docker二进制两种方式安装)(二)-CSDN博客 Prometheusgrafana环境搭建m…

HarmonyOS实战开发-一次开发,多端部署-视频应用

介绍 随着智能设备类型的不断丰富&#xff0c;用户可以在不同的设备上享受同样的服务&#xff0c;但由于设备形态不尽相同&#xff0c;开发者往往需要针对具体设备修改或重构代码&#xff0c;以实现功能完整性和界面美观性的统一。OpenHarmony为开发者提供了“一次开发&#x…

Ubuntu20.04安装MatlabR2018a

一、安装包 安装包下载链接 提取码&#xff1a;kve2 网上相关教程很多&#xff0c;此处仅作为安装软件记录&#xff0c;方便后续软件重装&#xff0c;大家按需取用。 二、安装 1. 相关文件一览 下载并解压文件后&#xff0c;如下图所示&#xff1a; 2. 挂载镜像并安装 2…

python实战之宝塔部署flask项目

一. 项目 这个demo只是提供了简单的几个api接口, 并没有前端页面 # -*- coding: utf-8 -*- import flask as fk from flask import jsonify, requestapp fk.Flask(__name__)app.route(/api/hello, methods[GET]) def get_data():return hello world# 假设我们要提供一个获取用…

rabbitmq死信交换机,死信队列使用

背景 对于核心业务需要保证消息必须正常消费&#xff0c;就必须考虑消费失败的场景&#xff0c;rabbitmq提供了以下三种消费失败处理机制 直接reject&#xff0c;丢弃消息&#xff08;默认&#xff09;返回nack&#xff0c;消息重新入队列将失败消息投递到指定的交换机 对于核…

vi/vim编辑器

一:vi/vim编辑器介绍 vi\vim 是visual interface简称&#xff0c;是Linux中最经典的文本编辑器 vim是vi的加强版&#xff0c;兼容vi的所有命令&#xff0c;而且还具有shell编程能力 二vi/vim编译器的三种工作模式 一:命令模式 二输入模式:编程模式&#xff0c;此模式下可对…

【电路笔记】-逻辑与门

逻辑与门 文章目录 逻辑与门1、概述2、2 输入晶体管与门3、数字与门类型4、7408 四路 2 输入与门逻辑与门是一种数字逻辑电路,仅当其所有输入均为高电平时,其输出才会变为高电平至逻辑电平 1。 1、概述 数字逻辑与门的输出状态仅在其任何输入处于逻辑电平“0”时再次返回“低…

每日一题 --- 右旋字符串[卡码][Go]

右旋字符串 题目&#xff1a;55. 右旋字符串&#xff08;第八期模拟笔试&#xff09; (kamacoder.com) 题目描述 字符串的右旋转操作是把字符串尾部的若干个字符转移到字符串的前面。给定一个字符串 s 和一个正整数 k&#xff0c;请编写一个函数&#xff0c;将字符串中的后面…

HarmonyOS 应用开发之同步任务开发指导 (TaskPool和Worker)

同步任务是指在多个线程之间协调执行的任务&#xff0c;其目的是确保多个任务按照一定的顺序和规则执行&#xff0c;例如使用锁来防止数据竞争。 同步任务的实现需要考虑多个线程之间的协作和同步&#xff0c;以确保数据的正确性和程序的正确执行。 由于TaskPool偏向于单个独…

scRNA+bulk+MR:动脉粥样硬化五个GEO数据集+GWAS,工作量十分到位

今天给大家分享一篇JCR一区&#xff0c;单细胞bulkMR的文章&#xff1a;An integrative analysis of single-cell and bulk transcriptome and bidirectional mendelian randomization analysis identified C1Q as a novel stimulated risk gene for Atherosclerosis 标题&…

MySQL 索引优化(一)

索引创建原则 先写代码&#xff0c;再建索引 不应该在创建完表之后立马就创建索引&#xff0c;等主体业务开发完毕以后&#xff0c;再把涉及到该表的 sql 分析过后再建立索引。联合索引尽量覆盖查询条件 在设计一个联合索引的时候&#xff0c;让联合索引尽可能的包含 sql 语句…