page cache 在内核中的数据结构

news2024/11/26 21:20:22

page cache 在内核中的数据结构是一个叫做 address_space 的结构体:struct address_space。

struct address_space {
 struct inode  *host;  // 关联 page cache 对应文件的 inode
 struct radix_tree_root page_tree; // 这里就是 page cache。里边缓存了文件的所有缓存页面
 spinlock_t  tree_lock; // 访问 page_tree 时用到的自旋锁
 unsigned long  nrpages; // page cache 中缓存的页面总数
         ..........省略..........
 const struct address_space_operations *a_ops; // 定义对 page cache 中缓存页的各种操作方法
         ..........省略..........
}

基树 radix_tree  (和mysql中B+很类似)

struct radix_tree_node {
 void __rcu *slots[RADIX_TREE_MAP_SIZE]; //包含 64 个指针的数组。用于指向下一层节点或者缓存页
 unsigned char offset; //父节点中指向该节点的指针在父节点 slots 数组中的偏移
 unsigned char count;//记录当前节点的 slots 数组指向了多少个节点
 struct radix_tree_node *parent; // 父节点指针
 struct radix_tree_root *root; // 根节点
    
         ..........省略.........

 unsigned long tags[RADIX_TREE_MAX_TAGS][RADIX_TREE_TAG_LONGS]; // radix_tree 中的二维标记数组,用于标记子节点的状态。
};

radix_tree 的标记

PG_dirty 和 PG_writeback 就是缓存页的状态,而内核不仅仅是需要在 page cache 中高效搜索请求数据所在的缓存页,还需要高效搜索给定状态的缓存页。

比如:快速查找 page cache 中的所有脏页。但是如果此时 page cache 中的大部分缓存页都不是脏页,那么顺序遍历 radix_tree 的方式就实在是太慢了,所以为了快速搜索到脏页,就需要在 radix_tree 中的每个节点 radix_tree_node 中加入一个针对其所有子节点的脏页标记,如果其中一个子节点被标记被脏时,那么这个子节点对应的父节点 radix_tree_node 结构中的对应脏页标记位就会被置 1 。

而用来存储脏页标记的正是上小节中提到的 tags 二维数组。其中第一维 tags[] 用来表示标记类型,有多少标记类型,数组大小就为多少,比如 tags[0] 表示 PG_dirty 标记数组,tags[1] 表示 PG_writeback 标记数组。

  • 内核首先调用 find_get_entry 方法根据缓存页的 offset 到 page cache 中去查找看请求的文件页是否已经在页高速缓存中。如果存在直接返回。

  • 如果请求的文件页不在 page cache 中,内核则会首先会在物理内存中分配一个内存页,然后将新分配的内存页加入到 page cache 中,并增加页引用计数。

  • 随后会通过 address_space_operations 重定义的 readpage 激活块设备驱动从磁盘中读取请求数据,然后用读取到的数据填充新分配的内存页。

page cache 中查找缓存页

  • 内核首先调用 find_get_entry 方法根据缓存页的 offset 到 page cache 中去查找看请求的文件页是否已经在页高速缓存中。如果存在直接返回。

  • 如果请求的文件页不在 page cache 中,内核则会首先会在物理内存中分配一个内存页,然后将新分配的内存页加入到 page cache 中,并增加页引用计数。

  • 随后会通过 address_space_operations 重定义的 readpage 激活块设备驱动从磁盘中读取请求数据,然后用读取到的数据填充新分配的内存页。

文件页的预读

  • 当前窗口(current window):  表示进程本次文件请求可以直接读取的页面集合,这个集合中的页面全部已经缓存在 page cache 中,进程可以直接读取返回。当前窗口中包含进程本次请求的文件页以及上次内核预读的文件页集合。表示进程本次可以从 page cache 直接获取的页面范围。

  • 预读窗口(ahead window):预读窗口的页面都是内核正在预读的文件页,它们此时并不在 page cache 中。这些页面并不是进程请求的文件页,但是内核根据空间局部性原理假定它们迟早会被进程请求。预读窗口内的页面紧跟着当前窗口后面,并且内核会动态调整预读窗口的大小(有点类似于 TCP 中的滑动窗口)。

 

 触发内核进行文件预读的场景:

  1. 当进程采用 Buffered IO 模式通过系统调用 read 进行文件读取时,内核会触发预读。

  2. 通过 POSIX_FADV_WILLNEED 参数执行系统调用 posix_fadvise,会通知内核这个指定范围的文件页不就将会被访问。触发预读。

  3. 当进程显示执行 readahead() 系统调用时,会显示触发内核的预读动作。

  4. 当内核为内存文件映射区域分配一个物理页面时,会触发预读。关于内存映射的相关内容,笔者会在后面的文章为大家详细介绍。

  5. 和 posix_fadvise 一样的道理,系统调用 madvise 主要用来指定内存文件映射区域的访问模式。可通过 advice = MADV_WILLNEED 通知内核,某个文件内存映射区域中的指定范围的文件页在不久将会被访问。触发预读。

