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

📄 balloc.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
{	struct ext2_reserve_window_node *next_rsv;	struct rb_node *next;	spinlock_t *rsv_lock = &EXT2_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 ext2_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);}/** * ext2_try_to_allocate_with_rsv() * @sb:			superblock * @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 * * 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 ext2_grpblk_text2_try_to_allocate_with_rsv(struct super_block *sb, unsigned int group,			struct buffer_head *bitmap_bh, ext2_grpblk_t grp_goal,			struct ext2_reserve_window_node * my_rsv,			unsigned long *count){	ext2_fsblk_t group_first_block, group_last_block;	ext2_grpblk_t ret = 0;	unsigned long num = *count;	/*	 * 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) {		return ext2_try_to_allocate(sb, group, bitmap_bh,						grp_goal, count, NULL);	}	/*	 * grp_goal is a group relative block number (if there is a goal)	 * 0 <= grp_goal < EXT2_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 = ext2_group_first_block_no(sb, group);	group_last_block = group_first_block + (EXT2_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(&EXT2_SB(sb)->s_rsv_window_root, 1);			BUG();		}		ret = ext2_try_to_allocate(sb, 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;	}	return ret;}/** * ext2_has_free_blocks() * @sbi:		in-core super block structure. * * Check if filesystem has at least 1 free block available for allocation. */static int ext2_has_free_blocks(struct ext2_sb_info *sbi){	ext2_fsblk_t free_blocks, root_blocks;	free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter);	root_blocks = le32_to_cpu(sbi->s_es->s_r_blocks_count);	if (free_blocks < root_blocks + 1 && !capable(CAP_SYS_RESOURCE) &&		sbi->s_resuid != current->fsuid &&		(sbi->s_resgid == 0 || !in_group_p (sbi->s_resgid))) {		return 0;	}	return 1;}/* * ext2_new_blocks() -- core block(s) allocation function * @inode:		file inode * @goal:		given target block(filesystem wide) * @count:		target number of blocks to allocate * @errp:		error code * * ext2_new_blocks uses a goal block to assist allocation.  If the goal is * free, or there is a free block within 32 blocks of the goal, that block * is allocated.  Otherwise a forward search is made for a free block; within  * each block group the search first looks for an entire free byte in the block * bitmap, and then for any free bit if that fails. * This function also updates quota and i_blocks field. */ext2_fsblk_t ext2_new_blocks(struct inode *inode, ext2_fsblk_t goal,		    unsigned long *count, int *errp){	struct buffer_head *bitmap_bh = NULL;	struct buffer_head *gdp_bh;	int group_no;	int goal_group;	ext2_grpblk_t grp_target_blk;	/* blockgroup relative goal block */	ext2_grpblk_t grp_alloc_blk;	/* blockgroup-relative allocated block*/	ext2_fsblk_t ret_block;		/* filesyetem-wide allocated block */	int bgi;			/* blockgroup iteration index */	int performed_allocation = 0;	ext2_grpblk_t free_blocks;	/* number of free blocks in a group */	struct super_block *sb;	struct ext2_group_desc *gdp;	struct ext2_super_block *es;	struct ext2_sb_info *sbi;	struct ext2_reserve_window_node *my_rsv = NULL;	struct ext2_block_alloc_info *block_i;	unsigned short windowsz = 0;	unsigned long ngroups;	unsigned long num = *count;	*errp = -ENOSPC;	sb = inode->i_sb;	if (!sb) {		printk("ext2_new_blocks: nonexistent device");		return 0;	}	/*	 * Check quota for allocation of this block.	 */	if (DQUOT_ALLOC_BLOCK(inode, num)) {		*errp = -EDQUOT;		return 0;	}	sbi = EXT2_SB(sb);	es = EXT2_SB(sb)->s_es;	ext2_debug("goal=%lu.\n", goal);	/*	 * Allocate a block from reservation only when	 * filesystem is mounted with reservation(default,-o reservation), and	 * it's a regular file, and	 * the desired window size is greater than 0 (One could use ioctl	 * command EXT2_IOC_SETRSVSZ to set the window size to 0 to turn off	 * reservation on that particular file)	 */	block_i = EXT2_I(inode)->i_block_alloc_info;	if (block_i) {		windowsz = block_i->rsv_window_node.rsv_goal_size;		if (windowsz > 0)			my_rsv = &block_i->rsv_window_node;	}	if (!ext2_has_free_blocks(sbi)) {		*errp = -ENOSPC;		goto out;	}	/*	 * First, test whether the goal block is free.	 */	if (goal < le32_to_cpu(es->s_first_data_block) ||	    goal >= le32_to_cpu(es->s_blocks_count))		goal = le32_to_cpu(es->s_first_data_block);	group_no = (goal - le32_to_cpu(es->s_first_data_block)) /			EXT2_BLOCKS_PER_GROUP(sb);	goal_group = group_no;retry_alloc:	gdp = ext2_get_group_desc(sb, group_no, &gdp_bh);	if (!gdp)		goto io_error;	free_blocks = le16_to_cpu(gdp->bg_free_blocks_count);	/*	 * if there is not enough free blocks to make a new resevation	 * turn off reservation for this allocation	 */	if (my_rsv && (free_blocks < windowsz)		&& (rsv_is_empty(&my_rsv->rsv_window)))		my_rsv = NULL;	if (free_blocks > 0) {		grp_target_blk = ((goal - le32_to_cpu(es->s_first_data_block)) %				EXT2_BLOCKS_PER_GROUP(sb));		bitmap_bh = read_block_bitmap(sb, group_no);		if (!bitmap_bh)			goto io_error;		grp_alloc_blk = ext2_try_to_allocate_with_rsv(sb, group_no,					bitmap_bh, grp_target_blk,					my_rsv, &num);		if (grp_alloc_blk >= 0)			goto allocated;	}	ngroups = EXT2_SB(sb)->s_groups_count;	smp_rmb();	/*	 * Now search the rest of the groups.  We assume that 	 * i and gdp correctly point to the last group visited.	 */	for (bgi = 0; bgi < ngroups; bgi++) {		group_no++;		if (group_no >= ngroups)			group_no = 0;		gdp = ext2_get_group_desc(sb, group_no, &gdp_bh);		if (!gdp)			goto io_error;		free_blocks = le16_to_cpu(gdp->bg_free_blocks_count);		/*		 * skip this group if the number of		 * free blocks is less than half of the reservation		 * window size.		 */		if (free_blocks <= (windowsz/2))			continue;		brelse(bitmap_bh);		bitmap_bh = read_block_bitmap(sb, group_no);		if (!bitmap_bh)			goto io_error;		/*		 * try to allocate block(s) from this group, without a goal(-1).		 */		grp_alloc_blk = ext2_try_to_allocate_with_rsv(sb, group_no,					bitmap_bh, -1, my_rsv, &num);		if (grp_alloc_blk >= 0)			goto allocated;	}	/*	 * We may end up a bogus ealier ENOSPC error due to	 * filesystem is "full" of reservations, but	 * there maybe indeed free blocks avaliable on disk	 * In this case, we just forget about the reservations	 * just do block allocation as without reservations.	 */	if (my_rsv) {		my_rsv = NULL;		windowsz = 0;		group_no = goal_group;		goto retry_alloc;	}	/* No space left on the device */	*errp = -ENOSPC;	goto out;allocated:	ext2_debug("using block group %d(%d)\n",			group_no, gdp->bg_free_blocks_count);	ret_block = grp_alloc_blk + ext2_group_first_block_no(sb, group_no);	if (in_range(le32_to_cpu(gdp->bg_block_bitmap), ret_block, num) ||	    in_range(le32_to_cpu(gdp->bg_inode_bitmap), ret_block, num) ||	    in_range(ret_block, le32_to_cpu(gdp->bg_inode_table),		      EXT2_SB(sb)->s_itb_per_group) ||	    in_range(ret_block + num - 1, le32_to_cpu(gdp->bg_inode_table),		      EXT2_SB(sb)->s_itb_per_group))		ext2_error(sb, "ext2_new_blocks",			    "Allocating block in system zone - "			    "blocks from "E2FSBLK", length %lu",			    ret_block, num);	performed_allocation = 1;	if (ret_block + num - 1 >= le32_to_cpu(es->s_blocks_count)) {		ext2_error(sb, "ext2_new_blocks",			    "block("E2FSBLK") >= blocks count(%d) - "			    "block_group = %d, es == %p ", ret_block,			le32_to_cpu(es->s_blocks_count), group_no, es);		goto out;	}	group_adjust_blocks(sb, group_no, gdp, gdp_bh, -num);	percpu_counter_sub(&sbi->s_freeblocks_counter, num);	mark_buffer_dirty(bitmap_bh);	if (sb->s_flags & MS_SYNCHRONOUS)		sync_dirty_buffer(bitmap_bh);	*errp = 0;	brelse(bitmap_bh);	DQUOT_FREE_BLOCK(inode, *count-num);	*count = num;	return ret_block;io_error:	*errp = -EIO;out:	/*	 * Undo the block allocation	 */	if (!performed_allocation)		DQUOT_FREE_BLOCK(inode, *count);	brelse(bitmap_bh);	return 0;}ext2_fsblk_t ext2_new_block(struct inode *inode, unsigned long goal, int *errp){	unsigned long count = 1;	return ext2_new_blocks(inode, goal, &count, errp);}#ifdef EXT2FS_DEBUGstatic const int nibblemap[] = {4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0};unsigned long ext2_count_free (struct buffer_head * map, unsigned int numchars){	unsigned int i;	unsigned long sum = 0;	if (!map)		return (0);	for (i = 0; i < numchars; i++)		sum += nibblemap[map->b_data[i] & 0xf] +			nibblemap[(map->b_data[i] >> 4) & 0xf];	return (sum);}#endif  /*  EXT2FS_DEBUG  */unsigned long ext2_count_free_blocks (struct super_block * sb){	struct ext2_group_desc * desc;	unsigned long desc_count = 0;	int i;#ifdef EXT2FS_DEBUG	unsigned long bitmap_count, x;	struct ext2_super_block *es;	es = EXT2_SB(sb)->s_es;	desc_count = 0;	bitmap_count = 0;	desc = NULL;	for (i = 0; i < EXT2_SB(sb)->s_groups_count; i++) {		struct buffer_head *bitmap_bh;		desc = ext2_get_group_desc (sb, i, NULL);		if (!desc)			continue;		desc_count += le16_to_cpu(desc->bg_free_blocks_count);		bitmap_bh = read_block_bitmap(sb, i);		if (!bitmap_bh)			continue;				x = ext2_count_free(bitmap_bh, sb->s_blocksize);		printk ("group %d: stored = %d, counted = %lu\n",			i, le16_to_cpu(desc->bg_free_blocks_count), x);		bitmap_count += x;		brelse(bitmap_bh);	}	printk("ext2_count_free_blocks: stored = %lu, computed = %lu, %lu\n",		(long)le32_to_cpu(es->s_free_blocks_count),		desc_count, bitmap_count);	return bitmap_count;#else        for (i = 0; i < EXT2_SB(sb)->s_groups_count; i++) {                desc = ext2_get_group_desc (sb, i, NULL);                if (!desc)                        continue;                desc_count += le16_to_cpu(desc->bg_free_blocks_count);	}	return desc_count;#endif}static inline int test_root(int a, int b){	int num = b;	while (a > num)		num *= b;	return num == a;}static int ext2_group_sparse(int group){	if (group <= 1)		return 1;	return (test_root(group, 3) || test_root(group, 5) ||		test_root(group, 7));}/** *	ext2_bg_has_super - number of blocks used by the superblock in group *	@sb: superblock for filesystem *	@group: group number to check * *	Return the number of blocks used by the superblock (primary or backup) *	in this group.  Currently this will be only 0 or 1. */int ext2_bg_has_super(struct super_block *sb, int group){	if (EXT2_HAS_RO_COMPAT_FEATURE(sb,EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)&&	    !ext2_group_sparse(group))		return 0;	return 1;}/** *	ext2_bg_num_gdb - number of blocks used by the group table in group *	@sb: superblock for filesystem *	@group: group number to check * *	Return the number of blocks used by the group descriptor table *	(primary or backup) in this group.  In the future there may be a *	different number of descriptor blocks in each group. */unsigned long ext2_bg_num_gdb(struct super_block *sb, int group){	if (EXT2_HAS_RO_COMPAT_FEATURE(sb,EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)&&	    !ext2_group_sparse(group))		return 0;	return EXT2_SB(sb)->s_gdb_count;}

⌨️ 快捷键说明

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