diff options
Diffstat (limited to 'fs/jbd/checkpoint.c')
-rw-r--r-- | fs/jbd/checkpoint.c | 37 |
1 files changed, 24 insertions, 13 deletions
diff --git a/fs/jbd/checkpoint.c b/fs/jbd/checkpoint.c index e4b87bc1fa5..f94fc48ff3a 100644 --- a/fs/jbd/checkpoint.c +++ b/fs/jbd/checkpoint.c | |||
@@ -22,6 +22,8 @@ | |||
22 | #include <linux/jbd.h> | 22 | #include <linux/jbd.h> |
23 | #include <linux/errno.h> | 23 | #include <linux/errno.h> |
24 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
25 | #include <linux/blkdev.h> | ||
26 | #include <trace/events/jbd.h> | ||
25 | 27 | ||
26 | /* | 28 | /* |
27 | * Unlink a buffer from a transaction checkpoint list. | 29 | * Unlink a buffer from a transaction checkpoint list. |
@@ -95,10 +97,14 @@ static int __try_to_free_cp_buf(struct journal_head *jh) | |||
95 | 97 | ||
96 | if (jh->b_jlist == BJ_None && !buffer_locked(bh) && | 98 | if (jh->b_jlist == BJ_None && !buffer_locked(bh) && |
97 | !buffer_dirty(bh) && !buffer_write_io_error(bh)) { | 99 | !buffer_dirty(bh) && !buffer_write_io_error(bh)) { |
100 | /* | ||
101 | * Get our reference so that bh cannot be freed before | ||
102 | * we unlock it | ||
103 | */ | ||
104 | get_bh(bh); | ||
98 | JBUFFER_TRACE(jh, "remove from checkpoint list"); | 105 | JBUFFER_TRACE(jh, "remove from checkpoint list"); |
99 | ret = __journal_remove_checkpoint(jh) + 1; | 106 | ret = __journal_remove_checkpoint(jh) + 1; |
100 | jbd_unlock_bh_state(bh); | 107 | jbd_unlock_bh_state(bh); |
101 | journal_remove_journal_head(bh); | ||
102 | BUFFER_TRACE(bh, "release"); | 108 | BUFFER_TRACE(bh, "release"); |
103 | __brelse(bh); | 109 | __brelse(bh); |
104 | } else { | 110 | } else { |
@@ -220,8 +226,8 @@ restart: | |||
220 | spin_lock(&journal->j_list_lock); | 226 | spin_lock(&journal->j_list_lock); |
221 | goto restart; | 227 | goto restart; |
222 | } | 228 | } |
229 | get_bh(bh); | ||
223 | if (buffer_locked(bh)) { | 230 | if (buffer_locked(bh)) { |
224 | get_bh(bh); | ||
225 | spin_unlock(&journal->j_list_lock); | 231 | spin_unlock(&journal->j_list_lock); |
226 | jbd_unlock_bh_state(bh); | 232 | jbd_unlock_bh_state(bh); |
227 | wait_on_buffer(bh); | 233 | wait_on_buffer(bh); |
@@ -240,7 +246,6 @@ restart: | |||
240 | */ | 246 | */ |
241 | released = __journal_remove_checkpoint(jh); | 247 | released = __journal_remove_checkpoint(jh); |
242 | jbd_unlock_bh_state(bh); | 248 | jbd_unlock_bh_state(bh); |
243 | journal_remove_journal_head(bh); | ||
244 | __brelse(bh); | 249 | __brelse(bh); |
245 | } | 250 | } |
246 | 251 | ||
@@ -253,9 +258,12 @@ static void | |||
253 | __flush_batch(journal_t *journal, struct buffer_head **bhs, int *batch_count) | 258 | __flush_batch(journal_t *journal, struct buffer_head **bhs, int *batch_count) |
254 | { | 259 | { |
255 | int i; | 260 | int i; |
261 | struct blk_plug plug; | ||
256 | 262 | ||
263 | blk_start_plug(&plug); | ||
257 | for (i = 0; i < *batch_count; i++) | 264 | for (i = 0; i < *batch_count; i++) |
258 | write_dirty_buffer(bhs[i], WRITE); | 265 | write_dirty_buffer(bhs[i], WRITE_SYNC); |
266 | blk_finish_plug(&plug); | ||
259 | 267 | ||
260 | for (i = 0; i < *batch_count; i++) { | 268 | for (i = 0; i < *batch_count; i++) { |
261 | struct buffer_head *bh = bhs[i]; | 269 | struct buffer_head *bh = bhs[i]; |
@@ -304,12 +312,12 @@ static int __process_buffer(journal_t *journal, struct journal_head *jh, | |||
304 | ret = 1; | 312 | ret = 1; |
305 | if (unlikely(buffer_write_io_error(bh))) | 313 | if (unlikely(buffer_write_io_error(bh))) |
306 | ret = -EIO; | 314 | ret = -EIO; |
315 | get_bh(bh); | ||
307 | J_ASSERT_JH(jh, !buffer_jbddirty(bh)); | 316 | J_ASSERT_JH(jh, !buffer_jbddirty(bh)); |
308 | BUFFER_TRACE(bh, "remove from checkpoint"); | 317 | BUFFER_TRACE(bh, "remove from checkpoint"); |
309 | __journal_remove_checkpoint(jh); | 318 | __journal_remove_checkpoint(jh); |
310 | spin_unlock(&journal->j_list_lock); | 319 | spin_unlock(&journal->j_list_lock); |
311 | jbd_unlock_bh_state(bh); | 320 | jbd_unlock_bh_state(bh); |
312 | journal_remove_journal_head(bh); | ||
313 | __brelse(bh); | 321 | __brelse(bh); |
314 | } else { | 322 | } else { |
315 | /* | 323 | /* |
@@ -358,6 +366,7 @@ int log_do_checkpoint(journal_t *journal) | |||
358 | * journal straight away. | 366 | * journal straight away. |
359 | */ | 367 | */ |
360 | result = cleanup_journal_tail(journal); | 368 | result = cleanup_journal_tail(journal); |
369 | trace_jbd_checkpoint(journal, result); | ||
361 | jbd_debug(1, "cleanup_journal_tail returned %d\n", result); | 370 | jbd_debug(1, "cleanup_journal_tail returned %d\n", result); |
362 | if (result <= 0) | 371 | if (result <= 0) |
363 | return result; | 372 | return result; |
@@ -503,6 +512,7 @@ int cleanup_journal_tail(journal_t *journal) | |||
503 | if (blocknr < journal->j_tail) | 512 | if (blocknr < journal->j_tail) |
504 | freed = freed + journal->j_last - journal->j_first; | 513 | freed = freed + journal->j_last - journal->j_first; |
505 | 514 | ||
515 | trace_jbd_cleanup_journal_tail(journal, first_tid, blocknr, freed); | ||
506 | jbd_debug(1, | 516 | jbd_debug(1, |
507 | "Cleaning journal tail from %d to %d (offset %u), " | 517 | "Cleaning journal tail from %d to %d (offset %u), " |
508 | "freeing %u\n", | 518 | "freeing %u\n", |
@@ -523,9 +533,9 @@ int cleanup_journal_tail(journal_t *journal) | |||
523 | /* | 533 | /* |
524 | * journal_clean_one_cp_list | 534 | * journal_clean_one_cp_list |
525 | * | 535 | * |
526 | * Find all the written-back checkpoint buffers in the given list and release them. | 536 | * Find all the written-back checkpoint buffers in the given list and release |
537 | * them. | ||
527 | * | 538 | * |
528 | * Called with the journal locked. | ||
529 | * Called with j_list_lock held. | 539 | * Called with j_list_lock held. |
530 | * Returns number of bufers reaped (for debug) | 540 | * Returns number of bufers reaped (for debug) |
531 | */ | 541 | */ |
@@ -632,8 +642,8 @@ out: | |||
632 | * checkpoint lists. | 642 | * checkpoint lists. |
633 | * | 643 | * |
634 | * The function returns 1 if it frees the transaction, 0 otherwise. | 644 | * The function returns 1 if it frees the transaction, 0 otherwise. |
645 | * The function can free jh and bh. | ||
635 | * | 646 | * |
636 | * This function is called with the journal locked. | ||
637 | * This function is called with j_list_lock held. | 647 | * This function is called with j_list_lock held. |
638 | * This function is called with jbd_lock_bh_state(jh2bh(jh)) | 648 | * This function is called with jbd_lock_bh_state(jh2bh(jh)) |
639 | */ | 649 | */ |
@@ -652,13 +662,14 @@ int __journal_remove_checkpoint(struct journal_head *jh) | |||
652 | } | 662 | } |
653 | journal = transaction->t_journal; | 663 | journal = transaction->t_journal; |
654 | 664 | ||
665 | JBUFFER_TRACE(jh, "removing from transaction"); | ||
655 | __buffer_unlink(jh); | 666 | __buffer_unlink(jh); |
656 | jh->b_cp_transaction = NULL; | 667 | jh->b_cp_transaction = NULL; |
668 | journal_put_journal_head(jh); | ||
657 | 669 | ||
658 | if (transaction->t_checkpoint_list != NULL || | 670 | if (transaction->t_checkpoint_list != NULL || |
659 | transaction->t_checkpoint_io_list != NULL) | 671 | transaction->t_checkpoint_io_list != NULL) |
660 | goto out; | 672 | goto out; |
661 | JBUFFER_TRACE(jh, "transaction has no more buffers"); | ||
662 | 673 | ||
663 | /* | 674 | /* |
664 | * There is one special case to worry about: if we have just pulled the | 675 | * There is one special case to worry about: if we have just pulled the |
@@ -669,10 +680,8 @@ int __journal_remove_checkpoint(struct journal_head *jh) | |||
669 | * The locking here around t_state is a bit sleazy. | 680 | * The locking here around t_state is a bit sleazy. |
670 | * See the comment at the end of journal_commit_transaction(). | 681 | * See the comment at the end of journal_commit_transaction(). |
671 | */ | 682 | */ |
672 | if (transaction->t_state != T_FINISHED) { | 683 | if (transaction->t_state != T_FINISHED) |
673 | JBUFFER_TRACE(jh, "belongs to running/committing transaction"); | ||
674 | goto out; | 684 | goto out; |
675 | } | ||
676 | 685 | ||
677 | /* OK, that was the last buffer for the transaction: we can now | 686 | /* OK, that was the last buffer for the transaction: we can now |
678 | safely remove this transaction from the log */ | 687 | safely remove this transaction from the log */ |
@@ -684,7 +693,6 @@ int __journal_remove_checkpoint(struct journal_head *jh) | |||
684 | wake_up(&journal->j_wait_logspace); | 693 | wake_up(&journal->j_wait_logspace); |
685 | ret = 1; | 694 | ret = 1; |
686 | out: | 695 | out: |
687 | JBUFFER_TRACE(jh, "exit"); | ||
688 | return ret; | 696 | return ret; |
689 | } | 697 | } |
690 | 698 | ||
@@ -703,6 +711,8 @@ void __journal_insert_checkpoint(struct journal_head *jh, | |||
703 | J_ASSERT_JH(jh, buffer_dirty(jh2bh(jh)) || buffer_jbddirty(jh2bh(jh))); | 711 | J_ASSERT_JH(jh, buffer_dirty(jh2bh(jh)) || buffer_jbddirty(jh2bh(jh))); |
704 | J_ASSERT_JH(jh, jh->b_cp_transaction == NULL); | 712 | J_ASSERT_JH(jh, jh->b_cp_transaction == NULL); |
705 | 713 | ||
714 | /* Get reference for checkpointing transaction */ | ||
715 | journal_grab_journal_head(jh2bh(jh)); | ||
706 | jh->b_cp_transaction = transaction; | 716 | jh->b_cp_transaction = transaction; |
707 | 717 | ||
708 | if (!transaction->t_checkpoint_list) { | 718 | if (!transaction->t_checkpoint_list) { |
@@ -752,6 +762,7 @@ void __journal_drop_transaction(journal_t *journal, transaction_t *transaction) | |||
752 | J_ASSERT(journal->j_committing_transaction != transaction); | 762 | J_ASSERT(journal->j_committing_transaction != transaction); |
753 | J_ASSERT(journal->j_running_transaction != transaction); | 763 | J_ASSERT(journal->j_running_transaction != transaction); |
754 | 764 | ||
765 | trace_jbd_drop_transaction(journal, transaction); | ||
755 | jbd_debug(1, "Dropping transaction %d, all done\n", transaction->t_tid); | 766 | jbd_debug(1, "Dropping transaction %d, all done\n", transaction->t_tid); |
756 | kfree(transaction); | 767 | kfree(transaction); |
757 | } | 768 | } |