关闭linux系统中读写页缓存,Linux文件系统FAQ

Linux文件系统FAQ

2010年03月25日

最近实验室搞了一些列讲座,阿福师兄关于文件系统的讲座帮我弄清楚了一些以前不清楚的问题,以问答的形式对文件系统常见的问题进行了总结。

Q: 文件系统如何看待底层物理块设备?

文件系统把块设备简单的看做线性的组合,即对文件系统而言,块设备是一系列可以读写的块。文件系统不需要知道这些物理设备的实际布局及如何读写,这些是设备驱动的工作。

Q: 跟文件系统相关的系统调用主要有那些?

打开文件open,读取文件read,写文件write,关闭文件close,删除文件unlink,创建目录mkdir,删除目录rmdir等,linux通过VFS提供了符合POSIX标准的接口。

Q: 如何实现一个文件系统?

实现VFS提供的一组文件系统操作接口,向内核注册;

实现用户空间文件系统或堆叠式文件系统;

Q: VFS如何管理super_block,inode,dentry,file,vfsmount等主要数据结构?

参见http://blog.chinaunix.net/u2/87570/showart_2126000 .html;

Q: 哪些接口必须实现?

VFS实现了很多通用接口,如基本所有的读写操作都可直接使用generic_file_aio_read,generic_file_aio_write接口(我的内核版本为2.6.19),ext2的读写就是使用该接口,但各个文件系统必须实现自己的read_page方法,用于从磁盘读取一页的数据(还可实现read_pages,一次读取多页,以提高效率),如果要实现direct_io访问,必须实现direct_IO接口。

read_page的实现需要基于文件系统实际的数据组织,它将用户的文件请求位置(逻辑页号)转换为物理块号,并向通用块层发送请求。

Q: ext2文件系统如何组织文件的数据?

ext2使用长度为15的数组(ext2_inode的一个字段),其中前12个数组元素记录直接块映射,即其内容即为文件前12个块的地址;第13个元素,记录一级索引关系,即该元素的内容为一个块的地址,这个块的内容为一系列块的地址;第14,15个元素分别为二级索引,三级索引。

Q: 内核如何根据用户态传递的路径名得到文件的inode,dentry信息?

通过路径名查找可以通过路径名得到inode,dentry的信息;

Linux提供了path_lookup接口来实现路径名的解析,其具体实现以下工作:

1. 获取路径名查找的起点,当前目录或是根目录;

2. 以/为分隔符,解析每个目录项。

3. 针对每个目录项,首先查找目录项高速缓存,判断当前的目录项对象是否在缓存中,如果在,则直接从缓存中获取结果;如果不在,则需要在上一级目录中调用实际文件系统实现的lookup方法查找,并读取目录项对应的inode信息,填充dentry结构,并将该结构加入到高速缓存。

Q: 内核如何根据路径名查找的结果得到file结构?

通过dentry_open实现,具体执行以下工作:

1. 分配一个文件对象;

2. 根据传递进来的dentry信息,vfsmnt信息,初始化file对象的f_fentry,f_vfsmnt;

3. 以索引节点的i_fop填充f_op。

4. 将文件对象插入到文件系统超级块的s_files字段所指向的链表中。

Q: 索引节点的i_fop,i_op,i_mapping的a_ops字段何时被初始化?

具体文件系统读取索引节点时初始化,如ext2的ext2_read_inode方法;

在ext2_read_inode中,根据文件的类型不同,将i_fop,i_op,i_mapping的a_ops初始化为相应的方法。

1. 对于普通的文件,三者的值分别为ext2_file_operations,ext2_file_inode_operations,ext2_aops;

2. 对于目录三者的值分别为ext2_dir_operations,ext2_dir_inode_operations,ext2_aops;

3. 对于链接文件i_op被赋值为ext2_symlink_inode_operations;

bdget()根据块设备号初始化一个block_device结构,该结构字段的bd_inode的i_data被初始化为def_blk_aops的地址,当不同过文件系统读取块设备时,def_blk_ops会被调用;def_blk_aops的read_page方法调用block_read_full_page以一次读一块的方式读取整个页的数据。

Q: 对于打开的文件,在用户态以fd标识,在内核态以file结构标识,fd与 file如何对应?

每一个进程由一个task_struct结构描述,其中的files字段是一个files_struct的结构,主要描述文件打开的文件信息,包括fd使用位图,files对象数组fd_array,其中fd_array的下标即对应着该file对象对应的fd。

当进程通过路径名获取到file对象后,会将file对象的指针放入fd_array数组的相应位置;

Q: direct io是怎么回事?

直接IO(direct io)是指读写文件系统数据时绕过页高速缓存。

具体文件系统支持直接IO需要实现a_ops中的direct_IO方法;

不管是直接IO,还是经过页高速缓存的IO操作,都是将请求通过bio发到通用块层来实现的。

Q: 高速缓存页分哪些类型?

含有普通文件数据或目录的页;

含有直接从块设备文件,跳过文件系统层,读出来的数据的页;

含有用户态进程数据的页,但页中的数据已经被交换到磁盘;

属于特殊文件系统的页,如共享内存的IPC所使用的特殊文件系统shm;

Q: 页高速缓存中页的数据都是不同的么?

页高速缓存可以包含同一磁盘数据的多个副本,可以一下两种方式可以访问普通文件的同一块:

1. 读文件,此时,数据包含在普通文件索引节点所拥有的页中;

2. 从文件所在的设备文件(磁盘分区)读取块,此时,数据就包含在块设备文件的主索引节点所拥有的块中。

Q: 页高速缓存如何组织?

Linux支持TB级的文件,访问大文件时,页高速缓存中可能充满太多的文件页,因此需要对这些页进行高效的组织,使得内核能迅速高效的查找页。

Linux采用基树(radix tree)对页高速缓存进行组织,添加,删除,查找页的操作的时间复杂度都为O(1)。Linux提供一组方法方法用于处理页高速缓存:

find_get_page()接受address_space对象指针及偏移量,返回对应的页描述符;

find_get_pages()查找一组具有相邻索引的页;

add_to_page_cache()把一个新页的描述符插入到页高速缓存;

remove_from_page_cache()将页从高速缓存中移除;

read_cache_page()确保高速缓存中包含最新版本的指定页;

Q: 缓冲区页于页内缓冲区的关系?

如下图所示:page结构的private字段指向第一个缓冲区首部,各个缓冲区首部通过b_this_page链接,并通过b_page指向包含自己的page结构,b_data为其相对于页的位置。当页在高端内存时,b_data为缓冲区块在业内的偏移量;否则,b_data为缓冲区的线性地址,因高端内存页没有固定的映射。

0818b9ca8b590ca3270a3433284dd417.png

Q: 什么情况下内核会创建缓冲区页?

当读或写的文件页在磁盘块上不相邻时,即文件系统为文件分配了非连续的块,或者因为文件有洞;在块大小与页大小相等的情况下,这种情况不会出现。

当访问一个单独的磁盘块时(如读超级块或索引节点块)。

Q: 如何创建和释放缓冲区页?

调用grow_buffers(),其具体执行如下步骤:

1. 如果对应的页不在块设备的基树中,需创建新的页。

2. 调用alloc_page_buffer()为页创建缓冲区,一次创建页能容纳的所有缓冲区,并建立好链接关系,进行必要的初始化。

调用try_to_free_page()释放缓冲区页。

Q: 如何在页高速缓存中搜索块?

将块号转换成页号索引,并通过基树提供的接口进行查找。

__find_get_block(), __getblk()接口提供搜索块的接口,根据给定的设备信息及块号,块大小,返回块对应的buffer_head结构,后者在块所在的缓冲区页不存在时会分配缓冲区页,创建缓冲区块,并返回对应块的buffer_head结构。

为了提高系统性能,内核维持了一个小的磁盘高速缓存数组bh_lrus(每CPU变量),数组包含8个元素,指向最近访问过的缓冲区首部。

Q: 如何向通用块层提交缓冲区首部?

使用submit_bh()向通用块层传递一个缓冲区首部,使用ll_rw_block可向通用块层传递一组缓冲区首部;两者都附带读写传输方向标志。

sumbit_bh()根据缓冲区首部内容创建一个bio,具体执行如下步骤:

1. 调用bio_alloc分配一个bio描述符;

2. 将bi_sector字段赋值为bh->b_blocknr * bh->b_size / 512;

3. 将bi_bdev字段赋值为bh->b_bdev;

4. 把bi_size设置为块大小bh->b_size;

5. 初始化bi_io_vec的第一个元素以使该段对应于块缓冲区;

bi_io_vec[0].bv_page = bh->b_page;

bi_io_vec[0].bv_len = bh->b_size;

bi_io_vec[0].bv_offset = bh->b_data;

6. 将bi_cnt字段置1,并把bi_idx置为0;

7. 将bi_end_io字段赋值为end_bh_bio_sync,bi_private字段赋值为缓冲区首部地址。

作为数据传输完毕后的执行方法,数据传输完后,通过bi_private获取buffer_head结构,执行期bi_end_io字段的方法。

8. 调用submit_bio将bio提交到通用块层。

ll_rw_block对数组中每个buffer_head调用submit_bh。

Q: 页高速缓存何时被刷新?

