文件IO系统调用内幕

栏目: 服务器 · Linux · 发布时间: 5年前

内容简介:Linux文件系统采用分层设计,不同层抽象出来完成不同层次的逻辑。其中的复杂的设计,可以拿两张图在不同程度上描绘:

分层结构

Linux文件系统采用分层设计,不同层抽象出来完成不同层次的逻辑。其中的复杂的设计,可以拿两张图在不同程度上描绘:

文件IO系统调用内幕

文件IO系统调用内幕

因此用户态的应用程序每一个IO请求产生的数据都会经过文件系统的不同抽象层,但是很多抽象层之间是异步交互的,这使我们理解文件系统的难度又进一步提升。当然,还可以用一个简单的抽象来表示其中每个抽象层之间的关系:

文件IO系统调用内幕

下面我们会简单分析一些场景文件IO系统调用的内核流程,让我们了解其中的内幕。

虚拟文件系统

为了连接不同文件系统的设计,内核在各种文件系统之上增加一个抽象层 虚拟文件系统(VFS) ,很多通用设计都在其中,包括一个文件在内核中如何表示、元数据 struct filestruct inode 等的,具体分析可以参考:《Linux虚拟文件系统》

每个文件 open 后,会得到一个 struct file 来,在用户进程中为一个 int fd 来表示,文件读写偏移等元数据存储在 struct file 中。

同时,每个文件有唯一的一个 struct inode ,文件权限、属性等存储在其中。

因此,多个 struct file 可以对应同一个 struct inode

pagecache

pagecache 是内核为文件创建的内存缓存,用以加速相关的文件操作。当应用程序需要读取文件中的数据时,操作系统先分配一些内存,将数据从存储设备读入到这些内存中,然后再将数据分发给应用程序;当需要往文件中写数据时,操作系统先分配内存接收用户数据,然后再将数据从内存写到磁盘上。

  • pagecache 的内存在内核中是匿名的物理页(不与用户进程的逻辑地址进行映射),由 struct page 表示,在内核中 pagecache 使用LRU管理,当用户进行 mmap 映射文件时,内核创建对应的 vma ,在访问到 mmap 的内存区域时,触发 page fault ,在 page fault 回调中 pagecache 内存所属的物理页与用户进程的虚拟地址 vma 进行映射。
  • 每个文件的 pagecache 元数据存储于对应的 struct inode->address_space 中,因此进程之间可以共享同一个文件的 pagecache ,同一个文件多次 open 不会影响其 pagecache
  • 文件的 pagecache 是延时分配的,当有读写命令时,才会按需创建缓存页。
  • pagecache 的脏页是单线程回写的,因此当一个文件大量写入时,写入的性能与单CPU的性能有相当的关系。

详细的分析可以参见: 《Linux内核文件Cache 机制》《Linux内核延迟写机制》

块设备层

块设备层在不同版本中有不同的划分方式,但是总的来说可以分为《Linux通用块设备层》和《Linux内核IO调度层》。其中两部分可以详见链接中的讲解。

关于块设备层中的主要逻辑流程,可以参考下图:

文件IO系统调用内幕

系统调用

open

open 负责在内核生成与文件相对应的 struct file 元数据结构,并且与文件系统中该文件的 struct inode 进行关联,装载对应文件系统的操作回调函数,然后返回一个 int fd 给用户进程。后续用户对该文件的相关操作,会涉及到其相关的 struct filestruct inodeinode->i_opinode->i_fopinode->i_mapping->a_ops 等。

注:文件操作对应的偏移存储于 struct file 中,每个 open 的文件单独维护一份,同一个文件的读写操作共享同一个偏移。

其整个内核逻辑流程可以用下图来表示:

文件IO系统调用内幕

write

write 的写逻辑路径有好几条,最常使用的就是利用 pagecache 延迟写的这条路径,所以主要分析这个。在 write 调用的调用、返回之间,其负责分配新的 pagecache ,将数据写入 pagecache ,同时根据系统参数,判断 pagecache 中的脏数据占比来确定是否要触发回写逻辑。其详细的代码分析可以参考: 《Linux内核写文件过程》《Linux内核延迟写机制》

其整个内核逻辑流程可以用下图来表示:

文件IO系统调用内幕

read

read 的读逻辑中包含预期 readahead 的逻辑,其可以通过与 fadvise 的配合达到文件预取的效果。这部分的代码分析可以参考: 《Linux内核读文件过程》

其整个内核逻辑流程可以用下图来表示:

文件IO系统调用内幕

fsync/fdatasync

fsyncfdatasync 主要逻辑流程基本相同。其通过触发对应文件的 pagecache 脏页回写,并且阻塞等待到回写逻辑完成,以达到同步数据的目的。

其整个内核逻辑流程可以用下图来表示: 文件IO系统调用内幕

mmap

用户调用 mmap 将文件映射到内存时,内核进行一系列的参数检查,然后创建对应的 vma ,然后给该 vma 绑定 vma_ops 。当用户访问到 mmap 对应的内存时,CPU会触发 page fault ,在 page fault 回调中,将申请 pagecache 中的匿名页,读取文件到其物理内存中,然后将 pagecache 中所属的物理页与用户进程的 vma 进行映射。

其整个内核逻辑流程可以用下图来表示,其中 page fault 部分比较简略,可以参考 Linux Page Fault(缺页异常)文件IO系统调用内幕

munmap

文件IO系统调用内幕

msync

msync 的实际实现与其手册中的描述有很大不同,其调用时, flag=MS_SYNC 等同于对 mmap 对应的文件调用 fsyncflag=MS_ASYNC/MS_INVALIDATE 其实什么都不执行。

文件IO系统调用内幕

madvise

文件IO系统调用内幕

fadvise

文件IO系统调用内幕


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

工程问题C++语言求解

工程问题C++语言求解

Delores M.Etter、Jeanine A.Ingber / 冯力、周凯 / 机械工业出版社 / 2014-8 / 79元

本书介绍了如何利用ANSIC++编程语言以基于对象的编程方式来解决工程问题。书中引用了大量来自于不同工程、科学和计算机科学领域的示例,是一本理论和实践结合紧密的教材。针对C++基本语法的各个部分,由浅入深地进行讲解。每讲解一部分基础知识,同时会结合多个相关实例,实例内容详实,紧贴所讲内容,使读者能够立刻对所学知识进行练习,实战性强。一起来看看 《工程问题C++语言求解》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具