ext4: Handling preallocated blocks in delayed allocation From: Mingming Cao This patch fix ext4 delayed allocation that allows it avoid doing delayed allocation handling for blocks that are already preallocated on disk. With delayed allocation, at write_begin() time, ext4_get_blocks_wrap() now is only doing block map with create = 0. ext4_get_blocks_wrap() returns 0 if the blocks are not allocated or preallocated(). If the blocks are prea-allocated, the resulting buffer head is not mapped marked, but ext4_get_blocks_wrap() returns the number of blocks are actually being preallocated. Right now delayed allocation mistream pre-allocated blocks as un-allocated as the buffer head is unmapped. This patch fix this by checking the number of blocks returned by ext4_get_blocks_wrap() rather than checking if buffer head is mapped or not. Signed-off-by: Mingming Cao Signed-off-by: "Theodore Ts'o" --- fs/ext4/inode.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) Index: linux-2.6.26-rc1/fs/ext4/inode.c =================================================================== --- linux-2.6.26-rc1.orig/fs/ext4/inode.c 2008-05-05 17:10:16.000000000 -0700 +++ linux-2.6.26-rc1/fs/ext4/inode.c 2008-05-05 17:10:16.000000000 -0700 @@ -1401,7 +1401,7 @@ static int ext4_journalled_write_end(str } /* - * this is a special callback for ->prepare_write() only + * this is a special callback for ->write_begin() only * it's intention is to return mapped block or reserve space */ static int ext4_da_get_block_prep(struct inode *inode, sector_t iblock, @@ -1412,24 +1412,24 @@ static int ext4_da_get_block_prep(struct BUG_ON(create == 0); BUG_ON(bh_result->b_size != inode->i_sb->s_blocksize); - /* first, we need to know whether the block is allocated already - * XXX: when the filesystem has a lot of free blocks, we could - * reserve even allocated blocks to save this lookup */ + /* + * first, we need to know whether the block is allocated already + * preallocated blocks are unmapped but should treated + * the same as allocated blocks. + */ ret = ext4_get_blocks_wrap(NULL, inode, iblock, 1, bh_result, 0, 0); - if (ret >= 0) { - if (buffer_mapped(bh_result)) { - bh_result->b_size = (ret << inode->i_blkbits); - } else { - /* the block isn't allocated yet, let's reserve space */ - /* XXX: call reservation here */ - /* - * XXX: __block_prepare_write() unmaps passed block, - * is it OK? - */ - map_bh(bh_result, inode->i_sb, 0); - set_buffer_new(bh_result); - set_buffer_delay(bh_result); - } + if (ret == 0) { + /* the block isn't allocated yet, let's reserve space */ + /* XXX: call reservation here */ + /* + * XXX: __block_prepare_write() unmaps passed block, + * is it OK? + */ + map_bh(bh_result, inode->i_sb, 0); + set_buffer_new(bh_result); + set_buffer_delay(bh_result); + } else if (ret > 0) { + bh_result->b_size = (ret << inode->i_blkbits); ret = 0; }