LINUX内核设计写实现之块IO层

来源:互联网 发布:淘宝麦迪黑莓手机网店 编辑:程序博客网 时间:2024/05/20 18:01

块设备:系统中能够随机(不需要按顺序)访问固定大小数据片(chunk)的设备.这些数据片称为块.一般而言,块设备都是以安装文件系统的方式使用的.所谓的随机性,是指被读取的块在磁盘上的位置不一定要连续,它能够在介质的不同区间前后移动.

字符设备:以字符流的方式有序访问的设备.

 

13.1 解剖一个块设备

扇区:块设备中最小的可寻址单元,是物理设备性质的.扇区是所有块设备的基本单元--块设备无法对比它还小的单元进行寻址和操作.只是许多块设备能够一次传输多个扇区.所有的I/O操作都是基于扇区来进行的;

:块是文件系统最小寻址单元,是软件意义性质的--只能基于块来访问文件系统.块只能数倍于扇区大小;

 

13.2 缓冲区和缓冲头

缓冲区的意义:

当一个块被调入内存时(也就是说,在读入或等待写出时),它要存储在一个缓冲区.每个缓冲区与一个块对应,它相当于磁盘块在内存中的表示.

缓冲区头:

内核在处理数据时需要一些相关的控制信息(如块属于哪一个块设备,块对应于哪个缓冲区等),每个缓冲区都有一个对应的描述符来记录这些信息.该描述符用buffer_head表示.

缓冲区头的目的在于描述磁盘块和物理内存缓冲区(在特定页面上的字节序列)之间的映射关系.

 

13.3 bio结构体

片断(segment):

一个片段是一小块连续的内存缓冲区;

内核中块I/O操作的基本容器bio结构体表示.该结构体代表了正在进行现场的(活动的)以片断(segment)链表形式组织的块I/O操作.定义于<linux/bio.h>.其最大的意义是用来代表正在进行现场执行的I/O操作.

缓冲区头的目的在于描述磁盘块和物理内存缓冲区(在特定页面上的字节序列)之间的映射关系.

 

13.3 bio结构体

片断(segment):

一个片段是一小块连续的内存缓冲区;

内核中块I/O操作的基本容器bio结构体表示.该结构体代表了正在进行现场的(活动的)以片断(segment)链表形式组织的块I/O操作.定义于<linux/bio.h>.其最大的意义是用来代表正在进行现场执行的I/O操作.

Bi_io_vecs域指向一个bio_vec结构体数组,该结构体链表包含了一个特定I/O操作所需要使用到的所有片段.每个bio_vec结构都以形式<page,offset,len>向量表示.它描述的是一个特定的片段:片段所在的物理页、块在物理页中的偏移位置、从给定的偏移量开始的块长度.

Bio结构体、bio_vec结构体和page结构体之间的关系.如下图:

请求:

每一个块I/O请求都通过一个bio结构体表示.每个请求包含一个或多个块,即每一个请求可以包含多个bio.

请求队列:

包含块设备I/O请求的队列,即内核管理块I/O请求的软件手段,此结构体被用来组织挂起的块I/O请求;

I/O调度器:

管理设备的请求队列.针对具体的物理块设备,对请求的队列上的请求进行合并、排序,来减少磁盘寻址时间,从而提升系统性能.

小结:

段、bio、请求、请求队列关系如下:

Segment被组织进bio,bio被组织进request,request被组织进request_queue,request queue又是I/O调度程序的管理对象.

 

13.4 I/O调度器

I/O调度程序的工作是管理块设备的请求队列.对请求的队列上的请求进行合并、排序,来减少磁盘寻址时间,从而提升系统性能.

内核有四种I/O调度器,如下:

一、Linus电梯

优点:

提供更好的系统吞吐量(通过最小化寻址),寻址时间最短;

缺点:

总按照扇区顺序将请求插入到队列,从不检查驻留时间过长的请求,更不会将请求插入到列队尾部,从而引发了不可取的请求饥饿问题.

二、最终期限I/O调度程序

背景知识:

写操作通常是内核有空时才将请求提交给磁盘的,它和提交它的应用程序异步执行;

读操作攻提交它的应用程序同步执行.

优点:

设定了请求的超时操作,默认情况下,读请求的超时时间是500毫秒,写请求的超时时间是5;新请求被安排插入队列尾部.通过这两方面的改进,有效地解决了linus电梯调度的请求饥饿问题;

缺点:

不能保证请求的响应时间,在系统处于繁重的写操作期间,每次提交读请求,优先处理读请求,所以磁盘首先为读操作进行寻址,执行读操作,然后再返回再寻址进行写操作,并且每个读请求都重复这个动作.这使得读请求得到及时响应,但是两次寻址(一次对读操作定位,一次返回来进行写操作定位)却损害了系统全局的吞吐量.

三、预测I/O调度程序

优点:

改进上述写请求的响应时间及系统全局吞吐量.

实现方式:主要是减少新到的读请求所带来的寻址数量.读请求通常会在超时前得到处理,但是请求提交后并不直接返回处理其他请求,而是有意空闲片刻(这个片刻可以设置,默认是6毫秒).这几毫秒,对应用程序来说是个提交其他读请求的好机会--任何对相邻磁盘位置操作的请求都会立刻得到处理.等待时间结束后,预测I/O调度程序重新返回原来的位置,继续执行以前剩下的请求.

缺点:

如果没有I/O请求在等待期到来,会造成系统性能的轻微损失.

预测I/O调度程序是linux内核中默认的I/O调度程序.

四、完全公正的排队I/O调度程序

主要针对专有工作负荷设计的.

主要特点:

每个提交I/O的进程都有自己的队列.

五、空操作的I/O调度程序

主要针对非机械性的块设备(U),因为像U盘这类不涉及到机械动作,选用其他调度程序没必要而且白白浪费掉系统花在请求排序这一过程.它主要完成的工作是合并,就把它与任一相信的请求合并.除了合并这一动作,空操作I/O调度程序确实没做什么了.它是专为随机访问设备而设计的.

 

13.4.1 I/O调度程序的选择

内核启动时通过命令行选项elevator=foo来覆盖默认的,这里的foo是一个有效而激活的I/O调度程序.如下表:

 

原创粉丝点击