From 30a7eb970c3aae6f1b74b2edea896fdca1cbea38 Mon Sep 17 00:00:00 2001 From: Tahsin Erdogan Date: Thu, 22 Jun 2017 11:42:09 -0400 Subject: ext4: cleanup transaction restarts during inode deletion During inode deletion, the number of journal credits that will be needed is hard to determine. For that reason we have journal extend/restart calls in several places. Whenever a transaction is restarted, filesystem must be in a consistent state because there is no atomicity guarantee beyond a restart call. Add ext4_xattr_ensure_credits() helper function which takes care of journal extend/restart logic. It also handles getting jbd2 write access and dirty metadata calls. This function is called at every iteration of handling an ea_inode reference. Signed-off-by: Tahsin Erdogan Signed-off-by: Theodore Ts'o --- fs/ext4/inode.c | 66 +++++++++++++++------------------------------------------ 1 file changed, 17 insertions(+), 49 deletions(-) (limited to 'fs/ext4/inode.c') diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 3e9415e2e74d..46def73d3472 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -239,7 +239,11 @@ void ext4_evict_inode(struct inode *inode) */ sb_start_intwrite(inode->i_sb); - handle = ext4_journal_start(inode, EXT4_HT_TRUNCATE, extra_credits); + if (!IS_NOQUOTA(inode)) + extra_credits += EXT4_MAXQUOTAS_DEL_BLOCKS(inode->i_sb); + + handle = ext4_journal_start(inode, EXT4_HT_TRUNCATE, + ext4_blocks_for_truncate(inode)+extra_credits); if (IS_ERR(handle)) { ext4_std_error(inode->i_sb, PTR_ERR(handle)); /* @@ -251,36 +255,9 @@ void ext4_evict_inode(struct inode *inode) sb_end_intwrite(inode->i_sb); goto no_delete; } + if (IS_SYNC(inode)) ext4_handle_sync(handle); - - /* - * Delete xattr inode before deleting the main inode. - */ - err = ext4_xattr_delete_inode(handle, inode, &ea_inode_array); - if (err) { - ext4_warning(inode->i_sb, - "couldn't delete inode's xattr (err %d)", err); - goto stop_handle; - } - - if (!IS_NOQUOTA(inode)) - extra_credits += 2 * EXT4_QUOTA_DEL_BLOCKS(inode->i_sb); - - if (!ext4_handle_has_enough_credits(handle, - ext4_blocks_for_truncate(inode) + extra_credits)) { - err = ext4_journal_extend(handle, - ext4_blocks_for_truncate(inode) + extra_credits); - if (err > 0) - err = ext4_journal_restart(handle, - ext4_blocks_for_truncate(inode) + extra_credits); - if (err != 0) { - ext4_warning(inode->i_sb, - "couldn't extend journal (err %d)", err); - goto stop_handle; - } - } - inode->i_size = 0; err = ext4_mark_inode_dirty(handle, inode); if (err) { @@ -298,25 +275,17 @@ void ext4_evict_inode(struct inode *inode) } } - /* - * ext4_ext_truncate() doesn't reserve any slop when it - * restarts journal transactions; therefore there may not be - * enough credits left in the handle to remove the inode from - * the orphan list and set the dtime field. - */ - if (!ext4_handle_has_enough_credits(handle, extra_credits)) { - err = ext4_journal_extend(handle, extra_credits); - if (err > 0) - err = ext4_journal_restart(handle, extra_credits); - if (err != 0) { - ext4_warning(inode->i_sb, - "couldn't extend journal (err %d)", err); - stop_handle: - ext4_journal_stop(handle); - ext4_orphan_del(NULL, inode); - sb_end_intwrite(inode->i_sb); - goto no_delete; - } + /* Remove xattr references. */ + err = ext4_xattr_delete_inode(handle, inode, &ea_inode_array, + extra_credits); + if (err) { + ext4_warning(inode->i_sb, "xattr delete (err %d)", err); +stop_handle: + ext4_journal_stop(handle); + ext4_orphan_del(NULL, inode); + sb_end_intwrite(inode->i_sb); + ext4_xattr_inode_array_free(ea_inode_array); + goto no_delete; } /* @@ -342,7 +311,6 @@ void ext4_evict_inode(struct inode *inode) ext4_clear_inode(inode); else ext4_free_inode(handle, inode); - ext4_journal_stop(handle); sb_end_intwrite(inode->i_sb); ext4_xattr_inode_array_free(ea_inode_array); -- cgit