summaryrefslogtreecommitdiff
path: root/fs/ext4/inode.c
diff options
context:
space:
mode:
authorTahsin Erdogan <tahsin@google.com>2017-06-22 11:42:09 -0400
committerTheodore Ts'o <tytso@mit.edu>2017-06-22 11:42:09 -0400
commit30a7eb970c3aae6f1b74b2edea896fdca1cbea38 (patch)
tree28f27a320e3f0db679e8629ea201c053c871c159 /fs/ext4/inode.c
parent02749a4c20827649859bf7e2435f1b238c24f935 (diff)
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 <tahsin@google.com> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Diffstat (limited to 'fs/ext4/inode.c')
-rw-r--r--fs/ext4/inode.c66
1 files changed, 17 insertions, 49 deletions
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);