绝大多数情况,内核读写磁盘时都引用页高速缓存。因为内核的数据与代码不从磁盘读。所以页高速缓存一般为以下类型:普通文件数据的页、目录的页、直接从块设备文件读出的页等。页高速缓存中每个页包含的数据肯定属于某个文件,这个文件叫做它的所有者。若非O_DIRECT标志被置位,所有文件读写都依赖于高速缓存。页高速缓存中信息单位显然是一完整数据页,它通过所有者(文件)及在其中的索引来标识。内核用address_space对象来描述页高速缓存。因为概念上页高速缓存属于文件,所以此数据结构嵌入在文件inode对象的i_data字段,且有i_mapping指向它,address_space对象的host也指向所有者的inode对象。另一种情况是页中数据来源于块设备文件,那么address_space会嵌入在与设备相关的特殊文件系统bdev中文件的主索引节点中。该对象的关键字段a_ops指向类型为address_space_operation的表,其中定义对页处理的方法,就是这些方法把inode对象与低级驱动程序相联系。此对象既然描述文件的页高速缓存,那么文件的缓存页肯定也可由它找到。直观的想法是将页描述符指针以一定数据结构在其中组织起来。考虑到大文件的页多,该数据结构必须设计精良以便快速操作。链表显然不行,引入基树来存放,效率高。基树必须有相关标记来指出脏页号。
Linux老版中,磁盘高速缓存有两种,除了前述的页高速缓存,还有对付块的缓存区高速缓存。新版中,后者没了,引入缓冲区页,其中由块缓存区构成。缓冲区页本身保存在页高速缓存中。块缓冲区由缓冲区首部buffer_head表示,其中有如块缓冲区所在缓冲区页的描述符指针,以及此块在缓冲区页offset。当然也有指针指向块缓冲区。同一缓冲区页的首部以链表链起来。缓冲区页在两种情况下被需要,1是文件页在文件系统中的块不连续,这时就将缓冲区页放入inode的address_space的基树中,并保存相应的缓冲区首部,因为它存着块设备逻辑号。2是访问单独磁盘块(如读inode或super_block对象),它的所有者并非文件,所以它的address_space位于与块设备相关的特殊文件系统bdev中,缓冲区页就存于它的基树中。这种情况所有块缓冲区涉及的块必须在块设备上相邻。在一个缓冲区页内的块缓冲区大小要相同,80x86体系上,按块大小,一缓冲区页可包括1~8缓冲区。
Pdflush内核线程负责周期性处理页高速缓存,刷新脏页。系统中这个内核线程的个数可以动态调整,最少2个最多8个。一个空闲1秒则删除它,最近1秒无空闲则创建一个新的。页高速缓存可能有大量页,Linux用复杂的机制对它的扫描划为几个执行流。
版权声明:本文为博主原创文章,未经博主允许不得转载。