aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4/extents.c
diff options
context:
space:
mode:
authorLukas Czerner <lczerner@redhat.com>2014-04-18 10:55:24 -0400
committerTheodore Ts'o <tytso@mit.edu>2014-04-18 10:55:24 -0400
commit6dd834effc12ba71092d9d1e4944530234b58ab1 (patch)
treea73e48e51bff230566810c72ea665768dd62d7ea /fs/ext4/extents.c
parentef24f6c234de9a03aed9368163dbaad9a4f6391f (diff)
ext4: fix extent merging in ext4_ext_shift_path_extents()
There is a bug in ext4_ext_shift_path_extents() where if we actually manage to merge a extent we would skip shifting the next extent. This will result in in one extent in the extent tree not being properly shifted. This is causing failure in various xfstests tests using fsx or fsstress with collapse range support. It will also cause file system corruption which looks something like: e2fsck 1.42.9 (4-Feb-2014) Pass 1: Checking inodes, blocks, and sizes Inode 20 has out of order extents (invalid logical block 3, physical block 492938, len 2) Clear? yes ... when running e2fsck. It's also very easily reproducible just by running fsx without any parameters. I can usually hit the problem within a minute. Fix it by increasing ex_start only if we're not merging the extent. Signed-off-by: Lukas Czerner <lczerner@redhat.com> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu> Reviewed-by: Namjae Jeon <namjae.jeon@samsung.com>
Diffstat (limited to 'fs/ext4/extents.c')
-rw-r--r--fs/ext4/extents.c15
1 files changed, 8 insertions, 7 deletions
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index eb7be8f08e10..d0860f2d36d0 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -5245,13 +5245,14 @@ ext4_ext_shift_path_extents(struct ext4_ext_path *path, ext4_lblk_t shift,
5245 5245
5246 while (ex_start <= ex_last) { 5246 while (ex_start <= ex_last) {
5247 le32_add_cpu(&ex_start->ee_block, -shift); 5247 le32_add_cpu(&ex_start->ee_block, -shift);
5248 if (ex_start > 5248 /* Try to merge to the left. */
5249 EXT_FIRST_EXTENT(path[depth].p_hdr)) { 5249 if ((ex_start >
5250 if (ext4_ext_try_to_merge_right(inode, 5250 EXT_FIRST_EXTENT(path[depth].p_hdr)) &&
5251 path, ex_start - 1)) 5251 ext4_ext_try_to_merge_right(inode,
5252 ex_last--; 5252 path, ex_start - 1))
5253 } 5253 ex_last--;
5254 ex_start++; 5254 else
5255 ex_start++;
5255 } 5256 }
5256 err = ext4_ext_dirty(handle, inode, path + depth); 5257 err = ext4_ext_dirty(handle, inode, path + depth);
5257 if (err) 5258 if (err)