diff options
author | Jan Kara <jack@suse.cz> | 2012-03-13 15:43:04 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2012-03-13 15:43:04 -0400 |
commit | a78bb11d7acd525623c6a0c2ff4e213d527573fa (patch) | |
tree | 6e2e228cc51a2138046b499d6d9002f35f6d56d0 /fs/jbd2 | |
parent | 24bcc89c7e7c64982e6192b4952a0a92379fc341 (diff) |
jbd2: protect all log tail updates with j_checkpoint_mutex
There are some log tail updates that are not protected by j_checkpoint_mutex.
Some of these are harmless because they happen during startup or shutdown but
updates in jbd2_journal_commit_transaction() and jbd2_journal_flush() can
really race with other log tail updates (e.g. someone doing
jbd2_journal_flush() with someone running jbd2_cleanup_journal_tail()). So
protect all log tail updates with j_checkpoint_mutex.
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/commit.c | 2 | ||||
-rw-r--r-- | fs/jbd2/journal.c | 19 |
2 files changed, 18 insertions, 3 deletions
diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c index 19371a8a9015..6705717d9b7f 100644 --- a/fs/jbd2/commit.c +++ b/fs/jbd2/commit.c | |||
@@ -340,7 +340,9 @@ void jbd2_journal_commit_transaction(journal_t *journal) | |||
340 | /* Do we need to erase the effects of a prior jbd2_journal_flush? */ | 340 | /* Do we need to erase the effects of a prior jbd2_journal_flush? */ |
341 | if (journal->j_flags & JBD2_FLUSHED) { | 341 | if (journal->j_flags & JBD2_FLUSHED) { |
342 | jbd_debug(3, "super block updated\n"); | 342 | jbd_debug(3, "super block updated\n"); |
343 | mutex_lock(&journal->j_checkpoint_mutex); | ||
343 | jbd2_journal_update_sb_log_tail(journal); | 344 | jbd2_journal_update_sb_log_tail(journal); |
345 | mutex_unlock(&journal->j_checkpoint_mutex); | ||
344 | } else { | 346 | } else { |
345 | jbd_debug(3, "superblock not updated\n"); | 347 | jbd_debug(3, "superblock not updated\n"); |
346 | } | 348 | } |
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index 6e75fbd75bad..fc5f2acc9f18 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c | |||
@@ -1123,8 +1123,11 @@ static int journal_reset(journal_t *journal) | |||
1123 | journal->j_errno); | 1123 | journal->j_errno); |
1124 | journal->j_flags |= JBD2_FLUSHED; | 1124 | journal->j_flags |= JBD2_FLUSHED; |
1125 | } else { | 1125 | } else { |
1126 | /* Lock here to make assertions happy... */ | ||
1127 | mutex_lock(&journal->j_checkpoint_mutex); | ||
1126 | /* Add the dynamic fields and write it to disk. */ | 1128 | /* Add the dynamic fields and write it to disk. */ |
1127 | jbd2_journal_update_sb_log_tail(journal); | 1129 | jbd2_journal_update_sb_log_tail(journal); |
1130 | mutex_unlock(&journal->j_checkpoint_mutex); | ||
1128 | } | 1131 | } |
1129 | return jbd2_journal_start_thread(journal); | 1132 | return jbd2_journal_start_thread(journal); |
1130 | } | 1133 | } |
@@ -1173,6 +1176,7 @@ void jbd2_journal_update_sb_log_tail(journal_t *journal) | |||
1173 | { | 1176 | { |
1174 | journal_superblock_t *sb = journal->j_superblock; | 1177 | journal_superblock_t *sb = journal->j_superblock; |
1175 | 1178 | ||
1179 | BUG_ON(!mutex_is_locked(&journal->j_checkpoint_mutex)); | ||
1176 | read_lock(&journal->j_state_lock); | 1180 | read_lock(&journal->j_state_lock); |
1177 | jbd_debug(1, "JBD2: updating superblock (start %ld, seq %d)\n", | 1181 | jbd_debug(1, "JBD2: updating superblock (start %ld, seq %d)\n", |
1178 | journal->j_tail, journal->j_tail_sequence); | 1182 | journal->j_tail, journal->j_tail_sequence); |
@@ -1201,6 +1205,7 @@ static void jbd2_mark_journal_empty(journal_t *journal) | |||
1201 | { | 1205 | { |
1202 | journal_superblock_t *sb = journal->j_superblock; | 1206 | journal_superblock_t *sb = journal->j_superblock; |
1203 | 1207 | ||
1208 | BUG_ON(!mutex_is_locked(&journal->j_checkpoint_mutex)); | ||
1204 | read_lock(&journal->j_state_lock); | 1209 | read_lock(&journal->j_state_lock); |
1205 | jbd_debug(1, "JBD2: Marking journal as empty (seq %d)\n", | 1210 | jbd_debug(1, "JBD2: Marking journal as empty (seq %d)\n", |
1206 | journal->j_tail_sequence); | 1211 | journal->j_tail_sequence); |
@@ -1434,9 +1439,11 @@ int jbd2_journal_destroy(journal_t *journal) | |||
1434 | spin_unlock(&journal->j_list_lock); | 1439 | spin_unlock(&journal->j_list_lock); |
1435 | 1440 | ||
1436 | if (journal->j_sb_buffer) { | 1441 | if (journal->j_sb_buffer) { |
1437 | if (!is_journal_aborted(journal)) | 1442 | if (!is_journal_aborted(journal)) { |
1443 | mutex_lock(&journal->j_checkpoint_mutex); | ||
1438 | jbd2_mark_journal_empty(journal); | 1444 | jbd2_mark_journal_empty(journal); |
1439 | else | 1445 | mutex_unlock(&journal->j_checkpoint_mutex); |
1446 | } else | ||
1440 | err = -EIO; | 1447 | err = -EIO; |
1441 | brelse(journal->j_sb_buffer); | 1448 | brelse(journal->j_sb_buffer); |
1442 | } | 1449 | } |
@@ -1630,6 +1637,7 @@ int jbd2_journal_flush(journal_t *journal) | |||
1630 | if (is_journal_aborted(journal)) | 1637 | if (is_journal_aborted(journal)) |
1631 | return -EIO; | 1638 | return -EIO; |
1632 | 1639 | ||
1640 | mutex_lock(&journal->j_checkpoint_mutex); | ||
1633 | jbd2_cleanup_journal_tail(journal); | 1641 | jbd2_cleanup_journal_tail(journal); |
1634 | 1642 | ||
1635 | /* Finally, mark the journal as really needing no recovery. | 1643 | /* Finally, mark the journal as really needing no recovery. |
@@ -1638,6 +1646,7 @@ int jbd2_journal_flush(journal_t *journal) | |||
1638 | * commits of data to the journal will restore the current | 1646 | * commits of data to the journal will restore the current |
1639 | * s_start value. */ | 1647 | * s_start value. */ |
1640 | jbd2_mark_journal_empty(journal); | 1648 | jbd2_mark_journal_empty(journal); |
1649 | mutex_unlock(&journal->j_checkpoint_mutex); | ||
1641 | write_lock(&journal->j_state_lock); | 1650 | write_lock(&journal->j_state_lock); |
1642 | J_ASSERT(!journal->j_running_transaction); | 1651 | J_ASSERT(!journal->j_running_transaction); |
1643 | J_ASSERT(!journal->j_committing_transaction); | 1652 | J_ASSERT(!journal->j_committing_transaction); |
@@ -1678,8 +1687,12 @@ int jbd2_journal_wipe(journal_t *journal, int write) | |||
1678 | write ? "Clearing" : "Ignoring"); | 1687 | write ? "Clearing" : "Ignoring"); |
1679 | 1688 | ||
1680 | err = jbd2_journal_skip_recovery(journal); | 1689 | err = jbd2_journal_skip_recovery(journal); |
1681 | if (write) | 1690 | if (write) { |
1691 | /* Lock to make assertions happy... */ | ||
1692 | mutex_lock(&journal->j_checkpoint_mutex); | ||
1682 | jbd2_mark_journal_empty(journal); | 1693 | jbd2_mark_journal_empty(journal); |
1694 | mutex_unlock(&journal->j_checkpoint_mutex); | ||
1695 | } | ||
1683 | 1696 | ||
1684 | no_recovery: | 1697 | no_recovery: |
1685 | return err; | 1698 | return err; |