代码语言:javascript复制
/*分析 块设备的工作原理*/
void ll_rw_block(int rw, int nr, struct buffer_head *bhs[])
{
int i;
for (i = 0; i < nr; i ) {
struct buffer_head *bh = bhs[i];
if (!trylock_buffer(bh))
continue;
//写操作
if (rw == WRITE) {
if (test_clear_buffer_dirty(bh)) {
bh->b_end_io = end_buffer_write_sync;
get_bh(bh);
submit_bh(WRITE, bh);
continue;
}
} else {
//读操作
if (!buffer_uptodate(bh)) {
bh->b_end_io = end_buffer_read_sync;
get_bh(bh);
//提交操作
submit_bh(rw, bh);
continue;
}
}
unlock_buffer(bh);
}
}
int submit_bh(int rw, struct buffer_head * bh)
{
/*
* from here on down, it's all bio -- do the initial mapping,
* submit_bio -> generic_make_request may further map this bio around
*/
//分配bio结构,然后用dh初始化bio结构
bio = bio_alloc(GFP_NOIO, 1);
bio->bi_sector = bh->b_blocknr * (bh->b_size >> 9);
bio->bi_bdev = bh->b_bdev;
bio->bi_io_vec[0].bv_page = bh->b_page;
bio->bi_io_vec[0].bv_len = bh->b_size;
bio->bi_io_vec[0].bv_offset = bh_offset(bh);
bio->bi_vcnt = 1;
bio->bi_idx = 0;
bio->bi_size = bh->b_size;
bio->bi_end_io = end_bio_bh_io_sync;
bio->bi_private = bh;
bio_get(bio);
//根据注释进一步初始化bio结构
submit_bio(rw, bio);
}
//用bio结构构造request请求
void submit_bio(int rw, struct bio *bio)
{
generic_make_request(bio);
}
void generic_make_request(struct bio *bio)
{
struct bio_list bio_list_on_stack;
//如果当前的bio_list存在了,直接返回
if (current->bio_list) {
/* make_request is active */
bio_list_add(current->bio_list, bio);
return;
}
//将bio_list_on_stack放入bio_list中
BUG_ON(bio->bi_next);
bio_list_init(&bio_list_on_stack);
current->bio_list = &bio_list_on_stack;
do {
//进一步构造通用请求
__generic_make_request(bio);
bio = bio_list_pop(current->bio_list);
} while (bio);
current->bio_list = NULL; /* deactivate */
}
static inline void __generic_make_request(struct bio *bio)
{
do {
//获得请求队列
q = bdev_get_queue(bio->bi_bdev);
//调用队列中的"构造请求函数"
ret = q->make_request_fn(q, bio); //当我们写驱动程序时,不提供request函数时,系统有一个默认的函数__make_request
} while (ret);
}
//看默认的request函数都干啥了
static int __make_request(struct request_queue *q, struct bio *bio)
{
/*
* Check if we can merge with the plugged list before grabbing
* any locks.
*/
//先尝试合并,如果合并成功则退出
if (attempt_plug_merge(current, q, bio))
goto out;
spin_lock_irq(q->queue_lock);
//如果不退出,则接着继续合并。调用的是电梯队列中的elevator_merge_fn函数
el_ret = elv_merge(q, &req, bio);
if (el_ret == ELEVATOR_BACK_MERGE) {//向后开始合并
if (bio_attempt_back_merge(q, req, bio)) {
if (!attempt_back_merge(q, req))
elv_merged_request(q, req, el_ret);
goto out_unlock;
}
} else if (el_ret == ELEVATOR_FRONT_MERGE) {//从前面开始合并
if (bio_attempt_front_merge(q, req, bio)) {
if (!attempt_front_merge(q, req))
elv_merged_request(q, req, el_ret);
goto out_unlock;
}
}
//如果合并不成功,则用bio结构构造request
init_request_from_bio(req, bio);
//执行队列
__blk_run_queue(q);
}void __blk_run_queue(struct request_queue *q)
{
if (unlikely(blk_queue_stopped(q)))
return;
//调用队列的处理函数, 当我们写驱动时,我们写的处理函数就在这里使用
q->request_fn(q);
}
/*
总结:
(1): 对于块设备来说,不能像字符设备是按顺序存取的。为了提高效率,总是将同方向的任务先处理(就像电梯一样)。这样系统的效率会大大的提高。
(2): 当处理任务时,先是把任务放入队列中,根据某种算法(电梯算法)来优化任务。重新排序任务的顺序等。
(3): 然后当我们写驱动程序的时候就会编写自己的request去替代默认的request函数去处理请求的。
*/