块I/O层
系统中能够随机(不需要按顺序)访问固定大小数据片(chunks)的硬件设备称为块设备,这些固定大小的数据片就称作块,硬盘是最常见的块设备。
如果一个硬件设备是以字符流(顺序访问)的方式被访问,就归于字符设备;如果一个设备是随机访问的,它就属于块设备。
1.块设备
块设备中最小可寻址单元是扇区,扇区的大小是设备的物理属性。
块是文件系统的一种抽象,物理磁盘寻址按照扇区进行,但内核执行的所有磁盘操作是按照块进行。因为扇区是设备的最小可寻址单元,所以块不能比扇区还小,只能数倍于扇区。内核要求块的大小是2的幂,不能超过一个页的大小。所以通常块大小为512字节、1KB、4KB,即扇区:块=1:N。
扇区称硬扇区或设备块;块有时称文件块或I/O块。
扩展阅读:Device file
2.缓冲区和缓冲区头
每个缓冲区对应一个块,它相当于磁盘块在内存中的表示。
内核定义一个buffer_head结构体来表示一个缓冲区,每个缓冲区都有这样一个描述符,它包含内核操作缓冲区的全部信息。
buffer_head:linux/buffer_head.h
|
|
b_state域表示缓冲区的状态,相关的标志位定义在bh_state_bits枚举中。
3. bio结构体
bio结构体表示内核操作块I/O的基本容器,代表了正在活动的以segment链表形式组织的块I/O操作。一个segment是一小块连续的内存,这样不需要保证单个缓冲区一定要连续,即使一个缓冲区分散在内存的多个位置,bio结构体也能对内核保证I/O操作的执行。这样的向量I/O就是所谓的聚散I/O。
bio结构体定义在:linux/blk_types.h
|
|
3.1 I/O向量
bi_io_vec域指向一个bio_vec结构体数组,该结构体链表包含了一个特定的I/O操作所需要用到的所有片段。每个bio_vec结构是形式为
bio_io_vec结构体数组整个一起表示了一个完整的缓冲区。bio_vec结构定义在:linux/bvec.h
|
|
bio结构体代表I/O操作,可以包含内存中的一个或多个页;buffer_head结构体代表一个缓冲区,描述的是磁盘上的一个块。利用bio代替buffer_head好处有:
- 不需要连续存储区,也不需要分割I/O操作
- bio很容易处理高端内存,因为它处理的是物理页而不是直接指针
- bio既可以代表普通页,也可以代表直接I/O
- bio便于执行分散——集中(矢量化)块I/O操作,操作中的数据可以来自多个物理页
- bio相比缓冲区头属于轻量级结构体
4.请求队列
块设备将他们挂起的块I/O请求保存在请求队列中,由request_queue结构体表示,请求队列只要不为空,队列对应的块设备驱动程序就会从队列头获取请求,然后将其送入对应的块设备上去。
请求队列request_queue定义在:linux/blkdev.h,包含一个双向请求链表以及相关控制信息,请求队列的每一项是一个request结构体。一个请求可能操作多个连续的磁盘块,所以每个请求可以由多个bio结构体构成。request结构体同样定义在:linux/blkdev.h
5. I/O调度程序
直接简单地将请求依次直接发送给块设备性能是不好的,磁盘寻址是整个计算机中最慢的操作之一,为了优化寻址操作,内核既不会简单地按请求次序,也不会立即将其提交给磁盘,在提交前他会合并和排序的预操作,从而大大提高性能,内核负责提交I/O请求的子系统称为I/O调度程序。
I/O调度程序通过两种方法减少磁盘寻址时间:合并和排序。
- 合并:将多个请求结合成一个新请求。将多次请求的开销压缩成一次,合并后只需要传递一条寻址指令给磁盘。
排序:I/O调度算法【整理】Linux I/O调度
1. Linus电梯
当一个请求加入到队列中时,会依次执行:- 如果队列中已存在一个队相邻磁盘扇区操作的请求,那么新请求将和这个已经存在的请求合并成一个请求,包括:向前合并和向后合并
- 如果队列中存在一个驻留时间过长的请求,那么新请求将被插入到队列尾部,以防请求饥饿
- 如果队列中以扇区方向为序存在合适的插入位置,那么新请求将被插入到该位置,保证队列中请求是以被访问磁盘物理位置为序进行排列
- 如果队列中不存在合适的请求插入位置,将请求插入队列尾部
- The Deadline I/O Scheduler
为了解决Linus电梯的饥饿问题,writes-starving-reads问题
文档
block/deadline-iosched.c
配置I/O调度
https://lwn.net/Articles/21274/
- The Complete Fair Queuing I/O Scheduler
注意与CFS的区别与联系,CFQ每个提交I/O的进程都有自己的队列。
block/cfq-iosched.c - The Noop I/O Scheduler
专为随机访问设备设计。
block/noop-iosched.c - The Kyber I/O scheduler
block/kyber-iosched.c - Budget Fair Queueing (BFQ) scheduler
6. 小结
- bio:表示活动的I/O操作
- buffer_head:表示块到页的映射
- request:表示具体I/O请求
- I/O调度程序
相关资料
Budget Fair Queueing (BFQ) Storage-I/O Scheduler
Linux I/O Scheduler
http://blog.csdn.net/vanbreaker/article/details/8278358
https://lwn.net/Articles/601799/