预读算法逻辑中,内核通过 struct file_ra_state 结构中封装的文件预读信息来判断文件的读取是否为顺序读。比如:

  • 通过检查 ra->prev_pos 和 offset 是否相同,来判断当前请求页是否和最近一次请求的页相同,如果重复访问同一页,预读就会停止。

  • 通过检查 ra->prev_pos 和 offset 是否相邻,来判断进程是否顺序读取文件。如果是顺序访问文件,预读就会增加。

  • 当进程第一次访问文件时,并且请求的第一个文件页在文件中的偏移量为 0 时表示进程从头开始读取文件,那么内核就会认为进程想要顺序的访问文件,随后内核就会从文件的第一页开始创建一个新的当前窗口,初始的当前窗口总是 2 的次幂,窗口具体大小与进程的读操作所请求的页数有一定的关系。请求页数越大,当前窗口就越大,直到最大值 ra->ra_pages 。

  • 相反,当进程第一次访问文件,但是请求页在文件中的偏移量不为 0 时,内核就会假定进程不准备顺序读取文件,函数就会暂时禁止预读。

  • 一旦内核发现进程在当前窗口内执行了顺序读取,那么预读窗口就会被建立,预读窗口总是紧挨着当前窗口的最后一页。

  • 预读窗口的大小和当前窗口有关,如果已经被预读的页不在 page cache 中(可能内存紧张,预读页被回收),那么预读窗口就会是 当前窗口大小 - 2,最小值为 4。否则预读窗口就会是当前窗口的4倍或者2倍。

  • 当进程继续顺序访问文件时,最终预读窗口就会变为当前窗口,随后新的预读窗口就会被建立,随着进程顺序地读取文件,预读会越来越大,但是内核一旦发现对于文件的访问 offset 相对于上一次的请求页 ra->prev_pos 不是顺序的时候,当前窗口和预读窗口就会被清空,预读被暂时禁止。

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

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

相关文章

拼多多购物中的4个开关需尽快关闭,防止个人购买信息泄露

拼多多购物中的4个开关需尽快关闭,防止个人购买信息泄露 随着网络购物的普及,越来越多的人选择在拼多多等平台进行购物。然而,在享受便利的同时,我们也要警惕个人购买信息泄露的风险。在拼多多购物时,有些设置可能会影…

Hyperledger Fabric核心配置文件(1)

1、core.yaml core.yaml配置文件是Peer节点的示例配置文件,具体路径在fabric-samples/config目 录下。该core.yaml示例配置文件共指定了如下六大部分内容。 1.日志部分 日志记录级别有6种: CRITICAL、 ERROR、 WARNING、 NOTICE、 INFO、 DEBUG. …

CUDA矩阵乘法GEMM优化,从全局内存到共享内存优化的详细流程

在​未优化的矩阵乘法​CA*B中,a、b和c分别是指向矩阵 A、B 和 C 的全局内存的指针;blockDim.x、blockDim.y、 和TILE_DIM都等于 w。wxw-thread 块中的每个线程计算 C 的tile中的一个元素,row并且col是由特定线程计算的 C 中元素的行和列。该…

celery----异步任务、延时任务、定时任务

Celery 是一个强大的分布式任务队列,它可以让任务的执行完全脱离主程序,甚至可以被分配到其他主机上运行。我们通常使用它来实现异步任务(async task)和定时任务(crontab)。它的架构组成如下图 &#xff1a…

初学帆软踩得坑——数据填报_Excel数据导入

第一次做数据填报,按照教程做完在用excel导入工具本地数据报表的时候出现 1、整块空白合并单元格,数据无法填入的现象 2、表格重新导入一批,无法成功入库,导致只能导入一次,如下图: 说明:点击…

python网络编程(四),用面向对象方式实现文件上传下载

一:背景 在之前已经实现了文件的下载,现在再来完善上传功能,并且使用面向对象来封装,让代码看起来更加清楚明了。 二: 使用规则和运行结果 下载文件,下载格式 get 文件名 get空格后面直接接文件名称&…

MySQL-SQL InnoDB引擎 (下)

