Commit a4130367 authored by Jan Kara's avatar Jan Kara Committed by Theodore Ts'o

ext4: Provide function to handle transaction restarts

Provide ext4_journal_ensure_credits_fn() function to ensure transaction
has given amount of credits and call helper function to prepare for
restarting a transaction. This allows to remove some boilerplate code
from various places, add proper error handling for the case where
transaction extension or restart fails, and reduces following changes
needed for proper revoke record reservation tracking.
Signed-off-by: default avatarJan Kara <jack@suse.cz>
Link: https://lore.kernel.org/r/20191105164437.32602-10-jack@suse.czSigned-off-by: default avatarTheodore Ts'o <tytso@mit.edu>
parent f2890730
...@@ -2604,7 +2604,6 @@ extern int ext4_can_truncate(struct inode *inode); ...@@ -2604,7 +2604,6 @@ extern int ext4_can_truncate(struct inode *inode);
extern int ext4_truncate(struct inode *); extern int ext4_truncate(struct inode *);
extern int ext4_break_layouts(struct inode *); extern int ext4_break_layouts(struct inode *);
extern int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length); extern int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length);
extern int ext4_truncate_restart_trans(handle_t *, struct inode *, int nblocks);
extern void ext4_set_inode_flags(struct inode *); extern void ext4_set_inode_flags(struct inode *);
extern int ext4_alloc_da_blocks(struct inode *inode); extern int ext4_alloc_da_blocks(struct inode *inode);
extern void ext4_set_aops(struct inode *inode); extern void ext4_set_aops(struct inode *inode);
...@@ -3296,6 +3295,9 @@ extern int ext4_swap_extents(handle_t *handle, struct inode *inode1, ...@@ -3296,6 +3295,9 @@ extern int ext4_swap_extents(handle_t *handle, struct inode *inode1,
ext4_lblk_t lblk2, ext4_lblk_t count, ext4_lblk_t lblk2, ext4_lblk_t count,
int mark_unwritten,int *err); int mark_unwritten,int *err);
extern int ext4_clu_mapped(struct inode *inode, ext4_lblk_t lclu); extern int ext4_clu_mapped(struct inode *inode, ext4_lblk_t lclu);
extern int ext4_datasem_ensure_credits(handle_t *handle, struct inode *inode,
int check_cred, int restart_cred);
/* move_extent.c */ /* move_extent.c */
extern void ext4_double_down_write_data_sem(struct inode *first, extern void ext4_double_down_write_data_sem(struct inode *first,
......
...@@ -133,6 +133,17 @@ handle_t *__ext4_journal_start_reserved(handle_t *handle, unsigned int line, ...@@ -133,6 +133,17 @@ handle_t *__ext4_journal_start_reserved(handle_t *handle, unsigned int line,
return handle; return handle;
} }
int __ext4_journal_ensure_credits(handle_t *handle, int check_cred,
int extend_cred)
{
if (!ext4_handle_valid(handle))
return 0;
if (handle->h_buffer_credits >= check_cred)
return 0;
return ext4_journal_extend(handle,
extend_cred - handle->h_buffer_credits);
}
static void ext4_journal_abort_handle(const char *caller, unsigned int line, static void ext4_journal_abort_handle(const char *caller, unsigned int line,
const char *err_fn, const char *err_fn,
struct buffer_head *bh, struct buffer_head *bh,
......
...@@ -346,6 +346,54 @@ static inline int ext4_journal_restart(handle_t *handle, int nblocks) ...@@ -346,6 +346,54 @@ static inline int ext4_journal_restart(handle_t *handle, int nblocks)
return 0; return 0;
} }
int __ext4_journal_ensure_credits(handle_t *handle, int check_cred,
int extend_cred);
/*
* Ensure @handle has at least @check_creds credits available. If not,
* transaction will be extended or restarted to contain at least @extend_cred
* credits. Before restarting transaction @fn is executed to allow for cleanup
* before the transaction is restarted.
*
* The return value is < 0 in case of error, 0 in case the handle has enough
* credits or transaction extension succeeded, 1 in case transaction had to be
* restarted.
*/
#define ext4_journal_ensure_credits_fn(handle, check_cred, extend_cred, fn) \
({ \
__label__ __ensure_end; \
int err = __ext4_journal_ensure_credits((handle), (check_cred), \
(extend_cred)); \
\
if (err <= 0) \
goto __ensure_end; \
err = (fn); \
if (err < 0) \
goto __ensure_end; \
err = ext4_journal_restart((handle), (extend_cred)); \
if (err == 0) \
err = 1; \
__ensure_end: \
err; \
})
/*
* Ensure given handle has at least requested amount of credits available,
* possibly restarting transaction if needed.
*/
static inline int ext4_journal_ensure_credits(handle_t *handle, int credits)
{
return ext4_journal_ensure_credits_fn(handle, credits, credits, 0);
}
static inline int ext4_journal_ensure_credits_batch(handle_t *handle,
int credits)
{
return ext4_journal_ensure_credits_fn(handle, credits,
EXT4_MAX_TRANS_DATA, 0);
}
static inline int ext4_journal_blocks_per_page(struct inode *inode) static inline int ext4_journal_blocks_per_page(struct inode *inode)
{ {
if (EXT4_JOURNAL(inode) != NULL) if (EXT4_JOURNAL(inode) != NULL)
......
...@@ -100,29 +100,40 @@ static int ext4_split_extent_at(handle_t *handle, ...@@ -100,29 +100,40 @@ static int ext4_split_extent_at(handle_t *handle,
static int ext4_find_delayed_extent(struct inode *inode, static int ext4_find_delayed_extent(struct inode *inode,
struct extent_status *newes); struct extent_status *newes);
static int ext4_ext_truncate_extend_restart(handle_t *handle, static int ext4_ext_trunc_restart_fn(struct inode *inode, int *dropped)
struct inode *inode,
int needed)
{ {
int err;
if (!ext4_handle_valid(handle))
return 0;
if (handle->h_buffer_credits >= needed)
return 0;
/* /*
* If we need to extend the journal get a few extra blocks * Drop i_data_sem to avoid deadlock with ext4_map_blocks. At this
* while we're at it for efficiency's sake. * moment, get_block can be called only for blocks inside i_size since
* page cache has been already dropped and writes are blocked by
* i_mutex. So we can safely drop the i_data_sem here.
*/ */
needed += 3; BUG_ON(EXT4_JOURNAL(inode) == NULL);
err = ext4_journal_extend(handle, needed - handle->h_buffer_credits); ext4_discard_preallocations(inode);
if (err <= 0) up_write(&EXT4_I(inode)->i_data_sem);
return err; *dropped = 1;
err = ext4_truncate_restart_trans(handle, inode, needed); return 0;
if (err == 0) }
err = -EAGAIN;
return err; /*
* Make sure 'handle' has at least 'check_cred' credits. If not, restart
* transaction with 'restart_cred' credits. The function drops i_data_sem
* when restarting transaction and gets it after transaction is restarted.
*
* The function returns 0 on success, 1 if transaction had to be restarted,
* and < 0 in case of fatal error.
*/
int ext4_datasem_ensure_credits(handle_t *handle, struct inode *inode,
int check_cred, int restart_cred)
{
int ret;
int dropped = 0;
ret = ext4_journal_ensure_credits_fn(handle, check_cred, restart_cred,
ext4_ext_trunc_restart_fn(inode, &dropped));
if (dropped)
down_write(&EXT4_I(inode)->i_data_sem);
return ret;
} }
/* /*
...@@ -2820,9 +2831,13 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode, ...@@ -2820,9 +2831,13 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode,
} }
credits += EXT4_MAXQUOTAS_TRANS_BLOCKS(inode->i_sb); credits += EXT4_MAXQUOTAS_TRANS_BLOCKS(inode->i_sb);
err = ext4_ext_truncate_extend_restart(handle, inode, credits); err = ext4_datasem_ensure_credits(handle, inode, credits,
if (err) credits);
if (err) {
if (err > 0)
err = -EAGAIN;
goto out; goto out;
}
err = ext4_ext_get_access(handle, inode, path + depth); err = ext4_ext_get_access(handle, inode, path + depth);
if (err) if (err)
...@@ -5206,13 +5221,10 @@ ext4_access_path(handle_t *handle, struct inode *inode, ...@@ -5206,13 +5221,10 @@ ext4_access_path(handle_t *handle, struct inode *inode,
* descriptor) for each block group; assume two block * descriptor) for each block group; assume two block
* groups * groups
*/ */
if (handle->h_buffer_credits < 7) {
credits = ext4_writepage_trans_blocks(inode); credits = ext4_writepage_trans_blocks(inode);
err = ext4_ext_truncate_extend_restart(handle, inode, credits); err = ext4_datasem_ensure_credits(handle, inode, 7, credits);
/* EAGAIN is success */ if (err < 0)
if (err && err != -EAGAIN)
return err; return err;
}
err = ext4_ext_get_access(handle, inode, path); err = ext4_ext_get_access(handle, inode, path);
return err; return err;
......
...@@ -699,27 +699,62 @@ int ext4_ind_trans_blocks(struct inode *inode, int nrblocks) ...@@ -699,27 +699,62 @@ int ext4_ind_trans_blocks(struct inode *inode, int nrblocks)
return DIV_ROUND_UP(nrblocks, EXT4_ADDR_PER_BLOCK(inode->i_sb)) + 4; return DIV_ROUND_UP(nrblocks, EXT4_ADDR_PER_BLOCK(inode->i_sb)) + 4;
} }
static int ext4_ind_trunc_restart_fn(handle_t *handle, struct inode *inode,
struct buffer_head *bh, int *dropped)
{
int err;
if (bh) {
BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata");
err = ext4_handle_dirty_metadata(handle, inode, bh);
if (unlikely(err))
return err;
}
err = ext4_mark_inode_dirty(handle, inode);
if (unlikely(err))
return err;
/*
* Drop i_data_sem to avoid deadlock with ext4_map_blocks. At this
* moment, get_block can be called only for blocks inside i_size since
* page cache has been already dropped and writes are blocked by
* i_mutex. So we can safely drop the i_data_sem here.
*/
BUG_ON(EXT4_JOURNAL(inode) == NULL);
ext4_discard_preallocations(inode);
up_write(&EXT4_I(inode)->i_data_sem);
*dropped = 1;
return 0;
}
/* /*
* Truncate transactions can be complex and absolutely huge. So we need to * Truncate transactions can be complex and absolutely huge. So we need to
* be able to restart the transaction at a conventient checkpoint to make * be able to restart the transaction at a conventient checkpoint to make
* sure we don't overflow the journal. * sure we don't overflow the journal.
* *
* Try to extend this transaction for the purposes of truncation. If * Try to extend this transaction for the purposes of truncation. If
* extend fails, we need to propagate the failure up and restart the * extend fails, we restart transaction.
* transaction in the top-level truncate loop. --sct
*
* Returns 0 if we managed to create more room. If we can't create more
* room, and the transaction must be restarted we return 1.
*/ */
static int try_to_extend_transaction(handle_t *handle, struct inode *inode) static int ext4_ind_truncate_ensure_credits(handle_t *handle,
struct inode *inode,
struct buffer_head *bh)
{ {
if (!ext4_handle_valid(handle)) int ret;
return 0; int dropped = 0;
if (ext4_handle_has_enough_credits(handle, EXT4_RESERVE_TRANS_BLOCKS+1))
return 0; ret = ext4_journal_ensure_credits_fn(handle, EXT4_RESERVE_TRANS_BLOCKS,
if (!ext4_journal_extend(handle, ext4_blocks_for_truncate(inode))) ext4_blocks_for_truncate(inode),
ext4_ind_trunc_restart_fn(handle, inode, bh, &dropped));
if (dropped)
down_write(&EXT4_I(inode)->i_data_sem);
if (ret <= 0)
return ret;
if (bh) {
BUFFER_TRACE(bh, "retaking write access");
ret = ext4_journal_get_write_access(handle, bh);
if (unlikely(ret))
return ret;
}
return 0; return 0;
return 1;
} }
/* /*
...@@ -854,27 +889,9 @@ static int ext4_clear_blocks(handle_t *handle, struct inode *inode, ...@@ -854,27 +889,9 @@ static int ext4_clear_blocks(handle_t *handle, struct inode *inode,
return 1; return 1;
} }
if (try_to_extend_transaction(handle, inode)) { err = ext4_ind_truncate_ensure_credits(handle, inode, bh);
if (bh) { if (err < 0)
BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata");
err = ext4_handle_dirty_metadata(handle, inode, bh);
if (unlikely(err))
goto out_err;
}
err = ext4_mark_inode_dirty(handle, inode);
if (unlikely(err))
goto out_err;
err = ext4_truncate_restart_trans(handle, inode,
ext4_blocks_for_truncate(inode));
if (unlikely(err))
goto out_err;
if (bh) {
BUFFER_TRACE(bh, "retaking write access");
err = ext4_journal_get_write_access(handle, bh);
if (unlikely(err))
goto out_err; goto out_err;
}
}
for (p = first; p < last; p++) for (p = first; p < last; p++)
*p = 0; *p = 0;
...@@ -1057,11 +1074,9 @@ static void ext4_free_branches(handle_t *handle, struct inode *inode, ...@@ -1057,11 +1074,9 @@ static void ext4_free_branches(handle_t *handle, struct inode *inode,
*/ */
if (ext4_handle_is_aborted(handle)) if (ext4_handle_is_aborted(handle))
return; return;
if (try_to_extend_transaction(handle, inode)) { if (ext4_ind_truncate_ensure_credits(handle, inode,
ext4_mark_inode_dirty(handle, inode); NULL) < 0)
ext4_truncate_restart_trans(handle, inode, return;
ext4_blocks_for_truncate(inode));
}
/* /*
* The forget flag here is critical because if * The forget flag here is critical because if
......
...@@ -163,32 +163,6 @@ int ext4_inode_is_fast_symlink(struct inode *inode) ...@@ -163,32 +163,6 @@ int ext4_inode_is_fast_symlink(struct inode *inode)
(inode->i_size < EXT4_N_BLOCKS * 4); (inode->i_size < EXT4_N_BLOCKS * 4);
} }
/*
* Restart the transaction associated with *handle. This does a commit,
* so before we call here everything must be consistently dirtied against
* this transaction.
*/
int ext4_truncate_restart_trans(handle_t *handle, struct inode *inode,
int nblocks)
{
int ret;
/*
* Drop i_data_sem to avoid deadlock with ext4_map_blocks. At this
* moment, get_block can be called only for blocks inside i_size since
* page cache has been already dropped and writes are blocked by
* i_mutex. So we can safely drop the i_data_sem here.
*/
BUG_ON(EXT4_JOURNAL(inode) == NULL);
jbd_debug(2, "restarting handle %p\n", handle);
up_write(&EXT4_I(inode)->i_data_sem);
ret = ext4_journal_restart(handle, nblocks);
down_write(&EXT4_I(inode)->i_data_sem);
ext4_discard_preallocations(inode);
return ret;
}
/* /*
* Called at the last iput() if i_nlink is zero. * Called at the last iput() if i_nlink is zero.
*/ */
......
...@@ -50,29 +50,9 @@ static int finish_range(handle_t *handle, struct inode *inode, ...@@ -50,29 +50,9 @@ static int finish_range(handle_t *handle, struct inode *inode,
needed = ext4_ext_calc_credits_for_single_extent(inode, needed = ext4_ext_calc_credits_for_single_extent(inode,
lb->last_block - lb->first_block + 1, path); lb->last_block - lb->first_block + 1, path);
/* retval = ext4_datasem_ensure_credits(handle, inode, needed, needed);
* Make sure the credit we accumalated is not really high if (retval < 0)
*/
if (needed && ext4_handle_has_enough_credits(handle,
EXT4_RESERVE_TRANS_BLOCKS)) {
up_write((&EXT4_I(inode)->i_data_sem));
retval = ext4_journal_restart(handle, needed);
down_write((&EXT4_I(inode)->i_data_sem));
if (retval)
goto err_out;
} else if (needed) {
retval = ext4_journal_extend(handle, needed);
if (retval) {
/*
* IF not able to extend the journal restart the journal
*/
up_write((&EXT4_I(inode)->i_data_sem));
retval = ext4_journal_restart(handle, needed);
down_write((&EXT4_I(inode)->i_data_sem));
if (retval)
goto err_out; goto err_out;
}
}
retval = ext4_ext_insert_extent(handle, inode, &path, &newext, 0); retval = ext4_ext_insert_extent(handle, inode, &path, &newext, 0);
err_out: err_out:
up_write((&EXT4_I(inode)->i_data_sem)); up_write((&EXT4_I(inode)->i_data_sem));
...@@ -196,26 +176,6 @@ static int update_tind_extent_range(handle_t *handle, struct inode *inode, ...@@ -196,26 +176,6 @@ static int update_tind_extent_range(handle_t *handle, struct inode *inode,
} }
static int extend_credit_for_blkdel(handle_t *handle, struct inode *inode)
{
int retval = 0, needed;
if (ext4_handle_has_enough_credits(handle, EXT4_RESERVE_TRANS_BLOCKS+1))
return 0;
/*
* We are freeing a blocks. During this we touch
* superblock, group descriptor and block bitmap.
* So allocate a credit of 3. We may update
* quota (user and group).
*/
needed = 3 + EXT4_MAXQUOTAS_TRANS_BLOCKS(inode->i_sb);
if (ext4_journal_extend(handle, needed) != 0)
retval = ext4_journal_restart(handle, needed);
return retval;
}
static int free_dind_blocks(handle_t *handle, static int free_dind_blocks(handle_t *handle,
struct inode *inode, __le32 i_data) struct inode *inode, __le32 i_data)
{ {
...@@ -223,6 +183,7 @@ static int free_dind_blocks(handle_t *handle, ...@@ -223,6 +183,7 @@ static int free_dind_blocks(handle_t *handle,
__le32 *tmp_idata; __le32 *tmp_idata;
struct buffer_head *bh; struct buffer_head *bh;
unsigned long max_entries = inode->i_sb->s_blocksize >> 2; unsigned long max_entries = inode->i_sb->s_blocksize >> 2;
int err;
bh = ext4_sb_bread(inode->i_sb, le32_to_cpu(i_data), 0); bh = ext4_sb_bread(inode->i_sb, le32_to_cpu(i_data), 0);
if (IS_ERR(bh)) if (IS_ERR(bh))
...@@ -231,7 +192,12 @@ static int free_dind_blocks(handle_t *handle, ...@@ -231,7 +192,12 @@ static int free_dind_blocks(handle_t *handle,
tmp_idata = (__le32 *)bh->b_data; tmp_idata = (__le32 *)bh->b_data;
for (i = 0; i < max_entries; i++) { for (i = 0; i < max_entries; i++) {
if (tmp_idata[i]) { if (tmp_idata[i]) {
extend_credit_for_blkdel(handle, inode); err = ext4_journal_ensure_credits(handle,
EXT4_RESERVE_TRANS_BLOCKS);
if (err < 0) {
put_bh(bh);
return err;
}
ext4_free_blocks(handle, inode, NULL, ext4_free_blocks(handle, inode, NULL,
le32_to_cpu(tmp_idata[i]), 1, le32_to_cpu(tmp_idata[i]), 1,
EXT4_FREE_BLOCKS_METADATA | EXT4_FREE_BLOCKS_METADATA |
...@@ -239,7 +205,9 @@ static int free_dind_blocks(handle_t *handle, ...@@ -239,7 +205,9 @@ static int free_dind_blocks(handle_t *handle,
} }
} }
put_bh(bh); put_bh(bh);
extend_credit_for_blkdel(handle, inode); err = ext4_journal_ensure_credits(handle, EXT4_RESERVE_TRANS_BLOCKS);
if (err < 0)
return err;
ext4_free_blocks(handle, inode, NULL, le32_to_cpu(i_data), 1, ext4_free_blocks(handle, inode, NULL, le32_to_cpu(i_data), 1,
EXT4_FREE_BLOCKS_METADATA | EXT4_FREE_BLOCKS_METADATA |
EXT4_FREE_BLOCKS_FORGET); EXT4_FREE_BLOCKS_FORGET);
...@@ -270,7 +238,9 @@ static int free_tind_blocks(handle_t *handle, ...@@ -270,7 +238,9 @@ static int free_tind_blocks(handle_t *handle,
} }
} }
put_bh(bh); put_bh(bh);
extend_credit_for_blkdel(handle, inode); retval = ext4_journal_ensure_credits(handle, EXT4_RESERVE_TRANS_BLOCKS);
if (retval < 0)
return retval;
ext4_free_blocks(handle, inode, NULL, le32_to_cpu(i_data), 1, ext4_free_blocks(handle, inode, NULL, le32_to_cpu(i_data), 1,
EXT4_FREE_BLOCKS_METADATA | EXT4_FREE_BLOCKS_METADATA |
EXT4_FREE_BLOCKS_FORGET); EXT4_FREE_BLOCKS_FORGET);
...@@ -283,7 +253,10 @@ static int free_ind_block(handle_t *handle, struct inode *inode, __le32 *i_data) ...@@ -283,7 +253,10 @@ static int free_ind_block(handle_t *handle, struct inode *inode, __le32 *i_data)
/* ei->i_data[EXT4_IND_BLOCK] */ /* ei->i_data[EXT4_IND_BLOCK] */
if (i_data[0]) { if (i_data[0]) {
extend_credit_for_blkdel(handle, inode); retval = ext4_journal_ensure_credits(handle,
EXT4_RESERVE_TRANS_BLOCKS);
if (retval < 0)
return retval;
ext4_free_blocks(handle, inode, NULL, ext4_free_blocks(handle, inode, NULL,
le32_to_cpu(i_data[0]), 1, le32_to_cpu(i_data[0]), 1,
EXT4_FREE_BLOCKS_METADATA | EXT4_FREE_BLOCKS_METADATA |
...@@ -318,12 +291,9 @@ static int ext4_ext_swap_inode_data(handle_t *handle, struct inode *inode, ...@@ -318,12 +291,9 @@ static int ext4_ext_swap_inode_data(handle_t *handle, struct inode *inode,
* One credit accounted for writing the * One credit accounted for writing the
* i_data field of the original inode * i_data field of the original inode
*/ */
retval = ext4_journal_extend(handle, 1); retval = ext4_journal_ensure_credits(handle, 1);
if (retval) { if (retval < 0)
retval = ext4_journal_restart(handle, 1);
if (retval)
goto err_out; goto err_out;
}
i_data[0] = ei->i_data[EXT4_IND_BLOCK]; i_data[0] = ei->i_data[EXT4_IND_BLOCK];
i_data[1] = ei->i_data[EXT4_DIND_BLOCK]; i_data[1] = ei->i_data[EXT4_DIND_BLOCK];
...@@ -391,15 +361,19 @@ static int free_ext_idx(handle_t *handle, struct inode *inode, ...@@ -391,15 +361,19 @@ static int free_ext_idx(handle_t *handle, struct inode *inode,
ix = EXT_FIRST_INDEX(eh); ix = EXT_FIRST_INDEX(eh);
for (i = 0; i < le16_to_cpu(eh->eh_entries); i++, ix++) { for (i = 0; i < le16_to_cpu(eh->eh_entries); i++, ix++) {
retval = free_ext_idx(handle, inode, ix); retval = free_ext_idx(handle, inode, ix);
if (retval) if (retval) {
break; put_bh(bh);
return retval;
}
} }
} }
put_bh(bh); put_bh(bh);
extend_credit_for_blkdel(handle, inode); retval = ext4_journal_ensure_credits(handle, EXT4_RESERVE_TRANS_BLOCKS);
if (retval < 0)
return retval;
ext4_free_blocks(handle, inode, NULL, block, 1, ext4_free_blocks(handle, inode, NULL, block, 1,
EXT4_FREE_BLOCKS_METADATA | EXT4_FREE_BLOCKS_FORGET); EXT4_FREE_BLOCKS_METADATA | EXT4_FREE_BLOCKS_FORGET);
return retval; return 0;
} }
/* /*
...@@ -574,9 +548,9 @@ int ext4_ext_migrate(struct inode *inode) ...@@ -574,9 +548,9 @@ int ext4_ext_migrate(struct inode *inode)
} }
/* We mark the tmp_inode dirty via ext4_ext_tree_init. */ /* We mark the tmp_inode dirty via ext4_ext_tree_init. */
if (ext4_journal_extend(handle, 1) != 0) retval = ext4_journal_ensure_credits(handle, 1);
ext4_journal_restart(handle, 1); if (retval < 0)
goto out_stop;
/* /*
* Mark the tmp_inode as of size zero * Mark the tmp_inode as of size zero
*/ */
...@@ -594,6 +568,7 @@ int ext4_ext_migrate(struct inode *inode) ...@@ -594,6 +568,7 @@ int ext4_ext_migrate(struct inode *inode)
/* Reset the extent details */ /* Reset the extent details */
ext4_ext_tree_init(handle, tmp_inode); ext4_ext_tree_init(handle, tmp_inode);
out_stop:
ext4_journal_stop(handle); ext4_journal_stop(handle);
out: out:
unlock_new_inode(tmp_inode); unlock_new_inode(tmp_inode);
......
...@@ -388,30 +388,6 @@ static struct buffer_head *bclean(handle_t *handle, struct super_block *sb, ...@@ -388,30 +388,6 @@ static struct buffer_head *bclean(handle_t *handle, struct super_block *sb,
return bh; return bh;
} }
/*
* If we have fewer than thresh credits, extend by EXT4_MAX_TRANS_DATA.
* If that fails, restart the transaction & regain write access for the
* buffer head which is used for block_bitmap modifications.
*/
static int extend_or_restart_transaction(handle_t *handle, int thresh)
{
int err;
if (ext4_handle_has_enough_credits(handle, thresh))
return 0;
err = ext4_journal_extend(handle, EXT4_MAX_TRANS_DATA);
if (err < 0)
return err;
if (err) {
err = ext4_journal_restart(handle, EXT4_MAX_TRANS_DATA);
if (err)
return err;
}
return 0;
}
/* /*
* set_flexbg_block_bitmap() mark clusters [@first_cluster, @last_cluster] used. * set_flexbg_block_bitmap() mark clusters [@first_cluster, @last_cluster] used.
* *
...@@ -451,8 +427,8 @@ static int set_flexbg_block_bitmap(struct super_block *sb, handle_t *handle, ...@@ -451,8 +427,8 @@ static int set_flexbg_block_bitmap(struct super_block *sb, handle_t *handle,
continue; continue;
} }
err = extend_or_restart_transaction(handle, 1); err = ext4_journal_ensure_credits_batch(handle, 1);
if (err) if (err < 0)
return err; return err;
bh = sb_getblk(sb, flex_gd->groups[group].block_bitmap); bh = sb_getblk(sb, flex_gd->groups[group].block_bitmap);
...@@ -544,8 +520,8 @@ static int setup_new_flex_group_blocks(struct super_block *sb, ...@@ -544,8 +520,8 @@ static int setup_new_flex_group_blocks(struct super_block *sb,
struct buffer_head *gdb; struct buffer_head *gdb;
ext4_debug("update backup group %#04llx\n", block); ext4_debug("update backup group %#04llx\n", block);
err = extend_or_restart_transaction(handle, 1); err = ext4_journal_ensure_credits_batch(handle, 1);
if (err) if (err < 0)
goto out; goto out;
gdb = sb_getblk(sb, block); gdb = sb_getblk(sb, block);
...@@ -602,8 +578,8 @@ static int setup_new_flex_group_blocks(struct super_block *sb, ...@@ -602,8 +578,8 @@ static int setup_new_flex_group_blocks(struct super_block *sb,
/* Initialize block bitmap of the @group */ /* Initialize block bitmap of the @group */
block = group_data[i].block_bitmap; block = group_data[i].block_bitmap;
err = extend_or_restart_transaction(handle, 1); err = ext4_journal_ensure_credits_batch(handle, 1);
if (err) if (err < 0)
goto out; goto out;
bh = bclean(handle, sb, block); bh = bclean(handle, sb, block);
...@@ -631,8 +607,8 @@ static int setup_new_flex_group_blocks(struct super_block *sb, ...@@ -631,8 +607,8 @@ static int setup_new_flex_group_blocks(struct super_block *sb,
/* Initialize inode bitmap of the @group */ /* Initialize inode bitmap of the @group */
block = group_data[i].inode_bitmap; block = group_data[i].inode_bitmap;
err = extend_or_restart_transaction(handle, 1); err = ext4_journal_ensure_credits_batch(handle, 1);
if (err) if (err < 0)
goto out; goto out;
/* Mark unused entries in inode bitmap used */ /* Mark unused entries in inode bitmap used */
bh = bclean(handle, sb, block); bh = bclean(handle, sb, block);
...@@ -1109,10 +1085,8 @@ static void update_backups(struct super_block *sb, sector_t blk_off, char *data, ...@@ -1109,10 +1085,8 @@ static void update_backups(struct super_block *sb, sector_t blk_off, char *data,
ext4_fsblk_t backup_block; ext4_fsblk_t backup_block;
/* Out of journal space, and can't get more - abort - so sad */ /* Out of journal space, and can't get more - abort - so sad */
if (ext4_handle_valid(handle) && err = ext4_journal_ensure_credits_batch(handle, 1);
handle->h_buffer_credits == 0 && if (err < 0)
ext4_journal_extend(handle, EXT4_MAX_TRANS_DATA) &&
(err = ext4_journal_restart(handle, EXT4_MAX_TRANS_DATA)))
break; break;
if (meta_bg == 0) if (meta_bg == 0)
......
...@@ -967,55 +967,6 @@ int __ext4_xattr_set_credits(struct super_block *sb, struct inode *inode, ...@@ -967,55 +967,6 @@ int __ext4_xattr_set_credits(struct super_block *sb, struct inode *inode,
return credits; return credits;
} }
static int ext4_xattr_ensure_credits(handle_t *handle, struct inode *inode,
int credits, struct buffer_head *bh,
bool dirty, bool block_csum)
{
int error;
if (!ext4_handle_valid(handle))
return 0;
if (handle->h_buffer_credits >= credits)
return 0;
error = ext4_journal_extend(handle, credits - handle->h_buffer_credits);
if (!error)
return 0;
if (error < 0) {
ext4_warning(inode->i_sb, "Extend journal (error %d)", error);
return error;
}
if (bh && dirty) {
if (block_csum)
ext4_xattr_block_csum_set(inode, bh);
error = ext4_handle_dirty_metadata(handle, NULL, bh);
if (error) {
ext4_warning(inode->i_sb, "Handle metadata (error %d)",
error);
return error;
}
}
error = ext4_journal_restart(handle, credits);
if (error) {
ext4_warning(inode->i_sb, "Restart journal (error %d)", error);
return error;
}
if (bh) {
error = ext4_journal_get_write_access(handle, bh);
if (error) {
ext4_warning(inode->i_sb,
"Get write access failed (error %d)",
error);
return error;
}
}
return 0;
}
static int ext4_xattr_inode_update_ref(handle_t *handle, struct inode *ea_inode, static int ext4_xattr_inode_update_ref(handle_t *handle, struct inode *ea_inode,
int ref_change) int ref_change)
{ {
...@@ -1149,6 +1100,24 @@ static int ext4_xattr_inode_inc_ref_all(handle_t *handle, struct inode *parent, ...@@ -1149,6 +1100,24 @@ static int ext4_xattr_inode_inc_ref_all(handle_t *handle, struct inode *parent,
return saved_err; return saved_err;
} }
static int ext4_xattr_restart_fn(handle_t *handle, struct inode *inode,
struct buffer_head *bh, bool block_csum, bool dirty)
{
int error;
if (bh && dirty) {
if (block_csum)
ext4_xattr_block_csum_set(inode, bh);
error = ext4_handle_dirty_metadata(handle, NULL, bh);
if (error) {
ext4_warning(inode->i_sb, "Handle metadata (error %d)",
error);
return error;
}
}
return 0;
}
static void static void
ext4_xattr_inode_dec_ref_all(handle_t *handle, struct inode *parent, ext4_xattr_inode_dec_ref_all(handle_t *handle, struct inode *parent,
struct buffer_head *bh, struct buffer_head *bh,
...@@ -1185,13 +1154,23 @@ ext4_xattr_inode_dec_ref_all(handle_t *handle, struct inode *parent, ...@@ -1185,13 +1154,23 @@ ext4_xattr_inode_dec_ref_all(handle_t *handle, struct inode *parent,
continue; continue;
} }
err = ext4_xattr_ensure_credits(handle, parent, credits, bh, err = ext4_journal_ensure_credits_fn(handle, credits, credits,
dirty, block_csum); ext4_xattr_restart_fn(handle, parent, bh, block_csum,
if (err) { dirty));
if (err < 0) {
ext4_warning_inode(ea_inode, "Ensure credits err=%d", ext4_warning_inode(ea_inode, "Ensure credits err=%d",
err); err);
continue; continue;
} }
if (err > 0) {
err = ext4_journal_get_write_access(handle, bh);
if (err) {
ext4_warning_inode(ea_inode,
"Re-get write access err=%d",
err);
continue;
}
}
err = ext4_xattr_inode_dec_ref(handle, ea_inode); err = ext4_xattr_inode_dec_ref(handle, ea_inode);
if (err) { if (err) {
...@@ -2862,11 +2841,8 @@ int ext4_xattr_delete_inode(handle_t *handle, struct inode *inode, ...@@ -2862,11 +2841,8 @@ int ext4_xattr_delete_inode(handle_t *handle, struct inode *inode,
struct inode *ea_inode; struct inode *ea_inode;
int error; int error;
error = ext4_xattr_ensure_credits(handle, inode, extra_credits, error = ext4_journal_ensure_credits(handle, extra_credits);
NULL /* bh */, if (error < 0) {
false /* dirty */,
false /* block_csum */);
if (error) {
EXT4_ERROR_INODE(inode, "ensure credits (error %d)", error); EXT4_ERROR_INODE(inode, "ensure credits (error %d)", error);
goto cleanup; goto cleanup;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment