前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >块设备工作原理分析

块设备工作原理分析

作者头像
DragonKingZhu
发布2022-05-08 16:12:52
4700
发布2022-05-08 16:12:52
举报
代码语言: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函数去处理请求的。
*/
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2015-02-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档