基于性能考虑,linux系统采用延迟写策略,即将把脏缓冲区写入块设备的操作延迟执行;基于延迟写,几次写操作可能只需要一次物理更新。从而使得物理块设备平均为读请求服务的时间多于写请求。

以下条件会触发把脏页写到磁盘:

1. 页高速缓存变得太满,但还需要更多的页,或者脏页的数量已经太多;

2. 从页变成脏页的时间太长,超过某一阈值;

3. 进程请求或者特定文件系统特定的变化。如同过sync(),fsync(),fdatasync()系统调用实现;

Linux通过pdflush内核线程系统地扫描页高速缓存以刷新脏页,pdflush线程的数量随着系统运行动态调整,具体原则如下:

1. 必须有至少两个,之多八个pdflush内核线程;

2. 如果到最近的1s期间没有空闲的pdflush,就应该创建新的pdflush;

3. 如果最近一次pdflush变为空闲的时间超过1s,就应该删除一个pdflush;

4. 通过定期唤醒的pdflush保证陈旧的页及时写回,页保持脏状态的最长时间为30s;

Q: sync(), fsync(),fdatasync()系统调用区别?

sync()把所有的脏缓冲区刷新到磁盘;

fsync()把属于特定打开文件的所有块刷新到磁盘;

fdatasync()与fsync()类似,但不刷新文件的索引节点块;

Q: linux文件系统如何预读取?

为了保证预读命中率,linux只对顺序读进行预读,内核通过如下条件判断read()是否为顺序读:

1. 这是文件被打开后的第一次读,并且从文件头开始读;

2. 当前的读请求与前一次读请求在文件内的位置是连续的;

否则为随机读,任何一次随机读将终止预读,而不是缩减预读窗口。

当确定了需要进行预读时,就需要确定合适的预读大小,预读粒度太小,效果提升不明显;预读太多,可能载入太多不需要的页面而造成资源浪费;linux的策略是:

1. 首次预读:readahead_size = read_size * 2; // or *4;

2. 后续预读:readahead_size = readahead_size * 2;

3. 系统设定的最大预读大小为128K,该值可配置;

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

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

相关文章

《JS权威指南学习总结--6.1原型》

内容要点: 一.每一个JS对象(null除外)都和另一个对象相关联。"另一个"对象就是我们熟知的原型,每一个对象都从原型继承属性. 二.所有通过对象直接量创建的对象都具有同一个原型对象,并可以通过JS代码Object.…

linux下执行shell修改用户密码,[转] 关于linux下通过shell命令(自动)修改用户密码...

本文章总结了如何手动、自动修改本地用户密码及远程机器的用户密码。对做自动化测试提供了自动修改用户密码的原理及方法。修改本地用户密码:1、交互配置本地用户:以root用户:passwd Changing password for user dewang.New UNIX password:BA…

Visual Studio提示Bonjour backend初始化失败

Visual Studio提示Bonjour backend初始化失败 错误信息:The Bonjour backend failed to initialize, automatic Mac Build server discovery will not be available.这是由于Windows下的Bonjour服务没有开启,需要到服务管理中,开启该服务&…

104 规约模拟器linux,变电站自动化系统调试装置 Substation automation system debugging device...

摘要:本发明涉及一种在电力系统中应用的变电站自动化系统调试装置,其结构为电源与触电保安器相连,触电保安器分别与平板电脑,标准规约模拟器,交换机及调制解调器相连;平板电脑通过多功能接口盒与交换机和电度表相连;通讯管理机分别与调制解调器,交换机及电度表相连.…

Unity3d 札记-Let's try shooting 知识点汇总

1\LineRenderer LineRenderer是用来在3d场景画直线的一个工具。 public LineRenderer laserline;laserline.SetPositon(0,startposition);laserline.SetPositon(1,endposition);//设置结束位置startpositon,endposition均为Vector3 ,空间三维坐标 laserline.enabled(true); las…

c语言如何控制电脑串口,C语言直接驱动硬件实现PC机的串口操作

熟悉C语言的人都知道,虽然C语言是一门高级语言,拥有很多高级语言的特性,但是作为一种由低级语言到高级的过渡,他又继承了很多低级语言的特性,那就是可以直接操作计算机的硬件设备。本人近日在学习有关PLC网络方面的知识…

iOS ReactiveCocoa 最全常用API整理(可做为手册查询)

本文出出http://www.code4app.com/blog-721976-195.html 本文适合有一定RAC基础的童鞋做不时的查询,所以本文不做详细解释。 一、常见类 1、RACSiganl 信号类。 RACEmptySignal :空信号,用来实现 RACSignal 的 empty 方法; RACRet…

c语言程序设计实验周信东指针,C语言程序设计实验4数组周信东

