📄 jbd-journal-chksum-2.6.18-vanilla.patch
字号:
+ __be32 h_blocktype;+ __be32 h_sequence;+ unsigned char h_chksum_type;+ unsigned char h_chksum_size;+ unsigned char h_padding[2];+ __be32 h_chksum[JFS_CHECKSUM_BYTES];+}; /* * The block tag: used to describe a single buffer in the journal @@ -234,12 +257,16 @@ typedef struct journal_superblock_s ((j)->j_format_version >= 2 && \ ((j)->j_superblock->s_feature_incompat & cpu_to_be32((mask)))) -#define JFS_FEATURE_INCOMPAT_REVOKE 0x00000001+#define JFS_FEATURE_COMPAT_CHECKSUM 0x00000001++#define JFS_FEATURE_INCOMPAT_REVOKE 0x00000001+#define JFS_FEATURE_INCOMPAT_ASYNC_COMMIT 0x00000004 /* Features known to this kernel version: */-#define JFS_KNOWN_COMPAT_FEATURES 0+#define JFS_KNOWN_COMPAT_FEATURES JFS_FEATURE_COMPAT_CHECKSUM #define JFS_KNOWN_ROCOMPAT_FEATURES 0-#define JFS_KNOWN_INCOMPAT_FEATURES JFS_FEATURE_INCOMPAT_REVOKE+#define JFS_KNOWN_INCOMPAT_FEATURES (JFS_FEATURE_INCOMPAT_REVOKE | \+ JFS_FEATURE_INCOMPAT_ASYNC_COMMIT) #ifdef __KERNEL__ @@ -1053,6 +1080,8 @@ extern int journal_check_available_fe (journal_t *, unsigned long, unsigned long, unsigned long); extern int journal_set_features (journal_t *, unsigned long, unsigned long, unsigned long);+extern int journal_clear_features+ (journal_t *, unsigned long, unsigned long, unsigned long); extern int journal_create (journal_t *); extern int journal_load (journal_t *journal); extern void journal_destroy (journal_t *);Index: linux-2.6.18.8/fs/jbd/recovery.c===================================================================--- linux-2.6.18.8.orig/fs/jbd/recovery.c+++ linux-2.6.18.8/fs/jbd/recovery.c@@ -21,6 +21,7 @@ #include <linux/jbd.h> #include <linux/errno.h> #include <linux/slab.h>+#include <linux/crc32.h> #endif /*@@ -307,6 +308,37 @@ int journal_skip_recovery(journal_t *jou return err; } +/*+ * calc_chksums calculates the checksums for the blocks described in the+ * descriptor block.+ */+static int calc_chksums(journal_t *journal, struct buffer_head *bh,+ unsigned long *next_log_block, __u32 *crc32_sum)+{+ int i, num_blks, err;+ unsigned long io_block;+ struct buffer_head *obh;++ num_blks = count_tags(bh, journal->j_blocksize);+ /* Calculate checksum of the descriptor block. */+ *crc32_sum = crc32_be(*crc32_sum, (void *)bh->b_data, bh->b_size);++ for (i = 0; i < num_blks; i++) {+ io_block = (*next_log_block)++;+ wrap(journal, *next_log_block);+ err = jread(&obh, journal, io_block);+ if (err) {+ printk(KERN_ERR "JBD: IO error %d recovering block "+ "%lu in log\n", err, io_block);+ return 1;+ } else {+ *crc32_sum = crc32_be(*crc32_sum, (void *)obh->b_data,+ obh->b_size);+ }+ }+ return 0;+}+ static int do_one_pass(journal_t *journal, struct recovery_info *info, enum passtype pass) {@@ -318,6 +350,7 @@ static int do_one_pass(journal_t *journa struct buffer_head * bh; unsigned int sequence; int blocktype;+ __u32 crc32_sum = ~0; /* Transactional Checksums */ /* Precompute the maximum metadata descriptors in a descriptor block */ int MAX_BLOCKS_PER_DESC;@@ -409,9 +442,24 @@ static int do_one_pass(journal_t *journa switch(blocktype) { case JFS_DESCRIPTOR_BLOCK: /* If it is a valid descriptor block, replay it- * in pass REPLAY; otherwise, just skip over the- * blocks it describes. */+ * in pass REPLAY; if journal_checksums enabled, then+ * calculate checksums in PASS_SCAN, otherwise,+ * just skip over the blocks it describes. */ if (pass != PASS_REPLAY) {+ if (pass == PASS_SCAN &&+ JFS_HAS_COMPAT_FEATURE(journal,+ JFS_FEATURE_COMPAT_CHECKSUM) &&+ !info->end_transaction) {+ if (calc_chksums(journal, bh,+ &next_log_block,+ &crc32_sum)) {+ put_bh(bh);+ break;+ }+ put_bh(bh);+ continue;+ }+ next_log_block += count_tags(bh, journal->j_blocksize); wrap(journal, next_log_block);@@ -506,9 +554,97 @@ static int do_one_pass(journal_t *journa continue; case JFS_COMMIT_BLOCK:- /* Found an expected commit block: not much to- * do other than move on to the next sequence+ /* How to differentiate between interrupted commit+ * and journal corruption ?+ *+ * {nth transaction}+ * Checksum Verification Failed+ * |+ * ____________________+ * | |+ * async_commit sync_commit+ * | |+ * | GO TO NEXT "Journal Corruption"+ * | TRANSACTION+ * |+ * {(n+1)th transanction}+ * |+ * _______|______________+ * | |+ * Commit block found Commit block not found+ * | |+ * "Journal Corruption" |+ * _____________|__________+ * | |+ * nth trans corrupt OR nth trans+ * and (n+1)th interrupted interrupted + * before commit block+ * could reach the disk.+ * (Cannot find the difference in above+ * mentioned conditions. Hence assume+ * "Interrupted Commit".)+ */++ /* Found an expected commit block: if checksums+ * are present verify them in PASS_SCAN; else not+ * much to do other than move on to the next sequence * number. */+ if (pass == PASS_SCAN &&+ JFS_HAS_COMPAT_FEATURE(journal,+ JFS_FEATURE_COMPAT_CHECKSUM)) {+ int chksum_err, chksum_seen;+ struct commit_header *cbh =+ (struct commit_header *)bh->b_data;+ unsigned found_chksum =+ be32_to_cpu(cbh->h_chksum[0]);++ chksum_err = chksum_seen = 0;++ if (info->end_transaction) {+ printk(KERN_ERR "JBD: Transaction %u "+ "found to be corrupt.\n",+ next_commit_ID - 1);+ brelse(bh);+ break;+ }++ if (crc32_sum == found_chksum &&+ cbh->h_chksum_type == JFS_CRC32_CHKSUM &&+ cbh->h_chksum_size ==+ JFS_CRC32_CHKSUM_SIZE) {+ chksum_seen = 1;+ } else if (!(cbh->h_chksum_type == 0 &&+ cbh->h_chksum_size == 0 &&+ found_chksum == 0 &&+ !chksum_seen)) {+ /*+ * If fs is mounted using an old kernel and then+ * kernel with journal_chksum is used then we+ * get a situation where the journal flag has+ * checksum flag set but checksums are not+ * present i.e chksum = 0, in the individual+ * commit blocks.+ * Hence to avoid checksum failures, in this+ * situation, this extra check is added.+ */+ chksum_err = 1;+ }++ if (chksum_err) {+ info->end_transaction = next_commit_ID;++ if (!JFS_HAS_INCOMPAT_FEATURE(journal,+ JFS_FEATURE_INCOMPAT_ASYNC_COMMIT)){+ printk(KERN_ERR+ "JBD: Transaction %u "+ "found to be corrupt.\n",+ next_commit_ID);+ brelse(bh);+ break;+ }+ }+ crc32_sum = ~0;+ } brelse(bh); next_commit_ID++; continue;@@ -544,9 +680,10 @@ static int do_one_pass(journal_t *journa * transaction marks the end of the valid log. */ - if (pass == PASS_SCAN)- info->end_transaction = next_commit_ID;- else {+ if (pass == PASS_SCAN) {+ if (!info->end_transaction)+ info->end_transaction = next_commit_ID;+ } else { /* It's really bad news if different passes end up at * different places (but possible due to IO errors). */ if (info->end_transaction != next_commit_ID) {Index: linux-2.6.18.8/fs/jbd/journal.c===================================================================--- linux-2.6.18.8.orig/fs/jbd/journal.c+++ linux-2.6.18.8/fs/jbd/journal.c@@ -67,6 +67,7 @@ EXPORT_SYMBOL(journal_update_format); EXPORT_SYMBOL(journal_check_used_features); EXPORT_SYMBOL(journal_check_available_features); EXPORT_SYMBOL(journal_set_features);+EXPORT_SYMBOL(journal_clear_features); EXPORT_SYMBOL(journal_create); EXPORT_SYMBOL(journal_load); EXPORT_SYMBOL(journal_destroy);@@ -1573,6 +1574,33 @@ int journal_set_features (journal_t *jou return 1; } +/**+ * int journal_clear_features () - Clear a given journal feature in the superblock+ * @journal: Journal to act on.+ * @compat: bitmask of compatible features+ * @ro: bitmask of features that force read-only mount+ * @incompat: bitmask of incompatible features+ *+ * Clear a given journal feature as present on the+ * superblock. Returns true if the requested features could be reset.+ *+ */+int journal_clear_features (journal_t *journal, unsigned long compat,+ unsigned long ro, unsigned long incompat)+{+ journal_superblock_t *sb;++ jbd_debug(1, "Clear features 0x%lx/0x%lx/0x%lx\n",+ compat, ro, incompat);++ sb = journal->j_superblock;++ sb->s_feature_compat &= ~cpu_to_be32(compat);+ sb->s_feature_ro_compat &= ~cpu_to_be32(ro);+ sb->s_feature_incompat &= ~cpu_to_be32(incompat);++ return 1;+} /** * int journal_update_format () - Update on-disk journal structure.Index: linux-2.6.18.8/fs/Kconfig===================================================================--- linux-2.6.18.8.orig/fs/Kconfig+++ linux-2.6.18.8/fs/Kconfig@@ -140,6 +140,7 @@ config EXT3_FS_SECURITY config JBD tristate+ select CRC32 help This is a generic journaling layer for block devices. It is currently used by the ext3 and OCFS2 file systems, but it couldIndex: linux-2.6.18.8/Documentation/filesystems/ext3.txt===================================================================--- linux-2.6.18.8.orig/Documentation/filesystems/ext3.txt+++ linux-2.6.18.8/Documentation/filesystems/ext3.txt@@ -14,6 +14,16 @@ Options When mounting an ext3 filesystem, the following option are accepted: (*) == default +journal_checksum Enable checksumming of the journal transactions.+ This will allow the recovery code in e2fsck and the+ kernel to detect corruption in the kernel. It is a+ compatible change and will be ignored by older kernels.++journal_async_commit Commit block can be written to disk without waiting+ for descriptor blocks. If enabled older kernels cannot+ mount the device. This will enable 'journal_checksum'+ internally.+ journal=update Update the ext3 file system's journal to the current format.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -