diff options
author | Dmitry Monakhov <dmonakhov@openvz.org> | 2010-05-17 01:00:00 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2010-05-17 01:00:00 -0400 |
commit | 0617b83fa239db9743a18ce6cc0e556f4d0fd567 (patch) | |
tree | 46d646c2d1af9d706848520a4657877d4cff768f /fs/ext4 | |
parent | 786ec7915e530936b9eb2e3d12274145cab7aa7d (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.c | 16 |
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 | ||
2368 | again: | ||
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) | |||
2478 | out: | 2478 | out: |
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; |