备注:新版本的linux(6.10)中只保留了mq-deadline调度器,该调度器保留了较老的deadline调度器的一些特征。本文分析4.19版本内核实现的MQ Deadline调度器。
在MQ Deadline调度器中使用struct deadline_data描述MQ-Deadline调度器的运行时数据,可用于管理和优化存储设备上的请求调度,该结构实现如下:
struct deadline_data {
/*
* run time data
*/
/*
* requests (deadline_rq s) are present on both sort_list and fifo_list
*/
//红黑树,用于维护请求的排序列表。
struct rb_root sort_list[2];
//链表头,用于实现先进先出 (FIFO) 的请求列表。这种列表通常用于按照请求到达的顺序进行调度。
struct list_head fifo_list[2];
/*
* next in sort order. read, write or both are NULL
*/
//用于存储下一个请求的指针数组,可以存储读取请求、写入请求或者两者的组合。
struct request *next_rq[2];
//表示连续发出的请求的数量
unsigned int batching; /* number of sequential requests made */
//表示读请求饥饿写请求的次数。可能用于调整读写请求之间的优先级或者调度策略。
unsigned int starved; /* times reads have starved writes */
/*
* settings that change how the i/o scheduler behaves
*/
int fifo_expire[2]; //FIFO 列表中请求的过期时间。这个设置可能用于确定请求在 FIFO 列表中保留的时间长度。
int fifo_batch; //FIFO 列表的批处理大小。可用于控制每次处理 FIFO 列表中请求的数量。
int writes_starved; //写请求饥饿的次数。可用于调整写请求的优先级或者调度策略。
int front_merges; //前端合并次数。可用于优化请求的合并操作,减少磁盘操作次数。
spinlock_t lock;
spinlock_t zone_lock;
struct list_head dispatch;
};
在内核中,使用struct elevator_type mq_deadline描述MQ Deadline调度器的具体行为:
static struct elevator_type mq_deadline = {
.ops.mq = {
.insert_requests = dd_insert_requests,
.dispatch_request = dd_dispatch_request,
.prepare_request = dd_prepare_request,
.finish_request = dd_finish_request,
.next_request = elv_rb_latter_request,
.former_request = elv_rb_former_request,
.bio_merge = dd_bio_merge,
.request_merge = dd_request_merge,
.requests_merged = dd_merged_requests,
.request_merged = dd_request_merged,
.has_work = dd_has_work,
.init_sched = dd_init_queue,
.exit_sched = dd_exit_queue,
},
.uses_mq = true,
#ifdef CONFIG_BLK_DEBUG_FS
.queue_debugfs_attrs = deadline_queue_debugfs_attrs,
#endif
.elevator_attrs = deadline_attrs,
.elevator_name = "mq-deadline",
.elevator_alias = "deadline",
.elevator_owner = THIS_MODULE,
};
从上述代码可知,该调度器实现了13个具体的调度行为,后文将分析这些回调函数。
一、调度器初始化/注销
MQ-Deadline调度器的初始化由dd_init_queue()完成,用于具体分配并初始化MQ-Deadline调度器的私有数据和电梯队列:
static int dd_init_queue(struct request_queue *q, struct elevator_type *e)
{
struct deadline_data *dd;
struct elevator_queue *eq;
eq = elevator_alloc(q, e);
if (!eq)
return -ENOMEM;
dd = kzalloc_node(sizeof(*dd), GFP_KERNEL, q->node);
if (!dd) {
kobject_put(&eq->kobj);
return -ENOMEM;
}
eq->elevator_data = dd;
INIT_LIST_HEAD(&dd->fifo_list[READ]);
INIT_LIST_HEAD(&dd->fifo_list[WRITE]);
dd->sort_list[READ] = RB_ROOT;
dd->sort_list[WRITE] = RB_ROOT;
dd->fifo_expire[READ] = read_expire;
dd->fifo_expire[WRITE] = write_expire;
dd->writes_starved = writes_starved;
dd->front_merges = 1;
dd->fifo_batch = fifo_batch;
spin_lock_init(&dd->lock);
spin_lock_init(&dd->zone_lock);
INIT_LIST_HEAD(&dd->dispatch);
q->elevator = eq;
return 0;
}
MQ-Deadline调度器的注销由dd_exit_queue()完成:
static void dd_exit_queue(struct elevator_queue *e)
{
struct deadline_data *dd = e->elevator_data;
BUG_ON(!list_empty(&dd->fifo_list[READ]));
BUG_ON(!list_empty(&dd->fifo_list[WRITE]));
kfree(dd);
}
在调度器注销操作中则是使用kfree()释放struct deadline_data。



被折叠的 条评论
为什么被折叠?



