hc
2024-05-14 bedbef8ad3e75a304af6361af235302bcc61d06b
kernel/fs/jbd2/recovery.c
....@@ -35,7 +35,6 @@
3535 int nr_revoke_hits;
3636 };
3737
38
-enum passtype {PASS_SCAN, PASS_REVOKE, PASS_REPLAY};
3938 static int do_one_pass(journal_t *journal,
4039 struct recovery_info *info, enum passtype pass);
4140 static int scan_revoke_records(journal_t *, struct buffer_head *,
....@@ -75,8 +74,8 @@
7574
7675 /* Do up to 128K of readahead */
7776 max = start + (128 * 1024 / journal->j_blocksize);
78
- if (max > journal->j_maxlen)
79
- max = journal->j_maxlen;
77
+ if (max > journal->j_total_len)
78
+ max = journal->j_total_len;
8079
8180 /* Do the readahead itself. We'll submit MAXBUF buffer_heads at
8281 * a time to the block device IO layer. */
....@@ -135,7 +134,7 @@
135134
136135 *bhp = NULL;
137136
138
- if (offset >= journal->j_maxlen) {
137
+ if (offset >= journal->j_total_len) {
139138 printk(KERN_ERR "JBD2: corrupted journal superblock\n");
140139 return -EFSCORRUPTED;
141140 }
....@@ -225,9 +224,50 @@
225224 /* Make sure we wrap around the log correctly! */
226225 #define wrap(journal, var) \
227226 do { \
228
- if (var >= (journal)->j_last) \
229
- var -= ((journal)->j_last - (journal)->j_first); \
227
+ unsigned long _wrap_last = \
228
+ jbd2_has_feature_fast_commit(journal) ? \
229
+ (journal)->j_fc_last : (journal)->j_last; \
230
+ \
231
+ if (var >= _wrap_last) \
232
+ var -= (_wrap_last - (journal)->j_first); \
230233 } while (0)
234
+
235
+static int fc_do_one_pass(journal_t *journal,
236
+ struct recovery_info *info, enum passtype pass)
237
+{
238
+ unsigned int expected_commit_id = info->end_transaction;
239
+ unsigned long next_fc_block;
240
+ struct buffer_head *bh;
241
+ int err = 0;
242
+
243
+ next_fc_block = journal->j_fc_first;
244
+ if (!journal->j_fc_replay_callback)
245
+ return 0;
246
+
247
+ while (next_fc_block <= journal->j_fc_last) {
248
+ jbd_debug(3, "Fast commit replay: next block %ld\n",
249
+ next_fc_block);
250
+ err = jread(&bh, journal, next_fc_block);
251
+ if (err) {
252
+ jbd_debug(3, "Fast commit replay: read error\n");
253
+ break;
254
+ }
255
+
256
+ err = journal->j_fc_replay_callback(journal, bh, pass,
257
+ next_fc_block - journal->j_fc_first,
258
+ expected_commit_id);
259
+ brelse(bh);
260
+ next_fc_block++;
261
+ if (err < 0 || err == JBD2_FC_REPLAY_STOP)
262
+ break;
263
+ err = 0;
264
+ }
265
+
266
+ if (err)
267
+ jbd_debug(3, "Fast commit replay failed, err = %d\n", err);
268
+
269
+ return err;
270
+}
231271
232272 /**
233273 * jbd2_journal_recover - recovers a on-disk journal
....@@ -286,7 +326,7 @@
286326 err = err2;
287327 /* Make sure all replayed data is on permanent storage */
288328 if (journal->j_flags & JBD2_BARRIER) {
289
- err2 = blkdev_issue_flush(journal->j_fs_dev, GFP_KERNEL, NULL);
329
+ err2 = blkdev_issue_flush(journal->j_fs_dev, GFP_KERNEL);
290330 if (!err)
291331 err = err2;
292332 }
....@@ -428,6 +468,8 @@
428468 __u32 crc32_sum = ~0; /* Transactional Checksums */
429469 int descr_csum_size = 0;
430470 int block_error = 0;
471
+ bool need_check_commit_time = false;
472
+ __u64 last_trans_commit_time = 0, commit_time;
431473
432474 /*
433475 * First thing is to establish what we expect to find in the log
....@@ -470,7 +512,9 @@
470512 break;
471513
472514 jbd_debug(2, "Scanning for sequence ID %u at %lu/%lu\n",
473
- next_commit_ID, next_log_block, journal->j_last);
515
+ next_commit_ID, next_log_block,
516
+ jbd2_has_feature_fast_commit(journal) ?
517
+ journal->j_fc_last : journal->j_last);
474518
475519 /* Skip over each chunk of the transaction looking
476520 * either the next descriptor block or the final commit
....@@ -520,12 +564,21 @@
520564 if (descr_csum_size > 0 &&
521565 !jbd2_descriptor_block_csum_verify(journal,
522566 bh->b_data)) {
523
- printk(KERN_ERR "JBD2: Invalid checksum "
524
- "recovering block %lu in log\n",
525
- next_log_block);
526
- err = -EFSBADCRC;
527
- brelse(bh);
528
- goto failed;
567
+ /*
568
+ * PASS_SCAN can see stale blocks due to lazy
569
+ * journal init. Don't error out on those yet.
570
+ */
571
+ if (pass != PASS_SCAN) {
572
+ pr_err("JBD2: Invalid checksum recovering block %lu in log\n",
573
+ next_log_block);
574
+ err = -EFSBADCRC;
575
+ brelse(bh);
576
+ goto failed;
577
+ }
578
+ need_check_commit_time = true;
579
+ jbd_debug(1,
580
+ "invalid descriptor block found in %lu\n",
581
+ next_log_block);
529582 }
530583
531584 /* If it is a valid descriptor block, replay it
....@@ -535,6 +588,7 @@
535588 if (pass != PASS_REPLAY) {
536589 if (pass == PASS_SCAN &&
537590 jbd2_has_feature_checksum(journal) &&
591
+ !need_check_commit_time &&
538592 !info->end_transaction) {
539593 if (calc_chksums(journal, bh,
540594 &next_log_block,
....@@ -683,20 +737,47 @@
683737 * mentioned conditions. Hence assume
684738 * "Interrupted Commit".)
685739 */
740
+ commit_time = be64_to_cpu(
741
+ ((struct commit_header *)bh->b_data)->h_commit_sec);
742
+ /*
743
+ * If need_check_commit_time is set, it means we are in
744
+ * PASS_SCAN and csum verify failed before. If
745
+ * commit_time is increasing, it's the same journal,
746
+ * otherwise it is stale journal block, just end this
747
+ * recovery.
748
+ */
749
+ if (need_check_commit_time) {
750
+ if (commit_time >= last_trans_commit_time) {
751
+ pr_err("JBD2: Invalid checksum found in transaction %u\n",
752
+ next_commit_ID);
753
+ err = -EFSBADCRC;
754
+ brelse(bh);
755
+ goto failed;
756
+ }
757
+ ignore_crc_mismatch:
758
+ /*
759
+ * It likely does not belong to same journal,
760
+ * just end this recovery with success.
761
+ */
762
+ jbd_debug(1, "JBD2: Invalid checksum ignored in transaction %u, likely stale data\n",
763
+ next_commit_ID);
764
+ err = 0;
765
+ brelse(bh);
766
+ goto done;
767
+ }
686768
687
- /* Found an expected commit block: if checksums
688
- * are present verify them in PASS_SCAN; else not
769
+ /*
770
+ * Found an expected commit block: if checksums
771
+ * are present, verify them in PASS_SCAN; else not
689772 * much to do other than move on to the next sequence
690
- * number. */
773
+ * number.
774
+ */
691775 if (pass == PASS_SCAN &&
692776 jbd2_has_feature_checksum(journal)) {
693
- int chksum_err, chksum_seen;
694777 struct commit_header *cbh =
695778 (struct commit_header *)bh->b_data;
696779 unsigned found_chksum =
697780 be32_to_cpu(cbh->h_chksum[0]);
698
-
699
- chksum_err = chksum_seen = 0;
700781
701782 if (info->end_transaction) {
702783 journal->j_failed_commit =
....@@ -705,42 +786,25 @@
705786 break;
706787 }
707788
708
- if (crc32_sum == found_chksum &&
709
- cbh->h_chksum_type == JBD2_CRC32_CHKSUM &&
710
- cbh->h_chksum_size ==
711
- JBD2_CRC32_CHKSUM_SIZE)
712
- chksum_seen = 1;
713
- else if (!(cbh->h_chksum_type == 0 &&
714
- cbh->h_chksum_size == 0 &&
715
- found_chksum == 0 &&
716
- !chksum_seen))
717
- /*
718
- * If fs is mounted using an old kernel and then
719
- * kernel with journal_chksum is used then we
720
- * get a situation where the journal flag has
721
- * checksum flag set but checksums are not
722
- * present i.e chksum = 0, in the individual
723
- * commit blocks.
724
- * Hence to avoid checksum failures, in this
725
- * situation, this extra check is added.
726
- */
727
- chksum_err = 1;
789
+ /* Neither checksum match nor unused? */
790
+ if (!((crc32_sum == found_chksum &&
791
+ cbh->h_chksum_type ==
792
+ JBD2_CRC32_CHKSUM &&
793
+ cbh->h_chksum_size ==
794
+ JBD2_CRC32_CHKSUM_SIZE) ||
795
+ (cbh->h_chksum_type == 0 &&
796
+ cbh->h_chksum_size == 0 &&
797
+ found_chksum == 0)))
798
+ goto chksum_error;
728799
729
- if (chksum_err) {
730
- info->end_transaction = next_commit_ID;
731
-
732
- if (!jbd2_has_feature_async_commit(journal)) {
733
- journal->j_failed_commit =
734
- next_commit_ID;
735
- brelse(bh);
736
- break;
737
- }
738
- }
739800 crc32_sum = ~0;
740801 }
741802 if (pass == PASS_SCAN &&
742803 !jbd2_commit_block_csum_verify(journal,
743804 bh->b_data)) {
805
+ chksum_error:
806
+ if (commit_time < last_trans_commit_time)
807
+ goto ignore_crc_mismatch;
744808 info->end_transaction = next_commit_ID;
745809
746810 if (!jbd2_has_feature_async_commit(journal)) {
....@@ -750,11 +814,24 @@
750814 break;
751815 }
752816 }
817
+ if (pass == PASS_SCAN)
818
+ last_trans_commit_time = commit_time;
753819 brelse(bh);
754820 next_commit_ID++;
755821 continue;
756822
757823 case JBD2_REVOKE_BLOCK:
824
+ /*
825
+ * Check revoke block crc in pass_scan, if csum verify
826
+ * failed, check commit block time later.
827
+ */
828
+ if (pass == PASS_SCAN &&
829
+ !jbd2_descriptor_block_csum_verify(journal,
830
+ bh->b_data)) {
831
+ jbd_debug(1, "JBD2: invalid revoke block found in %lu\n",
832
+ next_log_block);
833
+ need_check_commit_time = true;
834
+ }
758835 /* If we aren't in the REVOKE pass, then we can
759836 * just skip over this block. */
760837 if (pass != PASS_REVOKE) {
....@@ -799,6 +876,13 @@
799876 success = -EIO;
800877 }
801878 }
879
+
880
+ if (jbd2_has_feature_fast_commit(journal) && pass != PASS_REVOKE) {
881
+ err = fc_do_one_pass(journal, info, pass);
882
+ if (err)
883
+ success = err;
884
+ }
885
+
802886 if (block_error && success == 0)
803887 success = -EIO;
804888 return success;
....@@ -821,9 +905,6 @@
821905 header = (jbd2_journal_revoke_header_t *) bh->b_data;
822906 offset = sizeof(jbd2_journal_revoke_header_t);
823907 rcount = be32_to_cpu(header->r_count);
824
-
825
- if (!jbd2_descriptor_block_csum_verify(journal, header))
826
- return -EFSBADCRC;
827908
828909 if (jbd2_journal_has_csum_v2or3(journal))
829910 csum_size = sizeof(struct jbd2_journal_block_tail);