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>
This commit is contained in:

committed by
Theodore Ts'o

parent
02749a4c20
commit
30a7eb970c
@@ -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);
|
||||
|
Reference in New Issue
Block a user