关于linux文件系统的一些感想

晨曦之光 发布于 2012/04/10 15:00
阅读 473
收藏 0

一个常规文件一般位于一个块设备上,而块设备也是一个文件,只不过它是一个特殊文件罢了,unix的著名的一切皆文件的原则使得用户拥有了一个一致的操作视图,一切皆文件的设计初衷我想是这样的:在操作系统刚开始被开发出来以后,操作系统本身代表的就是机器的抽象,人们使用机器的目的是为了得到信息,包括已经存在的信息或者老信息经过加工得到的新信息,于是有必要将信息的载体以一种统一的视图呈现给用户,然后用户可以用一种统一的方式操作它们,这样用户就可以用一样的操作方式得到不同的信息,也就不会迷失于繁杂的操作细节上了,实质上信息的载体基本就是外设,比如磁盘,磁带,网络等等,cpu,内存本身只是加工信息所需要的,因此unix抽象出了块设备和字符设备,常规文件是更高一层意义上的信息载体,那是文件系统出现以后的事情,即便现在,有些大型数据库还是将数据直接存储于块设备上。理解了这些之后,我们发现块特殊文件倒是理所当然了,而常规文件倒是有些特殊了,是的,正是这样。不管怎么说,常规文件只是更高层意义上的信息抽象,用户按照文件系统的细节可以更加灵活的排布文件的布局,对于某些特殊的应用,这种文件系统的方式可以使磁盘的使用更加高效或者更加容易加速特殊的应用而不至于让信息的读取成为瓶颈,常规文件既然在块文件上,那么虽然两个文件可能会有数据重叠的部分但仍然会有两份mapping,因为它们不是一个层次的,没有必要用一个mapping,file的io会有很多形式,比如direct IO,bdev没有必要负责file的cache,如果bdev中缓存所有的file的cache的话,同步起来会很低效的,考虑一个direct IO,本身它的意思就是直接写盘/读盘的,可是bdev却缓存了该file的数据页面,它就必须应对这种情况从而不使用bdev的cache,然后还要刷新bdev对应该文件的cacahe,bdev对于mapping逻辑来讲是线性的,一个一个页面的,而对于文件系统来说却对于不同的文件系统有着不同的实现,要按照本文件系统的超级块以及元数据才能找到一个特定的文件,逻辑将非常的复杂,再说根本没有必要为不是一个层次的逻辑使用相同的cache。我说一下我的想法,刚才好像没有说清楚,一个文件对应的file cache和文件偏移是个线性关系,就是说在radix树中只要有数据在文件的偏移就可以找到对应的cache页面,而如果file的cache和 bdev的共享了,那么要处理的问题就是给定一个file的任意偏移就要快速的在bdev中找到对应的页面,首先一点该file在bdev中的位置就不好确定,需要读取大量的元数据或许对于不同的文件系统有的还要大量的间接寻址,这样会导致大量的IO,时间大量消耗掉,如此的cache还有意义吗?可能比不用cache还要慢吧,如果说将所有的元数据放入内存,那么将消耗大量的空间,值得吗?综上,第一,不同层次的不必公用一个cache;第二,不能为cahce而陷入时间或者空间的泥潭。

设计的初衷就是"一切皆文件"以及"模块的正交化最小集",块设备和一般的文件都被看成了文件,是文件就有文件的缓存,它们是不同的文件,因此内核维护不同的缓存,这样的正交化机制有利于内核的其它模块以及用户实现各种不同的策略,此乃机制和策略相分离的原则。另外你完全可以实现一个文件和bdev共享cache的文件系统,因为address_space的operations是基于文件系统的回调函数,类似面向对象中的接口或者超类,你实现readpage回调函数函数的时候让内核先在bdev的cache找找看,你要做的就是如何在一个块设备中快速定位到一个具体的文件以及该文件的一个偏移,想到这里,几乎没有文件系统是这么实现的,起码我是没有见到过。

从2.6的代码可以看得出,原来的buffer_head如今已经退化成读取文件元数据的容器--submit_bh的底层也是bio实现的,其它的io将都由bio来完成,机制就是mpage。mpage机制可以使得在文件系统层读写文件的时候,操作的仅仅是页面而不用管底层设备的块的概念,bio本质就是就是将一些不一定连续的页面拼接成连续的逻辑文件块。这里需要给出一个块的概念,块分为文件块和磁盘块,文件块就是一个常规文件按照块大小分割而成的一个个的区域,而磁盘块又有逻辑块而物理块,总之磁盘块就是文件块在磁盘上的位置,同一个文件的文件块按照偏移必然是连续的,但是其文件块所在的磁盘块却不一定连续,因为很多的文件公用了一个磁盘,文件块和磁盘块之间的映射就是文件系统的元数据内容,这个可以类比一下虚拟内存和物理内存,虚拟内存是基于进程的,进程内连续的虚拟内存在物理内存中不一定连续,因为所有的进程公用一个物理内存,计算机其实很简单,基本就是这么一些分层复用的东西。

在mpage的过程中,文件系统相关的get_block回调函数将负责解析常规文件的元数据来从文件的文件块映射到文件的磁盘块,在get_block的过程中将会读取基于buffer_head的元数据,和MMU的过程一样也有一个表要查询,对于ext2文件系统就是ext2_inode的i_data,它是一个数组,分别是直接索引,二级间接索引,...这个表的查询函数就是ext2_block_to_path,这个函数好像我的一篇文章已经分析过了,文章名字为《mpage机制中的BH_Boundary详解以及bio思想》,查完表以后的动作就是映射了,映射的函数就是ext2_get_branch,在该函数里面,会查找到文件的元数据然后返回帮助实施读写,其实就需要一个磁盘块号,但是该函数做了更多的事,这些事就是通过buffer_head做到的,buffer_head也就仅仅在这个读取元数据的地方有用,读到的元数据缓存到该文件所属的block_device的address_space中,如果下次再读到这个文件,它的元数据就可以直接从其所属的bdev的cache中取得了。

以上说的是元素据被缓存到bdev中的情况,如果我们直接读取/dev/sdaX,比如通过dd命令,那么块设备文件也会被缓存到内存中的其address_space中,也就是说,对于bdev这种块特殊文件来讲,其cache不光缓存常规文件的元数据,也会缓真实的数据,其实对于块特殊文件,任何它上面的数据都是真实的数据,元数据只是对其上的常规文件来讲的,你可以通过dd if=/dev/sda of=/tmp/dest bs=1 count=4096命令,然后用free来查看cache的变化,记住在执行上述命令之前首先通过sysctl -w vm.drop_caches=3来清空文件的cache。对于文件系统层的代码来看,它根本不管你是块设备还是常规文件或者是一个字符设备文件,它只要你提供file_operations函数集合而不会平白无故给与任何文件系统以特权。

总的来说,任何可操作实体一般都提供了一个连续的地址空间,所有的这种可操作实体在更高的范围公用一个地址空间,以此类推,文件系统也好,虚拟地址空间也罢。


原文链接:http://blog.csdn.net/dog250/article/details/5303679
加载中
返回顶部
顶部