ext2_try_to_allocate解析

        前面博客中我们描述了如何为文件分配一个预留窗口,而且我们知道,该预留窗口内的磁盘块有可能已经被占用了,而我们的最终目的是分配空闲磁盘块,而非预留窗口,所以我们这里描述的就是如何分配空闲磁盘块。

        这里我们分配磁盘块有两种途径:第一是通过预留窗口,即在某个预留窗口内分配磁盘块;第二是普通分配方式,这个只是限制在特定块组内分配即可,没有第一种的情况要求那么苛刻。至于使用哪种分配方式,是由上层调用者来决定的。

        对这个函数我们还必须明确一点:1. 分配的空闲磁盘块一定连续;2. 不一定能分配得到想要数量的磁盘块。

static int
ext2_try_to_allocate(struct super_block *sb, int group,
			struct buffer_head *bitmap_bh, ext2_grpblk_t grp_goal,
			unsigned long *count,
			struct ext2_reserve_window *my_rsv)
{
	ext2_fsblk_t group_first_block;
       	ext2_grpblk_t start, end;
	unsigned long num = 0;

	/* we do allocation within the reservation window if we have a window */
	/* here what we should decide is the range(start ~ end) between which we allocate free block(s)
	*/
	/*
	** 如果使用预留窗口,我们必须
	** 保证分配的范围落在预留窗口
	** 并且,要落在goal所在的块组中
	*/
	if (my_rsv) {
		//好像这里面的设置有点儿复杂
		group_first_block = ext2_group_first_block_no(sb, group);
		if (my_rsv->_rsv_start >= group_first_block)
			start = my_rsv->_rsv_start - group_first_block;
		else
			/* reservation window cross group boundary */
			start = 0;
		end = my_rsv->_rsv_end - group_first_block + 1;
		if (end > EXT2_BLOCKS_PER_GROUP(sb))
			/* reservation window crosses group boundary */
			end = EXT2_BLOCKS_PER_GROUP(sb);
		if ((start <= grp_goal) && (grp_goal < end))
			start = grp_goal;
		else
			grp_goal = -1;
	} 
	//如果不使用预留窗口,那么
	//就直接从goal处开始分配好了
	else {
		if (grp_goal > 0)
			start = grp_goal;
		else
			start = 0;
		end = EXT2_BLOCKS_PER_GROUP(sb);
	}

	BUG_ON(start > EXT2_BLOCKS_PER_GROUP(sb));

repeat:
	//如果grp_goal < 0 表示什么呢
	if (grp_goal < 0) {

		//找到grp_goal之后的第一个空闲磁盘块
		//当然查找是有个范围的
		grp_goal = find_next_usable_block(start, bitmap_bh, end);
		if (grp_goal < 0)
			goto fail_access;
		if (!my_rsv) {
			int i;

			for (i = 0; i < 7 && grp_goal > start &&
					!ext2_test_bit(grp_goal - 1,
					     		bitmap_bh->b_data);
			     		i++, grp_goal--)
				;
		}
	}
	start = grp_goal;

	//如果当前的goal 被占用了该函数会执行失败
	// 继续从下一个块开始,即转到repeat开始重试
	if (ext2_set_bit_atomic(sb_bgl_lock(EXT2_SB(sb), group), grp_goal,
			       				bitmap_bh->b_data)) {
		/*
		 * The block was allocated by another thread, or it was
		 * allocated and then freed by another thread
		 */
		start++;
		grp_goal++;
		if (start >= end)
			goto fail_access;
		goto repeat;
	}
	/* 如果之前的goal是空闲的
	** 那么再继续从下一个搜索
	** 看看下一个连续的块是否也是空闲的
	** 如果有,当然最好,我们可以多分配点
	** 
	*/
	num++;
	grp_goal++;
	while (num < *count && grp_goal < end
		&& !ext2_set_bit_atomic(sb_bgl_lock(EXT2_SB(sb), group),
					grp_goal, bitmap_bh->b_data)) {
		num++;
		grp_goal++;
	}
	*count = num;
	return grp_goal - num;
fail_access:
	*count = num;
	return -1;
}
        我们要明确该函数参数的意义:

  1. group:代表当前要分配的磁盘块所在的块组,无论我们使用的预留窗口有多大,我们最终的分配都必须限制在该块组之内;
  2. bitmap_bh:块组的位图信息,用于寻找空闲磁盘块;
  3. grp_goal:上层建议的从哪开始搜索分配,以达到最佳文件连续性;
  4. *count:上层传入的要分配磁盘块数量,同时这个也作为返回值告知调用者实际分配的磁盘块数量;
  5. my_rsv:是否使用预留窗口,如果其不为NULL,则在该预留窗口中进行分配。
        接下来让我们看看你函数的处理逻辑:

        首先,我们得判断本次分配是否使用预留窗口,如果使用,那么我们必须得计算好我们从哪开始分配,到哪里为止。至于其需要处理的原因在于预留窗口可能是跨块组的,所以我们必须得小心处理这种情况,如果真的跨块组,我们必须得截断,分配必须得在这个块组中进行。而且,我们得根据goal计算出其在块组内的偏移,即grp_goal,因为查找位图的时候是根据块组内偏移来查的。如果不适用预留窗口,那么就简单多了,如果设置了goal,直接从这里开始查找空闲块,否则从块组开始处查找。

         完成了上面查找的设置,接下来我们就是搜索位图开始查找空闲磁盘块了。我们从grp_goal这个位置开始判断:如果这个块被占用了,那么我们得从后面一个块开始重试,所以有一个repeat;如果这个块没被占用,那我们就继续往后找,看看后面的块是否还空闲,如果是,那连这个块一并分配。一直找到不是空闲磁盘块为止,我们的策略是尽可能分配多的连续块。

        最后,*count中保存了本次分配到的连续空闲磁盘块数量,而返回值则是分配的起始磁盘块号。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值