框架:
app: open, read, write, "1.txt"
---------------------------------------------------------------- 文件的读写
文件系统: vfat, ext2, ext3, yaffs2, jffs2 (把文件的读写转换为扇区的读写)
----------------------ll_rw_block------------------------------ 扇区的读写
|->1.把读写放入队列
2.调用队列的处理函数(优化:调序/合并)
块设备驱动程序
----------------------------------------------------------------
硬件:
硬盘,flash
ll_rw_block函数分析(linux-2.6.22.6\fs\Buffer.c):
ll_re_block->submit_bh
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 (rw == WRITE || rw == SWRITE) {
if (test_clear_buffer_dirty(bh)) {
...
submit_bh(WRITE, bh);
...
}
} else {
if (!buffer_uptodate(bh)) {
...
submit_bh(rw, bh);
...
}
}
...
}
}
submit_bh->submit_bio
int submit_bh(int rw, struct buffer_head * bh)
{
struct bio *bio;
...
bio = bio_alloc(GFP_NOIO, 1);
//利用bh构造bio
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);
submit_bio(rw, bio);
...
}
submit_bio->generic_make_request
void submit_bio(int rw, struct bio *bio)
{
...
generic_make_request(bio);
}
generic_make_request->_generic_make_request
void generic_make_request(struct bio *bio)
{
...
do {
...
__generic_make_request(bio);
...
} while (bio);
...
}
_generic_make_request->make_request_fn
static inline void __generic_make_request(struct bio *bio)
{
request_queue_t *q;
...
do {
...
q = bdev_get_queue(bio->bi_bdev);
...
//调用队列的“构造请求函数”
ret = q->make_request_fn(q, bio);
} while (ret);
}
这里插入介绍make_request_fn如何在blk_queue_make_request中赋值
void blk_queue_make_request(request_queue_t * q, make_request_fn * mfn)
{
...
q->make_request_fn = mfn;
...
}
而blk_queue_make_request在blk_init_queue_node中调用,令make_request_fn=__make_request,如下
request_queue_t *
blk_init_queue_node(request_fn_proc *rfn, spinlock_t *lock, int node_id)
{
request_queue_t *q = blk_alloc_queue_node(GFP_KERNEL, node_id);
blk_queue_make_request(q, __make_request);
...
}
接上_generic_make_request,_generic_make_request->_make_request->__generic_unplug_device
static int __make_request(request_queue_t *q, struct bio *bio)
{
struct request *req;
...
//先尝试合并
el_ret = elv_merge(q, &req, bio);
switch (el_ret) {
case ELEVATOR_BACK_MERGE: //ELEVATOR_BACK_MERGE:bio结构可作为末尾的bio而插入到某个请求中
...
blk_add_trace_bio(q, bio, BLK_TA_BACKMERGE);
req->biotail->bi_next = bio;
req->biotail = bio;
req->nr_sectors = req->hard_nr_sectors += nr_sectors;
req->ioprio = ioprio_best(req->ioprio, prio);
drive_stat_acct(req, nr_sectors, 0);
if (!attempt_back_merge(q, req))
elv_merged_request(q, req, el_ret);
goto out;
case ELEVATOR_FRONT_MERGE: //ELEVATOR_FRONT_MERGE:bio结构可作为某个请求的第一个bio被插入;
...
blk_add_trace_bio(q, bio, BLK_TA_FRONTMERGE);
bio->bi_next = req->bio;
req->bio = bio;
req->buffer = bio_data(bio);
req->current_nr_sectors = bio_cur_sectors(bio);
req->hard_cur_sectors = req->current_nr_sectors;
req->sector = req->hard_sector = bio->bi_sector;
req->nr_sectors = req->hard_nr_sectors += nr_sectors;
req->ioprio = ioprio_best(req->ioprio, prio);
drive_stat_acct(req, nr_sectors, 0);
if (!attempt_front_merge(q, req))
elv_merged_request(q, req, el_ret);
goto out;
default: //ELV_NO_MERGE:elevator says don't/can't merge
;
}
get_rq: //不能合并
...
init_request_from_bio(req, bio); //使用bio构造请求
...
add_request(q, req); //把请求放入队列
out:
if (sync)
__generic_unplug_device(q); //执行队列
spin_unlock_irq(q->queue_lock);
return 0;
end_io:
bio_endio(bio, nr_sectors << 9, err);
return 0;
}
__generic_unplug_device->request_fn
void __generic_unplug_device(request_queue_t *q)
{
...
q->request_fn(q); //调用队列的处理函数
}
而request_fn函数是按以下过程实现的:
以linux-2.6.22.6\drivers\block\Xd.c为例,在我们编写的块设备驱动程序中,会定义一个处理函数如do_xd_request,在初始化函数中初始化队列时将这个函数的地址作为参数传入
xd_init->blk_init_queue
static void do_xd_request (request_queue_t * q)
{
...
}
static struct request_queue *xd_queue;
static int __init xd_init(void)
{
...
xd_queue = blk_init_queue(do_xd_request, &xd_lock);
...
}
blk_init_queue->blk_init_queue_node
request_queue_t *blk_init_queue(request_fn_proc *rfn, spinlock_t *lock)
{
return blk_init_queue_node(rfn, lock, -1);
}
进入blk_init_queue_node函数,rfn=do_xd_request,而q->request_fn=rfn,故q->request_fn=do_xd_request
request_queue_t *
blk_init_queue_node(request_fn_proc *rfn, spinlock_t *lock, int node_id)
{
request_queue_t *q = blk_alloc_queue_node(GFP_KERNEL, node_id);
...
q->request_fn = rfn;
...
}