Commit 8dd42046 authored by Theodore Ts'o's avatar Theodore Ts'o

jbd2: Remove t_handle_lock from start_this_handle()

This should remove the last exclusive lock from start_this_handle(),
so that we should now be able to start multiple transactions at the
same time on large SMP systems.
Signed-off-by: default avatar"Theodore Ts'o" <tytso@mit.edu>
parent a931da6a
...@@ -1004,7 +1004,8 @@ void jbd2_journal_commit_transaction(journal_t *journal) ...@@ -1004,7 +1004,8 @@ void jbd2_journal_commit_transaction(journal_t *journal)
* File the transaction statistics * File the transaction statistics
*/ */
stats.ts_tid = commit_transaction->t_tid; stats.ts_tid = commit_transaction->t_tid;
stats.run.rs_handle_count = commit_transaction->t_handle_count; stats.run.rs_handle_count =
atomic_read(&commit_transaction->t_handle_count);
trace_jbd2_run_stats(journal->j_fs_dev->bd_dev, trace_jbd2_run_stats(journal->j_fs_dev->bd_dev,
commit_transaction->t_tid, &stats.run); commit_transaction->t_tid, &stats.run);
......
...@@ -57,6 +57,7 @@ jbd2_get_transaction(journal_t *journal, transaction_t *transaction) ...@@ -57,6 +57,7 @@ jbd2_get_transaction(journal_t *journal, transaction_t *transaction)
spin_lock_init(&transaction->t_handle_lock); spin_lock_init(&transaction->t_handle_lock);
atomic_set(&transaction->t_updates, 0); atomic_set(&transaction->t_updates, 0);
atomic_set(&transaction->t_outstanding_credits, 0); atomic_set(&transaction->t_outstanding_credits, 0);
atomic_set(&transaction->t_handle_count, 0);
INIT_LIST_HEAD(&transaction->t_inode_list); INIT_LIST_HEAD(&transaction->t_inode_list);
INIT_LIST_HEAD(&transaction->t_private_list); INIT_LIST_HEAD(&transaction->t_private_list);
...@@ -180,8 +181,8 @@ static int start_this_handle(journal_t *journal, handle_t *handle, ...@@ -180,8 +181,8 @@ static int start_this_handle(journal_t *journal, handle_t *handle,
* buffers requested by this operation, we need to stall pending a log * buffers requested by this operation, we need to stall pending a log
* checkpoint to free some more log space. * checkpoint to free some more log space.
*/ */
spin_lock(&transaction->t_handle_lock); needed = atomic_add_return(nblocks,
needed = atomic_read(&transaction->t_outstanding_credits) + nblocks; &transaction->t_outstanding_credits);
if (needed > journal->j_max_transaction_buffers) { if (needed > journal->j_max_transaction_buffers) {
/* /*
...@@ -192,7 +193,7 @@ static int start_this_handle(journal_t *journal, handle_t *handle, ...@@ -192,7 +193,7 @@ static int start_this_handle(journal_t *journal, handle_t *handle,
DEFINE_WAIT(wait); DEFINE_WAIT(wait);
jbd_debug(2, "Handle %p starting new commit...\n", handle); jbd_debug(2, "Handle %p starting new commit...\n", handle);
spin_unlock(&transaction->t_handle_lock); atomic_sub(nblocks, &transaction->t_outstanding_credits);
prepare_to_wait(&journal->j_wait_transaction_locked, &wait, prepare_to_wait(&journal->j_wait_transaction_locked, &wait,
TASK_UNINTERRUPTIBLE); TASK_UNINTERRUPTIBLE);
__jbd2_log_start_commit(journal, transaction->t_tid); __jbd2_log_start_commit(journal, transaction->t_tid);
...@@ -229,7 +230,7 @@ static int start_this_handle(journal_t *journal, handle_t *handle, ...@@ -229,7 +230,7 @@ static int start_this_handle(journal_t *journal, handle_t *handle,
*/ */
if (__jbd2_log_space_left(journal) < jbd_space_needed(journal)) { if (__jbd2_log_space_left(journal) < jbd_space_needed(journal)) {
jbd_debug(2, "Handle %p waiting for checkpoint...\n", handle); jbd_debug(2, "Handle %p waiting for checkpoint...\n", handle);
spin_unlock(&transaction->t_handle_lock); atomic_sub(nblocks, &transaction->t_outstanding_credits);
read_unlock(&journal->j_state_lock); read_unlock(&journal->j_state_lock);
write_lock(&journal->j_state_lock); write_lock(&journal->j_state_lock);
if (__jbd2_log_space_left(journal) < jbd_space_needed(journal)) if (__jbd2_log_space_left(journal) < jbd_space_needed(journal))
...@@ -239,23 +240,33 @@ static int start_this_handle(journal_t *journal, handle_t *handle, ...@@ -239,23 +240,33 @@ static int start_this_handle(journal_t *journal, handle_t *handle,
} }
/* OK, account for the buffers that this operation expects to /* OK, account for the buffers that this operation expects to
* use and add the handle to the running transaction. */ * use and add the handle to the running transaction.
*
if (time_after(transaction->t_start, ts)) { * In order for t_max_wait to be reliable, it must be
* protected by a lock. But doing so will mean that
* start_this_handle() can not be run in parallel on SMP
* systems, which limits our scalability. So we only enable
* it when debugging is enabled. We may want to use a
* separate flag, eventually, so we can enable this
* independently of debugging.
*/
#ifdef CONFIG_JBD2_DEBUG
if (jbd2_journal_enable_debug &&
time_after(transaction->t_start, ts)) {
ts = jbd2_time_diff(ts, transaction->t_start); ts = jbd2_time_diff(ts, transaction->t_start);
spin_lock(&transaction->t_handle_lock);
if (ts > transaction->t_max_wait) if (ts > transaction->t_max_wait)
transaction->t_max_wait = ts; transaction->t_max_wait = ts;
spin_unlock(&transaction->t_handle_lock);
} }
#endif
handle->h_transaction = transaction; handle->h_transaction = transaction;
atomic_add(nblocks, &transaction->t_outstanding_credits);
atomic_inc(&transaction->t_updates); atomic_inc(&transaction->t_updates);
transaction->t_handle_count++; atomic_inc(&transaction->t_handle_count);
jbd_debug(4, "Handle %p given %d credits (total %d, free %d)\n", jbd_debug(4, "Handle %p given %d credits (total %d, free %d)\n",
handle, nblocks, handle, nblocks,
atomic_read(&transaction->t_outstanding_credits), atomic_read(&transaction->t_outstanding_credits),
__jbd2_log_space_left(journal)); __jbd2_log_space_left(journal));
spin_unlock(&transaction->t_handle_lock);
read_unlock(&journal->j_state_lock); read_unlock(&journal->j_state_lock);
lock_map_acquire(&handle->h_lockdep_map); lock_map_acquire(&handle->h_lockdep_map);
......
...@@ -629,7 +629,7 @@ struct transaction_s ...@@ -629,7 +629,7 @@ struct transaction_s
/* /*
* How many handles used this transaction? [t_handle_lock] * How many handles used this transaction? [t_handle_lock]
*/ */
int t_handle_count; atomic_t t_handle_count;
/* /*
* This transaction is being forced and some process is * This transaction is being forced and some process is
......
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