♥️作者:小刘在C站 ♥️个人主页: 小刘主页 ♥️努力不一定有回报,但一定会有收获加油!一起努力,共赴美好人生! ♥️学习两年总结出的运维经验,以及思科模拟器全套网络实验教程。专栏&#xf…

【直播预告】HarmonyOS极客松赋能直播第三期:一次开发多端部署与ArkTS卡片开发

直播预约通道: 【直播预告】HarmonyOS极客松赋能直播第三期:一次开发多端部署与ArkTS卡片开发

朴素模式匹配算法(暴力寻找字串)

目录 0. 前言1. 算法简介2. 代码实现3. 运行结果 0. 前言 使用朴素模式匹配算法查找子串是否位于主串中 开发环境:Dev-Cpp 操作系统:Windows10 专业版 1. 算法简介 朴素模式匹配算法,也称为暴力模式匹配算法或穷举法,是一种简…

自己动手写C语言float浮点数转换字符串的函数

最近在项目中用到了holtek厂商的HT45F24A和BA45F5650两款单片机。 用的开发工具是HT-IDE3000,烧录软件是HOPE3000。 这两款单片机都是8位的单片机,支持寄存器位操作。 HT45F24A单片机不带UART串口,要想实现串口功能,只能自己用定时…

基于肺部图片与文本信息的多模态模型架构

文章题为 「A transformer-based representation learning model with unified processing of multimodal input for clinical diagnostics」 https://www.nature.com/articles/s41551-023-01045-x (arXiv版链接: https://arxiv.org/abs/2306.00864) htt…

2020年全国硕士研究生入学统一考试管理类专业学位联考数学试题——解析版

2020 级考研管理类联考数学真题 一、问题求解(本大题共 15 小题,每小题 3 分,共 45 分)下列每题给出 5 个选项中,只有一个是符合要求的,请在答题卡上将所选择的字母涂黑。 1、某产品去年涨价 10%&#xf…

备战2024秋招面试题-Vue的框架原理

前言: \textcolor{Green}{前言:} 前言: 💞快秋招了,那么这个专栏就专门来记录一下,同时呢整理一下常见面试题 💞部分题目来自自己的面试题,部分题目来自网络整理 给我冲 学习目标&am…

阿里云服务器ECS介绍_云主机_服务器托管_弹性计算

阿里云服务器安全可靠、弹性可伸缩,CPU可选256核、内存选到3072GB,云服务器ECS规格通用型、计算型、内存型、通用算力型、裸金属、GPU、大数据等ECS实例规格,公网带宽可选到200M,绑定弹性公网EIP带宽可达1000M,共享带宽…

9.外部中断

1.中断概念: (1)STM32的每个IO口都可以作为外部中断输入; (2)stm32的中断控制器支持19个外部中断/事件请求 线0~15:对应外部IO口的输入中断;线16:连接到PVD输出&#…

基于jsp+Servlet+mysql的汽车销售系统

基于jspServletmysql的汽车销售系统 一、系统介绍二、功能展示1.项目骨架2.登录界面3.首页4.购物车5.添加车辆6、编辑车辆信息 四、其它1.其他系统实现五.获取源码 一、系统介绍 项目类型:Java web项目 项目名称:基于JSPServlet的汽车销售系统 项目架…

新后端漏洞之----SSRF漏洞(服务端请求伪造)

笔记 前言SSRF漏洞概述SSRF漏洞检测与挖掘SSRF漏洞的回显分类SSRF漏洞利用SSRF漏洞防御 前言 这几天各种技术面试接踵而至,压得我喘不过气了!然后面试官问了我这个SSRF漏洞原理和利用方式以及防御手段,当然同时还问了好几个Top10漏洞&#x…

【React】React Hooks解析

React Hooks解析 React 16.8 认识和体验Hooks 为什么需要Hook? Hook是 React 16.8 的新增特性,它可以让我们在不编写class的情况下使用state以及其他的React特性(比如生命周期) 我们先来思考一下class组件相对于函数式组件有什么优势&…

企业知识竞赛答题pk活动怎么做?

随着互联网的发展,越来越多的企事业单位开始利用答题小程序进行线上PK答题活动,目的在于组织员工学习企业文化或是进行专题答题活动以适应时代的进步。其中最主流的有:网络安全知识竞赛、安全生产知识竞赛、企业文化PK答题竞赛、红色党史知识…

js中的树以及优先遍历!

树 什么是树? 在生活中,大家对树肯定不陌生,小朋友都知道树不就是一类植物嘛,不管在任何地方都有各种各样的树。但是在计算机科学里面树是什么呢?一种分层数据的抽象模型,在我们前端工作中无处不在。在 J…