1、实验 4 数 组姓名:XXX 学号: 实验日期:XXX1. 实验目的和要求(1)掌握一维数组与二维数组的定义、使用及初始化方法。(2)学习数组作为函数参数的用法。(3)掌握字符数组和字符串函数的使用方法。(4)掌握与数组有关的常用排序算法,…

使用Eclipse创建maven项目

前提:Eclipse中安装了maven插件,或者Eclipse版本在Mars以上(自集成maven) 1、new project --maven project 2、默认点击next 3、选择构建类型 4、填写groupId和artifactId,groupId就是顶级项目名,artifactId就是模块名&#xff08…

c#网页自动化脚本语言,c# – 创建用于创建网页的脚本语言

我正在创建一个用于创建网页的脚本语言,但不知道从哪里开始.我有一个看起来像这样的文件:mylanguagename(main) {OnLoad(protected) {Display(img,text,link);}Canvas(public) {Image img: "Images\my_image.png";img.Name: "img";img.Border: …

Js制作的文字游戏

自己制作的文字游戏。(: <!DOCTYPE html><html lang"en"><head> <meta charset"UTF-8"> <title>文字游戏</title> <style type"text/css"> #wrap{ width: 400px;height: …

c语言动态存储分配和链表,C语言静态链表和动态链表

1. 静态链表结构体中的成员可以是各种类型的指针变量&#xff0c;当一个结构体中有一个或多个成员的基类型是本结构体类型时&#xff0c;则称这种结构体为“引用自身的结构体”。如&#xff1a;struct link{char ch;struct link *p;} a;p是一个可以指向 struct link 类型变量的…

Go条件语句、switch和循环语句

一&#xff1a;Go条件语句 package mainimport "fmt"//go条件判断语句 func main() {var var1 int 10if var1 < 21 {fmt.Println("if 语法&#xff0c;小于")}if var1 < 20 {fmt.Println("if 语法")} else {fmt.Println("else 语法&…

c语言变量申明和定义区别,C语言中变量定义与声明的区别

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼在程序设计中&#xff0c;时时刻刻都用到变量的定义和变量的声明&#xff0c;可有些时候我们对这个概念不是很清楚&#xff0c;知道它是怎么用&#xff0c;但却不知是怎么一会事&#xff0c;下面我就简单的把他们的区别介绍如下&am…

初步认识JUnit

初步认识JUnit 目前大多数的基于Java的企业应用软件&#xff0c;肯定少不了单元测试&#xff0c;程序员通过编写单元测试来验证自己程序的有效性&#xff1b;管理者通过持续自动的执行单元测试和分析单元测试覆盖率来确保软件本身的质量。可以说单元测试和集成测试在软件开发整…

校招笔试C语言,校招c ++笔试题汇总

①链表反转单向链表的反转是一个经常被问到的一个面试题&#xff0c;也是一个非常基础的问题&#xff0c;最容易想到的方法遍历一遍链表&#xff0c;利用一个辅助指针&#xff0c;存储遍历过程中当前指针指向的下一个元素&#xff0c;然后将当前节点元素的指针反转后&#xff0…

STM32CubeMX使用方法及功能介绍

推荐 分享一个朋友的人工智能教程&#xff0c;零基础&#xff01;通俗易懂&#xff01;希望你也加入到人工智能的队伍中来&#xff01; http://www.captainbed.net/strongerhuang Ⅰ、写在前面 学习本文之前可以查看我前面的文章&#xff1a; STM32CubeMX介绍、下载与安装 主要…

君君喂大象C语言答案,2017年北师大版二年级语文上册句子专项复习题及答案

句子专项一、我会读拼音写句子。1. wǒ xiǎnɡ zhī do sh jia wai sh?n mē zha ynɡ sh?n q。_____________________________________________________________________________2.tā tiān tiān ɡēn zhe h? huā zi y qǐ , bǎ h? huā dānɡ ch?nɡ le hǎo p?…

2ab对应的c语言表达式是,编译原理 作业标准答案

《编译原理》第一次作业参考答案一、下列正则表达式定义了什么语言(用尽可能简短的自然语言描述)&#xff1f;1.b*(ab*ab*)*所有含有偶数个a的由a和b组成的字符串.2.c*a(a|c)*b(a|b|c)* | c*b(b|c)*a(a|b|c)*答案一&#xff1a;所有至少含有1个a和1个b的由a&#xff0c;b和c组成…

v4l2视频采集摄像头

v4l2 --是Linux内核中关于视频设备的内核驱动框架&#xff0c;为上层访问底层的视频设备提供了统一的接口。/dev/vidioX 1.打开设备文件 fdopen("/dev/video3"&#xff0c;O_RDWR); /dev/video3&#xff1a;视频设备文件名 O_RDWR&#xff1a;可读可写 fd: open成功反…