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 67bb0a2f35e5..f52e5e8049f1 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 663065142b42..0752bcda535f 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 15d5743ccfbb..01743b5446ff 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 |
