diff options
-rw-r--r-- | fs/jbd/checkpoint.c | 2 | ||||
-rw-r--r-- | fs/jbd/commit.c | 2 | ||||
-rw-r--r-- | fs/jbd/journal.c | 164 | ||||
-rw-r--r-- | include/linux/jbd.h | 2 | ||||
-rw-r--r-- | include/trace/events/jbd.h | 12 |
5 files changed, 104 insertions, 78 deletions
diff --git a/fs/jbd/checkpoint.c b/fs/jbd/checkpoint.c index 05f0754f2b46..80c85f3e087f 100644 --- a/fs/jbd/checkpoint.c +++ b/fs/jbd/checkpoint.c | |||
@@ -540,7 +540,7 @@ int cleanup_journal_tail(journal_t *journal) | |||
540 | journal->j_tail = blocknr; | 540 | journal->j_tail = blocknr; |
541 | spin_unlock(&journal->j_state_lock); | 541 | spin_unlock(&journal->j_state_lock); |
542 | if (!(journal->j_flags & JFS_ABORT)) | 542 | if (!(journal->j_flags & JFS_ABORT)) |
543 | journal_update_superblock(journal, 1); | 543 | journal_update_sb_log_tail(journal); |
544 | return 0; | 544 | return 0; |
545 | } | 545 | } |
546 | 546 | ||
diff --git a/fs/jbd/commit.c b/fs/jbd/commit.c index 9d31e6a39205..dba9cfd75f1a 100644 --- a/fs/jbd/commit.c +++ b/fs/jbd/commit.c | |||
@@ -308,7 +308,7 @@ void journal_commit_transaction(journal_t *journal) | |||
308 | /* Do we need to erase the effects of a prior journal_flush? */ | 308 | /* Do we need to erase the effects of a prior journal_flush? */ |
309 | if (journal->j_flags & JFS_FLUSHED) { | 309 | if (journal->j_flags & JFS_FLUSHED) { |
310 | jbd_debug(3, "super block updated\n"); | 310 | jbd_debug(3, "super block updated\n"); |
311 | journal_update_superblock(journal, 1); | 311 | journal_update_sb_log_tail(journal); |
312 | } else { | 312 | } else { |
313 | jbd_debug(3, "superblock not updated\n"); | 313 | jbd_debug(3, "superblock not updated\n"); |
314 | } | 314 | } |
diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c index 2047fd77bf38..44c104abfb36 100644 --- a/fs/jbd/journal.c +++ b/fs/jbd/journal.c | |||
@@ -923,8 +923,22 @@ static int journal_reset(journal_t *journal) | |||
923 | 923 | ||
924 | journal->j_max_transaction_buffers = journal->j_maxlen / 4; | 924 | journal->j_max_transaction_buffers = journal->j_maxlen / 4; |
925 | 925 | ||
926 | /* Add the dynamic fields and write it to disk. */ | 926 | /* |
927 | journal_update_superblock(journal, 1); | 927 | * As a special case, if the on-disk copy is already marked as needing |
928 | * no recovery (s_start == 0), then we can safely defer the superblock | ||
929 | * update until the next commit by setting JFS_FLUSHED. This avoids | ||
930 | * attempting a write to a potential-readonly device. | ||
931 | */ | ||
932 | if (sb->s_start == 0) { | ||
933 | jbd_debug(1,"JBD: Skipping superblock update on recovered sb " | ||
934 | "(start %u, seq %d, errno %d)\n", | ||
935 | journal->j_tail, journal->j_tail_sequence, | ||
936 | journal->j_errno); | ||
937 | journal->j_flags |= JFS_FLUSHED; | ||
938 | } else { | ||
939 | /* Add the dynamic fields and write it to disk. */ | ||
940 | journal_update_sb_log_tail(journal); | ||
941 | } | ||
928 | return journal_start_thread(journal); | 942 | return journal_start_thread(journal); |
929 | } | 943 | } |
930 | 944 | ||
@@ -1001,35 +1015,11 @@ int journal_create(journal_t *journal) | |||
1001 | return journal_reset(journal); | 1015 | return journal_reset(journal); |
1002 | } | 1016 | } |
1003 | 1017 | ||
1004 | /** | 1018 | static void journal_write_superblock(journal_t *journal) |
1005 | * void journal_update_superblock() - Update journal sb on disk. | ||
1006 | * @journal: The journal to update. | ||
1007 | * @wait: Set to '0' if you don't want to wait for IO completion. | ||
1008 | * | ||
1009 | * Update a journal's dynamic superblock fields and write it to disk, | ||
1010 | * optionally waiting for the IO to complete. | ||
1011 | */ | ||
1012 | void journal_update_superblock(journal_t *journal, int wait) | ||
1013 | { | 1019 | { |
1014 | journal_superblock_t *sb = journal->j_superblock; | ||
1015 | struct buffer_head *bh = journal->j_sb_buffer; | 1020 | struct buffer_head *bh = journal->j_sb_buffer; |
1016 | 1021 | ||
1017 | /* | 1022 | trace_journal_write_superblock(journal); |
1018 | * As a special case, if the on-disk copy is already marked as needing | ||
1019 | * no recovery (s_start == 0) and there are no outstanding transactions | ||
1020 | * in the filesystem, then we can safely defer the superblock update | ||
1021 | * until the next commit by setting JFS_FLUSHED. This avoids | ||
1022 | * attempting a write to a potential-readonly device. | ||
1023 | */ | ||
1024 | if (sb->s_start == 0 && journal->j_tail_sequence == | ||
1025 | journal->j_transaction_sequence) { | ||
1026 | jbd_debug(1,"JBD: Skipping superblock update on recovered sb " | ||
1027 | "(start %u, seq %d, errno %d)\n", | ||
1028 | journal->j_tail, journal->j_tail_sequence, | ||
1029 | journal->j_errno); | ||
1030 | goto out; | ||
1031 | } | ||
1032 | |||
1033 | if (buffer_write_io_error(bh)) { | 1023 | if (buffer_write_io_error(bh)) { |
1034 | char b[BDEVNAME_SIZE]; | 1024 | char b[BDEVNAME_SIZE]; |
1035 | /* | 1025 | /* |
@@ -1047,44 +1037,94 @@ void journal_update_superblock(journal_t *journal, int wait) | |||
1047 | set_buffer_uptodate(bh); | 1037 | set_buffer_uptodate(bh); |
1048 | } | 1038 | } |
1049 | 1039 | ||
1040 | BUFFER_TRACE(bh, "marking dirty"); | ||
1041 | mark_buffer_dirty(bh); | ||
1042 | sync_dirty_buffer(bh); | ||
1043 | if (buffer_write_io_error(bh)) { | ||
1044 | char b[BDEVNAME_SIZE]; | ||
1045 | printk(KERN_ERR "JBD: I/O error detected " | ||
1046 | "when updating journal superblock for %s.\n", | ||
1047 | journal_dev_name(journal, b)); | ||
1048 | clear_buffer_write_io_error(bh); | ||
1049 | set_buffer_uptodate(bh); | ||
1050 | } | ||
1051 | } | ||
1052 | |||
1053 | /** | ||
1054 | * journal_update_sb_log_tail() - Update log tail in journal sb on disk. | ||
1055 | * @journal: The journal to update. | ||
1056 | * | ||
1057 | * Update a journal's superblock information about log tail and write it to | ||
1058 | * disk, waiting for the IO to complete. | ||
1059 | */ | ||
1060 | void journal_update_sb_log_tail(journal_t *journal) | ||
1061 | { | ||
1062 | journal_superblock_t *sb = journal->j_superblock; | ||
1063 | |||
1050 | spin_lock(&journal->j_state_lock); | 1064 | spin_lock(&journal->j_state_lock); |
1051 | jbd_debug(1,"JBD: updating superblock (start %u, seq %d, errno %d)\n", | 1065 | jbd_debug(1,"JBD: updating superblock (start %u, seq %d, errno %d)\n", |
1052 | journal->j_tail, journal->j_tail_sequence, journal->j_errno); | 1066 | journal->j_tail, journal->j_tail_sequence, journal->j_errno); |
1053 | 1067 | ||
1054 | sb->s_sequence = cpu_to_be32(journal->j_tail_sequence); | 1068 | sb->s_sequence = cpu_to_be32(journal->j_tail_sequence); |
1055 | sb->s_start = cpu_to_be32(journal->j_tail); | 1069 | sb->s_start = cpu_to_be32(journal->j_tail); |
1056 | sb->s_errno = cpu_to_be32(journal->j_errno); | ||
1057 | spin_unlock(&journal->j_state_lock); | 1070 | spin_unlock(&journal->j_state_lock); |
1058 | 1071 | ||
1059 | BUFFER_TRACE(bh, "marking dirty"); | 1072 | journal_write_superblock(journal); |
1060 | mark_buffer_dirty(bh); | ||
1061 | if (wait) { | ||
1062 | sync_dirty_buffer(bh); | ||
1063 | if (buffer_write_io_error(bh)) { | ||
1064 | char b[BDEVNAME_SIZE]; | ||
1065 | printk(KERN_ERR "JBD: I/O error detected " | ||
1066 | "when updating journal superblock for %s.\n", | ||
1067 | journal_dev_name(journal, b)); | ||
1068 | clear_buffer_write_io_error(bh); | ||
1069 | set_buffer_uptodate(bh); | ||
1070 | } | ||
1071 | } else | ||
1072 | write_dirty_buffer(bh, WRITE); | ||
1073 | 1073 | ||
1074 | trace_jbd_update_superblock_end(journal, wait); | 1074 | /* Log is no longer empty */ |
1075 | out: | 1075 | spin_lock(&journal->j_state_lock); |
1076 | /* If we have just flushed the log (by marking s_start==0), then | 1076 | WARN_ON(!sb->s_sequence); |
1077 | * any future commit will have to be careful to update the | 1077 | journal->j_flags &= ~JFS_FLUSHED; |
1078 | * superblock again to re-record the true start of the log. */ | 1078 | spin_unlock(&journal->j_state_lock); |
1079 | } | ||
1080 | |||
1081 | /** | ||
1082 | * mark_journal_empty() - Mark on disk journal as empty. | ||
1083 | * @journal: The journal to update. | ||
1084 | * | ||
1085 | * Update a journal's dynamic superblock fields to show that journal is empty. | ||
1086 | * Write updated superblock to disk waiting for IO to complete. | ||
1087 | */ | ||
1088 | static void mark_journal_empty(journal_t *journal) | ||
1089 | { | ||
1090 | journal_superblock_t *sb = journal->j_superblock; | ||
1079 | 1091 | ||
1080 | spin_lock(&journal->j_state_lock); | 1092 | spin_lock(&journal->j_state_lock); |
1081 | if (sb->s_start) | 1093 | jbd_debug(1, "JBD: Marking journal as empty (seq %d)\n", |
1082 | journal->j_flags &= ~JFS_FLUSHED; | 1094 | journal->j_tail_sequence); |
1083 | else | 1095 | |
1084 | journal->j_flags |= JFS_FLUSHED; | 1096 | sb->s_sequence = cpu_to_be32(journal->j_tail_sequence); |
1097 | sb->s_start = cpu_to_be32(0); | ||
1098 | spin_unlock(&journal->j_state_lock); | ||
1099 | |||
1100 | journal_write_superblock(journal); | ||
1101 | |||
1102 | spin_lock(&journal->j_state_lock); | ||
1103 | /* Log is empty */ | ||
1104 | journal->j_flags |= JFS_FLUSHED; | ||
1085 | spin_unlock(&journal->j_state_lock); | 1105 | spin_unlock(&journal->j_state_lock); |
1086 | } | 1106 | } |
1087 | 1107 | ||
1108 | /** | ||
1109 | * journal_update_sb_errno() - Update error in the journal. | ||
1110 | * @journal: The journal to update. | ||
1111 | * | ||
1112 | * Update a journal's errno. Write updated superblock to disk waiting for IO | ||
1113 | * to complete. | ||
1114 | */ | ||
1115 | static void journal_update_sb_errno(journal_t *journal) | ||
1116 | { | ||
1117 | journal_superblock_t *sb = journal->j_superblock; | ||
1118 | |||
1119 | spin_lock(&journal->j_state_lock); | ||
1120 | jbd_debug(1, "JBD: updating superblock error (errno %d)\n", | ||
1121 | journal->j_errno); | ||
1122 | sb->s_errno = cpu_to_be32(journal->j_errno); | ||
1123 | spin_unlock(&journal->j_state_lock); | ||
1124 | |||
1125 | journal_write_superblock(journal); | ||
1126 | } | ||
1127 | |||
1088 | /* | 1128 | /* |
1089 | * Read the superblock for a given journal, performing initial | 1129 | * Read the superblock for a given journal, performing initial |
1090 | * validation of the format. | 1130 | * validation of the format. |
@@ -1268,14 +1308,11 @@ int journal_destroy(journal_t *journal) | |||
1268 | 1308 | ||
1269 | if (journal->j_sb_buffer) { | 1309 | if (journal->j_sb_buffer) { |
1270 | if (!is_journal_aborted(journal)) { | 1310 | if (!is_journal_aborted(journal)) { |
1271 | /* We can now mark the journal as empty. */ | ||
1272 | journal->j_tail = 0; | ||
1273 | journal->j_tail_sequence = | 1311 | journal->j_tail_sequence = |
1274 | ++journal->j_transaction_sequence; | 1312 | ++journal->j_transaction_sequence; |
1275 | journal_update_superblock(journal, 1); | 1313 | mark_journal_empty(journal); |
1276 | } else { | 1314 | } else |
1277 | err = -EIO; | 1315 | err = -EIO; |
1278 | } | ||
1279 | brelse(journal->j_sb_buffer); | 1316 | brelse(journal->j_sb_buffer); |
1280 | } | 1317 | } |
1281 | 1318 | ||
@@ -1457,7 +1494,6 @@ int journal_flush(journal_t *journal) | |||
1457 | { | 1494 | { |
1458 | int err = 0; | 1495 | int err = 0; |
1459 | transaction_t *transaction = NULL; | 1496 | transaction_t *transaction = NULL; |
1460 | unsigned int old_tail; | ||
1461 | 1497 | ||
1462 | spin_lock(&journal->j_state_lock); | 1498 | spin_lock(&journal->j_state_lock); |
1463 | 1499 | ||
@@ -1499,14 +1535,8 @@ int journal_flush(journal_t *journal) | |||
1499 | * the magic code for a fully-recovered superblock. Any future | 1535 | * the magic code for a fully-recovered superblock. Any future |
1500 | * commits of data to the journal will restore the current | 1536 | * commits of data to the journal will restore the current |
1501 | * s_start value. */ | 1537 | * s_start value. */ |
1538 | mark_journal_empty(journal); | ||
1502 | spin_lock(&journal->j_state_lock); | 1539 | spin_lock(&journal->j_state_lock); |
1503 | old_tail = journal->j_tail; | ||
1504 | journal->j_tail = 0; | ||
1505 | spin_unlock(&journal->j_state_lock); | ||
1506 | journal_update_superblock(journal, 1); | ||
1507 | spin_lock(&journal->j_state_lock); | ||
1508 | journal->j_tail = old_tail; | ||
1509 | |||
1510 | J_ASSERT(!journal->j_running_transaction); | 1540 | J_ASSERT(!journal->j_running_transaction); |
1511 | J_ASSERT(!journal->j_committing_transaction); | 1541 | J_ASSERT(!journal->j_committing_transaction); |
1512 | J_ASSERT(!journal->j_checkpoint_transactions); | 1542 | J_ASSERT(!journal->j_checkpoint_transactions); |
@@ -1547,7 +1577,7 @@ int journal_wipe(journal_t *journal, int write) | |||
1547 | 1577 | ||
1548 | err = journal_skip_recovery(journal); | 1578 | err = journal_skip_recovery(journal); |
1549 | if (write) | 1579 | if (write) |
1550 | journal_update_superblock(journal, 1); | 1580 | mark_journal_empty(journal); |
1551 | 1581 | ||
1552 | no_recovery: | 1582 | no_recovery: |
1553 | return err; | 1583 | return err; |
@@ -1615,7 +1645,7 @@ static void __journal_abort_soft (journal_t *journal, int errno) | |||
1615 | __journal_abort_hard(journal); | 1645 | __journal_abort_hard(journal); |
1616 | 1646 | ||
1617 | if (errno) | 1647 | if (errno) |
1618 | journal_update_superblock(journal, 1); | 1648 | journal_update_sb_errno(journal); |
1619 | } | 1649 | } |
1620 | 1650 | ||
1621 | /** | 1651 | /** |
diff --git a/include/linux/jbd.h b/include/linux/jbd.h index f265682ae134..9716d370c501 100644 --- a/include/linux/jbd.h +++ b/include/linux/jbd.h | |||
@@ -864,7 +864,7 @@ extern int journal_destroy (journal_t *); | |||
864 | extern int journal_recover (journal_t *journal); | 864 | extern int journal_recover (journal_t *journal); |
865 | extern int journal_wipe (journal_t *, int); | 865 | extern int journal_wipe (journal_t *, int); |
866 | extern int journal_skip_recovery (journal_t *); | 866 | extern int journal_skip_recovery (journal_t *); |
867 | extern void journal_update_superblock (journal_t *, int); | 867 | extern void journal_update_sb_log_tail (journal_t *); |
868 | extern void journal_abort (journal_t *, int); | 868 | extern void journal_abort (journal_t *, int); |
869 | extern int journal_errno (journal_t *); | 869 | extern int journal_errno (journal_t *); |
870 | extern void journal_ack_err (journal_t *); | 870 | extern void journal_ack_err (journal_t *); |
diff --git a/include/trace/events/jbd.h b/include/trace/events/jbd.h index 9305e1b5edc3..d9658a940a39 100644 --- a/include/trace/events/jbd.h +++ b/include/trace/events/jbd.h | |||
@@ -169,24 +169,20 @@ TRACE_EVENT(jbd_cleanup_journal_tail, | |||
169 | __entry->block_nr, __entry->freed) | 169 | __entry->block_nr, __entry->freed) |
170 | ); | 170 | ); |
171 | 171 | ||
172 | TRACE_EVENT(jbd_update_superblock_end, | 172 | TRACE_EVENT(journal_write_superblock, |
173 | TP_PROTO(journal_t *journal, int wait), | 173 | TP_PROTO(journal_t *journal), |
174 | 174 | ||
175 | TP_ARGS(journal, wait), | 175 | TP_ARGS(journal), |
176 | 176 | ||
177 | TP_STRUCT__entry( | 177 | TP_STRUCT__entry( |
178 | __field( dev_t, dev ) | 178 | __field( dev_t, dev ) |
179 | __field( int, wait ) | ||
180 | ), | 179 | ), |
181 | 180 | ||
182 | TP_fast_assign( | 181 | TP_fast_assign( |
183 | __entry->dev = journal->j_fs_dev->bd_dev; | 182 | __entry->dev = journal->j_fs_dev->bd_dev; |
184 | __entry->wait = wait; | ||
185 | ), | 183 | ), |
186 | 184 | ||
187 | TP_printk("dev %d,%d wait %d", | 185 | TP_printk("dev %d,%d", MAJOR(__entry->dev), MINOR(__entry->dev)) |
188 | MAJOR(__entry->dev), MINOR(__entry->dev), | ||
189 | __entry->wait) | ||
190 | ); | 186 | ); |
191 | 187 | ||
192 | #endif /* _TRACE_JBD_H */ | 188 | #endif /* _TRACE_JBD_H */ |