免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 971 | 回复: 0
打印 上一主题 下一主题

Linux操作系统中不同层次的缓冲机制 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2006-12-24 12:46 |只看该作者 |倒序浏览

1.  Linux内存管理中的缓冲机制:
        1.1.   缓冲区高速缓存
        缓冲区高速缓存中包含了由块设备使用的数据缓冲区。这些缓冲区中包含了从设备中读取的数据块或写入设备的数据块。缓冲区高速缓存由设备标识号和块标号索引,能快速找出数据。如果数据能够在缓冲区高速缓存中找到就不必在物理块设备上进行实际的读操作。
描述缓冲区的数据结构是buffer_head,缓冲区的大小一般比页小,所以一页中可以包含几个缓冲区,同一页中的缓冲区用链表连接。
由于Linux采用了这种缓存机制,所以当把一个数据写入文件时,内枋将会把该数据写入内存缓冲区,而不是直接写入磁盘。这样就很可能导致写磁盘的命令已经返回,而实际的写入磁盘的操作还未执行。为此用户应使用正确的关机命令关机,而不是直接关掉计算机的电源。用户也可以使用sync命令刷新缓冲区高速缓存,从而把缓冲区中的数据强制写到磁盘上。
1.2.      页高速缓存
       页高速缓存用来加速对磁盘上的映像和数据的访问。页高速缓存用来缓存某个文件的逻辑内容,并通过文件的VFS索引节点和偏移量访问。页从磁盘上读到物理内存时就缓存在页高速缓存中。下面一段源代码就是把读入的页存于缓存中:
void add_to_page_cache_locked(struct page * page, struct address_space * mapping, unsigned long index)
{
      spinlock_t * pg_lock;
      
      if(!PageLocked(page))
             BUG();
      page_cache_get(page);
      pg_lock=__PAGECACHE_LOCK(mapping, index);
      spin_lock(pg_lock);
      page->index=index;
      add_page_to_inode_queue(mapping, page);
      add_page_to_hash_queue(page, page_hash(mapping, index));
      lru_cache_add(page);
      spin_unlock(pg_lock);
}
1.3.      交换高速缓存
        当将页交换到交换文件中时,Linux总是避免写页。页已经被交换出内存后若有进程再次访问时又要将它重新调入内存。只要页在内存中没有被写过,交换文件中的拷贝就是有效的。
Linux使用交换缓存来跟踪这些页。这个交换缓存是一个页表入口链表,每一个对应于系统中的物理页。交换缓存对应于交换出页的页表入口,并且描述页放置在哪个交换文件中以及在交换文件中的位置。如果交换缓存入口为非0值表示在交换文件中的这一页没有被修改。如果此页被修改(或者写入),则其入口将从交换缓存中删除。
当Linux需要将一个物理页交换到交换文件时,它将检查交换缓存。如果对应此页存在有效入口,则不必将这个页写到交换文件中。这是因为内存中这一页在最近一次由交换文件中读出后还没被修改过。
交换缓存中的入口是已换出页的页表入口。它们虽被标记为无效,但为Linux提供了页在哪个交换文件中以及文件中的位置等信息。
1.4.      硬件高速缓存
        常见的硬件缓存是对页表项的缓存,如TLB。它通常在MMU内部,条目的数量较少。每一个TLB寄存器的每一个条目包含一页的信息:有效位、虚页位、修改位、保护位和页所有的物理页号。当一个虚地址被送到MMU翻译时,硬件先将其与TLB中的所有条目进行比较。如果虚页号在TLB中,且访问没有违反保护位,其页帧会直接从TLB中取出而不访问页表。如果页号在TLB中,但当前指令试图写一个只读的页,这时将发生页故障,与直接访问页表时相同。如果MMU发现在TLB中没有该页,就进行常规的页表查找,然后从TLB中淘汰一个条目,并把它替换为刚找到的页表项。
2.  Linux文件管理中的缓冲机制
2.1.      VFS中的索引节点缓存
          搜索安装文件系统时,其VFS索引节点不断地被读或写。虚拟文件系统通过维护一个索引节点缓存来加速对所有已安装文件系统的访问。每次VFS索引节点都可从索引节点缓存中读取出来以加速对物理设备的访问。VFS索引节点缓存是一个入口为VFS inodes链表指针的哈希表,哈希表的每一项包含一个指向VFS索引节点的指针,这个节点在这个链的链首。同一链表的索引节点拥有相同的哈希值,这个值是根据索引节点和该文件所在的物理设备的标识符得到的。
