static int ext4_alloc_branch(handle_t *handle,
			     struct ext4_allocation_request *ar,
			     int indirect_blks, ext4_lblk_t *offsets,
			     Indirect *branch)
{
	struct buffer_head *		bh;
	ext4_fsblk_t			b, new_blocks[4];
	__le32				*p;
	int				i, j, err, len = 1;

	for (i = 0; i <= indirect_blks; i++) {
		if (i == indirect_blks) {
			new_blocks[i] = ext4_mb_new_blocks(handle, ar, &err);
		} else {
			ar->goal = new_blocks[i] = ext4_new_meta_blocks(handle,
					ar->inode, ar->goal,
					ar->flags & EXT4_MB_DELALLOC_RESERVED,
					NULL, &err);
			/* Simplify error cleanup... */
			branch[i+1].bh = NULL;
		}
		if (err) {
			i--;
			goto failed;
		}
		branch[i].key = cpu_to_le32(new_blocks[i]);
		if (i == 0)
			continue;

		bh = branch[i].bh = sb_getblk(ar->inode->i_sb, new_blocks[i-1]);
		if (unlikely(!bh)) {
			err = -ENOMEM;
			goto failed;
		}
		lock_buffer(bh);
		BUFFER_TRACE(bh, "call get_create_access");
		err = ext4_journal_get_create_access(handle, bh);
		if (err) {
			unlock_buffer(bh);
			goto failed;
		}

		memset(bh->b_data, 0, bh->b_size);
		p = branch[i].p = (__le32 *) bh->b_data + offsets[i];
		b = new_blocks[i];

		if (i == indirect_blks)
			len = ar->len;
		for (j = 0; j < len; j++)
			*p++ = cpu_to_le32(b++);

		BUFFER_TRACE(bh, "marking uptodate");
		set_buffer_uptodate(bh);
		unlock_buffer(bh);

		BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata");
		err = ext4_handle_dirty_metadata(handle, ar->inode, bh);
		if (err)
			goto failed;
	}
	return 0;
failed:
	if (i == indirect_blks) {
		/* Free data blocks */
		ext4_free_blocks(handle, ar->inode, NULL, new_blocks[i],
				 ar->len, 0);
		i--;
	}
	for (; i >= 0; i--) {
		/*
		 * We want to ext4_forget() only freshly allocated indirect
		 * blocks. Buffer for new_blocks[i] is at branch[i+1].bh
		 * (buffer at branch[0].bh is indirect block / inode already
		 * existing before ext4_alloc_branch() was called). Also
		 * because blocks are freshly allocated, we don't need to
		 * revoke them which is why we don't set
		 * EXT4_FREE_BLOCKS_METADATA.
		 */
		ext4_free_blocks(handle, ar->inode, branch[i+1].bh,
				 new_blocks[i], 1,
				 branch[i+1].bh ? EXT4_FREE_BLOCKS_FORGET : 0);
	}
	return err;
}
static int ext4_alloc_branch(handle_t *handle,
			     struct ext4_allocation_request *ar,
			     int indirect_blks, ext4_lblk_t *offsets,
			     Indirect *branch)
{
	struct buffer_head *		bh;
	ext4_fsblk_t			b, new_blocks[4];
	__le32				*p;
	int				i, j, err, len = 1;

	for (i = 0; i <= indirect_blks; i++) {
		if (i == indirect_blks) {
			new_blocks[i] = ext4_mb_new_blocks(handle, ar, &err);
		} else {
			ar->goal = new_blocks[i] = ext4_new_meta_blocks(handle,
					ar->inode, ar->goal,
					ar->flags & EXT4_MB_DELALLOC_RESERVED,
					NULL, &err);
			 
			branch[i+1].bh = NULL;
		}
		if (err) {
			i--;
			goto failed;
		}
		branch[i].key = cpu_to_le32(new_blocks[i]);
		if (i == 0)
			continue;

		bh = branch[i].bh = sb_getblk(ar->inode->i_sb, new_blocks[i-1]);
		if (unlikely(!bh)) {
			err = -ENOMEM;
			goto failed;
		}
		lock_buffer(bh);
		BUFFER_TRACE(bh, "call get_create_access");
		err = ext4_journal_get_create_access(handle, bh);
		if (err) {
			unlock_buffer(bh);
			goto failed;
		}

		memset(bh->b_data, 0, bh->b_size);
		p = branch[i].p = (__le32 *) bh->b_data + offsets[i];
		b = new_blocks[i];

		if (i == indirect_blks)
			len = ar->len;
		for (j = 0; j < len; j++)
			*p++ = cpu_to_le32(b++);

		BUFFER_TRACE(bh, "marking uptodate");
		set_buffer_uptodate(bh);
		unlock_buffer(bh);

		BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata");
		err = ext4_handle_dirty_metadata(handle, ar->inode, bh);
		if (err)
			goto failed;
	}
	return 0;
failed:
	if (i == indirect_blks) {
		 
		ext4_free_blocks(handle, ar->inode, NULL, new_blocks[i],
				 ar->len, 0);
		i--;
	}
	for (; i >= 0; i--) {
		 
		ext4_free_blocks(handle, ar->inode, branch[i+1].bh,
				 new_blocks[i], 1,
				 branch[i+1].bh ? EXT4_FREE_BLOCKS_FORGET : 0);
	}
	return err;
}