戳蓝字「TopCoder」关注咱们哦!html
编者注:在分析完 Linux inode 基础概念 以后,让咱们看下inode在内存中对应的文件系统抽象VFS,而后分析下关于 磁盘操做 中Page Cache的回写策略。node
VFS(虚拟文件系统层)
VFS是虚拟文件系统层(进程与文件系统之间的抽象层),与它相关的数据结构只存在于物理内存当中。其目的是屏蔽下层具体文件系统操做的差别,为上层的操做提供一个统一接口,正是因为VFS的存在,Linux中容许多个不一样的文件系统共存。web
VFS中包含着向物理文件系统转换的一系列数据结构,如VFS超级块、VFS的Inode、各类操做函数的转换入口等。Linux中VFS依靠四个主要的数据结构来描述其结构信息,分别为超级块、索引结点、目录项和文件对象,这些数据结构大都会与磁盘上的对应上。算法
超级块(Super Block):超级块对象表示一个文件系统。它存储一个已安装的文件系统的控制信息,包括文件系统名称(好比Ext2)、文件系统的大小和状态、块设备的引用和元数据信息(好比空闲列表等等)。超级块与磁盘上文件系统的超级块对应。缓存
索引结点(Inode):索引结点对象存储了文件的相关元数据信息,例如:文件大小、设备标识符、用户标识符、用户组标识符等等。Inode分为两种:一种是VFS的Inode,一种是具体文件系统的Inode。前者在内存中,后者在磁盘中。因此每次实际上是将磁盘中的Inode调进填充内存中的Inode,这样才是算使用了磁盘文件Inode。当建立一个文件的时候,就给文件分配了一个Inode。一个Inode只对应一个实际文件,一个文件也会只有一个Inode(Unix/Linux系统中目录也是一种文件,打开目录实际上就是打开目录文件。目录文件的结构很是简单,就是一系列目录项(dirent)的列表。每一个目录项,由两部分组成:所包含文件的文件名,以及该文件名对应的inode号码)。微信
目录项(Dentry):引入目录项对象的概念主要是出于方便查找文件的目的。不一样于前面的两个对象,目录项对象只存在于内存中,实际对应的是磁盘的目录innode对象。VFS在查找的时候,根据一层一层的目录项找到对应的每一个目录项的Inode,那么沿着目录项进行操做就能够找到最终的文件。数据结构
文件对象(File):文件对象描述的是进程已经打开的文件。由于一个文件能够被多个进程打开,因此一个文件能够存在多个文件对象,但多个文件对象其对应的索引节点和目录项对象确定是唯一的,关系以下图:app
因为进程中File对象有独立的文件偏移量(current file offset),所以多个进程能够读写文件的不一样位置的数据,可是通常不建议这样玩,由于系统不保证该状况下的写的原子性,多进程能够经过文件锁实现对文件内容的写保护。函数
PageCache
Page cache是经过将磁盘中的数据缓存到内存中,从而减小磁盘I/O操做,从而提升性能。此外,还要确保在page cache中的数据更改时可以被同步到磁盘上,后者被称为page回写(page writeback)。一个inode对应一个page cache对象,一个page cache对象包含多个物理page。性能
当内核发起一个读请求时(例如进程发起read()请求),首先会检查请求的数据是否缓存到了page cache中,若是有,那么直接从内存中读取,不须要访问磁盘,这被称为cache命中(cache hit)。若是cache中没有请求的数据,即cache未命中(cache miss),就必须从磁盘中读取数据。而后内核将读取的数据缓存到cache中,这样后续的读请求就能够命中cache了。page能够只缓存一个文件部分的内容,不须要把整个文件都缓存进来。
当内核发起一个写请求时(例如进程发起write()请求),一样是直接往cache中写入,此时不会当即同步到磁盘,而是将写入的page设置为脏页,并将其加入dirty list中,内核会负责按期同步到磁盘保持两者一执行。
page cache另外一个主要工做是回收page释放内存空间,此时会选择合适的page进行释放,若是是脏页会先同步到磁盘而后释放。此时是如何选择cache页的呢?Linux使用的策略是基于LRU改进的Two-List策略:
Two-List策略维护了两个list,active list 和 inactive list。在active list上的page被认为是hot的,不能释放。只有inactive list上的page能够被释放的。首次缓存的数据的page会被加入到inactive list中,已经在inactive list中的page若是再次被访问,就会移入active list中。两个链表都使用了伪LRU算法维护,新的page从尾部加入,移除时从头部移除,就像队列同样。若是active list中page的数量远大于inactive list,那么active list头部的页面会被移入inactive list中,从而位置两个表的平衡。
触发脏页回写到磁盘时机以下:
用户进程调用sync() 和 fsync()系统调用;
空闲内存低于特定的阈值(threshold);
Dirty数据在内存中驻留的时间超过一个特定的阈值。
注意这里的page cache的脏页回写机制能够和mmap的脏页回写机制作下对比,mmap会在必定时间后系统自动回写脏页面到磁盘,也就是说mamp中修改过的脏页面并不会当即更新回文件中,而是有一段时间的延迟,能够调用msync()来强制同步, 这样所写的内容就能当即保存到文件里了。
推荐阅读
本文分享自微信公众号 - TopCoder(gh_12e4a74a5c9c)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。