Skip to content

Commit 46e294e

Browse files
jankaratytso
authored andcommitted
ext4: fix deadlock with fs freezing and EA inodes
Xattr code using inodes with large xattr data can end up dropping last inode reference (and thus deleting the inode) from places like ext4_xattr_set_entry(). That function is called with transaction started and so ext4_evict_inode() can deadlock against fs freezing like: CPU1 CPU2 removexattr() freeze_super() vfs_removexattr() ext4_xattr_set() handle = ext4_journal_start() ... ext4_xattr_set_entry() iput(old_ea_inode) ext4_evict_inode(old_ea_inode) sb->s_writers.frozen = SB_FREEZE_FS; sb_wait_write(sb, SB_FREEZE_FS); ext4_freeze() jbd2_journal_lock_updates() -> blocks waiting for all handles to stop sb_start_intwrite() -> blocks as sb is already in SB_FREEZE_FS state Generally it is advisable to delete inodes from a separate transaction as it can consume quite some credits however in this case it would be quite clumsy and furthermore the credits for inode deletion are quite limited and already accounted for. So just tweak ext4_evict_inode() to avoid freeze protection if we have transaction already started and thus it is not really needed anyway. Cc: [email protected] Fixes: dec214d ("ext4: xattr inode deduplication") Signed-off-by: Jan Kara <[email protected]> Reviewed-by: Andreas Dilger <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Theodore Ts'o <[email protected]>
1 parent 9bd23c3 commit 46e294e

File tree

1 file changed

+14
-5
lines changed

1 file changed

+14
-5
lines changed

fs/ext4/inode.c

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ void ext4_evict_inode(struct inode *inode)
175175
*/
176176
int extra_credits = 6;
177177
struct ext4_xattr_inode_array *ea_inode_array = NULL;
178+
bool freeze_protected = false;
178179

179180
trace_ext4_evict_inode(inode);
180181

@@ -232,9 +233,14 @@ void ext4_evict_inode(struct inode *inode)
232233

233234
/*
234235
* Protect us against freezing - iput() caller didn't have to have any
235-
* protection against it
236+
* protection against it. When we are in a running transaction though,
237+
* we are already protected against freezing and we cannot grab further
238+
* protection due to lock ordering constraints.
236239
*/
237-
sb_start_intwrite(inode->i_sb);
240+
if (!ext4_journal_current_handle()) {
241+
sb_start_intwrite(inode->i_sb);
242+
freeze_protected = true;
243+
}
238244

239245
if (!IS_NOQUOTA(inode))
240246
extra_credits += EXT4_MAXQUOTAS_DEL_BLOCKS(inode->i_sb);
@@ -253,7 +259,8 @@ void ext4_evict_inode(struct inode *inode)
253259
* cleaned up.
254260
*/
255261
ext4_orphan_del(NULL, inode);
256-
sb_end_intwrite(inode->i_sb);
262+
if (freeze_protected)
263+
sb_end_intwrite(inode->i_sb);
257264
goto no_delete;
258265
}
259266

@@ -294,7 +301,8 @@ void ext4_evict_inode(struct inode *inode)
294301
stop_handle:
295302
ext4_journal_stop(handle);
296303
ext4_orphan_del(NULL, inode);
297-
sb_end_intwrite(inode->i_sb);
304+
if (freeze_protected)
305+
sb_end_intwrite(inode->i_sb);
298306
ext4_xattr_inode_array_free(ea_inode_array);
299307
goto no_delete;
300308
}
@@ -323,7 +331,8 @@ void ext4_evict_inode(struct inode *inode)
323331
else
324332
ext4_free_inode(handle, inode);
325333
ext4_journal_stop(handle);
326-
sb_end_intwrite(inode->i_sb);
334+
if (freeze_protected)
335+
sb_end_intwrite(inode->i_sb);
327336
ext4_xattr_inode_array_free(ea_inode_array);
328337
return;
329338
no_delete:

0 commit comments

Comments
 (0)