【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_request将bio添加到一个请求。
【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试图在请求队列中找到一个能够合并该bio的request,该函数返回三个可能值:ELEVATOR_NO_MERGE,队列已经存在的请求中不包含bio结构,需要创建一个新的请求。ELEVATOR_BACK_MERGE,bio结构作为末尾的bio而插入到某个请求中。ELEVATOR_FRONT_MERGE,bio结构可作为某个请求的第一个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_bio将bio添加到该请求。如果设置了plug则请求队列被阻塞,当多个请求产生时,请求才得以处理,以此获得最佳性能。如果没有设置plug则调用函数__blk_run_queue立即对请求进行处理。该函数将调用请求处理函数q->request_fn(q);。