前文介紹了CFQ調度器的一些概念和結構之間的關系,這裡再結合實際的代碼,來分析CFQ的工作流程。
Linux I/O Scheduler--CFQ(上) http://www.linuxidc.com/Linux/2012-12/76163.htm
CFQ調度器的定義如下:
static struct elevator_type iosched_cfq = {
.ops = {
.elevator_merge_fn = cfq_merge,
.elevator_merged_fn = cfq_merged_request,
.elevator_merge_req_fn = cfq_merged_requests,
.elevator_allow_merge_fn = cfq_allow_merge,
.elevator_dispatch_fn = cfq_dispatch_requests,
.elevator_add_req_fn = cfq_insert_request,
.elevator_activate_req_fn = cfq_activate_request,
.elevator_deactivate_req_fn = cfq_deactivate_request,
.elevator_queue_empty_fn = cfq_queue_empty,
.elevator_completed_req_fn = cfq_completed_request,
.elevator_former_req_fn = elv_rb_former_request,
.elevator_latter_req_fn = elv_rb_latter_request,
.elevator_set_req_fn = cfq_set_request,
.elevator_put_req_fn = cfq_put_request,
.elevator_may_queue_fn = cfq_may_queue,
.elevator_init_fn = cfq_init_queue,
.elevator_exit_fn = cfq_exit_queue,
.trim = cfq_free_io_context,
},
.elevator_attrs = cfq_attrs,
.elevator_name = "cfq",
.elevator_owner = THIS_MODULE,
};
可以看到CFQ調度器涉及到的操作函數還是比較多的,這裡我只打算選一些和提交bio以及request相關的函數進行分析。在提交bio的時候,如果在通用層尋找可以合並bio的途徑失敗,要通過cfq_merge()來判斷是否能夠將bio插入到某個request的bio鏈表首部
static struct request *
cfq_find_rq_fmerge(struct cfq_data *cfqd, struct bio *bio)
{
struct task_struct *tsk = current;
struct cfq_io_context *cic;
struct cfq_queue *cfqq;
//在進程的io_context中,找到進程特定於塊設備的cfq_io_context
cic = cfq_cic_lookup(cfqd, tsk->io_context);
if (!cic)
return NULL;
//根據同步還是異步,確定cfq_queue
cfqq = cic_to_cfqq(cic, cfq_bio_sync(bio));
if (cfqq) {
sector_t sector = bio->bi_sector + bio_sectors(bio);//得到末尾扇區號
//從cfq_queue的紅黑樹中查找對應的節點
return elv_rb_find(&cfqq->sort_list, sector);
}
return NULL;
}