diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/jbd2/journal.c | 47 |
1 files changed, 47 insertions, 0 deletions
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index f04ab6c4b428..9072f03d30b5 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c | |||
@@ -106,6 +106,34 @@ int jbd2_verify_csum_type(journal_t *j, journal_superblock_t *sb) | |||
106 | return sb->s_checksum_type == JBD2_CRC32C_CHKSUM; | 106 | return sb->s_checksum_type == JBD2_CRC32C_CHKSUM; |
107 | } | 107 | } |
108 | 108 | ||
109 | static __u32 jbd2_superblock_csum(journal_t *j, journal_superblock_t *sb) | ||
110 | { | ||
111 | __u32 csum, old_csum; | ||
112 | |||
113 | old_csum = sb->s_checksum; | ||
114 | sb->s_checksum = 0; | ||
115 | csum = jbd2_chksum(j, ~0, (char *)sb, sizeof(journal_superblock_t)); | ||
116 | sb->s_checksum = old_csum; | ||
117 | |||
118 | return cpu_to_be32(csum); | ||
119 | } | ||
120 | |||
121 | int jbd2_superblock_csum_verify(journal_t *j, journal_superblock_t *sb) | ||
122 | { | ||
123 | if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2)) | ||
124 | return 1; | ||
125 | |||
126 | return sb->s_checksum == jbd2_superblock_csum(j, sb); | ||
127 | } | ||
128 | |||
129 | void jbd2_superblock_csum_set(journal_t *j, journal_superblock_t *sb) | ||
130 | { | ||
131 | if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2)) | ||
132 | return; | ||
133 | |||
134 | sb->s_checksum = jbd2_superblock_csum(j, sb); | ||
135 | } | ||
136 | |||
109 | /* | 137 | /* |
110 | * Helper function used to manage commit timeouts | 138 | * Helper function used to manage commit timeouts |
111 | */ | 139 | */ |
@@ -1357,6 +1385,7 @@ static void jbd2_journal_update_sb_errno(journal_t *journal) | |||
1357 | jbd_debug(1, "JBD2: updating superblock error (errno %d)\n", | 1385 | jbd_debug(1, "JBD2: updating superblock error (errno %d)\n", |
1358 | journal->j_errno); | 1386 | journal->j_errno); |
1359 | sb->s_errno = cpu_to_be32(journal->j_errno); | 1387 | sb->s_errno = cpu_to_be32(journal->j_errno); |
1388 | jbd2_superblock_csum_set(journal, sb); | ||
1360 | read_unlock(&journal->j_state_lock); | 1389 | read_unlock(&journal->j_state_lock); |
1361 | 1390 | ||
1362 | jbd2_write_superblock(journal, WRITE_SYNC); | 1391 | jbd2_write_superblock(journal, WRITE_SYNC); |
@@ -1449,6 +1478,17 @@ static int journal_get_superblock(journal_t *journal) | |||
1449 | } | 1478 | } |
1450 | } | 1479 | } |
1451 | 1480 | ||
1481 | /* Check superblock checksum */ | ||
1482 | if (!jbd2_superblock_csum_verify(journal, sb)) { | ||
1483 | printk(KERN_ERR "JBD: journal checksum error\n"); | ||
1484 | goto out; | ||
1485 | } | ||
1486 | |||
1487 | /* Precompute checksum seed for all metadata */ | ||
1488 | if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V2)) | ||
1489 | journal->j_csum_seed = jbd2_chksum(journal, ~0, sb->s_uuid, | ||
1490 | sizeof(sb->s_uuid)); | ||
1491 | |||
1452 | set_buffer_verified(bh); | 1492 | set_buffer_verified(bh); |
1453 | 1493 | ||
1454 | return 0; | 1494 | return 0; |
@@ -1732,6 +1772,13 @@ int jbd2_journal_set_features (journal_t *journal, unsigned long compat, | |||
1732 | return 0; | 1772 | return 0; |
1733 | } | 1773 | } |
1734 | } | 1774 | } |
1775 | |||
1776 | /* Precompute checksum seed for all metadata */ | ||
1777 | if (JBD2_HAS_INCOMPAT_FEATURE(journal, | ||
1778 | JBD2_FEATURE_INCOMPAT_CSUM_V2)) | ||
1779 | journal->j_csum_seed = jbd2_chksum(journal, ~0, | ||
1780 | sb->s_uuid, | ||
1781 | sizeof(sb->s_uuid)); | ||
1735 | } | 1782 | } |
1736 | 1783 | ||
1737 | /* If enabling v1 checksums, downgrade superblock */ | 1784 | /* If enabling v1 checksums, downgrade superblock */ |