err = -EBUSY; 
int ext3_group_add(struct super_block *sb, struct ext3_new_group_data *input){	struct ext3_sb_info *sbi = EXT3_SB(sb);	struct ext3_super_block *es = sbi->s_es;	int reserved_gdb = ext3_bg_has_super(sb, input->group) ?		le16_to_cpu(es->s_reserved_gdt_blocks) : 0;	struct buffer_head *primary = NULL;	struct ext3_group_desc *gdp;	struct inode *inode = NULL;	handle_t *handle;	int gdb_off, gdb_num;	int err, err2;	gdb_num = input->group / EXT3_DESC_PER_BLOCK(sb);	gdb_off = input->group % EXT3_DESC_PER_BLOCK(sb);	if (gdb_off == 0 && !EXT3_HAS_RO_COMPAT_FEATURE(sb,					EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER)) {		ext3_warning(sb, __FUNCTION__,			     "Can't resize non-sparse filesystem further\n");		return -EPERM;	}	if (reserved_gdb || gdb_off == 0) {		if (!EXT3_HAS_COMPAT_FEATURE(sb,					     EXT3_FEATURE_COMPAT_RESIZE_INODE)){			ext3_warning(sb, __FUNCTION__,				     "No reserved GDT blocks, can't resize\n");			return -EPERM;		}		inode = iget(sb, EXT3_RESIZE_INO);		if (!inode || is_bad_inode(inode)) {			ext3_warning(sb, __FUNCTION__,				     "Error opening resize inode\n");			iput(inode);			return -ENOENT;		}	}	if ((err = verify_group_input(sb, input)))		goto exit_put;	if ((err = setup_new_group_blocks(sb, input)))		goto exit_put;	/*	 * We will always be modifying at least the superblock and a GDT	 * block.  If we are adding a group past the last current GDT block,	 * we will also modify the inode and the dindirect block.  If we	 * are adding a group with superblock/GDT backups  we will also	 * modify each of the reserved GDT dindirect blocks.	 */	handle = ext3_journal_start_sb(sb,				       ext3_bg_has_super(sb, input->group) ?				       3 + reserved_gdb : 4);	if (IS_ERR(handle)) {		err = PTR_ERR(handle);		goto exit_put;	}	lock_super(sb);	if (input->group != EXT3_SB(sb)->s_groups_count) {		ext3_warning(sb, __FUNCTION__,			     "multiple resizers run on filesystem!\n");		goto exit_journal;	}	if ((err = ext3_journal_get_write_access(handle, sbi->s_sbh)))		goto exit_journal;	/*	 * We will only either add reserved group blocks to a backup group	 * or remove reserved blocks for the first group in a new group block.	 * Doing both would be mean more complex code, and sane people don't	 * use non-sparse filesystems anymore.  This is already checked above.	 */	if (gdb_off) {		primary = sbi->s_group_desc[gdb_num];		if ((err = ext3_journal_get_write_access(handle, primary)))			goto exit_journal;		if (reserved_gdb && ext3_bg_num_gdb(sb, input->group) &&		    (err = reserve_backup_gdb(handle, inode, input)))			goto exit_journal;	} else if ((err = add_new_gdb(handle, inode, input, &primary)))		goto exit_journal;	/*	 * OK, now we've set up the new group.  Time to make it active.	 *	 * Current kernels don't lock all allocations via lock_super(),	 * so we have to be safe wrt. concurrent accesses the group	 * data.  So we need to be careful to set all of the relevant	 * group descriptor data etc. *before* we enable the group.	 *	 * The key field here is EXT3_SB(sb)->s_groups_count: as long as	 * that retains its old value, nobody is going to access the new	 * group.	 *	 * So first we update all the descriptor metadata for the new	 * group; then we update the total disk blocks count; then we	 * update the groups count to enable the group; then finally we	 * update the free space counts so that the system can start	 * using the new disk blocks.	 */	/* Update group descriptor block for new group */	gdp = (struct ext3_group_desc *)primary->b_data + gdb_off;	gdp->bg_block_bitmap = cpu_to_le32(input->block_bitmap);	gdp->bg_inode_bitmap = cpu_to_le32(input->inode_bitmap);	gdp->bg_inode_table = cpu_to_le32(input->inode_table);	gdp->bg_free_blocks_count = cpu_to_le16(input->free_blocks_count);	gdp->bg_free_inodes_count = cpu_to_le16(EXT3_INODES_PER_GROUP(sb));	/*	 * Make the new blocks and inodes valid next.  We do this before	 * increasing the group count so that once the group is enabled,	 * all of its blocks and inodes are already valid.	 *	 * We always allocate group-by-group, then block-by-block or	 * inode-by-inode within a group, so enabling these	 * blocks/inodes before the group is live won't actually let us	 * allocate the new space yet.	 */	es->s_blocks_count = cpu_to_le32(le32_to_cpu(es->s_blocks_count) +		input->blocks_count);	es->s_inodes_count = cpu_to_le32(le32_to_cpu(es->s_inodes_count) +		EXT3_INODES_PER_GROUP(sb));	/*	 * We need to protect s_groups_count against other CPUs seeing	 * inconsistent state in the superblock.	 *	 * The precise rules we use are:	 *	 * * Writers of s_groups_count *must* hold lock_super	 * AND	 * * Writers must perform a smp_wmb() after updating all dependent	 *   data and before modifying the groups count	 *	 * * Readers must hold lock_super() over the access	 * OR	 * * Readers must perform an smp_rmb() after reading the groups count	 *   and before reading any dependent data.	 *	 * NB. These rules can be relaxed when checking the group count	 * while freeing data, as we can only allocate from a block	 * group after serialising against the group count, and we can	 * only then free after serialising in turn against that	 * allocation.	 */	smp_wmb();	/* Update the global fs size fields */	EXT3_SB(sb)->s_groups_count++;	ext3_journal_dirty_metadata(handle, primary);	/* Update the reserved block counts only once the new group is	 * active. */	es->s_r_blocks_count = cpu_to_le32(le32_to_cpu(es->s_r_blocks_count) +		input->reserved_blocks);	/* Update the free space counts */	percpu_counter_mod(&sbi->s_freeblocks_counter,			   input->free_blocks_count);	percpu_counter_mod(&sbi->s_freeinodes_counter,			   EXT3_INODES_PER_GROUP(sb));	ext3_journal_dirty_metadata(handle, EXT3_SB(sb)->s_sbh);	sb->s_dirt = 1;exit_journal:	unlock_super(sb);	if ((err2 = ext3_journal_stop(handle)) && !err)		err = err2;	if (!err) {		update_backups(sb, sbi->s_sbh->b_blocknr, (char *)es,			       sizeof(struct ext3_super_block));		update_backups(sb, primary->b_blocknr, primary->b_data,			       primary->b_size);	}exit_put:	iput(inode);	return err;} /* ext3_group_add */
10457	/local/tlutelli/issta_data/temp/c/2005_temp/2005/10457/aa877b3dc9f2a1fdffac4ea36bee97c21db11a69/resize.c/buggy/fs/ext3/resize.c