⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 balloc.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
				;		}	}	start = grp_goal;	if (!claim_block(sb_bgl_lock(EXT4_SB(sb), group),		grp_goal, bitmap_bh)) {		/*		 * 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;	}	num++;	grp_goal++;	while (num < *count && grp_goal < end		&& ext4_test_allocatable(grp_goal, bitmap_bh)		&& claim_block(sb_bgl_lock(EXT4_SB(sb), group),				grp_goal, bitmap_bh)) {		num++;		grp_goal++;	}	*count = num;	return grp_goal - num;fail_access:	*count = num;	return -1;}/** *	find_next_reservable_window(): *		find a reservable space within the given range. *		It does not allocate the reservation window for now: *		alloc_new_reservation() will do the work later. * *	@search_head: the head of the searching list; *		This is not necessarily the list head of the whole filesystem * *		We have both head and start_block to assist the search *		for the reservable space. The list starts from head, *		but we will shift to the place where start_block is, *		then start from there, when looking for a reservable space. * *	@size: the target new reservation window size * *	@group_first_block: the first block we consider to start *			the real search from * *	@last_block: *		the maximum block number that our goal reservable space *		could start from. This is normally the last block in this *		group. The search will end when we found the start of next *		possible reservable space is out of this boundary. *		This could handle the cross boundary reservation window *		request. * *	basically we search from the given range, rather than the whole *	reservation double linked list, (start_block, last_block) *	to find a free region that is of my size and has not *	been reserved. * */static int find_next_reservable_window(				struct ext4_reserve_window_node *search_head,				struct ext4_reserve_window_node *my_rsv,				struct super_block * sb,				ext4_fsblk_t start_block,				ext4_fsblk_t last_block){	struct rb_node *next;	struct ext4_reserve_window_node *rsv, *prev;	ext4_fsblk_t cur;	int size = my_rsv->rsv_goal_size;	/* TODO: make the start of the reservation window byte-aligned */	/* cur = *start_block & ~7;*/	cur = start_block;	rsv = search_head;	if (!rsv)		return -1;	while (1) {		if (cur <= rsv->rsv_end)			cur = rsv->rsv_end + 1;		/* TODO?		 * in the case we could not find a reservable space		 * that is what is expected, during the re-search, we could		 * remember what's the largest reservable space we could have		 * and return that one.		 *		 * For now it will fail if we could not find the reservable		 * space with expected-size (or more)...		 */		if (cur > last_block)			return -1;		/* fail */		prev = rsv;		next = rb_next(&rsv->rsv_node);		rsv = rb_entry(next,struct ext4_reserve_window_node,rsv_node);		/*		 * Reached the last reservation, we can just append to the		 * previous one.		 */		if (!next)			break;		if (cur + size <= rsv->rsv_start) {			/*			 * Found a reserveable space big enough.  We could			 * have a reservation across the group boundary here			 */			break;		}	}	/*	 * we come here either :	 * when we reach the end of the whole list,	 * and there is empty reservable space after last entry in the list.	 * append it to the end of the list.	 *	 * or we found one reservable space in the middle of the list,	 * return the reservation window that we could append to.	 * succeed.	 */	if ((prev != my_rsv) && (!rsv_is_empty(&my_rsv->rsv_window)))		rsv_window_remove(sb, my_rsv);	/*	 * Let's book the whole avaliable window for now.  We will check the	 * disk bitmap later and then, if there are free blocks then we adjust	 * the window size if it's larger than requested.	 * Otherwise, we will remove this node from the tree next time	 * call find_next_reservable_window.	 */	my_rsv->rsv_start = cur;	my_rsv->rsv_end = cur + size - 1;	my_rsv->rsv_alloc_hit = 0;	if (prev != my_rsv)		ext4_rsv_window_add(sb, my_rsv);	return 0;}/** *	alloc_new_reservation()--allocate a new reservation window * *		To make a new reservation, we search part of the filesystem *		reservation list (the list that inside the group). We try to *		allocate a new reservation window near the allocation goal, *		or the beginning of the group, if there is no goal. * *		We first find a reservable space after the goal, then from *		there, we check the bitmap for the first free block after *		it. If there is no free block until the end of group, then the *		whole group is full, we failed. Otherwise, check if the free *		block is inside the expected reservable space, if so, we *		succeed. *		If the first free block is outside the reservable space, then *		start from the first free block, we search for next available *		space, and go on. * *	on succeed, a new reservation will be found and inserted into the list *	It contains at least one free block, and it does not overlap with other *	reservation windows. * *	failed: we failed to find a reservation window in this group * *	@rsv: the reservation * *	@grp_goal: The goal (group-relative).  It is where the search for a *		free reservable space should start from. *		if we have a grp_goal(grp_goal >0 ), then start from there, *		no grp_goal(grp_goal = -1), we start from the first block *		of the group. * *	@sb: the super block *	@group: the group we are trying to allocate in *	@bitmap_bh: the block group block bitmap * */static int alloc_new_reservation(struct ext4_reserve_window_node *my_rsv,		ext4_grpblk_t grp_goal, struct super_block *sb,		unsigned int group, struct buffer_head *bitmap_bh){	struct ext4_reserve_window_node *search_head;	ext4_fsblk_t group_first_block, group_end_block, start_block;	ext4_grpblk_t first_free_block;	struct rb_root *fs_rsv_root = &EXT4_SB(sb)->s_rsv_window_root;	unsigned long size;	int ret;	spinlock_t *rsv_lock = &EXT4_SB(sb)->s_rsv_window_lock;	group_first_block = ext4_group_first_block_no(sb, group);	group_end_block = group_first_block + (EXT4_BLOCKS_PER_GROUP(sb) - 1);	if (grp_goal < 0)		start_block = group_first_block;	else		start_block = grp_goal + group_first_block;	size = my_rsv->rsv_goal_size;	if (!rsv_is_empty(&my_rsv->rsv_window)) {		/*		 * if the old reservation is cross group boundary		 * and if the goal is inside the old reservation window,		 * we will come here when we just failed to allocate from		 * the first part of the window. We still have another part		 * that belongs to the next group. In this case, there is no		 * point to discard our window and try to allocate a new one		 * in this group(which will fail). we should		 * keep the reservation window, just simply move on.		 *		 * Maybe we could shift the start block of the reservation		 * window to the first block of next group.		 */		if ((my_rsv->rsv_start <= group_end_block) &&				(my_rsv->rsv_end > group_end_block) &&				(start_block >= my_rsv->rsv_start))			return -1;		if ((my_rsv->rsv_alloc_hit >		     (my_rsv->rsv_end - my_rsv->rsv_start + 1) / 2)) {			/*			 * if the previously allocation hit ratio is			 * greater than 1/2, then we double the size of			 * the reservation window the next time,			 * otherwise we keep the same size window			 */			size = size * 2;			if (size > EXT4_MAX_RESERVE_BLOCKS)				size = EXT4_MAX_RESERVE_BLOCKS;			my_rsv->rsv_goal_size= size;		}	}	spin_lock(rsv_lock);	/*	 * shift the search start to the window near the goal block	 */	search_head = search_reserve_window(fs_rsv_root, start_block);	/*	 * find_next_reservable_window() simply finds a reservable window	 * inside the given range(start_block, group_end_block).	 *	 * To make sure the reservation window has a free bit inside it, we	 * need to check the bitmap after we found a reservable window.	 */retry:	ret = find_next_reservable_window(search_head, my_rsv, sb,						start_block, group_end_block);	if (ret == -1) {		if (!rsv_is_empty(&my_rsv->rsv_window))			rsv_window_remove(sb, my_rsv);		spin_unlock(rsv_lock);		return -1;	}	/*	 * On success, find_next_reservable_window() returns the	 * reservation window where there is a reservable space after it.	 * Before we reserve this reservable space, we need	 * to make sure there is at least a free block inside this region.	 *	 * searching the first free bit on the block bitmap and copy of	 * last committed bitmap alternatively, until we found a allocatable	 * block. Search start from the start block of the reservable space	 * we just found.	 */	spin_unlock(rsv_lock);	first_free_block = bitmap_search_next_usable_block(			my_rsv->rsv_start - group_first_block,			bitmap_bh, group_end_block - group_first_block + 1);	if (first_free_block < 0) {		/*		 * no free block left on the bitmap, no point		 * to reserve the space. return failed.		 */		spin_lock(rsv_lock);		if (!rsv_is_empty(&my_rsv->rsv_window))			rsv_window_remove(sb, my_rsv);		spin_unlock(rsv_lock);		return -1;		/* failed */	}	start_block = first_free_block + group_first_block;	/*	 * check if the first free block is within the	 * free space we just reserved	 */	if (start_block >= my_rsv->rsv_start && start_block <= my_rsv->rsv_end)		return 0;		/* success */	/*	 * if the first free bit we found is out of the reservable space	 * continue search for next reservable space,	 * start from where the free block is,	 * we also shift the list head to where we stopped last time	 */	search_head = my_rsv;	spin_lock(rsv_lock);	goto retry;}/** * try_to_extend_reservation() * @my_rsv:		given reservation window * @sb:			super block * @size:		the delta to extend * * Attempt to expand the reservation window large enough to have * required number of free blocks * * Since ext4_try_to_allocate() will always allocate blocks within * the reservation window range, if the window size is too small, * multiple blocks allocation has to stop at the end of the reservation * window. To make this more efficient, given the total number of * blocks needed and the current size of the window, we try to * expand the reservation window size if necessary on a best-effort * basis before ext4_new_blocks() tries to allocate blocks, */static void try_to_extend_reservation(struct ext4_reserve_window_node *my_rsv,			struct super_block *sb, int size){	struct ext4_reserve_window_node *next_rsv;	struct rb_node *next;	spinlock_t *rsv_lock = &EXT4_SB(sb)->s_rsv_window_lock;	if (!spin_trylock(rsv_lock))		return;	next = rb_next(&my_rsv->rsv_node);	if (!next)		my_rsv->rsv_end += size;	else {		next_rsv = rb_entry(next, struct ext4_reserve_window_node, rsv_node);		if ((next_rsv->rsv_start - my_rsv->rsv_end - 1) >= size)			my_rsv->rsv_end += size;		else			my_rsv->rsv_end = next_rsv->rsv_start - 1;	}	spin_unlock(rsv_lock);}/** * ext4_try_to_allocate_with_rsv() * @sb:			superblock * @handle:		handle to this transaction * @group:		given allocation block group * @bitmap_bh:		bufferhead holds the block bitmap * @grp_goal:		given target block within the group * @count:		target number of blocks to allocate * @my_rsv:		reservation window * @errp:		pointer to store the error code * * This is the main function used to allocate a new block and its reservation * window. * * Each time when a new block allocation is need, first try to allocate from * its own reservation.  If it does not have a reservation window, instead of * looking for a free bit on bitmap first, then look up the reservation list to * see if it is inside somebody else's reservation window, we try to allocate a * reservation window for it starting from the goal first. Then do the block * allocation within the reservation window. * * This will avoid keeping on searching the reservation list again and * again when somebody is looking for a free block (without * reservation), and there are lots of free blocks, but they are all * being reserved. * * We use a red-black tree for the per-filesystem reservation list. * */static ext4_grpblk_text4_try_to_allocate_with_rsv(struct super_block *sb, handle_t *handle,			unsigned int group, struct buffer_head *bitmap_bh,			ext4_grpblk_t grp_goal,			struct ext4_reserve_window_node * my_rsv,			unsigned long *count, int *errp){	ext4_fsblk_t group_first_block, group_last_block;	ext4_grpblk_t ret = 0;	int fatal;	unsigned long num = *count;	*errp = 0;	/*	 * Make sure we use undo access for the bitmap, because it is critical	 * that we do the frozen_data COW on bitmap buffers in all cases even	 * if the buffer is in BJ_Forget state in the committing transaction.	 */	BUFFER_TRACE(bitmap_bh, "get undo access for new block");	fatal = ext4_journal_get_undo_access(handle, bitmap_bh);	if (fatal) {		*errp = fatal;		return -1;	}	/*	 * we don't deal with reservation when	 * filesystem is mounted without reservation	 * or the file is not a regular file	 * or last attempt to allocate a block with reservation turned on failed	 */	if (my_rsv == NULL ) {		ret = ext4_try_to_allocate(sb, handle, group, bitmap_bh,						grp_goal, count, NULL);		goto out;	}	/*	 * grp_goal is a group relative block number (if there is a goal)	 * 0 <= grp_goal < EXT4_BLOCKS_PER_GROUP(sb)	 * first block is a filesystem wide block number	 * first block is the block number of the first block in this group	 */	group_first_block = ext4_group_first_block_no(sb, group);	group_last_block = group_first_block + (EXT4_BLOCKS_PER_GROUP(sb) - 1);	/*	 * Basically we will allocate a new block from inode's reservation	 * window.	 *	 * We need to allocate a new reservation window, if:	 * a) inode does not have a reservation window; or	 * b) last attempt to allocate a block from existing reservation	 *    failed; or	 * c) we come here with a goal and with a reservation window	 *	 * We do not need to allocate a new reservation window if we come here	 * at the beginning with a goal and the goal is inside the window, or	 * we don't have a goal but already have a reservation window.	 * then we could go to allocate from the reservation window directly.	 */	while (1) {		if (rsv_is_empty(&my_rsv->rsv_window) || (ret < 0) ||			!goal_in_my_reservation(&my_rsv->rsv_window,						grp_goal, group, sb)) {			if (my_rsv->rsv_goal_size < *count)				my_rsv->rsv_goal_size = *count;			ret = alloc_new_reservation(my_rsv, grp_goal, sb,							group, bitmap_bh);			if (ret < 0)				break;			/* failed */			if (!goal_in_my_reservation(&my_rsv->rsv_window,							grp_goal, group, sb))				grp_goal = -1;		} else if (grp_goal >= 0) {			int curr = my_rsv->rsv_end -					(grp_goal + group_first_block) + 1;			if (curr < *count)				try_to_extend_reservation(my_rsv, sb,							*count - curr);		}		if ((my_rsv->rsv_start > group_last_block) ||				(my_rsv->rsv_end < group_first_block)) {			rsv_window_dump(&EXT4_SB(sb)->s_rsv_window_root, 1);			BUG();		}		ret = ext4_try_to_allocate(sb, handle, group, bitmap_bh,					   grp_goal, &num, &my_rsv->rsv_window);		if (ret >= 0) {			my_rsv->rsv_alloc_hit += num;			*count = num;			break;				/* succeed */		}		num = *count;	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -