Index: linux-2.6.5-7.283-full/include/linux/ext3_fs.h =================================================================== --- linux-2.6.5-7.283-full.orig/include/linux/ext3_fs.h 2007-03-28 02:13:37.000000000 +0400 +++ linux-2.6.5-7.283-full/include/linux/ext3_fs.h 2007-03-28 02:21:37.000000000 +0400 @@ -815,7 +815,7 @@ extern struct inode_operations ext3_fast /* extents.c */ extern int ext3_ext_writepage_trans_blocks(struct inode *, int); -extern int ext3_ext_get_block(handle_t *, struct inode *, long, +extern int ext3_ext_get_block(handle_t *, struct inode *, long, int, struct buffer_head *, int, int); extern void ext3_ext_truncate(struct inode *, struct page *); extern void ext3_ext_init(struct super_block *); Index: linux-2.6.5-7.283-full/fs/ext3/extents.c =================================================================== --- linux-2.6.5-7.283-full.orig/fs/ext3/extents.c 2007-03-28 02:14:25.000000000 +0400 +++ linux-2.6.5-7.283-full/fs/ext3/extents.c 2007-03-28 02:21:37.000000000 +0400 @@ -2024,7 +2024,8 @@ void ext3_init_tree_desc(struct ext3_ext } int ext3_ext_get_block(handle_t *handle, struct inode *inode, - long iblock, struct buffer_head *bh_result, + long iblock, int max_blocks, + struct buffer_head *bh_result, int create, int extend_disksize) { struct ext3_ext_path *path = NULL; @@ -2032,6 +2033,11 @@ int ext3_ext_get_block(handle_t *handle, struct ext3_extent *ex; int goal, newblock, err = 0, depth; struct ext3_extents_tree tree; + unsigned long next; + int allocated = 0; + + /* until we have multiblock allocation */ + max_blocks = 1; __clear_bit(BH_New, &bh_result->b_state); ext3_init_tree_desc(&tree, inode); @@ -2051,6 +2057,9 @@ int ext3_ext_get_block(handle_t *handle, } else if (goal == EXT3_EXT_CACHE_EXTENT) { /* block is already allocated */ newblock = iblock - newex.ee_block + newex.ee_start; + /* number of remaining blocks in the extent */ + EXT_ASSERT(iblock >= newex.ee_block); + allocated = newex.ee_len - (iblock - newex.ee_block); goto out; } else { EXT_ASSERT(0); @@ -2078,6 +2087,8 @@ int ext3_ext_get_block(handle_t *handle, /* if found exent covers block, simple return it */ if (iblock >= ex->ee_block && iblock < ex->ee_block + ex->ee_len) { newblock = iblock - ex->ee_block + ex->ee_start; + /* number of remaining blocks in the extent */ + allocated = ex->ee_len - (iblock - ex->ee_block); ext_debug(&tree, "%d fit into %d:%d -> %d\n", (int) iblock, ex->ee_block, ex->ee_len, newblock); @@ -2098,6 +2109,15 @@ int ext3_ext_get_block(handle_t *handle, goto out2; } + /* find next allocated block so that we know how many + * blocks we can allocate without ovelapping next extent */ + EXT_ASSERT(iblock >= ex->ee_block + ex->ee_len); + next = ext3_ext_next_allocated_block(path); + EXT_ASSERT(next > iblock); + allocated = next - iblock; + if (allocated > max_blocks) + allocated = max_blocks; + /* allocate new block */ goal = ext3_ext_find_goal(inode, path, iblock); newblock = ext3_new_block(handle, inode, goal, &err); @@ -2112,8 +2132,11 @@ int ext3_ext_get_block(handle_t *handle, newex.ee_start_hi = 0; newex.ee_len = 1; err = ext3_ext_insert_extent(handle, &tree, path, &newex); - if (err) + if (err) { + /* free data blocks we just allocated */ + ext3_free_blocks(handle, inode, newex.ee_start, newex.ee_len); goto out2; + } if (extend_disksize && inode->i_size > EXT3_I(inode)->i_disksize) EXT3_I(inode)->i_disksize = inode->i_size; @@ -2125,10 +2148,13 @@ int ext3_ext_get_block(handle_t *handle, ext3_ext_put_in_cache(&tree, newex.ee_block, newex.ee_len, newex.ee_start, EXT3_EXT_CACHE_EXTENT); out: + if (allocated > max_blocks) + allocated = max_blocks; ext3_ext_show_leaf(&tree, path); __set_bit(BH_Mapped, &bh_result->b_state); bh_result->b_bdev = inode->i_sb->s_bdev; bh_result->b_blocknr = newblock; + bh_result->b_size = (allocated << inode->i_blkbits); out2: if (path) { ext3_ext_drop_refs(path); Index: linux-2.6.5-7.283-full/fs/ext3/inode.c =================================================================== --- linux-2.6.5-7.283-full.orig/fs/ext3/inode.c 2007-03-28 02:13:37.000000000 +0400 +++ linux-2.6.5-7.283-full/fs/ext3/inode.c 2007-03-28 02:50:19.000000000 +0400 @@ -800,13 +800,17 @@ changed: static inline int ext3_get_block_wrap(handle_t *handle, struct inode *inode, long block, - struct buffer_head *bh, int create, int extend_disksize) + int max_blocks, struct buffer_head *bh, int create, + int extend_disksize) { + int ret; if (EXT3_I(inode)->i_flags & EXT3_EXTENTS_FL) - return ext3_ext_get_block(handle, inode, block, bh, create, - extend_disksize); - return ext3_get_block_handle(handle, inode, block, bh, create, + return ext3_ext_get_block(handle, inode, block, max_blocks, + bh, create, extend_disksize); + ret = ext3_get_block_handle(handle, inode, block, bh, create, extend_disksize); + bh->b_size = (1 << inode->i_blkbits); + return ret; } static int ext3_get_block(struct inode *inode, sector_t iblock, @@ -819,7 +823,7 @@ static int ext3_get_block(struct inode * handle = ext3_journal_current_handle(); J_ASSERT(handle != 0); } - ret = ext3_get_block_wrap(handle, inode, iblock, + ret = ext3_get_block_wrap(handle, inode, iblock, 1, bh_result, create, 1); return ret; } @@ -847,10 +851,8 @@ ext3_direct_io_get_blocks(struct inode * } } if (ret == 0) - ret = ext3_get_block_wrap(handle, inode, iblock, + ret = ext3_get_block_wrap(handle, inode, iblock, max_blocks, bh_result, create, 0); - if (ret == 0) - bh_result->b_size = (1 << inode->i_blkbits); return ret; } @@ -869,7 +871,7 @@ struct buffer_head *ext3_getblk(handle_t dummy.b_state = 0; dummy.b_blocknr = -1000; buffer_trace_init(&dummy.b_history); - *errp = ext3_get_block_wrap(handle, inode, block, &dummy, create, 1); + *errp = ext3_get_block_wrap(handle, inode, block, 1, &dummy, create, 1); if (!*errp && buffer_mapped(&dummy)) { struct buffer_head *bh; bh = sb_getblk(inode->i_sb, dummy.b_blocknr);