diff options
author | Theodore Ts'o <tytso@mit.edu> | 2010-08-03 21:38:29 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2010-08-03 21:38:29 -0400 |
commit | 8dd420466c7bfc459fa04680bd5690bfc41a4553 (patch) | |
tree | 6004eaaa7266979397a9d87e30066fc91d3650c3 | |
parent | a931da6ac9331a6c80dd91c199105806f2336188 (diff) |
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: "Theodore Ts'o" <tytso@mit.edu>
-rw-r--r-- | fs/jbd2/commit.c | 3 | ||||
-rw-r--r-- | fs/jbd2/transaction.c | 33 | ||||
-rw-r--r-- | include/linux/jbd2.h | 2 |
3 files changed, 25 insertions, 13 deletions
diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c index 67bb0a2f35e..f52e5e8049f 100644 --- a/fs/jbd2/commit.c +++ b/fs/jbd2/commit.c | |||
@@ -1004,7 +1004,8 @@ restart_loop: | |||
1004 | * File the transaction statistics | 1004 | * File the transaction statistics |
1005 | */ | 1005 | */ |
1006 | stats.ts_tid = commit_transaction->t_tid; | 1006 | stats.ts_tid = commit_transaction->t_tid; |
1007 | stats.run.rs_handle_count = commit_transaction->t_handle_count; | 1007 | stats.run.rs_handle_count = |
1008 | atomic_read(&commit_transaction->t_handle_count); | ||
1008 | trace_jbd2_run_stats(journal->j_fs_dev->bd_dev, | 1009 | trace_jbd2_run_stats(journal->j_fs_dev->bd_dev, |
1009 | commit_transaction->t_tid, &stats.run); | 1010 | commit_transaction->t_tid, &stats.run); |
1010 | 1011 | ||
diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index 663065142b4..0752bcda535 100644 --- a/fs/jbd2/transaction.c +++ b/fs/jbd2/transaction.c | |||
@@ -57,6 +57,7 @@ jbd2_get_transaction(journal_t *journal, transaction_t *transaction) | |||
57 | spin_lock_init(&transaction->t_handle_lock); | 57 | spin_lock_init(&transaction->t_handle_lock); |
58 | atomic_set(&transaction->t_updates, 0); | 58 | atomic_set(&transaction->t_updates, 0); |
59 | atomic_set(&transaction->t_outstanding_credits, 0); | 59 | atomic_set(&transaction->t_outstanding_credits, 0); |
60 | atomic_set(&transaction->t_handle_count, 0); | ||
60 | INIT_LIST_HEAD(&transaction->t_inode_list); | 61 | INIT_LIST_HEAD(&transaction->t_inode_list); |
61 | INIT_LIST_HEAD(&transaction->t_private_list); | 62 | INIT_LIST_HEAD(&transaction->t_private_list); |
62 | 63 | ||
@@ -180,8 +181,8 @@ repeat: | |||
180 | * buffers requested by this operation, we need to stall pending a log | 181 | * buffers requested by this operation, we need to stall pending a log |
181 | * checkpoint to free some more log space. | 182 | * checkpoint to free some more log space. |
182 | */ | 183 | */ |
183 | spin_lock(&transaction->t_handle_lock); | 184 | needed = atomic_add_return(nblocks, |
184 | needed = atomic_read(&transaction->t_outstanding_credits) + nblocks; | 185 | &transaction->t_outstanding_credits); |
185 | 186 | ||
186 | if (needed > journal->j_max_transaction_buffers) { | 187 | if (needed > journal->j_max_transaction_buffers) { |
187 | /* | 188 | /* |
@@ -192,7 +193,7 @@ repeat: | |||
192 | DEFINE_WAIT(wait); | 193 | DEFINE_WAIT(wait); |
193 | 194 | ||
194 | jbd_debug(2, "Handle %p starting new commit...\n", handle); | 195 | jbd_debug(2, "Handle %p starting new commit...\n", handle); |
195 | spin_unlock(&transaction->t_handle_lock); | 196 | atomic_sub(nblocks, &transaction->t_outstanding_credits); |
196 | prepare_to_wait(&journal->j_wait_transaction_locked, &wait, | 197 | prepare_to_wait(&journal->j_wait_transaction_locked, &wait, |
197 | TASK_UNINTERRUPTIBLE); | 198 | TASK_UNINTERRUPTIBLE); |
198 | __jbd2_log_start_commit(journal, transaction->t_tid); | 199 | __jbd2_log_start_commit(journal, transaction->t_tid); |
@@ -229,7 +230,7 @@ repeat: | |||
229 | */ | 230 | */ |
230 | if (__jbd2_log_space_left(journal) < jbd_space_needed(journal)) { | 231 | if (__jbd2_log_space_left(journal) < jbd_space_needed(journal)) { |
231 | jbd_debug(2, "Handle %p waiting for checkpoint...\n", handle); | 232 | jbd_debug(2, "Handle %p waiting for checkpoint...\n", handle); |
232 | spin_unlock(&transaction->t_handle_lock); | 233 | atomic_sub(nblocks, &transaction->t_outstanding_credits); |
233 | read_unlock(&journal->j_state_lock); | 234 | read_unlock(&journal->j_state_lock); |
234 | write_lock(&journal->j_state_lock); | 235 | write_lock(&journal->j_state_lock); |
235 | if (__jbd2_log_space_left(journal) < jbd_space_needed(journal)) | 236 | if (__jbd2_log_space_left(journal) < jbd_space_needed(journal)) |
@@ -239,23 +240,33 @@ repeat: | |||
239 | } | 240 | } |
240 | 241 | ||
241 | /* OK, account for the buffers that this operation expects to | 242 | /* OK, account for the buffers that this operation expects to |
242 | * use and add the handle to the running transaction. */ | 243 | * use and add the handle to the running transaction. |
243 | 244 | * | |
244 | if (time_after(transaction->t_start, ts)) { | 245 | * In order for t_max_wait to be reliable, it must be |
246 | * protected by a lock. But doing so will mean that | ||
247 | * start_this_handle() can not be run in parallel on SMP | ||
248 | * systems, which limits our scalability. So we only enable | ||
249 | * it when debugging is enabled. We may want to use a | ||
250 | * separate flag, eventually, so we can enable this | ||
251 | * independently of debugging. | ||
252 | */ | ||
253 | #ifdef CONFIG_JBD2_DEBUG | ||
254 | if (jbd2_journal_enable_debug && | ||
255 | time_after(transaction->t_start, ts)) { | ||
245 | ts = jbd2_time_diff(ts, transaction->t_start); | 256 | ts = jbd2_time_diff(ts, transaction->t_start); |
257 | spin_lock(&transaction->t_handle_lock); | ||
246 | if (ts > transaction->t_max_wait) | 258 | if (ts > transaction->t_max_wait) |
247 | transaction->t_max_wait = ts; | 259 | transaction->t_max_wait = ts; |
260 | spin_unlock(&transaction->t_handle_lock); | ||
248 | } | 261 | } |
249 | 262 | #endif | |
250 | handle->h_transaction = transaction; | 263 | handle->h_transaction = transaction; |
251 | atomic_add(nblocks, &transaction->t_outstanding_credits); | ||
252 | atomic_inc(&transaction->t_updates); | 264 | atomic_inc(&transaction->t_updates); |
253 | transaction->t_handle_count++; | 265 | atomic_inc(&transaction->t_handle_count); |
254 | jbd_debug(4, "Handle %p given %d credits (total %d, free %d)\n", | 266 | jbd_debug(4, "Handle %p given %d credits (total %d, free %d)\n", |
255 | handle, nblocks, | 267 | handle, nblocks, |
256 | atomic_read(&transaction->t_outstanding_credits), | 268 | atomic_read(&transaction->t_outstanding_credits), |
257 | __jbd2_log_space_left(journal)); | 269 | __jbd2_log_space_left(journal)); |
258 | spin_unlock(&transaction->t_handle_lock); | ||
259 | read_unlock(&journal->j_state_lock); | 270 | read_unlock(&journal->j_state_lock); |
260 | 271 | ||
261 | lock_map_acquire(&handle->h_lockdep_map); | 272 | lock_map_acquire(&handle->h_lockdep_map); |
diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h index 15d5743ccfb..01743b5446f 100644 --- a/include/linux/jbd2.h +++ b/include/linux/jbd2.h | |||
@@ -629,7 +629,7 @@ struct transaction_s | |||
629 | /* | 629 | /* |
630 | * How many handles used this transaction? [t_handle_lock] | 630 | * How many handles used this transaction? [t_handle_lock] |
631 | */ | 631 | */ |
632 | int t_handle_count; | 632 | atomic_t t_handle_count; |
633 | 633 | ||
634 | /* | 634 | /* |
635 | * This transaction is being forced and some process is | 635 | * This transaction is being forced and some process is |