diff options
Diffstat (limited to 'fs/jbd2/journal.c')
-rw-r--r-- | fs/jbd2/journal.c | 132 |
1 files changed, 130 insertions, 2 deletions
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index 1afb701622b0..e9a3c4c85594 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c | |||
@@ -97,6 +97,43 @@ EXPORT_SYMBOL(jbd2_inode_cache); | |||
97 | static void __journal_abort_soft (journal_t *journal, int errno); | 97 | static void __journal_abort_soft (journal_t *journal, int errno); |
98 | static int jbd2_journal_create_slab(size_t slab_size); | 98 | static int jbd2_journal_create_slab(size_t slab_size); |
99 | 99 | ||
100 | /* Checksumming functions */ | ||
101 | int jbd2_verify_csum_type(journal_t *j, journal_superblock_t *sb) | ||
102 | { | ||
103 | if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2)) | ||
104 | return 1; | ||
105 | |||
106 | return sb->s_checksum_type == JBD2_CRC32C_CHKSUM; | ||
107 | } | ||
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 | |||
100 | /* | 137 | /* |
101 | * Helper function used to manage commit timeouts | 138 | * Helper function used to manage commit timeouts |
102 | */ | 139 | */ |
@@ -1348,6 +1385,7 @@ static void jbd2_journal_update_sb_errno(journal_t *journal) | |||
1348 | jbd_debug(1, "JBD2: updating superblock error (errno %d)\n", | 1385 | jbd_debug(1, "JBD2: updating superblock error (errno %d)\n", |
1349 | journal->j_errno); | 1386 | journal->j_errno); |
1350 | 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); | ||
1351 | read_unlock(&journal->j_state_lock); | 1389 | read_unlock(&journal->j_state_lock); |
1352 | 1390 | ||
1353 | jbd2_write_superblock(journal, WRITE_SYNC); | 1391 | jbd2_write_superblock(journal, WRITE_SYNC); |
@@ -1376,6 +1414,9 @@ static int journal_get_superblock(journal_t *journal) | |||
1376 | } | 1414 | } |
1377 | } | 1415 | } |
1378 | 1416 | ||
1417 | if (buffer_verified(bh)) | ||
1418 | return 0; | ||
1419 | |||
1379 | sb = journal->j_superblock; | 1420 | sb = journal->j_superblock; |
1380 | 1421 | ||
1381 | err = -EINVAL; | 1422 | err = -EINVAL; |
@@ -1413,6 +1454,43 @@ static int journal_get_superblock(journal_t *journal) | |||
1413 | goto out; | 1454 | goto out; |
1414 | } | 1455 | } |
1415 | 1456 | ||
1457 | if (JBD2_HAS_COMPAT_FEATURE(journal, JBD2_FEATURE_COMPAT_CHECKSUM) && | ||
1458 | JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V2)) { | ||
1459 | /* Can't have checksum v1 and v2 on at the same time! */ | ||
1460 | printk(KERN_ERR "JBD: Can't enable checksumming v1 and v2 " | ||
1461 | "at the same time!\n"); | ||
1462 | goto out; | ||
1463 | } | ||
1464 | |||
1465 | if (!jbd2_verify_csum_type(journal, sb)) { | ||
1466 | printk(KERN_ERR "JBD: Unknown checksum type\n"); | ||
1467 | goto out; | ||
1468 | } | ||
1469 | |||
1470 | /* Load the checksum driver */ | ||
1471 | if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V2)) { | ||
1472 | journal->j_chksum_driver = crypto_alloc_shash("crc32c", 0, 0); | ||
1473 | if (IS_ERR(journal->j_chksum_driver)) { | ||
1474 | printk(KERN_ERR "JBD: Cannot load crc32c driver.\n"); | ||
1475 | err = PTR_ERR(journal->j_chksum_driver); | ||
1476 | journal->j_chksum_driver = NULL; | ||
1477 | goto out; | ||
1478 | } | ||
1479 | } | ||
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 | |||
1492 | set_buffer_verified(bh); | ||
1493 | |||
1416 | return 0; | 1494 | return 0; |
1417 | 1495 | ||
1418 | out: | 1496 | out: |
@@ -1564,6 +1642,8 @@ int jbd2_journal_destroy(journal_t *journal) | |||
1564 | iput(journal->j_inode); | 1642 | iput(journal->j_inode); |
1565 | if (journal->j_revoke) | 1643 | if (journal->j_revoke) |
1566 | jbd2_journal_destroy_revoke(journal); | 1644 | jbd2_journal_destroy_revoke(journal); |
1645 | if (journal->j_chksum_driver) | ||
1646 | crypto_free_shash(journal->j_chksum_driver); | ||
1567 | kfree(journal->j_wbuf); | 1647 | kfree(journal->j_wbuf); |
1568 | kfree(journal); | 1648 | kfree(journal); |
1569 | 1649 | ||
@@ -1653,6 +1733,10 @@ int jbd2_journal_check_available_features (journal_t *journal, unsigned long com | |||
1653 | int jbd2_journal_set_features (journal_t *journal, unsigned long compat, | 1733 | int jbd2_journal_set_features (journal_t *journal, unsigned long compat, |
1654 | unsigned long ro, unsigned long incompat) | 1734 | unsigned long ro, unsigned long incompat) |
1655 | { | 1735 | { |
1736 | #define INCOMPAT_FEATURE_ON(f) \ | ||
1737 | ((incompat & (f)) && !(sb->s_feature_incompat & cpu_to_be32(f))) | ||
1738 | #define COMPAT_FEATURE_ON(f) \ | ||
1739 | ((compat & (f)) && !(sb->s_feature_compat & cpu_to_be32(f))) | ||
1656 | journal_superblock_t *sb; | 1740 | journal_superblock_t *sb; |
1657 | 1741 | ||
1658 | if (jbd2_journal_check_used_features(journal, compat, ro, incompat)) | 1742 | if (jbd2_journal_check_used_features(journal, compat, ro, incompat)) |
@@ -1661,16 +1745,54 @@ int jbd2_journal_set_features (journal_t *journal, unsigned long compat, | |||
1661 | if (!jbd2_journal_check_available_features(journal, compat, ro, incompat)) | 1745 | if (!jbd2_journal_check_available_features(journal, compat, ro, incompat)) |
1662 | return 0; | 1746 | return 0; |
1663 | 1747 | ||
1748 | /* Asking for checksumming v2 and v1? Only give them v2. */ | ||
1749 | if (incompat & JBD2_FEATURE_INCOMPAT_CSUM_V2 && | ||
1750 | compat & JBD2_FEATURE_COMPAT_CHECKSUM) | ||
1751 | compat &= ~JBD2_FEATURE_COMPAT_CHECKSUM; | ||
1752 | |||
1664 | jbd_debug(1, "Setting new features 0x%lx/0x%lx/0x%lx\n", | 1753 | jbd_debug(1, "Setting new features 0x%lx/0x%lx/0x%lx\n", |
1665 | compat, ro, incompat); | 1754 | compat, ro, incompat); |
1666 | 1755 | ||
1667 | sb = journal->j_superblock; | 1756 | sb = journal->j_superblock; |
1668 | 1757 | ||
1758 | /* If enabling v2 checksums, update superblock */ | ||
1759 | if (INCOMPAT_FEATURE_ON(JBD2_FEATURE_INCOMPAT_CSUM_V2)) { | ||
1760 | sb->s_checksum_type = JBD2_CRC32C_CHKSUM; | ||
1761 | sb->s_feature_compat &= | ||
1762 | ~cpu_to_be32(JBD2_FEATURE_COMPAT_CHECKSUM); | ||
1763 | |||
1764 | /* Load the checksum driver */ | ||
1765 | if (journal->j_chksum_driver == NULL) { | ||
1766 | journal->j_chksum_driver = crypto_alloc_shash("crc32c", | ||
1767 | 0, 0); | ||
1768 | if (IS_ERR(journal->j_chksum_driver)) { | ||
1769 | printk(KERN_ERR "JBD: Cannot load crc32c " | ||
1770 | "driver.\n"); | ||
1771 | journal->j_chksum_driver = NULL; | ||
1772 | return 0; | ||
1773 | } | ||
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)); | ||
1782 | } | ||
1783 | |||
1784 | /* If enabling v1 checksums, downgrade superblock */ | ||
1785 | if (COMPAT_FEATURE_ON(JBD2_FEATURE_COMPAT_CHECKSUM)) | ||
1786 | sb->s_feature_incompat &= | ||
1787 | ~cpu_to_be32(JBD2_FEATURE_INCOMPAT_CSUM_V2); | ||
1788 | |||
1669 | sb->s_feature_compat |= cpu_to_be32(compat); | 1789 | sb->s_feature_compat |= cpu_to_be32(compat); |
1670 | sb->s_feature_ro_compat |= cpu_to_be32(ro); | 1790 | sb->s_feature_ro_compat |= cpu_to_be32(ro); |
1671 | sb->s_feature_incompat |= cpu_to_be32(incompat); | 1791 | sb->s_feature_incompat |= cpu_to_be32(incompat); |
1672 | 1792 | ||
1673 | return 1; | 1793 | return 1; |
1794 | #undef COMPAT_FEATURE_ON | ||
1795 | #undef INCOMPAT_FEATURE_ON | ||
1674 | } | 1796 | } |
1675 | 1797 | ||
1676 | /* | 1798 | /* |
@@ -1975,10 +2097,16 @@ int jbd2_journal_blocks_per_page(struct inode *inode) | |||
1975 | */ | 2097 | */ |
1976 | size_t journal_tag_bytes(journal_t *journal) | 2098 | size_t journal_tag_bytes(journal_t *journal) |
1977 | { | 2099 | { |
2100 | journal_block_tag_t tag; | ||
2101 | size_t x = 0; | ||
2102 | |||
2103 | if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V2)) | ||
2104 | x += sizeof(tag.t_checksum); | ||
2105 | |||
1978 | if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_64BIT)) | 2106 | if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_64BIT)) |
1979 | return JBD2_TAG_SIZE64; | 2107 | return x + JBD2_TAG_SIZE64; |
1980 | else | 2108 | else |
1981 | return JBD2_TAG_SIZE32; | 2109 | return x + JBD2_TAG_SIZE32; |
1982 | } | 2110 | } |
1983 | 2111 | ||
1984 | /* | 2112 | /* |