diff options
Diffstat (limited to 'fs/jbd/checkpoint.c')
-rw-r--r-- | fs/jbd/checkpoint.c | 27 |
1 files changed, 15 insertions, 12 deletions
diff --git a/fs/jbd/checkpoint.c b/fs/jbd/checkpoint.c index dea7503b47e8..61655a37c731 100644 --- a/fs/jbd/checkpoint.c +++ b/fs/jbd/checkpoint.c | |||
@@ -96,10 +96,14 @@ static int __try_to_free_cp_buf(struct journal_head *jh) | |||
96 | 96 | ||
97 | if (jh->b_jlist == BJ_None && !buffer_locked(bh) && | 97 | if (jh->b_jlist == BJ_None && !buffer_locked(bh) && |
98 | !buffer_dirty(bh) && !buffer_write_io_error(bh)) { | 98 | !buffer_dirty(bh) && !buffer_write_io_error(bh)) { |
99 | /* | ||
100 | * Get our reference so that bh cannot be freed before | ||
101 | * we unlock it | ||
102 | */ | ||
103 | get_bh(bh); | ||
99 | JBUFFER_TRACE(jh, "remove from checkpoint list"); | 104 | JBUFFER_TRACE(jh, "remove from checkpoint list"); |
100 | ret = __journal_remove_checkpoint(jh) + 1; | 105 | ret = __journal_remove_checkpoint(jh) + 1; |
101 | jbd_unlock_bh_state(bh); | 106 | jbd_unlock_bh_state(bh); |
102 | journal_remove_journal_head(bh); | ||
103 | BUFFER_TRACE(bh, "release"); | 107 | BUFFER_TRACE(bh, "release"); |
104 | __brelse(bh); | 108 | __brelse(bh); |
105 | } else { | 109 | } else { |
@@ -221,8 +225,8 @@ restart: | |||
221 | spin_lock(&journal->j_list_lock); | 225 | spin_lock(&journal->j_list_lock); |
222 | goto restart; | 226 | goto restart; |
223 | } | 227 | } |
228 | get_bh(bh); | ||
224 | if (buffer_locked(bh)) { | 229 | if (buffer_locked(bh)) { |
225 | get_bh(bh); | ||
226 | spin_unlock(&journal->j_list_lock); | 230 | spin_unlock(&journal->j_list_lock); |
227 | jbd_unlock_bh_state(bh); | 231 | jbd_unlock_bh_state(bh); |
228 | wait_on_buffer(bh); | 232 | wait_on_buffer(bh); |
@@ -241,7 +245,6 @@ restart: | |||
241 | */ | 245 | */ |
242 | released = __journal_remove_checkpoint(jh); | 246 | released = __journal_remove_checkpoint(jh); |
243 | jbd_unlock_bh_state(bh); | 247 | jbd_unlock_bh_state(bh); |
244 | journal_remove_journal_head(bh); | ||
245 | __brelse(bh); | 248 | __brelse(bh); |
246 | } | 249 | } |
247 | 250 | ||
@@ -305,12 +308,12 @@ static int __process_buffer(journal_t *journal, struct journal_head *jh, | |||
305 | ret = 1; | 308 | ret = 1; |
306 | if (unlikely(buffer_write_io_error(bh))) | 309 | if (unlikely(buffer_write_io_error(bh))) |
307 | ret = -EIO; | 310 | ret = -EIO; |
311 | get_bh(bh); | ||
308 | J_ASSERT_JH(jh, !buffer_jbddirty(bh)); | 312 | J_ASSERT_JH(jh, !buffer_jbddirty(bh)); |
309 | BUFFER_TRACE(bh, "remove from checkpoint"); | 313 | BUFFER_TRACE(bh, "remove from checkpoint"); |
310 | __journal_remove_checkpoint(jh); | 314 | __journal_remove_checkpoint(jh); |
311 | spin_unlock(&journal->j_list_lock); | 315 | spin_unlock(&journal->j_list_lock); |
312 | jbd_unlock_bh_state(bh); | 316 | jbd_unlock_bh_state(bh); |
313 | journal_remove_journal_head(bh); | ||
314 | __brelse(bh); | 317 | __brelse(bh); |
315 | } else { | 318 | } else { |
316 | /* | 319 | /* |
@@ -526,9 +529,9 @@ int cleanup_journal_tail(journal_t *journal) | |||
526 | /* | 529 | /* |
527 | * journal_clean_one_cp_list | 530 | * journal_clean_one_cp_list |
528 | * | 531 | * |
529 | * Find all the written-back checkpoint buffers in the given list and release them. | 532 | * Find all the written-back checkpoint buffers in the given list and release |
533 | * them. | ||
530 | * | 534 | * |
531 | * Called with the journal locked. | ||
532 | * Called with j_list_lock held. | 535 | * Called with j_list_lock held. |
533 | * Returns number of bufers reaped (for debug) | 536 | * Returns number of bufers reaped (for debug) |
534 | */ | 537 | */ |
@@ -635,8 +638,8 @@ out: | |||
635 | * checkpoint lists. | 638 | * checkpoint lists. |
636 | * | 639 | * |
637 | * The function returns 1 if it frees the transaction, 0 otherwise. | 640 | * The function returns 1 if it frees the transaction, 0 otherwise. |
641 | * The function can free jh and bh. | ||
638 | * | 642 | * |
639 | * This function is called with the journal locked. | ||
640 | * This function is called with j_list_lock held. | 643 | * This function is called with j_list_lock held. |
641 | * This function is called with jbd_lock_bh_state(jh2bh(jh)) | 644 | * This function is called with jbd_lock_bh_state(jh2bh(jh)) |
642 | */ | 645 | */ |
@@ -655,13 +658,14 @@ int __journal_remove_checkpoint(struct journal_head *jh) | |||
655 | } | 658 | } |
656 | journal = transaction->t_journal; | 659 | journal = transaction->t_journal; |
657 | 660 | ||
661 | JBUFFER_TRACE(jh, "removing from transaction"); | ||
658 | __buffer_unlink(jh); | 662 | __buffer_unlink(jh); |
659 | jh->b_cp_transaction = NULL; | 663 | jh->b_cp_transaction = NULL; |
664 | journal_put_journal_head(jh); | ||
660 | 665 | ||
661 | if (transaction->t_checkpoint_list != NULL || | 666 | if (transaction->t_checkpoint_list != NULL || |
662 | transaction->t_checkpoint_io_list != NULL) | 667 | transaction->t_checkpoint_io_list != NULL) |
663 | goto out; | 668 | goto out; |
664 | JBUFFER_TRACE(jh, "transaction has no more buffers"); | ||
665 | 669 | ||
666 | /* | 670 | /* |
667 | * There is one special case to worry about: if we have just pulled the | 671 | * There is one special case to worry about: if we have just pulled the |
@@ -672,10 +676,8 @@ int __journal_remove_checkpoint(struct journal_head *jh) | |||
672 | * The locking here around t_state is a bit sleazy. | 676 | * The locking here around t_state is a bit sleazy. |
673 | * See the comment at the end of journal_commit_transaction(). | 677 | * See the comment at the end of journal_commit_transaction(). |
674 | */ | 678 | */ |
675 | if (transaction->t_state != T_FINISHED) { | 679 | if (transaction->t_state != T_FINISHED) |
676 | JBUFFER_TRACE(jh, "belongs to running/committing transaction"); | ||
677 | goto out; | 680 | goto out; |
678 | } | ||
679 | 681 | ||
680 | /* OK, that was the last buffer for the transaction: we can now | 682 | /* OK, that was the last buffer for the transaction: we can now |
681 | safely remove this transaction from the log */ | 683 | safely remove this transaction from the log */ |
@@ -687,7 +689,6 @@ int __journal_remove_checkpoint(struct journal_head *jh) | |||
687 | wake_up(&journal->j_wait_logspace); | 689 | wake_up(&journal->j_wait_logspace); |
688 | ret = 1; | 690 | ret = 1; |
689 | out: | 691 | out: |
690 | JBUFFER_TRACE(jh, "exit"); | ||
691 | return ret; | 692 | return ret; |
692 | } | 693 | } |
693 | 694 | ||
@@ -706,6 +707,8 @@ void __journal_insert_checkpoint(struct journal_head *jh, | |||
706 | J_ASSERT_JH(jh, buffer_dirty(jh2bh(jh)) || buffer_jbddirty(jh2bh(jh))); | 707 | J_ASSERT_JH(jh, buffer_dirty(jh2bh(jh)) || buffer_jbddirty(jh2bh(jh))); |
707 | J_ASSERT_JH(jh, jh->b_cp_transaction == NULL); | 708 | J_ASSERT_JH(jh, jh->b_cp_transaction == NULL); |
708 | 709 | ||
710 | /* Get reference for checkpointing transaction */ | ||
711 | journal_grab_journal_head(jh2bh(jh)); | ||
709 | jh->b_cp_transaction = transaction; | 712 | jh->b_cp_transaction = transaction; |
710 | 713 | ||
711 | if (!transaction->t_checkpoint_list) { | 714 | if (!transaction->t_checkpoint_list) { |