Linux 核心--10.文件系统(8) 目录cache也由散列表组成,每个入口指向具有相同散列值的目录cache人口链表。散列函数使用包含此文件系统的设备号以及目录名称来计算在此散列表中的偏移值或者索引值, 这样能很快找到被缓存的目录。 如果在cache中的搜寻消耗的时间太长或者甚至没有找到则使用此cache用处不大。 为了保证cache的有效性和及时更新,VFS保存着一个最近最少使用(LRU)的目录cache人口链表。当首次查找此目录时其目录入口被首次放入cache中并添加到第一级LRU链表的尾部。在已经充满的cache 中它代替位于LRU链表最前端的现存入口。此目录入口被再次使用时它将被放到第二级LRU cache链表的最后。此时需要将位于第二级LRU cache链表的最前端的那个替换掉。入口在链表前端的唯一原因是它们已经很久没被访问过了。如果被访问过那么它们将位于此链表的尾部附近。位于第二级LRU cache链表中的入口要比位于第一级LRU cache链表中的安全一些。 9.3 The Buffer Cache 图9.7 Buffer Cache示意图 操纵已安装文件系统将产生大量对此块设备的读写请求。这些块读写请求都是通过标准核心例程调用以buffer_head结构形式传递到设备驱动中。它们提供了设备驱动所需的所有信息:表示设备的设备标志符以及请求的块号。所有块设备都被看成相同块大小的线性块集合。为了加速对物理块设备的访问,Linux 使用了一个块buffer cache。系统中全部的块缓冲,包括那些没使用过的新缓冲都保存在此buffer cache中。这个cache被多个物理块设备共享;任何时刻此cache中都有许多属于不同系统块设备且状态不同的块缓冲。如果有效数据可以从buffer cache中找到则将节省大量访问物理设备的时间。任何对块设备读写的块缓冲都被放入此cache中。随时间的变化有些块缓冲可能将会被此cache中删除以为更需要它的缓冲腾出空间,如果它被频繁使用则可以一直保存在此cache中。 此cache中的块缓冲由设备标志符以及缓冲对应的块号来唯一的表示。它由两个功能部分组成。其一是空闲块缓冲链表。它为每个可支持的块大小提供了一个链表并且系统中的空闲块缓冲在创建或者被丢弃时都被排入此链表中。当前可支持的块大小为512、1024、2048、4096与8192字节。其二是cache自身。它是用一组指向具有相同散列索引值的缓冲链的散列表。这个散列索引值通过其自身的设备标志符与数据块设备的块号来产生。图9.7给出了一个带有一些入口的散列表。块缓冲要么在空闲链表中要么在此buffer cache中。如果在buffer cache中则它们按照最近最少使用(LRU)链表来排列。 对于每种缓冲类型都有一个LRU链表,系统使用它们来对某种缓冲进行操作,如将带新数据的缓冲写入到磁盘上。缓冲的类型表示其当前状态,Linux现在支持以下集中类型: clean 未使用的新缓冲 locked 等待写入且加锁的缓冲 dirty dirty缓冲。它们包含新的有效数据,但目前没被调度执行写操作。 shared 共享缓冲 unshared 以前被共享但现在没有被共享的缓冲 当文件系统需要从其底层物理设备读取一个缓冲块时,它将首先在buffer cache里寻找。如果在此buffer cache中找不到则它将从适当大小的空闲链表中取得一个clean状态的节点, 同时将新缓冲添加到buffer cache 中去。如果所需的缓冲位于buffer cache中,那么它可能已经或没有更新。如果没有被更新或者它为新块则文件系统必须请求相应的数据驱动从磁盘中读取该数据块。 为了让此buffer cache运行更加有效并且在使用此buffer cache的块设备之间合理的分配cache入口,系统必须对其进行维护。Linux使用bdflush核心后台进行来对此cache执行许多琐碎工作,但有时作为使用cache 的结构自动进行。 9.3.1 bdflush 核心后台进程 bdflush是对过多的dirty缓冲系统提供动态响应的简单核心后台进程;这些缓冲块中包含必须被写入到硬盘上的数据。它在系统启动时作为一个核心线程运行,其名字叫"kflushd"。你可以使用ps命令看到此系统进程。通常情况下此进程一直在睡眠直到系统中的dirty缓冲数目增大到一定数目。当分配与丢弃缓冲时,系统中dirty缓冲的数目将做一个统计。如果其数目超过某个数值则唤醒bdflush进程。缺省的阀值为60%, 但是如果系统急需缓冲则任何时刻都可能唤醒bdflush。使用update命令可以看到和改变这个数值。