块设备的驱动程序框架

框架:

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;
	...
}


 
 
 
 
 



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值