aboutsummaryrefslogtreecommitdiffstats
path: root/fs/jbd2/journal.c
diff options
context:
space:
mode:
authorHidehiro Kawai <hidehiro.kawai.ez@hitachi.com>2008-10-10 20:29:13 -0400
committerTheodore Ts'o <tytso@mit.edu>2008-10-10 20:29:13 -0400
commit44519faf22ad6ce924ad0352d3dc200d9e0b66e8 (patch)
tree332dd28cf16439fc4c78ad198e04c12ff7c16e66 /fs/jbd2/journal.c
parent77e841de8abac4755cc83ca224fdf71418d65380 (diff)
jbd2: fix error handling for checkpoint io
When a checkpointing IO fails, current JBD2 code doesn't check the error and continue journaling. This means latest metadata can be lost from both the journal and filesystem. This patch leaves the failed metadata blocks in the journal space and aborts journaling in the case of jbd2_log_do_checkpoint(). To achieve this, we need to do: 1. don't remove the failed buffer from the checkpoint list where in the case of __try_to_free_cp_buf() because it may be released or overwritten by a later transaction 2. jbd2_log_do_checkpoint() is the last chance, remove the failed buffer from the checkpoint list and abort the journal 3. when checkpointing fails, don't update the journal super block to prevent the journaled contents from being cleaned. For safety, don't update j_tail and j_tail_sequence either 4. when checkpointing fails, notify this error to the ext4 layer so that ext4 don't clear the needs_recovery flag, otherwise the journaled contents are ignored and cleaned in the recovery phase 5. if the recovery fails, keep the needs_recovery flag 6. prevent jbd2_cleanup_journal_tail() from being called between __jbd2_journal_drop_transaction() and jbd2_journal_abort() (a possible race issue between jbd2_log_do_checkpoint()s called by jbd2_journal_flush() and __jbd2_log_wait_for_space()) Signed-off-by: Hidehiro Kawai <hidehiro.kawai.ez@hitachi.com> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Diffstat (limited to 'fs/jbd2/journal.c')
-rw-r--r--fs/jbd2/journal.c28
1 files changed, 22 insertions, 6 deletions
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c
index 01c3901c3a07..783de118de92 100644
--- a/fs/jbd2/journal.c
+++ b/fs/jbd2/journal.c
@@ -1451,9 +1451,12 @@ recovery_error:
1451 * 1451 *
1452 * Release a journal_t structure once it is no longer in use by the 1452 * Release a journal_t structure once it is no longer in use by the
1453 * journaled object. 1453 * journaled object.
1454 * Return <0 if we couldn't clean up the journal.
1454 */ 1455 */
1455void jbd2_journal_destroy(journal_t *journal) 1456int jbd2_journal_destroy(journal_t *journal)
1456{ 1457{
1458 int err = 0;
1459
1457 /* Wait for the commit thread to wake up and die. */ 1460 /* Wait for the commit thread to wake up and die. */
1458 journal_kill_thread(journal); 1461 journal_kill_thread(journal);
1459 1462
@@ -1476,11 +1479,16 @@ void jbd2_journal_destroy(journal_t *journal)
1476 J_ASSERT(journal->j_checkpoint_transactions == NULL); 1479 J_ASSERT(journal->j_checkpoint_transactions == NULL);
1477 spin_unlock(&journal->j_list_lock); 1480 spin_unlock(&journal->j_list_lock);
1478 1481
1479 /* We can now mark the journal as empty. */
1480 journal->j_tail = 0;
1481 journal->j_tail_sequence = ++journal->j_transaction_sequence;
1482 if (journal->j_sb_buffer) { 1482 if (journal->j_sb_buffer) {
1483 jbd2_journal_update_superblock(journal, 1); 1483 if (!is_journal_aborted(journal)) {
1484 /* We can now mark the journal as empty. */
1485 journal->j_tail = 0;
1486 journal->j_tail_sequence =
1487 ++journal->j_transaction_sequence;
1488 jbd2_journal_update_superblock(journal, 1);
1489 } else {
1490 err = -EIO;
1491 }
1484 brelse(journal->j_sb_buffer); 1492 brelse(journal->j_sb_buffer);
1485 } 1493 }
1486 1494
@@ -1492,6 +1500,8 @@ void jbd2_journal_destroy(journal_t *journal)
1492 jbd2_journal_destroy_revoke(journal); 1500 jbd2_journal_destroy_revoke(journal);
1493 kfree(journal->j_wbuf); 1501 kfree(journal->j_wbuf);
1494 kfree(journal); 1502 kfree(journal);
1503
1504 return err;
1495} 1505}
1496 1506
1497 1507
@@ -1717,10 +1727,16 @@ int jbd2_journal_flush(journal_t *journal)
1717 spin_lock(&journal->j_list_lock); 1727 spin_lock(&journal->j_list_lock);
1718 while (!err && journal->j_checkpoint_transactions != NULL) { 1728 while (!err && journal->j_checkpoint_transactions != NULL) {
1719 spin_unlock(&journal->j_list_lock); 1729 spin_unlock(&journal->j_list_lock);
1730 mutex_lock(&journal->j_checkpoint_mutex);
1720 err = jbd2_log_do_checkpoint(journal); 1731 err = jbd2_log_do_checkpoint(journal);
1732 mutex_unlock(&journal->j_checkpoint_mutex);
1721 spin_lock(&journal->j_list_lock); 1733 spin_lock(&journal->j_list_lock);
1722 } 1734 }
1723 spin_unlock(&journal->j_list_lock); 1735 spin_unlock(&journal->j_list_lock);
1736
1737 if (is_journal_aborted(journal))
1738 return -EIO;
1739
1724 jbd2_cleanup_journal_tail(journal); 1740 jbd2_cleanup_journal_tail(journal);
1725 1741
1726 /* Finally, mark the journal as really needing no recovery. 1742 /* Finally, mark the journal as really needing no recovery.
@@ -1742,7 +1758,7 @@ int jbd2_journal_flush(journal_t *journal)
1742 J_ASSERT(journal->j_head == journal->j_tail); 1758 J_ASSERT(journal->j_head == journal->j_tail);
1743 J_ASSERT(journal->j_tail_sequence == journal->j_transaction_sequence); 1759 J_ASSERT(journal->j_tail_sequence == journal->j_transaction_sequence);
1744 spin_unlock(&journal->j_state_lock); 1760 spin_unlock(&journal->j_state_lock);
1745 return err; 1761 return 0;
1746} 1762}
1747 1763
1748/** 1764/**