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

jbd2: Factor out common parts of stopping and restarting a handle

jbd2__journal_restart() has quite some code that is common with
jbd2_journal_stop(). Factor this functionality into stop_this_handle()
helper and use it from both functions. Note that this also drops
t_handle_lock protection from jbd2__journal_restart() as
jbd2_journal_stop() does the same thing without it.
Signed-off-by: default avatarJan Kara <jack@suse.cz>
Link: https://lore.kernel.org/r/20191105164437.32602-17-jack@suse.czSigned-off-by: default avatarTheodore Ts'o <tytso@mit.edu>
parent 5559b2d8
...@@ -512,12 +512,17 @@ handle_t *jbd2_journal_start(journal_t *journal, int nblocks) ...@@ -512,12 +512,17 @@ handle_t *jbd2_journal_start(journal_t *journal, int nblocks)
} }
EXPORT_SYMBOL(jbd2_journal_start); EXPORT_SYMBOL(jbd2_journal_start);
void jbd2_journal_free_reserved(handle_t *handle) static void __jbd2_journal_unreserve_handle(handle_t *handle)
{ {
journal_t *journal = handle->h_journal; journal_t *journal = handle->h_journal;
WARN_ON(!handle->h_reserved); WARN_ON(!handle->h_reserved);
sub_reserved_credits(journal, handle->h_buffer_credits); sub_reserved_credits(journal, handle->h_buffer_credits);
}
void jbd2_journal_free_reserved(handle_t *handle)
{
__jbd2_journal_unreserve_handle(handle);
jbd2_free_handle(handle); jbd2_free_handle(handle);
} }
EXPORT_SYMBOL(jbd2_journal_free_reserved); EXPORT_SYMBOL(jbd2_journal_free_reserved);
...@@ -655,6 +660,28 @@ int jbd2_journal_extend(handle_t *handle, int nblocks) ...@@ -655,6 +660,28 @@ int jbd2_journal_extend(handle_t *handle, int nblocks)
return result; return result;
} }
static void stop_this_handle(handle_t *handle)
{
transaction_t *transaction = handle->h_transaction;
journal_t *journal = transaction->t_journal;
J_ASSERT(journal_current_handle() == handle);
J_ASSERT(atomic_read(&transaction->t_updates) > 0);
current->journal_info = NULL;
atomic_sub(handle->h_buffer_credits,
&transaction->t_outstanding_credits);
if (handle->h_rsv_handle)
__jbd2_journal_unreserve_handle(handle->h_rsv_handle);
if (atomic_dec_and_test(&transaction->t_updates))
wake_up(&journal->j_wait_updates);
rwsem_release(&journal->j_trans_commit_map, 1, _THIS_IP_);
/*
* Scope of the GFP_NOFS context is over here and so we can restore the
* original alloc context.
*/
memalloc_nofs_restore(handle->saved_alloc_context);
}
/** /**
* int jbd2_journal_restart() - restart a handle . * int jbd2_journal_restart() - restart a handle .
...@@ -677,52 +704,34 @@ int jbd2__journal_restart(handle_t *handle, int nblocks, gfp_t gfp_mask) ...@@ -677,52 +704,34 @@ int jbd2__journal_restart(handle_t *handle, int nblocks, gfp_t gfp_mask)
transaction_t *transaction = handle->h_transaction; transaction_t *transaction = handle->h_transaction;
journal_t *journal; journal_t *journal;
tid_t tid; tid_t tid;
int need_to_start, ret; int need_to_start;
/* If we've had an abort of any type, don't even think about /* If we've had an abort of any type, don't even think about
* actually doing the restart! */ * actually doing the restart! */
if (is_handle_aborted(handle)) if (is_handle_aborted(handle))
return 0; return 0;
journal = transaction->t_journal; journal = transaction->t_journal;
tid = transaction->t_tid;
/* /*
* First unlink the handle from its current transaction, and start the * First unlink the handle from its current transaction, and start the
* commit on that. * commit on that.
*/ */
J_ASSERT(atomic_read(&transaction->t_updates) > 0); jbd_debug(2, "restarting handle %p\n", handle);
J_ASSERT(journal_current_handle() == handle); stop_this_handle(handle);
read_lock(&journal->j_state_lock);
spin_lock(&transaction->t_handle_lock);
atomic_sub(handle->h_buffer_credits,
&transaction->t_outstanding_credits);
if (handle->h_rsv_handle) {
sub_reserved_credits(journal,
handle->h_rsv_handle->h_buffer_credits);
}
if (atomic_dec_and_test(&transaction->t_updates))
wake_up(&journal->j_wait_updates);
tid = transaction->t_tid;
spin_unlock(&transaction->t_handle_lock);
handle->h_transaction = NULL; handle->h_transaction = NULL;
current->journal_info = NULL;
jbd_debug(2, "restarting handle %p\n", handle); /*
* TODO: If we use READ_ONCE / WRITE_ONCE for j_commit_request we can
* get rid of pointless j_state_lock traffic like this.
*/
read_lock(&journal->j_state_lock);
need_to_start = !tid_geq(journal->j_commit_request, tid); need_to_start = !tid_geq(journal->j_commit_request, tid);
read_unlock(&journal->j_state_lock); read_unlock(&journal->j_state_lock);
if (need_to_start) if (need_to_start)
jbd2_log_start_commit(journal, tid); jbd2_log_start_commit(journal, tid);
rwsem_release(&journal->j_trans_commit_map, 1, _THIS_IP_);
handle->h_buffer_credits = nblocks; handle->h_buffer_credits = nblocks;
/* return start_this_handle(journal, handle, gfp_mask);
* Restore the original nofs context because the journal restart
* is basically the same thing as journal stop and start.
* start_this_handle will start a new nofs context.
*/
memalloc_nofs_restore(handle->saved_alloc_context);
ret = start_this_handle(journal, handle, gfp_mask);
return ret;
} }
EXPORT_SYMBOL(jbd2__journal_restart); EXPORT_SYMBOL(jbd2__journal_restart);
...@@ -1718,16 +1727,12 @@ int jbd2_journal_stop(handle_t *handle) ...@@ -1718,16 +1727,12 @@ int jbd2_journal_stop(handle_t *handle)
* Handle is already detached from the transaction so there is * Handle is already detached from the transaction so there is
* nothing to do other than free the handle. * nothing to do other than free the handle.
*/ */
if (handle->h_rsv_handle) memalloc_nofs_restore(handle->saved_alloc_context);
jbd2_free_handle(handle->h_rsv_handle);
goto free_and_exit; goto free_and_exit;
} }
journal = transaction->t_journal; journal = transaction->t_journal;
tid = transaction->t_tid; tid = transaction->t_tid;
J_ASSERT(journal_current_handle() == handle);
J_ASSERT(atomic_read(&transaction->t_updates) > 0);
if (is_handle_aborted(handle)) if (is_handle_aborted(handle))
err = -EIO; err = -EIO;
...@@ -1797,9 +1802,6 @@ int jbd2_journal_stop(handle_t *handle) ...@@ -1797,9 +1802,6 @@ int jbd2_journal_stop(handle_t *handle)
if (handle->h_sync) if (handle->h_sync)
transaction->t_synchronous_commit = 1; transaction->t_synchronous_commit = 1;
current->journal_info = NULL;
atomic_sub(handle->h_buffer_credits,
&transaction->t_outstanding_credits);
/* /*
* If the handle is marked SYNC, we need to set another commit * If the handle is marked SYNC, we need to set another commit
...@@ -1826,27 +1828,19 @@ int jbd2_journal_stop(handle_t *handle) ...@@ -1826,27 +1828,19 @@ int jbd2_journal_stop(handle_t *handle)
} }
/* /*
* Once we drop t_updates, if it goes to zero the transaction * Once stop_this_handle() drops t_updates, the transaction could start
* could start committing on us and eventually disappear. So * committing on us and eventually disappear. So we must not
* once we do this, we must not dereference transaction * dereference transaction pointer again after calling
* pointer again. * stop_this_handle().
*/ */
if (atomic_dec_and_test(&transaction->t_updates)) stop_this_handle(handle);
wake_up(&journal->j_wait_updates);
rwsem_release(&journal->j_trans_commit_map, 1, _THIS_IP_);
if (wait_for_commit) if (wait_for_commit)
err = jbd2_log_wait_commit(journal, tid); err = jbd2_log_wait_commit(journal, tid);
if (handle->h_rsv_handle)
jbd2_journal_free_reserved(handle->h_rsv_handle);
free_and_exit: free_and_exit:
/* if (handle->h_rsv_handle)
* Scope of the GFP_NOFS context is over here and so we can restore the jbd2_free_handle(handle->h_rsv_handle);
* original alloc context.
*/
memalloc_nofs_restore(handle->saved_alloc_context);
jbd2_free_handle(handle); jbd2_free_handle(handle);
return err; return err;
} }
......
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