您的位置:首页 > 运维架构 > Linux

Linux IO调度层分析-1

2014-03-17 14:23 260 查看
Linux IO调度程序是块设备I/O子系统的主要组件,它介于通用块层和块设备驱动程序之间,所图2-1所示。当Linux内核组件要读写一些数据时,并不是请求一发出,内核便立即执行该请求,而是将其推迟执行。延迟的设定是块设备性能的关键机制!当传输一个新数据块时,内核检查能否通过扩展前一个一直处于等待状态的请求而满足新请求。




图 IO调度层所在系统中的位置
在2.6内核中,内核中实现了四种IO调度算法,分别为预期(Anticipatory)算法、最后期限(Deadline)算法、完全公平队列(CFQ)算法以及NOOP算法(No Operation)。可以在内核引导式指定一种I/O调度算法,也可以在运行时通过sysfs文件系统/sys/block/sda/queue/scheduler来为块设备定制一个特定的I/O调度算法或查看块设备目前所使用的何种IO调度算法。
由于Linux IO调度程序是介于通用块层和块设备驱动程序之间,所以它接收来自通用块层的请求,试图合并请求,并找到最合适的请求下发到块设备驱动程序中。之后块设备驱动程序会调用一个策略函数来相应这个请求。这个策略函数是由设备类型来决定的,例如,如果设备是SCSI硬盘,那么scsi总线层便将scsi_request_fn注册到该策略函数中。
在linux2.6.21的内核源代码中,用于实现IO调度程序的文件有:
文件路径
描述
/include/linux/elevator.h

定义了调度算法一些公用的数据结构以及操作函数接口

/block/elevator.c

实现elevator.h中声明的一些函数

/block/noop-iosched.c

用于实现Noop算法

/block/as-iosched.c

用于实现预期算法

/block/deadline-iosched.c

用于实现最后期限算法

/block/cfq-iosched.c

用于实现完全公平队列算法

在elevator.h中定义了一些重要的数据结构,包括elevator_ops,elevator_type以及elevator_queue。
Ø elevator_ops定义了一些操作函数接口,这些接口函数由不同的IO调度算法重载,下面是该数据结构中一些主要字段的意义:
字段

类型

描述

elevator_merge_fn

elevator_merge_fn *

将bio合并到合适的request中(准确地说,插入到request链表的首部)

elevator_merged_fn

elevator_merged_fn *

执行插入bio之后的一些附加操作

elevator_merge_req_fn

elevator_merge_req_fn*

合并两个request操作

elevator_allow_merge_fn

elevator_allow_merge_fn*

判断bio是否允许合并到request中

elevator_dispatch_fn

elevator_dispatch_fn*

在队列中取出最合适的request

elevator_add_req_fn

elevator_add_req_fn*

向队列中插入一个新的request

elevator_queue_empty_fn

elevator_queue_empty_fn*

判断队列是否为空

elevator_completed_req_fn

elevator_completed_req_fn*

请求完成时进行的一些操作

elevator_former_req_fn

elevator_request_list_fn*

取前一个request操作

elevator_latter_req_fn

elevator_request_list_fn*

取后一个request操作

elevator_init_fn

elevator_init_fn*

初始化操作

elevator_exit_fn

elevator_exit_fn*

退出操作

Ø elevator_type结构用于描述调度的种类,其中主要字段描述如下:
字段

类型

描述

ops

struct elevator_ops

实现该调度算法函数操作

elevator_attrs

struct elv_fs_entry *

Sys接口

elevator_name

Char *

该调度算法的名称

Ø elevator_queue结构描述了该块设备驱动使用何种IO调度算法。通常每个物理块设备都自己维护一个请求队列,每个请求队列上单独执行I/O调度。在请求对列中有一个字段elevator,它的类型指向sturct elevator_queue的指针。elevator_queue结构如下:
struct elevator_queue
{
struct elevator_ops *ops;
void *elevator_data;
struct kobject kobj;
struct elevator_type *elevator_type;
struct mutex sysfs_lock;
struct hlist_head *hash;
};
字段ops定义了调度算法的所有可能的操作:链接和断开elevator,增加和合并队列中的请求,从队列中删除请求,获得队列中下一个待处理的请求等等。
字段是elevator_type,它是指向struct elevator_type类型的指针,它描述了块设备所使用io调度算法。
字段hash包含了处理请求队列所需的所有信息,通过这个哈希表可以快速索引我们需要的某个request。
字段elevator_data用于描述IO调度程序用来处理请求的附加数据结构,如果使用Deadline算法,elevator_data指向struct deadline_data结构。
按照我的理解,elevator.h定义了一个框架,它类似面向对象程序中的基类,每个具体的 IO调度程序可以看作是它的派生类。父类elevator中定义了一些公用的方法,而这些方法的实现依据不同的调度算法其实现的方式也不同。子类会实现父类elevator中定义的函数集elevator_ops。下一节以deadline算法为例来描述IO调度程序是如何处理来自通用块层的请求,并最终下发到物理设备上。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: