dirty file page
转自:https://www.cnblogs.com/zhiminyu/p/17330763.html
0.前言
Linux 内核Page Cache 和Buffer Cache 关系及演化历史 一文中讲过Linux 2.4之后将Page Cache和Buffer Cache 进行了融合,在buffer_head 中添加了b_page,很容易就能找到缓存的Page Cache,而buffer_head 的存在就是能够快速确定页中的一个块在磁盘中的地址。
Linux内核由于存在page cache, 一般修改的文件数据并不会马上同步到磁盘,会缓存在内存的page cache中,我们把这种和磁盘数据不一致的页称为脏页,脏页会在合适的时机同步到磁盘。为了回写page cache中的脏页,需要标记页为脏(dirty)。
脏页跟踪是指内核如何在合适的时机记录文件页为脏,以便内核在进行脏页回写时,知道将哪些页面回写到磁盘。匿名页不需要跟踪脏页,因为不需要同步到磁盘;私有文件页也不需要跟踪脏页,因为映射的时候,可写页会映射为只读,写访问会发生写时复制,转变为匿名页;所以只有共享的文件页需要跟踪脏页。跟踪有两个层面:一个是页表项记录,一个是页描述符记录。
访问文件页有两种方式:
一种是通过mmap映射文件;
一种是通过文件系统的write接口操作文件;
本文将对这两种方式进行讲解。在Linux内核中,因为跟踪脏页会涉及到文件回写、缺页异常、反向映射等技术,所以本文也重点讲解在Linux内核中如何跟踪脏页。
1. 引入脏页提高性能
Linux在设计IO模块的时候,认为读写操作的紧迫性是不一样的,读操作的紧迫性要高于写操作。所以Linux的写默认是延迟的,因为这样不仅仅可以显著的提高效率:
写操作合并:多次写操作才会真正的发起一次写物理磁盘,大幅提升IO性能;
IO栈中还有通用块层和IO调度层,在具体的文件系统层有文件在文件系统中的逻辑块映射,也就是文件的文件块在磁盘上对应的磁盘块的地址,这时候在通用块层会把这些信息封装成BIO对象,然后提交到gendisk->request_queue,在提交的过程中,如果BIO和已有的request中的BIO在物理地址上是连续的,那么这些BIO就会合并成一个request。在IO调度层,一次request就意味着一次IO,因为这时候磁盘需要重新寻址,所以这个合并其实是在io调度层入队列的时候完成的;
你可以通过iostat查看物理盘IO情况的时候看到对应的监控指标:rrqm/s、wrqm/s等;
读操作比写操作更紧迫:
通常延迟写物理磁盘不会导致进程挂起,写到page cache然后修改该页的PG_dirty标志即可返回(如果open的时候设置了sync标志或者调用了fsync、sync函数,那么会将写page cache的内容封装成一个IO request放到IO调度层的request_queue中,然后由调度层的调度算法来写到物理磁盘);
但是如果读操作读的时候page cache中没有缓存数据,读操作就需要去读物理磁盘,此时延迟读就会让用户感知,这就很糟糕了,用户就会感觉OS卡顿,Linux作为桌面系统的时候,他还是要优先保证和用户良好的交互性;
你还可以从IO scheduler的调度算法deadline的默认配置感受一下,读延迟是500ms,写延迟是5s,这就很明显的感受到Linux对读写操作紧迫性的区别对待;
2. mmap 映射的文件页
基本过程如下:
step1,通过mmap映射共享文件;
step2,第一次访问文件页时,发生缺页后读文件页到page cache,如果是写访问则设置相应进程的页表项为脏、可写;
step3,脏页回写时,会通过反向映射机制,查找映射这个页的每一个vma, 设置相应进程的页表项为只读,清脏标记;
step4,假如第二次写访问这个文件页时,脏页的处理有两种情况:
page cache中的文件页还未回写到磁盘(step3 之前), 此刻,这个文件页依然是脏页。因为相应进程的页表项为脏、可写,所以可以直接写这个页;
page cache中的文件页已经回写到磁盘(step3 之后), 此刻,这个文件页不再是脏页。因为页表项为只读,所以写访问会发生写时复制缺页异常,异常处理中将处理共享文件页映射,重新将相应进程的页表项为设置为脏、可写
2.1 第一次写访问文件页
/mm/memory.chandle_pte_fault->do_fault->do_shared_fault|->__do_fault //读文件页到page cache|->do_page_mkwrite| ->vmf->vma->vm_ops->page_mkwrite| ->filemap_page_mkwrite /mm/filemap.c| ->set_page_dirty| ->__set_page_dirty_buffers| ->TestSetPageDirty //设置页描述符脏标记| ->__set_page_dirty //page cache中标记页为脏 |->finish_fault //设置页表项->alloc_set_pte->maybe_mkwrite //设置页表项脏、可写
2.2 脏页回写
1 /mm/page_writeback.c2 3 write_cache_pages4 5 ->clear_page_dirty_for_io //对于回写的每一个页6 7 |->page_mkclean //清脏标记 mm/rmap.c 8 9 | ->page_mkclean_one //反向映射查找这个页的每个vma,调用清脏标记和写保护处理 10 11 | ->entry = pmdp_invalidate(vma, address, pmd); 12 | entry = pmd_wrprotect(entry); //写保护处理,设置只读 13 | entry = pmd_mkclean(entry); //清脏标记 set_pte_at(vma->vm_mm, address, pte, entry) //设置到页表项中 14 15 |->set_page_dirty
2.3 第二次写访问文件页
1)脏页还没有回写时(确切的说是调用clear_page_dirty_for_io之前),页描述符已经设置了脏标记,页表项已经设置了脏标记、可写。
这时可以直接写访问文件页,不会发生缺页。
2)脏页已经回写时(确切的说是调用clear_page_dirty_for_io之后),页描述符已经清除了脏标记,页表项已经清除了脏标记,且只读。
这时写访问文件页会发生写时复制缺页异常(访问权限错误缺页)。
调用链如下:
1 /mm/memory.c2 3 handle_pte_fault4 5 ->if (vmf->flags & FAULT_FLAG_WRITE) { //vma可写6 if (!pte_write(entry)) //页表项没有可写属性7 do_wp_page(vmf) //写时复制缺页异常处理8 9 ->if (unlikely((vma->vm_flags & (VM_WRITE|VM_SHARED)) //是共享可写的文件映射vma 10 wp_page_shared 11 12 |->do_page_mkwrite 13 14 | ->vmf->vma->vm_ops->page_mkwrite 15 16 | ->filemap_page_mkwrite /mm/filemap.c 17 18 | ->set_page_dirty 19 20 | ->__set_page_dirty_buffers 21 22 | ->TestSetPageDirty //设置页描述符脏标记 23 24 | ->__set_page_dirty //page cache中标记页为脏 25 |->finish_mkwrite_fault 26 27 ->wp_page_reuse 28 29 ->entry = maybe_mkwrite(pte_mkdirty(entry), vma); //重新设置页表项脏、可写
2.4 再次写访问
重复上面步骤
3. write 接口操作的文件页
由于通过write接口访问文件页时,会读取文件页到page cache,不会映射到任何进程地址空间,所有这种方式跟踪脏页是通过设置/清除页描述符脏标记来实现。
3.1 第一次写访问文件页
会首先读文件页到page cache,然后将用户空间写缓冲区数据写到page cache,调用链如下:
1 /fs/ext4/file.c2 3 ext4_file_write_iter4 5 ->__generic_file_write_iter6 7 ->generic_perform_write8 9 ->a_ops->write_begin //写之前处理 分配page cache页 10 11 ->__block_commit_write 12 13 ->mark_buffer_dirty 14 15 ->__set_page_dirty //设置页为脏(设置页描述符脏标记) 16 17 ->iov_iter_copy_from_user_atomic //用户空间写缓冲区数据写到page cache页
3.2 脏页回写
1 write_cache_pages //mm/page-writeback.c 2 3 ->clear_page_dirty_for_io 4 5 ->TestClearPageDirty(page) //清除页描述符脏标记
3.3 第二次写访问文件页
脏页回写之前,页描述符脏标志位依然被置位,等待回写, 不需要设置页描述符脏标志位。
脏页回写之后,页描述符脏标志位是清零的,文件写页调用链会设置页描述符脏标志位。
4. 总结
1)对于mmap映射的共享文件页,因为这个文件页可能会被多个进程共享到多个vma中,所以通过页表项的脏标志位来跟踪脏页:第一次写访问发生缺页异常会读文件页到page cache中并设置进程的页表项的脏标志,回写之前(clear_page_dirty_for_io完成之前),页表项的脏标志是置位的,回写的时候(clear_page_dirty_for_io的调用)会通过反向映射机制将所有映射这个页的页表项的脏标志位清零并设置只读权限,回写之后(clear_page_dirty_for_io完成之后),再次的写访问会发生写时复制缺页异常,再次设置页表项的脏标志位,如此重复,从而跟踪了脏页。
2)对于直接通过write接口访问的文件页,因为这个文件页只会被读取到page cache中,并没有映射到任何进程地址空间,进程写访问是通过copy_from_user的方式,所以通过页描述符记录脏页。回写之前(clear_page_dirty_for_io完成之前),写文件的时候通过文件系统的写文件的调用链会设置页描述符脏标志位,回写的时候(clear_page_dirty_for_io的调用)会清除页描述符脏标志位,回写之后(clear_page_dirty_for_io完成之后),再次通过write接口写访问时,再次通过文件系统的写文件的调用链会再次设置页描述符脏标志位,如此重复,从而跟踪了脏页。
相关文章:
dirty file page
转自:https://www.cnblogs.com/zhiminyu/p/17330763.html 0.前言 Linux 内核Page Cache 和Buffer Cache 关系及演化历史 一文中讲过Linux 2.4之后将Page Cache和Buffer Cache 进行了融合,在buffer_head 中添加了b_page,很容易就能找到缓存的…...

