分类: LINUX
2012-05-08 14:25:42
};
以上是CFQ调度器在电梯算法接口中的实现函数,本文对重要的函数进行解析:
cfq_dispatch_requests:
该函数是电梯算法用到的最重要的一个函数,底层的设备驱动会调用电梯算法的接口elevator_dispatch_fn来获取下一个执行的请求,也就是调用cfq_dispatch_requests
#2582 可以看到cfq_data指针存在request_queue->elevator->elevator_data中
#2585 如果cfq_data->busy_queues为0,说明没有请求队列,直接返回
#2588 cfq_forced_dispatch后面再讲
#2591 cfq_select_queue前面已经提过,最终是给出一个结果:保留当前cfq_queue还是重新选一个cfq_queue。这里面涉及了诸如 time slice是否耗尽,是否需要slice_idle和group_idle,当前cfq_queue里是否还有请求等一系列判断。如果选择了新的一个 cfq_queue,那么把这个新的cfq_queue放到cfq_data->active_queue里,把原来的cfq_queue也加入到 cfq_data,cfq_group的一系列service tree, prio tree这些红黑树中
#2598 找到了cfq_queue之后,开始调用cfq_dispatch_request,该函数的作用和代码中的注释一样
/*
* Dispatch a request from cfqq, moving them to the request queue
* dispatch list.
*/
#2551 调用cfq_may_dispatch来判断当前是否可以分发给下层驱动请求,该函数的解析请看前一篇
#2557 调用cfq_check_fifo,查看并返回cfq_queue->fifo队列里已经超时的请求。我们前面提到过,cfq_queue内部是按 照部分类似deadline的调度算法来进行的。如果没有超时的请求,则返回正常的红黑树的下一个请求next_rq
这里再提下cfq_queue的请求队列,cfq_queue->sort_list是一个红黑树结构,里面是这个队列里排过序的请求。请求 排序的key是基于请求的起始sector的,也就是blk_rq_pos(request),具体可以参考elv_rb_add的实现
#2564 是真正把请求下发到底层驱动的实现
/*
* Move request from internal lists to the request queue dispatch list.
*/
static void cfq_dispatch_insert(struct request_queue *q, struct request *rq)
{
struct cfq_data *cfqd = q->elevator->elevator_data;
struct cfq_queue *cfqq = RQ_CFQQ(rq);
cfq_log_cfqq(cfqd, cfqq, "dispatch_insert");
cfqq->next_rq = cfq_find_next_rq(cfqd, cfqq, rq);
cfq_remove_request(rq);
cfqq->dispatched++;
(RQ_CFQG(rq))->dispatched++;
elv_dispatch_sort(q, rq);
cfqd->rq_in_flight[cfq_cfqq_sync(cfqq)]++;
cfqq->nr_sectors += blk_rq_sectors(rq);
cfq_blkiocg_update_dispatch_stats(&cfqq->cfqg->blkg, blk_rq_bytes(rq),
rq_data_dir(rq), rq_is_sync(rq));
}
此时rq要被下发到底层驱动,所以需要找一个和rq磁盘位置最近的请求作为cfq_queue->next_rq,之后调用 cfq_remove_request把请求从cfq_queue队列里删除。之后调用elv_dispatch_sort把请求加入到分发队列中并排序
#2608 如果cfq_data->busy_queues大于1,同时该cfq_queue是一个异步队列,同时cfq_queue使用的时间已经超出了 cfq_prio_to_maxrq计算出来的时间或者该队列是idle class,都会调用cfq_slice_expired立刻让队列过期
static void cfq_insert_request(struct request_queue *q, struct request *rq):
#define RQ_CIC(rq) ((struct cfq_io_context *) (rq)->elevator_private[0])
#define RQ_CFQQ(rq) (struct cfq_queue *) ((rq)->elevator_private[1])
#define RQ_CFQG(rq) (struct cfq_group *) ((rq)->elevator_private[2])
从上面3个宏定义可以看出,request相关联的cfq_io_context, cfq_queue, cfq_group都是存在request->elevator_private数组中的,因此
#3466 - #3467 通过request_queue->elevator->elevator_data得到cfq_data,通过request得到相关联的 cfq_queue,通过request得到相关联cfq_io_context进而得到io_context
#3470 调用cfq_init_prio_data
#2852 如果cfq_cfqq_prio_changed(cfqq)为false,直接返回,因为如果优先级没变化,没必要改变cfq_queue的优先级变量
#2855 通过io_context得到进程的io优先级ioprio_class
#2859 - #2879 ioprio_class有IOPRIO_CLASS_NONE, IOPRIO_CLASS_RT, IOPRIO_CLASS_BE, IOPRIO_CLASS_IDLE,相应的ioprio也有不同的计算方法
#2885 - #2887 按照ioprio_class, ioprio初始化好cfq_queue
#3473 cfqq->fifo加到request->queuelist末尾
#3474 调用cfq_add_rq_rb把request添加到cfq_queue的红黑树中
#3478 调用cfq_rq_enqueue
cfq_completed_request(struct request_queue *q, struct request *rq):
开始顺序调用cfqd->rq_in_driver--,cfqd->rq_in_flight--, cfqq->dispatched--, cfq_group->dispatched--
如果cfqq是当前cfqd->active_queue
/*
* If this is the active queue, check if it needs to be expired,
* or if we want to idle in case it has no pending requests.
*/
/*
* Idling is not enabled on:
* - expired queues
* - idle-priority queues
* - async queues
* - queues with still some requests queued
* - when there is a close cooperator
*/