文件读写流程

本文深入解析Linux内核中的文件读写流程,从VFS、磁盘高速缓存、通用块层、IO调度器到设备驱动程序,逐层剖析普通磁盘文件读写的工作机制。涉及关键概念如O_DIRECT、bio结构、IO调度算法等,并介绍了read/write系统调用的执行流程。
摘要由CSDN通过智能技术生成

在《linux内核虚拟文件系统浅析》这篇文章中,我们看到文件是如何被打开、文件的读写是如何被触发的。
对一个已打开的文件fd进行read/write系统调用时,内核中该文件所对应的file结构的f_op->read/f_op->write被调用。
本文将顺着这条路走下去,大致看看普通磁盘文件的读写是怎样实现的。

linux内核响应一个块设备文件读写的层次结构如图(摘自ULK3):




1、VFS,虚拟文件系统。
之前我们已经看到f_op->read/f_op->write如何被调用,这就是VFS干的事(参见:《linux内核虚拟文件系统浅析》);

2、Disk Caches,磁盘高速缓存。
将磁盘上的数据缓存在内存中,加速文件的读写。实际上,在一般情况下,read/write是只跟缓存打交道的。(当然,存在特殊情况。下面会说到。)
read就直接从缓存读数据。如果要读的数据还不在缓存中,则触发一次读盘操作,然后等待磁盘上的数据被更新到磁盘高速缓存中;write也是直接写到缓存里去,然后就不用管了。后续内核会负责将数据写回磁盘。

为了实现这样的缓存,每个文件的inode内嵌了一个address_space结构,通过inode->i_mapping来访问。address_space结构中维护了一棵radix树,用于磁盘高速缓存的内存页面就挂在这棵树上。而既然磁盘高速缓存是跟文件的inode关联上的,则打开这个文件的每个进程都共用同一份缓存。
radix树的具体实现细节这里可以不用关心,可以把它理解成一个数组。数组中的每个元素就是一个页面,文件的内容就顺序存放在这些页面中。

于是,通过要读写的文件pos,可以换算得到要读写的是第几页(pos是以字节为单位,只需要除以每个页的字节数即可)。
inode被载入内存的时候,对应的磁盘高速缓存是空的(radix树上没有页面)。随着文件的读写,磁盘上的数据被载入内存,相应的内存页被挂到radix树的相应位置上。
如果文件被写,则仅仅是对应inode的radix树上的对应页上的内容被更新,并不会直接写回磁盘。这样被写过,但还没有更新到磁盘的页称为脏页。
内核线程pdflush定期将每个inode上的脏页更新到磁盘,也会适时地将radix上的页面回收,这些内容都不在这里深入探讨了。

当需要读写的文件内容尚未载入到对应的radix树时,read/write的执行过程会向底层的“通用块层”发起读请求,以便将数据读入。
而如果文件打开时指定了O_DIRECT选项,则表示绕开磁盘高速缓存,直接与“通用块层”打交道。
既然磁盘高速缓存提供了有利于提高读写效率的缓存机制,为什么又要使用O_DIRECT选项来绕开它呢?一般情况下,这样做的应用程序会自己在用户态维护一套更利于应用程序使用的专用的缓存机制,用以取代内核提供的磁盘高速缓存这种通用的缓存机制。(数据库程序通常就会这么干。)
既然使用O_DIRECT选项后,文件的缓存从内核提供的磁盘高速缓存变成了用户态的缓存,那么打开同一文件的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值