read--->vfs_read--->do_sync_read--->aio_read--->do_generic_file_read--->readpage--->mpage_readpage--->mpage_bio_submit

static struct bio *mpage_bio_submit(int rw, struct bio *bio)

{

bio->bi_end_io = mpage_end_io;

submit_bio(rw, bio);

return NULL;

}

read--->vfs_read--->do_sync_read--->aio_read--->do_generic_file_read--->readpage--->mpage_readpage--->mpage_bio_submit--->submit_bio

void submit_bio(int rw, struct bio *bio)

{

int count = bio_sectors(bio);

 

bio->bi_rw |= rw;

......

generic_make_request(bio);

}

通过函数generic_make_requestbio添加到一个请求。

 

read--->vfs_read--->do_sync_read--->aio_read--->do_generic_file_read--->readpage--->mpage_readpage--->mpage_bio_submit--->submit_bio--->generic_make_request

 

void generic_make_request(struct bio *bio)

{

struct bio_list bio_list_on_stack;

 

if (!generic_make_request_checks(bio))

return;

 

if (current->bio_list) {

bio_list_add(current->bio_list, bio);

return;

}

 

BUG_ON(bio->bi_next);

bio_list_init(&bio_list_on_stack);

current->bio_list = &bio_list_on_stack;

do {

struct request_queue *q = bdev_get_queue(bio->bi_bdev);

 

q->make_request_fn(q, bio);

 

bio = bio_list_pop(current->bio_list);

} while (bio);

current->bio_list = NULL; /* deactivate */

}

获取bio对应的块设备文件对应的磁盘对象的请求队列,然后调用函数q->make_request_fn创建一个请求用bio初始化并添加到请求队列中。

 

 

blk_init_queue

每一个数据请求都挂在请求队列上并接受请求队列中请求处理函数request_fn的处理。所以这里先分析请求队列的创建与初始化。

struct request_queue *blk_init_queue(request_fn_proc *rfn, spinlock_t *lock)

{

return blk_init_queue_node(rfn, lock, -1);

}

 

blk_init_queue--->blk_init_queue_node

struct request_queue *blk_init_queue_node(request_fn_proc *rfn, spinlock_t *lock, int node_id)

{

struct request_queue *uninit_q, *q;

 

uninit_q = blk_alloc_queue_node(GFP_KERNEL, node_id);

if (!uninit_q)

return NULL;

 

q = blk_init_allocated_queue(uninit_q, rfn, lock);

if (!q)

blk_cleanup_queue(uninit_q);

 

return q;

}

 

首先通过函数blk_alloc_queue_node分配一个请求队列结构 request_queue。然后通过函数blk_init_allocated_queue初始化已分配的请求队列。函数指针rfn是请求处理函数,最终将让请求队列的request_fn字段指向该函数。

 

blk_init_queue--->blk_init_queue_node--->blk_init_allocated_queue

struct request_queue *blk_init_allocated_queue(struct request_queue *q, request_fn_proc *rfn, spinlock_t *lock)

{

.......

q->request_fn = rfn;

......

blk_queue_make_request(q, blk_queue_bio);

......

return NULL;

}

首先让请求队列的request_fn字段指向实际请求处理函数。然后在函数blk_queue_make_request中让请求队列的make_request_fn字段指向实际请求创建函数blk_queue_bio

 

read--->vfs_read--->do_sync_read--->aio_read--->do_generic_file_read--->readpage--->mpage_readpage--->mpage_bio_submit--->submit_bio--->generic_make_request--->make_request_fn

 

void blk_queue_bio(struct request_queue *q, struct bio *bio)

{

const bool sync = !!(bio->bi_rw & REQ_SYNC);

struct blk_plug *plug;

int el_ret, rw_flags, where = ELEVATOR_INSERT_SORT;

struct request *req;

unsigned int request_count = 0;

 

blk_queue_bounce(q, &bio);

 

if (bio->bi_rw & (REQ_FLUSH | REQ_FUA)) {

spin_lock_irq(q->queue_lock);

where = ELEVATOR_INSERT_FLUSH;

goto get_rq;

}

 

if (attempt_plug_merge(q, bio, &request_count))

return;

 

spin_lock_irq(q->queue_lock);

 

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;

}

}

函数elv_merge试图在请求队列中找到一个能够合并该biorequest,该函数返回三个可能值:ELEVATOR_NO_MERGE,队列已经存在的请求中不包含bio结构,需要创建一个新的请求。ELEVATOR_BACK_MERGEbio结构作为末尾的bio而插入到某个请求中。ELEVATOR_FRONT_MERGEbio结构可作为某个请求的第一个bio被插入。

get_rq:

rw_flags = bio_data_dir(bio);

if (sync)

rw_flags |= REQ_SYNC;

 

req = get_request_wait(q, rw_flags, bio);

if (unlikely(!req)) {

bio_endio(bio, -ENODEV); /* @q is dead */

goto out_unlock;

}

 

init_request_from_bio(req, bio);

 

if (test_bit(QUEUE_FLAG_SAME_COMP, &q->queue_flags))

req->cpu = raw_smp_processor_id();

 

plug = current->plug;

if (plug) {

if (list_empty(&plug->list))

trace_block_plug(q);

else {

if (!plug->should_sort) {

struct request *__rq;

 

__rq = list_entry_rq(plug->list.prev);

if (__rq->q != q)

plug->should_sort = 1;

}

if (request_count >= BLK_MAX_REQUEST_COUNT) {

blk_flush_plug_list(plug, false);

trace_block_plug(q);

}

}

list_add_tail(&req->queuelist, &plug->list);

drive_stat_acct(req, 1);

} else {

spin_lock_irq(q->queue_lock);

add_acct_request(q, req, where);

__blk_run_queue(q);

out_unlock:

spin_unlock_irq(q->queue_lock);

}

}

当函数elv_merge返回ELEVATOR_NO_MERGE即需要创建一个新的请求时,先调用函数get_request_wait分配一个请求,然后通过函数init_request_from_biobio添加到该请求。如果设置了plug则请求队列被阻塞,当多个请求产生时,请求才得以处理,以此获得最佳性能。如果没有设置plug则调用函数__blk_run_queue立即对请求进行处理。该函数将调用请求处理函数q->request_fn(q);