diff options
author | Tahsin Erdogan <tahsin@google.com> | 2017-06-22 11:42:09 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2017-06-22 11:42:09 -0400 |
commit | 30a7eb970c3aae6f1b74b2edea896fdca1cbea38 (patch) | |
tree | 28f27a320e3f0db679e8629ea201c053c871c159 /fs/ext4/inode.c | |
parent | 02749a4c20827649859bf7e2435f1b238c24f935 (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.c | 66 |
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); |