正所谓没吃过猪肉也看过猪跑,会看这篇文章的想必都是听说过 内核 这个词的吧,今天就让 我来请大家吃一回"猪肉",了解一下内核如何实现I/O。

实现内核I/o要靠三个主要的子系统: 虚拟文件系统 页缓存 页回写

虚拟文件系统

先说说虚拟文件系统,也称作VFS,Linux中有句名言叫做, 一切皆文件 ,能达到这样的效果, 这个VFS功不可没。他可以让内核在 不了解也不要了解文件系统类型的情况下 调用调用文件系统 函数并操作文件系统数据。

由此,系统调用可以读任意类型文件,工具可以直接从一个文件系统拷贝到令一个上。

页缓存

缓存的存在是为了在CPU的高速和硬盘的低速之间起一个过渡作用,内核查找文件系统数据会先在缓存中 查找,找不到才会访问硬盘。

在这里要介绍两个重要的原理 时间局部性空间局部性

时间局部性

时间局部性原理认为,刚刚访问过的区域再被访问的可能性很大,所以在第一次访问时会对数据缓存, 虽然消耗内存,但是可以避免开销巨大的硬盘I/O。

空间局部性

空间局部性原理认为,访问数据往往是连续的,而且访问连续空间比随机访问更快,所以每次读操作 都会额外的读取几个比特,也叫做预读。

页缓存动态变化

内存终究是有限的,不可能无限的缓存,所以也缓存需要动态变化。

在页缓存被消耗完了之后,就会 裁剪 不常用的部分,然后 交换 给硬盘,腾出来的空间 留给常用的部分。Linux内核的启发式算法会处理这些问题。

页回写

数据从硬盘读出来,放在缓存中,自然还需要再写会硬盘,因为RAM中的东西会在断电之后丢失。

像这些缓存中的数据被读写操作过后,和硬盘中的数据不一样了,就被叫做 脏数据 ,脏数据需要 回写硬盘让他变干净,所以就有了页回写。

回写是通过 flusher 的内核线程来执行的,当空闲内存低于设定的阈值或者脏缓冲区存在时间 超出设定时,就会触发回写。

这里还是有个问题,就是万一还没有回写系统就断电了。那很可悲,这些数据就丢失了,所以关键应用 可以使用同步I/O来保证数据不会丢失。

参考源