diff options
Diffstat (limited to 'fs/jbd2/transaction.c')
-rw-r--r-- | fs/jbd2/transaction.c | 33 |
1 files changed, 22 insertions, 11 deletions
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); |