VFS要访问某个节点时首先查看VFS索引节点缓存,通过计算哈希值找到对应的hash_table,在索引节点链表中查找与指定设备号和索引节点号匹配的索引节点。如果访问的节点在索引节点缓存中则访问计数i_count加1,否则需要找到一个空闲VFS索引节点,以便文件系统能从内存中读取此节点。
VFS有许多种选择可以取得空闲的索引节点。如果系统可以分配多个VFS索引节点,将按如下步骤进行:首先分配一物理页面,将其按索引节点长度分割并放入索引节点链表中。如果系统已经拥有所有的索引节点就必须找到便于重新使用的节点,即节点的记数i_count为0,这种索引节点是没有使用的。重要的VFS索引节点,如文件系统的根节点,其count域总是大于0,所以它使用的索引节点是不能被重新使用的。
获得空闲的VFS节点后VFS会调用文件系统专有的例程从逻辑文件系统中读取信息并开始填充该索引节点,使节点的使用计数为1,同时被锁定,以免其他进程访问该节点。填充完毕后节点被解锁。
2.2.      VFS中的目录缓存
        为了加速对常用目录的访问VFS维护了一个目录入口缓冲区。
在实际文件系统寻找目录时,有关此目录的细节将被存入目录缓存中。再次寻找此目录时,比如在此目录下列出文件名或打开文件,这些信息就可以在目录缓存中找到。由于较短目录名的目录是使用最频繁的,因此在实际实现中只有短目录(最多15个字符)被缓存。该目录缓存由一个哈希表来管理,哈希索引值由文件所在的设备号以及目录名称计算得到。
为了保证目录缓存的有效性和及时更新,VFS保存了一个最近最少使用(LRU)的目录缓存链表。首次查找此目录项时,其目录项被首次放入缓存中并添加到第一级LRU链表的尾部。如果缓冲区被全部占用,它就代替LRU链表的表头。此目录项被再次使用时,将被放到第二级LRU链表的末尾,此时需要将位于第二级LRU链表的表头替换掉。目录项在链表的前端表示它们已经很勺没被访问过了。如果被访问过,那么它们将位于此链表的尾部附近。位于第二级LRU链表中的项要比位于第一级LRU链表中的安全一些。
对目录缓存操作的函数在fs/dcache.c中定义。
2.3.      缓冲区缓存
         Linux支持的文件系统大多以块的形式组织文件,为了减少对物理块设备的访问,当文件以块的形式调入内存后,可以使用块缓冲区对它们进行管理。每个块缓冲区中存在一个缓冲区首部(用数据结构buffer_head表示)和存储数据的缓冲区空间。缓冲区首部不与数据区域相连,数据区域独立存储,两者之间由一个指针*b_data链接。
所有数据块的读/写请求以buffer_head数据结构的形式传递给设备驱动程序。
缓冲区缓存由两个部分组成:一是空闲块缓冲区链表,它为每个可支持的块大小提供了一个链表,并且系统中的空闲块缓冲区在创建或被丢弃时都被链接到此链表中;二是缓存本身,这是一张哈希表。每个入口是指向由指针串起来的缓冲区链表的指针。哈希索引值由数据块拥有的设备标识符和块号码产生。
块缓冲区在空闲链表中或是在哈希缓冲区缓存中。如果在缓冲区缓存中它们按照LRU链表来排列。对于每种缓冲区类型都有一个LRU链表。
文件系统需要从其底层物理设备读取一个缓冲块时,首先在缓冲区缓存中寻找。如果在此缓冲区缓存中得不到一个缓冲区,则将从适当大小的空闲链表中取得一个clean状态的节点,同时将新缓冲区添加到缓冲区缓存中去。如果所需的缓冲区位于缓冲区缓存中,则可能已经含有最新的数据。如果没有被更新或者为新块则文件系统必须请求相应的设备驱动程序从磁盘中读取该数据块。
为了让此缓冲区缓存运行更加有效,并且在使用此缓冲区缓存的块设备之间合理地分配缓存入口,Linux使用bdflush监控程序来执行缓存的看护工作。bdflush对过多的dirty缓冲系统提供动态响应的简单核心后台进程,这些缓冲块中包含必须被写入到硬盘上的数据。通常此进程一直在休眠,直到系统中的dirty缓冲区数目增大到一定数量。分配与丢弃缓冲区时系统将检查dirty缓冲区的数目,如果超过某个百分比(默认为60%),则唤醒bdflush进程。但如果系统急需缓冲区,则任何时刻都可能唤醒bdflush。这个域值可以通过update命令修改。数据写入缓冲区使之变成dirty时,所有的dirty缓冲区被链接到一个BUF_DIRTY LRU链表中,bdflush会将适当数目的缓冲块(默认值为500)写到磁盘上。
至于update,它不仅仅是一个命令,还是一个后台进程。当作为超级用户运行时(在系统初始化时),它将周期性调用系统服务例程,将老的dirty缓冲区内容冲刷到磁盘上去。这个工作与bdflush类似。一个dirty缓冲区完成此操作后,它将把本应写入各自磁盘上的时间标记到buffer_head结构中。update每次运行时将在系统中的所有dirty缓冲区中查找那些冲刷时间已超过一定期限的缓冲区,这些过期缓冲区都要被写入磁盘。


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/28832/showart_220391.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP