>
> - Ted
>
> ext4: restart ext4_ext_remove_space() after transaction restart
>
> From: Dmitry Monakhov <dmonakhov@openvz.org>
>
> 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>
> ---
> 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 ffcaa11..0a47bec 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,
> if (err <= 0)
> return err;
> err = ext4_truncate_restart_trans(handle, inode, needed);
> - /*
> - * We have dropped i_data_sem so someone might have cached again
> - * an extent we are going to truncate.
> - */
> - ext4_ext_invalidate_cache(inode);
> + if (err == 0)
> + err = -EAGAIN;
>
> return err;
> }
> @@ -2359,7 +2356,7 @@ static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start)
> int depth = ext_depth(inode);
> struct ext4_ext_path *path;
> handle_t *handle;
> - int i = 0, err = 0;
> + int i, err;
>
> ext_debug("truncate since %u\n", start);
>
> @@ -2368,23 +2365,26 @@ static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start)
> if (IS_ERR(handle))
> return PTR_ERR(handle);
>
> +again:
> ext4_ext_invalidate_cache(inode);
>
> /*
> * We start scanning from right side, freeing all the blocks
> * 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);
> if (path == NULL) {
> ext4_journal_stop(handle);
> return -ENOMEM;
> }
> + path[0].p_depth = depth;
> path[0].p_hdr = ext_inode_hdr(inode);
> if (ext4_ext_check(inode, path[0].p_hdr, depth)) {
> err = -EIO;
> goto out;
> }
> - path[0].p_depth = depth;
> + i = err = 0;
>
> while (i >= 0 && err == 0) {
> if (i == depth) {
> @@ -2478,6 +2478,8 @@ static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start)
> out:
> ext4_ext_drop_refs(path);
> kfree(path);
> + if (err == -EAGAIN)
> + goto again;
> ext4_journal_stop(handle);
>
> return err;
>