提交 0617b83f 编写于 作者: D Dmitry Monakhov 提交者: Theodore Ts'o

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=15827Signed-off-by: NDmitry Monakhov <dmonakhov@openvz.org>
Signed-off-by: N"Theodore Ts'o" <tytso@mit.edu>
Acked-by: NJan Kara <jack@suse.cz>
上级 786ec791
...@@ -107,11 +107,8 @@ static int ext4_ext_truncate_extend_restart(handle_t *handle, ...@@ -107,11 +107,8 @@ static int ext4_ext_truncate_extend_restart(handle_t *handle,
if (err <= 0) if (err <= 0)
return err; return err;
err = ext4_truncate_restart_trans(handle, inode, needed); err = ext4_truncate_restart_trans(handle, inode, needed);
/* if (err == 0)
* We have dropped i_data_sem so someone might have cached again err = -EAGAIN;
* an extent we are going to truncate.
*/
ext4_ext_invalidate_cache(inode);
return err; return err;
} }
...@@ -2359,7 +2356,7 @@ static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start) ...@@ -2359,7 +2356,7 @@ static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start)
int depth = ext_depth(inode); int depth = ext_depth(inode);
struct ext4_ext_path *path; struct ext4_ext_path *path;
handle_t *handle; handle_t *handle;
int i = 0, err = 0; int i, err;
ext_debug("truncate since %u\n", start); ext_debug("truncate since %u\n", start);
...@@ -2368,23 +2365,26 @@ static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start) ...@@ -2368,23 +2365,26 @@ static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start)
if (IS_ERR(handle)) if (IS_ERR(handle))
return PTR_ERR(handle); return PTR_ERR(handle);
again:
ext4_ext_invalidate_cache(inode); ext4_ext_invalidate_cache(inode);
/* /*
* We start scanning from right side, freeing all the blocks * We start scanning from right side, freeing all the blocks
* after i_size and walking into the tree depth-wise. * after i_size and walking into the tree depth-wise.
*/ */
depth = ext_depth(inode);
path = kzalloc(sizeof(struct ext4_ext_path) * (depth + 1), GFP_NOFS); path = kzalloc(sizeof(struct ext4_ext_path) * (depth + 1), GFP_NOFS);
if (path == NULL) { if (path == NULL) {
ext4_journal_stop(handle); ext4_journal_stop(handle);
return -ENOMEM; return -ENOMEM;
} }
path[0].p_depth = depth;
path[0].p_hdr = ext_inode_hdr(inode); path[0].p_hdr = ext_inode_hdr(inode);
if (ext4_ext_check(inode, path[0].p_hdr, depth)) { if (ext4_ext_check(inode, path[0].p_hdr, depth)) {
err = -EIO; err = -EIO;
goto out; goto out;
} }
path[0].p_depth = depth; i = err = 0;
while (i >= 0 && err == 0) { while (i >= 0 && err == 0) {
if (i == depth) { if (i == depth) {
...@@ -2478,6 +2478,8 @@ static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start) ...@@ -2478,6 +2478,8 @@ static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start)
out: out:
ext4_ext_drop_refs(path); ext4_ext_drop_refs(path);
kfree(path); kfree(path);
if (err == -EAGAIN)
goto again;
ext4_journal_stop(handle); ext4_journal_stop(handle);
return err; return err;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册