Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

jbd: Split updating of journal superblock and marking journal empty

There are three case of updating journal superblock. In the first case, we want
to mark journal as empty (setting s_sequence to 0), in the second case we want
to update log tail, in the third case we want to update s_errno. Split these
cases into separate functions. It makes the code slightly more straightforward
and later patches will make the distinction even more important.

Signed-off-by: Jan Kara <jack@suse.cz>

Jan Kara 9754e39c f72cf5e2

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