balloc.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 895 行 · 第 1/2 页

C
895
字号
			goto fail_access;		goto repeat;	}	BUFFER_TRACE(bitmap_bh, "journal_dirty_metadata for bitmap block");	fatal = ext3_journal_dirty_metadata(handle, bitmap_bh);	if (fatal) {		*errp = fatal;		goto fail;	}	return goal;fail_access:	BUFFER_TRACE(bitmap_bh, "journal_release_buffer");	ext3_journal_release_buffer(handle, bitmap_bh, credits);fail:	return -1;}static int ext3_has_free_blocks(struct ext3_sb_info *sbi){	int 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;}/* * ext3_should_retry_alloc() is called when ENOSPC is returned, and if * it is profitable to retry the operation, this function will wait * for the current or commiting transaction to complete, and then * return TRUE. */int ext3_should_retry_alloc(struct super_block *sb, int *retries){	if (!ext3_has_free_blocks(EXT3_SB(sb)) || (*retries)++ > 3)		return 0;	jbd_debug(1, "%s: retrying operation after ENOSPC\n", sb->s_id);	return journal_force_commit_nested(EXT3_SB(sb)->s_journal);}/* * ext3_new_block 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. */intext3_new_block(handle_t *handle, struct inode *inode, unsigned long goal,		u32 *prealloc_count, u32 *prealloc_block, int *errp){	struct buffer_head *bitmap_bh = NULL;	/* bh */	struct buffer_head *gdp_bh;		/* bh2 */	int group_no;				/* i */	int ret_block;				/* j */	int bgi;				/* blockgroup iteration index */	int target_block;			/* tmp */	int fatal = 0, err;	int performed_allocation = 0;	int free_blocks;	struct super_block *sb;	struct ext3_group_desc *gdp;	struct ext3_super_block *es;	struct ext3_sb_info *sbi;#ifdef EXT3FS_DEBUG	static int goal_hits, goal_attempts;#endif	*errp = -ENOSPC;	sb = inode->i_sb;	if (!sb) {		printk("ext3_new_block: nonexistent device");		return 0;	}	/*	 * Check quota for allocation of this block.	 */	if (DQUOT_ALLOC_BLOCK(inode, 1)) {		*errp = -EDQUOT;		return 0;	}	sbi = EXT3_SB(sb);	es = EXT3_SB(sb)->s_es;	ext3_debug("goal=%lu.\n", goal);	if (!ext3_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)) /			EXT3_BLOCKS_PER_GROUP(sb);	gdp = ext3_get_group_desc(sb, group_no, &gdp_bh);	if (!gdp)		goto io_error;	free_blocks = le16_to_cpu(gdp->bg_free_blocks_count);	if (free_blocks > 0) {		ret_block = ((goal - le32_to_cpu(es->s_first_data_block)) %				EXT3_BLOCKS_PER_GROUP(sb));		bitmap_bh = read_block_bitmap(sb, group_no);		if (!bitmap_bh)			goto io_error;		ret_block = ext3_try_to_allocate(sb, handle, group_no,					bitmap_bh, ret_block, &fatal);		if (fatal)			goto out;		if (ret_block >= 0)			goto allocated;	}	/*	 * Now search the rest of the groups.  We assume that 	 * i and gdp correctly point to the last group visited.	 */	for (bgi = 0; bgi < EXT3_SB(sb)->s_groups_count; bgi++) {		group_no++;		if (group_no >= EXT3_SB(sb)->s_groups_count)			group_no = 0;		gdp = ext3_get_group_desc(sb, group_no, &gdp_bh);		if (!gdp) {			*errp = -EIO;			goto out;		}		free_blocks = le16_to_cpu(gdp->bg_free_blocks_count);		if (free_blocks <= 0)			continue;		brelse(bitmap_bh);		bitmap_bh = read_block_bitmap(sb, group_no);		if (!bitmap_bh)			goto io_error;		ret_block = ext3_try_to_allocate(sb, handle, group_no,						bitmap_bh, -1, &fatal);		if (fatal)			goto out;		if (ret_block >= 0) 			goto allocated;	}	/* No space left on the device */	*errp = -ENOSPC;	goto out;allocated:	ext3_debug("using block group %d(%d)\n",			group_no, gdp->bg_free_blocks_count);	BUFFER_TRACE(gdp_bh, "get_write_access");	fatal = ext3_journal_get_write_access(handle, gdp_bh);	if (fatal)		goto out;	target_block = ret_block + group_no * EXT3_BLOCKS_PER_GROUP(sb)				+ le32_to_cpu(es->s_first_data_block);	if (target_block == le32_to_cpu(gdp->bg_block_bitmap) ||	    target_block == le32_to_cpu(gdp->bg_inode_bitmap) ||	    in_range(target_block, le32_to_cpu(gdp->bg_inode_table),		      EXT3_SB(sb)->s_itb_per_group))		ext3_error(sb, "ext3_new_block",			    "Allocating block in system zone - "			    "block = %u", target_block);	performed_allocation = 1;#ifdef CONFIG_JBD_DEBUG	{		struct buffer_head *debug_bh;		/* Record bitmap buffer state in the newly allocated block */		debug_bh = sb_find_get_block(sb, target_block);		if (debug_bh) {			BUFFER_TRACE(debug_bh, "state when allocated");			BUFFER_TRACE2(debug_bh, bitmap_bh, "bitmap state");			brelse(debug_bh);		}	}	jbd_lock_bh_state(bitmap_bh);	spin_lock(sb_bgl_lock(sbi, group_no));	if (buffer_jbd(bitmap_bh) && bh2jh(bitmap_bh)->b_committed_data) {		if (ext3_test_bit(ret_block,				bh2jh(bitmap_bh)->b_committed_data)) {			printk("%s: block was unexpectedly set in "				"b_committed_data\n", __FUNCTION__);		}	}	ext3_debug("found bit %d\n", ret_block);	spin_unlock(sb_bgl_lock(sbi, group_no));	jbd_unlock_bh_state(bitmap_bh);#endif	/* ret_block was blockgroup-relative.  Now it becomes fs-relative */	ret_block = target_block;	if (ret_block >= le32_to_cpu(es->s_blocks_count)) {		ext3_error(sb, "ext3_new_block",			    "block(%d) >= blocks count(%d) - "			    "block_group = %d, es == %p ", ret_block,			le32_to_cpu(es->s_blocks_count), group_no, es);		goto out;	}	/*	 * It is up to the caller to add the new buffer to a journal	 * list of some description.  We don't know in advance whether	 * the caller wants to use it as metadata or data.	 */	ext3_debug("allocating block %d. Goal hits %d of %d.\n",			ret_block, goal_hits, goal_attempts);	spin_lock(sb_bgl_lock(sbi, group_no));	gdp->bg_free_blocks_count =			cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count) - 1);	spin_unlock(sb_bgl_lock(sbi, group_no));	percpu_counter_mod(&sbi->s_freeblocks_counter, -1);	BUFFER_TRACE(gdp_bh, "journal_dirty_metadata for group descriptor");	err = ext3_journal_dirty_metadata(handle, gdp_bh);	if (!fatal)		fatal = err;	sb->s_dirt = 1;	if (fatal)		goto out;	*errp = 0;	brelse(bitmap_bh);	return ret_block;io_error:	*errp = -EIO;out:	if (fatal) {		*errp = fatal;		ext3_std_error(sb, fatal);	}	/*	 * Undo the block allocation	 */	if (!performed_allocation)		DQUOT_FREE_BLOCK(inode, 1);	brelse(bitmap_bh);	return 0;}unsigned long ext3_count_free_blocks(struct super_block *sb){	unsigned long desc_count;	struct ext3_group_desc *gdp;	int i;#ifdef EXT3FS_DEBUG	struct ext3_super_block *es;	unsigned long bitmap_count, x;	struct buffer_head *bitmap_bh = NULL;	lock_super(sb);	es = EXT3_SB(sb)->s_es;	desc_count = 0;	bitmap_count = 0;	gdp = NULL;	for (i = 0; i < EXT3_SB(sb)->s_groups_count; i++) {		gdp = ext3_get_group_desc(sb, i, NULL);		if (!gdp)			continue;		desc_count += le16_to_cpu(gdp->bg_free_blocks_count);		brelse(bitmap_bh);		bitmap_bh = read_block_bitmap(sb, i);		if (bitmap_bh == NULL)			continue;		x = ext3_count_free(bitmap_bh, sb->s_blocksize);		printk("group %d: stored = %d, counted = %lu\n",			i, le16_to_cpu(gdp->bg_free_blocks_count), x);		bitmap_count += x;	}	brelse(bitmap_bh);	printk("ext3_count_free_blocks: stored = %u, computed = %lu, %lu\n",	       le32_to_cpu(es->s_free_blocks_count), desc_count, bitmap_count);	unlock_super(sb);	return bitmap_count;#else	desc_count = 0;	for (i = 0; i < EXT3_SB(sb)->s_groups_count; i++) {		gdp = ext3_get_group_desc(sb, i, NULL);		if (!gdp)			continue;		desc_count += le16_to_cpu(gdp->bg_free_blocks_count);	}	return desc_count;#endif}static inline int block_in_use(unsigned long block,				struct super_block * sb,				unsigned char * map){	return ext3_test_bit ((block -		le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block)) %			 EXT3_BLOCKS_PER_GROUP(sb), map);}static inline int test_root(int a, int b){	if (a == 0)		return 1;	while (1) {		if (a == 1)			return 1;		if (a % b)			return 0;		a = a / b;	}}int ext3_group_sparse(int group){	return (test_root(group, 3) || test_root(group, 5) ||		test_root(group, 7));}/** *	ext3_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 ext3_bg_has_super(struct super_block *sb, int group){	if (EXT3_HAS_RO_COMPAT_FEATURE(sb,EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER)&&	    !ext3_group_sparse(group))		return 0;	return 1;}/** *	ext3_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 ext3_bg_num_gdb(struct super_block *sb, int group){	if (EXT3_HAS_RO_COMPAT_FEATURE(sb,EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER)&&	    !ext3_group_sparse(group))		return 0;	return EXT3_SB(sb)->s_gdb_count;}#ifdef CONFIG_EXT3_CHECK/* Called at mount-time, super-block is locked */void ext3_check_blocks_bitmap (struct super_block * sb){	struct ext3_super_block *es;	unsigned long desc_count, bitmap_count, x, j;	unsigned long desc_blocks;	struct buffer_head *bitmap_bh = NULL;	struct ext3_group_desc *gdp;	int i;	es = EXT3_SB(sb)->s_es;	desc_count = 0;	bitmap_count = 0;	gdp = NULL;	for (i = 0; i < EXT3_SB(sb)->s_groups_count; i++) {		gdp = ext3_get_group_desc (sb, i, NULL);		if (!gdp)			continue;		desc_count += le16_to_cpu(gdp->bg_free_blocks_count);		brelse(bitmap_bh);		bitmap_bh = read_block_bitmap(sb, i);		if (bitmap_bh == NULL)			continue;		if (ext3_bg_has_super(sb, i) &&				!ext3_test_bit(0, bitmap_bh->b_data))			ext3_error(sb, __FUNCTION__,				   "Superblock in group %d is marked free", i);		desc_blocks = ext3_bg_num_gdb(sb, i);		for (j = 0; j < desc_blocks; j++)			if (!ext3_test_bit(j + 1, bitmap_bh->b_data))				ext3_error(sb, __FUNCTION__,					   "Descriptor block #%ld in group "					   "%d is marked free", j, i);		if (!block_in_use (le32_to_cpu(gdp->bg_block_bitmap),						sb, bitmap_bh->b_data))			ext3_error (sb, "ext3_check_blocks_bitmap",				    "Block bitmap for group %d is marked free",				    i);		if (!block_in_use (le32_to_cpu(gdp->bg_inode_bitmap),						sb, bitmap_bh->b_data))			ext3_error (sb, "ext3_check_blocks_bitmap",				    "Inode bitmap for group %d is marked free",				    i);		for (j = 0; j < EXT3_SB(sb)->s_itb_per_group; j++)			if (!block_in_use (le32_to_cpu(gdp->bg_inode_table) + j,							sb, bitmap_bh->b_data))				ext3_error (sb, "ext3_check_blocks_bitmap",					    "Block #%d of the inode table in "					    "group %d is marked free", j, i);		x = ext3_count_free(bitmap_bh, sb->s_blocksize);		if (le16_to_cpu(gdp->bg_free_blocks_count) != x)			ext3_error (sb, "ext3_check_blocks_bitmap",				    "Wrong free blocks count for group %d, "				    "stored = %d, counted = %lu", i,				    le16_to_cpu(gdp->bg_free_blocks_count), x);		bitmap_count += x;	}	brelse(bitmap_bh);	if (le32_to_cpu(es->s_free_blocks_count) != bitmap_count)		ext3_error (sb, "ext3_check_blocks_bitmap",			"Wrong free blocks count in super block, "			"stored = %lu, counted = %lu",			(unsigned long)le32_to_cpu(es->s_free_blocks_count),			bitmap_count);}#endif

⌨️ 快捷键说明

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