aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4/inode.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/ext4/inode.c')
-rw-r--r--fs/ext4/inode.c23
1 files changed, 19 insertions, 4 deletions
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 9a4c929b16dc..d61fb523308f 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -192,11 +192,24 @@ static int try_to_extend_transaction(handle_t *handle, struct inode *inode)
192 * so before we call here everything must be consistently dirtied against 192 * so before we call here everything must be consistently dirtied against
193 * this transaction. 193 * this transaction.
194 */ 194 */
195static int ext4_journal_test_restart(handle_t *handle, struct inode *inode) 195 int ext4_truncate_restart_trans(handle_t *handle, struct inode *inode,
196 int nblocks)
196{ 197{
198 int ret;
199
200 /*
201 * Drop i_data_sem to avoid deadlock with ext4_get_blocks At this
202 * moment, get_block can be called only for blocks inside i_size since
203 * page cache has been already dropped and writes are blocked by
204 * i_mutex. So we can safely drop the i_data_sem here.
205 */
197 BUG_ON(EXT4_JOURNAL(inode) == NULL); 206 BUG_ON(EXT4_JOURNAL(inode) == NULL);
198 jbd_debug(2, "restarting handle %p\n", handle); 207 jbd_debug(2, "restarting handle %p\n", handle);
199 return ext4_journal_restart(handle, blocks_for_truncate(inode)); 208 up_write(&EXT4_I(inode)->i_data_sem);
209 ret = ext4_journal_restart(handle, blocks_for_truncate(inode));
210 down_write(&EXT4_I(inode)->i_data_sem);
211
212 return ret;
200} 213}
201 214
202/* 215/*
@@ -3658,7 +3671,8 @@ static void ext4_clear_blocks(handle_t *handle, struct inode *inode,
3658 ext4_handle_dirty_metadata(handle, inode, bh); 3671 ext4_handle_dirty_metadata(handle, inode, bh);
3659 } 3672 }
3660 ext4_mark_inode_dirty(handle, inode); 3673 ext4_mark_inode_dirty(handle, inode);
3661 ext4_journal_test_restart(handle, inode); 3674 ext4_truncate_restart_trans(handle, inode,
3675 blocks_for_truncate(inode));
3662 if (bh) { 3676 if (bh) {
3663 BUFFER_TRACE(bh, "retaking write access"); 3677 BUFFER_TRACE(bh, "retaking write access");
3664 ext4_journal_get_write_access(handle, bh); 3678 ext4_journal_get_write_access(handle, bh);
@@ -3869,7 +3883,8 @@ static void ext4_free_branches(handle_t *handle, struct inode *inode,
3869 return; 3883 return;
3870 if (try_to_extend_transaction(handle, inode)) { 3884 if (try_to_extend_transaction(handle, inode)) {
3871 ext4_mark_inode_dirty(handle, inode); 3885 ext4_mark_inode_dirty(handle, inode);
3872 ext4_journal_test_restart(handle, inode); 3886 ext4_truncate_restart_trans(handle, inode,
3887 blocks_for_truncate(inode));
3873 } 3888 }
3874 3889
3875 ext4_free_blocks(handle, inode, nr, 1, 1); 3890 ext4_free_blocks(handle, inode, nr, 1, 1);