HTAP(Hybrid Transactional/Analytical Processing)系统之统一存储的实时之道
文章目录 HTAP与时俱进LASER中的存储关键知识LSM(Log-Structured Merge Tree)SkipList(跳表)CDC(Changed Data Capture)SST(Sorted Sequence Table) 特性列组(Column Gro…...

【linux】tcpdump 使用
tcpdump 是一个强大的网络分析工具,可以在 UNIX 和类 UNIX 系统上使用,用于捕获和分析网络流量。它允许用户截取和显示发送或接收过网络的 TCP/IP 和其他数据包。 一、安装 tcpdump 通常是默认安装在大多数 Linux 发行版中的。如果未安装,可…...

数字图像处理常用算法的原理和代码实现详解
本专栏详细地分析了常用图像处理算法的数学原理、实现步骤。配有matlab或C实现代码,并对代码进行了详细的注释。最后,对算法的效果进行了测试。相信通过这个专栏,你可以对这些算法的原理及实现有深入的理解! 如有疑问…...
Pandas实战100例 | 案例 26: 检测异常值
案例 26: 检测异常值 知识点讲解 在数据分析中,检测和处理异常值(或离群值)是一个重要的步骤。异常值可能会影响数据的整体分析。一种常用的方法是使用四分位数和四分位数间距(IQR)来识别异常值。 四分位数和 IQR: …...

C语言学习NO.11-字符函数strlen,strlen函数的使用,与三种strlen函数的模拟实现
(一)strlen函数的使用 strlen函数的演示 #include <stdio.h> #include <string.h>int main() {char arr1[] "abcdef";char arr2[] "good";printf("arr1 %d,arr2 %d",strlen(arr1),strlen(arr2));return …...
Vue3+ts获取props的值并且定义props值的类型的方法。
1.引入withDefaults模块,给defineProps绑定默认值。 import { withDefaults } from vue2.定义Props传输值的类型。 interface Props {// 类型type: string;name: string;id: number; }3.给props的值设置默认值。 const props withDefaults(defineProps<Prop…...
EasyExcel 不使用科学计数发并以千分位展示
EasyExcel 不使用科学计数发并以千分位展示 不使用科学计数法 不使用科学计数法 BigDecimalStringConverter 将 BigDecimal 类型的数值转换为字符串类型,并将其导出到 Excel 文件中。在 convertToExcelData 方法中,我们将 BigDecimal 转换为字符串&…...

【Python机器学习】SVM——调参
下面是支持向量机一个二维二分类数据集的训练结果: import mglearn import matplotlib.pyplot as plt from sklearn.svm import SVCplt.rcParams[font.sans-serif] [SimHei] plt.rcParams[axes.unicode_minus] False X,ymglearn.tools.make_handcrafted_dataset()…...

网络传输(TCP)
前言 我们tcpdump抓包时会看到除报文数据外,前面还有一段其他的数据,这段数据分为两部分,ip包头(一般20字节)和tcp包头(一般20字节),一般这两个头长度和为40,我们直接跳…...
MFC模拟消息发送,自定义以及系统消息
在MFC框架下,有很多系统已经定义好的消息,例如ON_WM_LBUTTONDOWN()、ON_WM_MBUTTONDOWN()等等。我们在使用的时候只需要声明并调用就可以了,最简单的用法。 提升了一点难度的用法就是自己设置自定义消息,再提升一点难度的就是如何…...
并发,并行,线程与UI操作
并行和并发是计算机领域中两个相关但不同的概念。 并行(Parallel)指的是同时执行多个任务或操作,它依赖于具有多个处理单元的系统。在并行计算中,任务被分成多个子任务,并且这些子任务可以同时在不同的处理单元上执行…...
react 6种方式编写样式
在React中,编写样式主要有以下几种方式: 1. 内联样式: 直接在React组件中使用style属性来定义样式。这种方式比较适合定义动态的样式,因为它允许你将JavaScript表达式作为样式的值。 2. 外部样式表 :通过创建外部的…...

计算机找不到msvcr100.dll的多种解决方法分享,轻松解决dll问题
msvcr100.dll作为系统运行过程中不可或缺的一部分,它的主要功能在于提供必要的运行时支持,确保相关应用程序能够顺利完成编译和执行。因此,当操作系统或应用程序在运行阶段搜索不到该文件时,自然会导致各类依赖于它的代码无法正常…...

系分笔记数据库反规范化、SQL语句和大数据
文章目录 1、概要2、反规范化3、大数据4、SQL语句5、总结 1、概要 数据库设计是考试重点,常考和必考内容,本篇主要记录了知识点:反规范化、SQL语句及大数据。 2、反规范化 数据库遵循范式的设计,使得多表查询和连接表查询较多的时…...

php实现支付宝商户转账
目录 一:背景介绍 一:准备工作 三:代码实现 一:背景介绍 最近工作中,要用到支付宝的商家转账功能,用php代码实现,网上找的内容,有些是老版本的实现,有些是调用sdk&am…...
并发编程(十一)
性能测试的常用命令 1、Netstat是在内核中访问网络连接状态及其相关信息的程序,它能够显示协议统计和当前TCP/IP的网络连接。 Netstat命令的常用格式如下: netstat -a:显示所有网络连接和侦听端口。 netstat -b:显示在创建网络…...

vue3 指令详解
系列文章目录 TypeScript 从入门到进阶专栏 文章目录 系列文章目录前言一、v-model (双向绑定功能)二、v-bind(用于将一个或多个属性绑定到元素的属性或组件的 prop)三、v-if、v-else、v-else-if(用于根据条件选择性地渲染元素)四、v-show(根…...

数据科学竞赛平台推荐
✅作者简介:人工智能专业本科在读,喜欢计算机与编程,写博客记录自己的学习历程。 🍎个人主页:小嗷犬的个人主页 🍊个人网站:小嗷犬的技术小站 🥭个人信条:为天地立心&…...
安全防御之安全审计技术
安全防御中的安全审计技术是保障信息系统安全的重要手段之一。其主要目标是对信息系统及其活动进行记录、审查和评估,以确保系统符合安全策略、法规要求,并能够及时发现潜在的安全风险和异常行为。通过安全审计,可以对系统中的各种活动进行记…...
Java 语言特性(面试系列2)
一、SQL 基础 1. 复杂查询 (1)连接查询(JOIN) 内连接(INNER JOIN):返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...
CVPR 2025 MIMO: 支持视觉指代和像素grounding 的医学视觉语言模型
CVPR 2025 | MIMO:支持视觉指代和像素对齐的医学视觉语言模型 论文信息 标题:MIMO: A medical vision language model with visual referring multimodal input and pixel grounding multimodal output作者:Yanyuan Chen, Dexuan Xu, Yu Hu…...
在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:
在 HarmonyOS 应用开发中,手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力,既支持点击、长按、拖拽等基础单一手势的精细控制,也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档,…...

苍穹外卖--缓存菜品
1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得,如果用户端访问量比较大,数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据,减少数据库查询操作。 缓存逻辑分析: ①每个分类下的菜品保持一份缓存数据…...
管理学院权限管理系统开发总结
文章目录 🎓 管理学院权限管理系统开发总结 - 现代化Web应用实践之路📝 项目概述🏗️ 技术架构设计后端技术栈前端技术栈 💡 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 🗄️ 数据库设…...

基于 TAPD 进行项目管理
起因 自己写了个小工具,仓库用的Github。之前在用markdown进行需求管理,现在随着功能的增加,感觉有点难以管理了,所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD,需要提供一个企业名新建一个项目&#…...

MFC 抛体运动模拟:常见问题解决与界面美化
在 MFC 中开发抛体运动模拟程序时,我们常遇到 轨迹残留、无效刷新、视觉单调、物理逻辑瑕疵 等问题。本文将针对这些痛点,详细解析原因并提供解决方案,同时兼顾界面美化,让模拟效果更专业、更高效。 问题一:历史轨迹与小球残影残留 现象 小球运动后,历史位置的 “残影”…...
Web中间件--tomcat学习
Web中间件–tomcat Java虚拟机详解 什么是JAVA虚拟机 Java虚拟机是一个抽象的计算机,它可以执行Java字节码。Java虚拟机是Java平台的一部分,Java平台由Java语言、Java API和Java虚拟机组成。Java虚拟机的主要作用是将Java字节码转换为机器代码&#x…...
LOOI机器人的技术实现解析:从手势识别到边缘检测
LOOI机器人作为一款创新的AI硬件产品,通过将智能手机转变为具有情感交互能力的桌面机器人,展示了前沿AI技术与传统硬件设计的完美结合。作为AI与玩具领域的专家,我将全面解析LOOI的技术实现架构,特别是其手势识别、物体识别和环境…...
第八部分:阶段项目 6:构建 React 前端应用
现在,是时候将你学到的 React 基础知识付诸实践,构建一个简单的前端应用来模拟与后端 API 的交互了。在这个阶段,你可以先使用模拟数据,或者如果你的后端 API(阶段项目 5)已经搭建好,可以直接连…...