Skip to content

Commit 1811bc4

Browse files
yangerkuntytso
authored andcommitted
ext4: refresh the ext4_ext_path struct after dropping i_data_sem.
After we drop i_data sem, we need to reload the ext4_ext_path structure since the extent tree can change once i_data_sem is released. This addresses the BUG: [52117.465187] ------------[ cut here ]------------ [52117.465686] kernel BUG at fs/ext4/extents.c:1756! ... [52117.478306] Call Trace: [52117.478565] ext4_ext_shift_extents+0x3ee/0x710 [52117.479020] ext4_fallocate+0x139c/0x1b40 [52117.479405] ? __do_sys_newfstat+0x6b/0x80 [52117.479805] vfs_fallocate+0x151/0x4b0 [52117.480177] ksys_fallocate+0x4a/0xa0 [52117.480533] __x64_sys_fallocate+0x22/0x30 [52117.480930] do_syscall_64+0x35/0x80 [52117.481277] entry_SYSCALL_64_after_hwframe+0x44/0xae [52117.481769] RIP: 0033:0x7fa062f855ca Cc: [email protected] Link: https://lore.kernel.org/r/[email protected] Signed-off-by: yangerkun <[email protected]> Signed-off-by: Theodore Ts'o <[email protected]>
1 parent 4268496 commit 1811bc4

File tree

1 file changed

+13
-1
lines changed

1 file changed

+13
-1
lines changed

fs/ext4/extents.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5014,8 +5014,11 @@ ext4_ext_shift_path_extents(struct ext4_ext_path *path, ext4_lblk_t shift,
50145014
restart_credits = ext4_writepage_trans_blocks(inode);
50155015
err = ext4_datasem_ensure_credits(handle, inode, credits,
50165016
restart_credits, 0);
5017-
if (err)
5017+
if (err) {
5018+
if (err > 0)
5019+
err = -EAGAIN;
50185020
goto out;
5021+
}
50195022

50205023
err = ext4_ext_get_access(handle, inode, path + depth);
50215024
if (err)
@@ -5089,6 +5092,7 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle,
50895092
int ret = 0, depth;
50905093
struct ext4_extent *extent;
50915094
ext4_lblk_t stop, *iterator, ex_start, ex_end;
5095+
ext4_lblk_t tmp = EXT_MAX_BLOCKS;
50925096

50935097
/* Let path point to the last extent */
50945098
path = ext4_find_extent(inode, EXT_MAX_BLOCKS - 1, NULL,
@@ -5142,11 +5146,15 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle,
51425146
* till we reach stop. In case of right shift, iterator points to stop
51435147
* and it is decreased till we reach start.
51445148
*/
5149+
again:
51455150
if (SHIFT == SHIFT_LEFT)
51465151
iterator = &start;
51475152
else
51485153
iterator = &stop;
51495154

5155+
if (tmp != EXT_MAX_BLOCKS)
5156+
*iterator = tmp;
5157+
51505158
/*
51515159
* Its safe to start updating extents. Start and stop are unsigned, so
51525160
* in case of right shift if extent with 0 block is reached, iterator
@@ -5175,6 +5183,7 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle,
51755183
}
51765184
}
51775185

5186+
tmp = *iterator;
51785187
if (SHIFT == SHIFT_LEFT) {
51795188
extent = EXT_LAST_EXTENT(path[depth].p_hdr);
51805189
*iterator = le32_to_cpu(extent->ee_block) +
@@ -5193,6 +5202,9 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle,
51935202
}
51945203
ret = ext4_ext_shift_path_extents(path, shift, inode,
51955204
handle, SHIFT);
5205+
/* iterator can be NULL which means we should break */
5206+
if (ret == -EAGAIN)
5207+
goto again;
51965208
if (ret)
51975209
break;
51985210
}

0 commit comments

Comments
 (0)