aboutsummaryrefslogtreecommitdiffstats
path: root/fs/jbd2
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2013-06-04 12:22:15 -0400
committerTheodore Ts'o <tytso@mit.edu>2013-06-04 12:22:15 -0400
commitfe1e8db598b259eafdffbe3dd5fe849cd2ad97d5 (patch)
treea5f7f35d95ab0737457f3ab6ea3a0234c3009df8 /fs/jbd2
parent76c39904561004ac8675f858a290129e439d5168 (diff)
jbd2: fix race in t_outstanding_credits update in jbd2_journal_extend()
jbd2_journal_extend() first checked whether transaction can accept extending handle with more credits and then added credits to t_outstanding_credits. This can race with start_this_handle() adding another handle to a transaction and thus overbooking a transaction. Make jbd2_journal_extend() use atomic_add_return() to close the race. Reviewed-by: Zheng Liu <wenqing.lz@taobao.com> Signed-off-by: Jan Kara <jack@suse.cz> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs/jbd2')
-rw-r--r--fs/jbd2/transaction.c6
1 files changed, 4 insertions, 2 deletions
diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c
index f9cd43190b43..f14288b04042 100644
--- a/fs/jbd2/transaction.c
+++ b/fs/jbd2/transaction.c
@@ -433,11 +433,13 @@ int jbd2_journal_extend(handle_t *handle, int nblocks)
433 } 433 }
434 434
435 spin_lock(&transaction->t_handle_lock); 435 spin_lock(&transaction->t_handle_lock);
436 wanted = atomic_read(&transaction->t_outstanding_credits) + nblocks; 436 wanted = atomic_add_return(nblocks,
437 &transaction->t_outstanding_credits);
437 438
438 if (wanted > journal->j_max_transaction_buffers) { 439 if (wanted > journal->j_max_transaction_buffers) {
439 jbd_debug(3, "denied handle %p %d blocks: " 440 jbd_debug(3, "denied handle %p %d blocks: "
440 "transaction too large\n", handle, nblocks); 441 "transaction too large\n", handle, nblocks);
442 atomic_sub(nblocks, &transaction->t_outstanding_credits);
441 goto unlock; 443 goto unlock;
442 } 444 }
443 445
@@ -445,6 +447,7 @@ int jbd2_journal_extend(handle_t *handle, int nblocks)
445 jbd2_log_space_left(journal)) { 447 jbd2_log_space_left(journal)) {
446 jbd_debug(3, "denied handle %p %d blocks: " 448 jbd_debug(3, "denied handle %p %d blocks: "
447 "insufficient log space\n", handle, nblocks); 449 "insufficient log space\n", handle, nblocks);
450 atomic_sub(nblocks, &transaction->t_outstanding_credits);
448 goto unlock; 451 goto unlock;
449 } 452 }
450 453
@@ -456,7 +459,6 @@ int jbd2_journal_extend(handle_t *handle, int nblocks)
456 459
457 handle->h_buffer_credits += nblocks; 460 handle->h_buffer_credits += nblocks;
458 handle->h_requested_credits += nblocks; 461 handle->h_requested_credits += nblocks;
459 atomic_add(nblocks, &transaction->t_outstanding_credits);
460 result = 0; 462 result = 0;
461 463
462 jbd_debug(3, "extended handle %p by %d\n", handle, nblocks); 464 jbd_debug(3, "extended handle %p by %d\n", handle, nblocks);