diff options
author | Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> | 2008-01-28 23:58:27 -0500 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2008-01-28 23:58:27 -0500 |
commit | c278bfecebfb1ed67c326ef472660878baa745cd (patch) | |
tree | 7207594cef5bd04ea7333a8321d78aefee01a540 | |
parent | 01f4adc04480a4e0395906d0268c056cf09c39c0 (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.c | 9 | ||||
-rw-r--r-- | fs/ext4/inode.c | 69 | ||||
-rw-r--r-- | include/linux/ext4_fs.h | 2 |
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 | */ | ||
2132 | int ext4_ext_get_blocks(handle_t *handle, struct inode *inode, | 2136 | int 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) | ||
2452 | retry: | 2454 | retry: |
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 | ||
246 | static 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 | */ |
356 | static Indirect *ext4_get_branch(struct inode *inode, int depth, | 350 | static 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 | ||
383 | changed: | ||
384 | brelse(bh); | ||
385 | *err = -EAGAIN; | ||
386 | goto no_block; | ||
387 | failure: | 374 | failure: |
388 | *err = -EIO; | 375 | *err = -EIO; |
389 | no_block: | 376 | no_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 | */ |
791 | int ext4_get_blocks_handle(handle_t *handle, struct inode *inode, | 782 | int 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 | ||