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 | /* |
