aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4
diff options
context:
space:
mode:
authorDmitry Monakhov <dmonakhov@openvz.org>2010-05-17 01:00:00 -0400
committerTheodore Ts'o <tytso@mit.edu>2010-05-17 01:00:00 -0400
commit0617b83fa239db9743a18ce6cc0e556f4d0fd567 (patch)
tree46d646c2d1af9d706848520a4657877d4cff768f /fs/ext4
parent786ec7915e530936b9eb2e3d12274145cab7aa7d (diff)
ext4: restart ext4_ext_remove_space() after transaction restart
If i_data_sem was internally dropped due to transaction restart, it is necessary to restart path look-up because extents tree was possibly modified by ext4_get_block(). https://bugzilla.kernel.org/show_bug.cgi?id=15827 Signed-off-by: Dmitry Monakhov <dmonakhov@openvz.org> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu> Acked-by: Jan Kara <jack@suse.cz>
Diffstat (limited to 'fs/ext4')
-rw-r--r--fs/ext4/extents.c16
1 files changed, 9 insertions, 7 deletions
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index ffcaa1137def..0a47becf668a 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -107,11 +107,8 @@ static int ext4_ext_truncate_extend_restart(handle_t *handle,
107 if (err <= 0) 107 if (err <= 0)
108 return err; 108 return err;
109 err = ext4_truncate_restart_trans(handle, inode, needed); 109 err = ext4_truncate_restart_trans(handle, inode, needed);
110 /* 110 if (err == 0)
111 * We have dropped i_data_sem so someone might have cached again 111 err = -EAGAIN;
112 * an extent we are going to truncate.
113 */
114 ext4_ext_invalidate_cache(inode);
115 112
116 return err; 113 return err;
117} 114}
@@ -2359,7 +2356,7 @@ static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start)
2359 int depth = ext_depth(inode); 2356 int depth = ext_depth(inode);
2360 struct ext4_ext_path *path; 2357 struct ext4_ext_path *path;
2361 handle_t *handle; 2358 handle_t *handle;
2362 int i = 0, err = 0; 2359 int i, err;
2363 2360
2364 ext_debug("truncate since %u\n", start); 2361 ext_debug("truncate since %u\n", start);
2365 2362
@@ -2368,23 +2365,26 @@ static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start)
2368 if (IS_ERR(handle)) 2365 if (IS_ERR(handle))
2369 return PTR_ERR(handle); 2366 return PTR_ERR(handle);
2370 2367
2368again:
2371 ext4_ext_invalidate_cache(inode); 2369 ext4_ext_invalidate_cache(inode);
2372 2370
2373 /* 2371 /*
2374 * We start scanning from right side, freeing all the blocks 2372 * We start scanning from right side, freeing all the blocks
2375 * after i_size and walking into the tree depth-wise. 2373 * after i_size and walking into the tree depth-wise.
2376 */ 2374 */
2375 depth = ext_depth(inode);
2377 path = kzalloc(sizeof(struct ext4_ext_path) * (depth + 1), GFP_NOFS); 2376 path = kzalloc(sizeof(struct ext4_ext_path) * (depth + 1), GFP_NOFS);
2378 if (path == NULL) { 2377 if (path == NULL) {
2379 ext4_journal_stop(handle); 2378 ext4_journal_stop(handle);
2380 return -ENOMEM; 2379 return -ENOMEM;
2381 } 2380 }
2381 path[0].p_depth = depth;
2382 path[0].p_hdr = ext_inode_hdr(inode); 2382 path[0].p_hdr = ext_inode_hdr(inode);
2383 if (ext4_ext_check(inode, path[0].p_hdr, depth)) { 2383 if (ext4_ext_check(inode, path[0].p_hdr, depth)) {
2384 err = -EIO; 2384 err = -EIO;
2385 goto out; 2385 goto out;
2386 } 2386 }
2387 path[0].p_depth = depth; 2387 i = err = 0;
2388 2388
2389 while (i >= 0 && err == 0) { 2389 while (i >= 0 && err == 0) {
2390 if (i == depth) { 2390 if (i == depth) {
@@ -2478,6 +2478,8 @@ static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start)
2478out: 2478out:
2479 ext4_ext_drop_refs(path); 2479 ext4_ext_drop_refs(path);
2480 kfree(path); 2480 kfree(path);
2481 if (err == -EAGAIN)
2482 goto again;
2481 ext4_journal_stop(handle); 2483 ext4_journal_stop(handle);
2482 2484
2483 return err; 2485 return err;