aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorMingming Cao <cmm@us.ibm.com>2008-02-25 15:29:55 -0500
committerTheodore Ts'o <tytso@mit.edu>2008-02-25 15:29:55 -0500
commitf5ab0d1f8f7df937778c60c3da6f4ef939a54a7b (patch)
tree9a5b63d45dc805383f7789bba75f7935626767fe /fs
parent825f1481ead4ce40671089bae7412ac3519e8caa (diff)
ext4: Fix BUG when writing to an unitialized extent
This patch fixes a bug when writing to preallocated but uninitialized blocks, which resulted in a BUG in fs/buffer.c saying that the buffer is not mapped. When writing to a file, ext4_get_block_wrap() is called with create=1 in order to request that blocks be allocated if necessary. It currently calls ext4_get_blocks() with create=0 in order to do a lookup first. If the inode contains an unitialized data block, the buffer head is left unampped, which ext4_get_blocks_wrap() returns, causing the BUG. We fix this by checking to see if the buffer head is unmapped, and if so, we make sure the the buffer head is mapped by calling ext4_ext_get_blocks with create=1. Signed-off-by: Mingming Cao <cmm@us.ibm.com> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs')
-rw-r--r--fs/ext4/extents.c13
-rw-r--r--fs/ext4/inode.c47
2 files changed, 57 insertions, 3 deletions
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index 8a59f7ba30e6..bcf5d040e328 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -2287,9 +2287,22 @@ out:
2287} 2287}
2288 2288
2289/* 2289/*
2290 * Block allocation/map/preallocation routine for extents based files
2291 *
2292 *
2290 * Need to be called with 2293 * Need to be called with
2291 * down_read(&EXT4_I(inode)->i_data_sem) if not allocating file system block 2294 * down_read(&EXT4_I(inode)->i_data_sem) if not allocating file system block
2292 * (ie, create is zero). Otherwise down_write(&EXT4_I(inode)->i_data_sem) 2295 * (ie, create is zero). Otherwise down_write(&EXT4_I(inode)->i_data_sem)
2296 *
2297 * return > 0, number of of blocks already mapped/allocated
2298 * if create == 0 and these are pre-allocated blocks
2299 * buffer head is unmapped
2300 * otherwise blocks are mapped
2301 *
2302 * return = 0, if plain look up failed (blocks have not been allocated)
2303 * buffer head is unmapped
2304 *
2305 * return < 0, error case.
2293 */ 2306 */
2294int ext4_ext_get_blocks(handle_t *handle, struct inode *inode, 2307int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
2295 ext4_lblk_t iblock, 2308 ext4_lblk_t iblock,
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 34f3eb615fd5..945cbf6cb1fc 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -908,11 +908,38 @@ out:
908 */ 908 */
909#define DIO_CREDITS 25 909#define DIO_CREDITS 25
910 910
911
912/*
913 *
914 *
915 * ext4_ext4 get_block() wrapper function
916 * It will do a look up first, and returns if the blocks already mapped.
917 * Otherwise it takes the write lock of the i_data_sem and allocate blocks
918 * and store the allocated blocks in the result buffer head and mark it
919 * mapped.
920 *
921 * If file type is extents based, it will call ext4_ext_get_blocks(),
922 * Otherwise, call with ext4_get_blocks_handle() to handle indirect mapping
923 * based files
924 *
925 * On success, it returns the number of blocks being mapped or allocate.
926 * if create==0 and the blocks are pre-allocated and uninitialized block,
927 * the result buffer head is unmapped. If the create ==1, it will make sure
928 * the buffer head is mapped.
929 *
930 * It returns 0 if plain look up failed (blocks have not been allocated), in
931 * that casem, buffer head is unmapped
932 *
933 * It returns the error in case of allocation failure.
934 */
911int ext4_get_blocks_wrap(handle_t *handle, struct inode *inode, sector_t block, 935int ext4_get_blocks_wrap(handle_t *handle, struct inode *inode, sector_t block,
912 unsigned long max_blocks, struct buffer_head *bh, 936 unsigned long max_blocks, struct buffer_head *bh,
913 int create, int extend_disksize) 937 int create, int extend_disksize)
914{ 938{
915 int retval; 939 int retval;
940
941 clear_buffer_mapped(bh);
942
916 /* 943 /*
917 * Try to see if we can get the block without requesting 944 * Try to see if we can get the block without requesting
918 * for new file system block. 945 * for new file system block.
@@ -926,12 +953,26 @@ int ext4_get_blocks_wrap(handle_t *handle, struct inode *inode, sector_t block,
926 inode, block, max_blocks, bh, 0, 0); 953 inode, block, max_blocks, bh, 0, 0);
927 } 954 }
928 up_read((&EXT4_I(inode)->i_data_sem)); 955 up_read((&EXT4_I(inode)->i_data_sem));
929 if (!create || (retval > 0)) 956
957 /* If it is only a block(s) look up */
958 if (!create)
959 return retval;
960
961 /*
962 * Returns if the blocks have already allocated
963 *
964 * Note that if blocks have been preallocated
965 * ext4_ext_get_block() returns th create = 0
966 * with buffer head unmapped.
967 */
968 if (retval > 0 && buffer_mapped(bh))
930 return retval; 969 return retval;
931 970
932 /* 971 /*
933 * We need to allocate new blocks which will result 972 * New blocks allocate and/or writing to uninitialized extent
934 * in i_data update 973 * will possibly result in updating i_data, so we take
974 * the write lock of i_data_sem, and call get_blocks()
975 * with create == 1 flag.
935 */ 976 */
936 down_write((&EXT4_I(inode)->i_data_sem)); 977 down_write((&EXT4_I(inode)->i_data_sem));
937 /* 978 /*