aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>2008-01-28 23:58:27 -0500
committerTheodore Ts'o <tytso@mit.edu>2008-01-28 23:58:27 -0500
commitc278bfecebfb1ed67c326ef472660878baa745cd (patch)
tree7207594cef5bd04ea7333a8321d78aefee01a540
parent01f4adc04480a4e0395906d0268c056cf09c39c0 (diff)
ext4: Make ext4_get_blocks_wrap take the truncate_mutex early.
When doing a migrate from ext3 to ext4 inode we need to make sure the test for inode type and walking inode data happens inside lock. To make this happen move truncate_mutex early before checking the i_flags. This actually should enable us to remove the verify_chain(). Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
-rw-r--r--fs/ext4/extents.c9
-rw-r--r--fs/ext4/inode.c69
-rw-r--r--include/linux/ext4_fs.h2
3 files changed, 16 insertions, 64 deletions
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index 8593e59020fe..ec5019fa552f 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -2129,6 +2129,10 @@ out:
2129 return err ? err : allocated; 2129 return err ? err : allocated;
2130} 2130}
2131 2131
2132/*
2133 * Need to be called with
2134 * mutex_lock(&EXT4_I(inode)->truncate_mutex);
2135 */
2132int ext4_ext_get_blocks(handle_t *handle, struct inode *inode, 2136int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
2133 ext4_lblk_t iblock, 2137 ext4_lblk_t iblock,
2134 unsigned long max_blocks, struct buffer_head *bh_result, 2138 unsigned long max_blocks, struct buffer_head *bh_result,
@@ -2144,7 +2148,6 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
2144 __clear_bit(BH_New, &bh_result->b_state); 2148 __clear_bit(BH_New, &bh_result->b_state);
2145 ext_debug("blocks %u/%lu requested for inode %u\n", 2149 ext_debug("blocks %u/%lu requested for inode %u\n",
2146 iblock, max_blocks, inode->i_ino); 2150 iblock, max_blocks, inode->i_ino);
2147 mutex_lock(&EXT4_I(inode)->truncate_mutex);
2148 2151
2149 /* check in cache */ 2152 /* check in cache */
2150 goal = ext4_ext_in_cache(inode, iblock, &newex); 2153 goal = ext4_ext_in_cache(inode, iblock, &newex);
@@ -2318,8 +2321,6 @@ out2:
2318 ext4_ext_drop_refs(path); 2321 ext4_ext_drop_refs(path);
2319 kfree(path); 2322 kfree(path);
2320 } 2323 }
2321 mutex_unlock(&EXT4_I(inode)->truncate_mutex);
2322
2323 return err ? err : allocated; 2324 return err ? err : allocated;
2324} 2325}
2325 2326
@@ -2449,6 +2450,7 @@ long ext4_fallocate(struct inode *inode, int mode, loff_t offset, loff_t len)
2449 * modify 1 super block, 1 block bitmap and 1 group descriptor. 2450 * modify 1 super block, 1 block bitmap and 1 group descriptor.
2450 */ 2451 */
2451 credits = EXT4_DATA_TRANS_BLOCKS(inode->i_sb) + 3; 2452 credits = EXT4_DATA_TRANS_BLOCKS(inode->i_sb) + 3;
2453 mutex_lock(&EXT4_I(inode)->truncate_mutex)
2452retry: 2454retry:
2453 while (ret >= 0 && ret < max_blocks) { 2455 while (ret >= 0 && ret < max_blocks) {
2454 block = block + ret; 2456 block = block + ret;
@@ -2505,6 +2507,7 @@ retry:
2505 if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries)) 2507 if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
2506 goto retry; 2508 goto retry;
2507 2509
2510 mutex_unlock(&EXT4_I(inode)->truncate_mutex)
2508 /* 2511 /*
2509 * Time to update the file size. 2512 * Time to update the file size.
2510 * Update only when preallocation was requested beyond the file size. 2513 * Update only when preallocation was requested beyond the file size.
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index eaace1373ccb..71c7ad0c6723 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -243,13 +243,6 @@ static inline void add_chain(Indirect *p, struct buffer_head *bh, __le32 *v)
243 p->bh = bh; 243 p->bh = bh;
244} 244}
245 245
246static int verify_chain(Indirect *from, Indirect *to)
247{
248 while (from <= to && from->key == *from->p)
249 from++;
250 return (from > to);
251}
252
253/** 246/**
254 * ext4_block_to_path - parse the block number into array of offsets 247 * ext4_block_to_path - parse the block number into array of offsets
255 * @inode: inode in question (we are only interested in its superblock) 248 * @inode: inode in question (we are only interested in its superblock)
@@ -348,10 +341,11 @@ static int ext4_block_to_path(struct inode *inode,
348 * (pointer to last triple returned, *@err == 0) 341 * (pointer to last triple returned, *@err == 0)
349 * or when it gets an IO error reading an indirect block 342 * or when it gets an IO error reading an indirect block
350 * (ditto, *@err == -EIO) 343 * (ditto, *@err == -EIO)
351 * or when it notices that chain had been changed while it was reading
352 * (ditto, *@err == -EAGAIN)
353 * or when it reads all @depth-1 indirect blocks successfully and finds 344 * or when it reads all @depth-1 indirect blocks successfully and finds
354 * the whole chain, all way to the data (returns %NULL, *err == 0). 345 * the whole chain, all way to the data (returns %NULL, *err == 0).
346 *
347 * Need to be called with
348 * mutex_lock(&EXT4_I(inode)->truncate_mutex)
355 */ 349 */
356static Indirect *ext4_get_branch(struct inode *inode, int depth, 350static Indirect *ext4_get_branch(struct inode *inode, int depth,
357 ext4_lblk_t *offsets, 351 ext4_lblk_t *offsets,
@@ -370,9 +364,6 @@ static Indirect *ext4_get_branch(struct inode *inode, int depth,
370 bh = sb_bread(sb, le32_to_cpu(p->key)); 364 bh = sb_bread(sb, le32_to_cpu(p->key));
371 if (!bh) 365 if (!bh)
372 goto failure; 366 goto failure;
373 /* Reader: pointers */
374 if (!verify_chain(chain, p))
375 goto changed;
376 add_chain(++p, bh, (__le32*)bh->b_data + *++offsets); 367 add_chain(++p, bh, (__le32*)bh->b_data + *++offsets);
377 /* Reader: end */ 368 /* Reader: end */
378 if (!p->key) 369 if (!p->key)
@@ -380,10 +371,6 @@ static Indirect *ext4_get_branch(struct inode *inode, int depth,
380 } 371 }
381 return NULL; 372 return NULL;
382 373
383changed:
384 brelse(bh);
385 *err = -EAGAIN;
386 goto no_block;
387failure: 374failure:
388 *err = -EIO; 375 *err = -EIO;
389no_block: 376no_block:
@@ -787,6 +774,10 @@ err_out:
787 * return > 0, # of blocks mapped or allocated. 774 * return > 0, # of blocks mapped or allocated.
788 * return = 0, if plain lookup failed. 775 * return = 0, if plain lookup failed.
789 * return < 0, error case. 776 * return < 0, error case.
777 *
778 *
779 * Need to be called with
780 * mutex_lock(&EXT4_I(inode)->truncate_mutex)
790 */ 781 */
791int ext4_get_blocks_handle(handle_t *handle, struct inode *inode, 782int ext4_get_blocks_handle(handle_t *handle, struct inode *inode,
792 ext4_lblk_t iblock, unsigned long maxblocks, 783 ext4_lblk_t iblock, unsigned long maxblocks,
@@ -825,18 +816,6 @@ int ext4_get_blocks_handle(handle_t *handle, struct inode *inode,
825 while (count < maxblocks && count <= blocks_to_boundary) { 816 while (count < maxblocks && count <= blocks_to_boundary) {
826 ext4_fsblk_t blk; 817 ext4_fsblk_t blk;
827 818
828 if (!verify_chain(chain, partial)) {
829 /*
830 * Indirect block might be removed by
831 * truncate while we were reading it.
832 * Handling of that case: forget what we've
833 * got now. Flag the err as EAGAIN, so it
834 * will reread.
835 */
836 err = -EAGAIN;
837 count = 0;
838 break;
839 }
840 blk = le32_to_cpu(*(chain[depth-1].p + count)); 819 blk = le32_to_cpu(*(chain[depth-1].p + count));
841 820
842 if (blk == first_block + count) 821 if (blk == first_block + count)
@@ -844,44 +823,13 @@ int ext4_get_blocks_handle(handle_t *handle, struct inode *inode,
844 else 823 else
845 break; 824 break;
846 } 825 }
847 if (err != -EAGAIN) 826 goto got_it;
848 goto got_it;
849 } 827 }
850 828
851 /* Next simple case - plain lookup or failed read of indirect block */ 829 /* Next simple case - plain lookup or failed read of indirect block */
852 if (!create || err == -EIO) 830 if (!create || err == -EIO)
853 goto cleanup; 831 goto cleanup;
854 832
855 mutex_lock(&ei->truncate_mutex);
856
857 /*
858 * If the indirect block is missing while we are reading
859 * the chain(ext4_get_branch() returns -EAGAIN err), or
860 * if the chain has been changed after we grab the semaphore,
861 * (either because another process truncated this branch, or
862 * another get_block allocated this branch) re-grab the chain to see if
863 * the request block has been allocated or not.
864 *
865 * Since we already block the truncate/other get_block
866 * at this point, we will have the current copy of the chain when we
867 * splice the branch into the tree.
868 */
869 if (err == -EAGAIN || !verify_chain(chain, partial)) {
870 while (partial > chain) {
871 brelse(partial->bh);
872 partial--;
873 }
874 partial = ext4_get_branch(inode, depth, offsets, chain, &err);
875 if (!partial) {
876 count++;
877 mutex_unlock(&ei->truncate_mutex);
878 if (err)
879 goto cleanup;
880 clear_buffer_new(bh_result);
881 goto got_it;
882 }
883 }
884
885 /* 833 /*
886 * Okay, we need to do block allocation. Lazily initialize the block 834 * Okay, we need to do block allocation. Lazily initialize the block
887 * allocation info here if necessary 835 * allocation info here if necessary
@@ -923,7 +871,6 @@ int ext4_get_blocks_handle(handle_t *handle, struct inode *inode,
923 */ 871 */
924 if (!err && extend_disksize && inode->i_size > ei->i_disksize) 872 if (!err && extend_disksize && inode->i_size > ei->i_disksize)
925 ei->i_disksize = inode->i_size; 873 ei->i_disksize = inode->i_size;
926 mutex_unlock(&ei->truncate_mutex);
927 if (err) 874 if (err)
928 goto cleanup; 875 goto cleanup;
929 876
diff --git a/include/linux/ext4_fs.h b/include/linux/ext4_fs.h
index 55a376e7bca0..583049c1d366 100644
--- a/include/linux/ext4_fs.h
+++ b/include/linux/ext4_fs.h
@@ -1113,6 +1113,7 @@ ext4_get_blocks_wrap(handle_t *handle, struct inode *inode, sector_t block,
1113 int create, int extend_disksize) 1113 int create, int extend_disksize)
1114{ 1114{
1115 int retval; 1115 int retval;
1116 mutex_lock(&EXT4_I(inode)->truncate_mutex);
1116 if (EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL) { 1117 if (EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL) {
1117 retval = ext4_ext_get_blocks(handle, inode, 1118 retval = ext4_ext_get_blocks(handle, inode,
1118 (ext4_lblk_t)block, max_blocks, 1119 (ext4_lblk_t)block, max_blocks,
@@ -1122,6 +1123,7 @@ ext4_get_blocks_wrap(handle_t *handle, struct inode *inode, sector_t block,
1122 (ext4_lblk_t)block, max_blocks, 1123 (ext4_lblk_t)block, max_blocks,
1123 bh, create, extend_disksize); 1124 bh, create, extend_disksize);
1124 } 1125 }
1126 mutex_unlock(&EXT4_I(inode)->truncate_mutex);
1125 return retval; 1127 return retval;
1126} 1128}
1127 1129