Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

Vinllen Chen


但行好事,莫问前程

Linux块I/O

  Linux下有两种基本的设备类型,一种是字符设备,另外一种是块设备。如果一个硬件设备是以字符流的方式被访问的话,则属于字符设备;反之,如果一个设备是随机(无序)访问的话,则属于块设备。比如键盘属于字符设备,硬盘属于块设备。字符设备仅仅需要控制一个位置--当前位置,而块设备访问的位置必须能够在截至的不同区间前后移动。
  扇区是块设备最小寻址单元,一般为512字节。块是文件系统的一种抽象--只能基于块来访问文件系统。虽然物理磁盘寻址是按照扇区级进行的,但是内核执行的所有磁盘操作都是按块进行的。内核还要求块大小是2的整数倍,而且不能超过一个页的长度。总结来说,扇区是设备的最小寻址单元,而块是文件系统的最小寻址单元。

1.缓冲区和缓冲区头

  当一个块被调入内存时,它要存储在一个缓冲区中,每一个缓冲区与一个块对于,它相当于是磁盘块在内存中的表示。每个缓冲区都有一个对应的描述符:buffer_head,我们称为缓冲区头,它包含了内核操作缓冲区所需要的全部信息。
chunk1

  缓冲区头的目的在于描述磁盘块和物理内存缓冲区之间的映射关系。缺点在于:1.缓冲区头是一个很大且不易控制的数据结构体,在2.6内核中,许多I/O操作都是通过内核直接对页面或地址空间进行操作来完成,不再使用缓冲区头。2.它仅能描述单个缓冲区。

2.bio结构体

  目前,内核中块I/O操作的基本容器由bio结构体来表示。该结构体代表了正在现场(活动的)以片段(segement)链表形式组织的块I/O操作。一个片段是一小块连续的内存缓冲区。这样的话,就不需要保证单个缓冲区一定要连续。所以通过用片段来描述缓冲区,即使一个缓冲区分散在内存的多个位置上,bio结构体也能对内核保证I/O操作的执行。像这样的向量I/O就是所谓的聚散I/O。
chunk2

  使用bio结构体的目的主要是代表正在现场执行的I/O操作,所以该结构体中的主要域都是用来管理先关信息的,如下所示:
chunk3

  bi_io_vec域指向一个bio_vec结构体数组,该结构体链表包含了一个特定I/O操作所需要使用到得所有片段。每个bio_vec结构都是一个形为<page, offset, len>的向量,它描述的是一个特定的片段:片段所在的物理页、块在物理页中的偏移位置、从给定偏移量开始的块长度。整个bio_io_vec结构体数组表示了一个完整地缓冲区。每一个块I/O请求都是通过一个bio结构体表示,每个请求包含一个或多个块,这些块存储在bio_vec结构体数组中。
chunk4

3.两种方式的对比

  bio结构体代表的是I/O操作,它可以包括内存中的一个或多个页;而另一方面,buffer_head结构体代表的是一个缓冲区,它描述的仅仅是硬盘中的一个块。因为缓冲区头关联的是单独页中的单独磁盘块,所以可能会引起不必要的分割,将请求按块分为单位划分,只能靠以后才能再重新组合。由于bio结构体是轻量级的,它描述的块可以不需要连续存储区,并且不需要分割I/O操作。
  利用bio结构体代替buffer_head结构体还有以下好处:

  • bio结构体很容易处理高端内存,因为它处理的是物理页而不是直接指针。
  • bio结构体既可以代表普通I/O,同时也可以代表直接I/O(指那些不通过页高速缓存的I/O操作)。
  • bio结构体便于执行分散-集中块I/O操作,操作中的数据可取自多个物理页面。
  • bio结构体相比缓冲区头属于轻量级结构体。因为它只需要包含块I/O操作所需的信息就可以,不用包含与缓冲区本身相关的不必要信息。

4.请求队列

  块设备将他们挂起的块I/O请求保存在请求队列中,该队列由reques_queue结构体表示,包含一个双向请求链表以及相关控制信息。请求队列中的每一项都是一个单独的请求,由reques结构体表示。因为一个请求可能要操作多个连续的磁盘块,所以每个请求可以由多个bio结构体表示。

5.I/O调度程序

  如果简单以内核产生的请求的次序向块设备发送请求的话,性能肯定让人难以接受。磁盘寻址是整个计算机中最慢的操作之一,所以尽量缩短寻址时间是提高系统性能的关键。内核在提交磁盘请求时,先执行名为合并与排序的预操作,这种预操作可以极大地提高系统的整体性能。在内核中负责提交I/O请求的子系统称为I/O调度程序。I/O调度程序将磁盘I/O资源分配给系统中所有挂起的块I/O请求。它决定队列中的请求排列顺序以及什么时候发送请求到块设备。坦率的说,一个I/O调度器可能为了提高系统整体性能而对某些请求不公平。
  主要的I/O调度算法包括:Linus电梯算法,最终期限I/O调度程序,预测I/O调度程序,完全公正的排队I/O调度程序,空操作的I/O调度程序。具体可以查看书本内容。

参考

《Linux内核设计与艺术》

说明

装载请注明出处:http://vinllen.com/linuxkuai-ioceng/


About the author

vinllen chen

Beijing, China

格物致知


Discussions

comments powered by Disqus