Linux文件系统
为了取得真正需要的VFS inode,文件系统可能需要存取几类其它inode。我们读取一个目录时虽然只需要最后一级目录但是所有的中间目录也被读了出来。由于使用了VFS inode cache,较少使用的inode将被丢弃而较多使用的inode将保存在cache中。
9.2.9 目录 Cache 为了加速对常用目录的访问,VFS维护着一个目录入口cache。
当在实际文件系统寻找目录时,有关此目录的细节将被存入目录cache中。当再次寻找此目录时,例如在此目录中列文件名或打开文件,则这些信息就可以在目录cache中找到。在实际实现中只有短目录入口(最多15个字 符)被缓存,这是因为那些较短目录名的目录正是使用最频繁的。例如/usr/X11R6/bin这个短目录经常被X server所使用。
目录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中,那么它可能已经或没有更新。如果没有被更新或者它为新块则文件系统必须请求相应的数据驱动从磁盘中读取该数据块。
|